Correct way to initialize semaphore in linux driver - c

I wrote this linux char driver just to control open call,
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/init.h>
#include <linux/fs.h>
#include <linux/uaccess.h>
#include <linux/semaphore.h>
#include <linux/device.h>
#include <linux/cdev.h>
MODULE_LICENSE("GPL");
#define CLASS_NAME "myclass"
#define MINOR_NUM 0
#define MINOR_CNT 1
static struct class *myclass=NULL;
static struct device *mydevice=NULL;
static dev_t mycdevt;
static struct cdev *mycdev;
static struct semaphore *sem;
static int myopen(struct inode *inod, struct file *fp)
{
down(sem);
printk(KERN_INFO "critical section\n");
return 0;
}
static int myclose(struct inode *inod, struct file *fp )
{
up(sem);
printk(KERN_INFO "critical section freed\n");
return 0;
}
static ssize_t myread(struct file *fp, char *buf, size_t len, loff_t *off)
{
return 0;
}
static ssize_t mywrite(struct file *fp, char *buf, size_t len, loff_t *off)
{
return 0;
}
static struct file_operations fops =
{
.open = myopen,
.release = myclose,
.read = myread,
.write = mywrite,
};
static int __init myinit(void)
{
int ret;
ret = alloc_chrdev_region ( &mycdevt, MINOR_NUM, MINOR_CNT, "mycdevt");
if(ret<0)
{
printk(KERN_INFO "chardev can't be allocated\n");
// goto label;//todo
}
mycdev = cdev_alloc();//instead of cdev_alloc, we can use cdev_init(&mycdev, &fops);
if(mycdev == NULL)
{
printk(KERN_INFO"cdev_alloc failed\n");
// goto label;//todo
}
mycdev->ops = &fops;
ret = cdev_add(mycdev, mycdevt, 1);
if(ret < 0)
{
printk(KERN_INFO"cdev_add failed\n");
// goto label;//todo
}
myclass = class_create(THIS_MODULE, CLASS_NAME);
if(myclass == NULL)
{
printk(KERN_INFO"class create failed\n");
// goto label;//todo
}
mydevice = device_create(myclass, NULL, mycdevt, NULL, "mydevice");
if(mydevice == NULL)
{
printk(KERN_INFO"device create failed\n");
// goto label;//todo
}
sema_init(sem, 1);//here is the problem
printk(KERN_INFO"myinit done\n");
return 0;
}
static void __exit myexit(void)
{
device_destroy(myclass, mycdevt);
class_unregister(myclass);
class_destroy(myclass);
cdev_del(mycdev);
unregister_chrdev(MAJOR(mycdevt), "mycdevt");
printk(KERN_INFO "exited\n");
}
module_init(myinit);
module_exit(myexit);
I am following ldd3 book, and tried to use simple APIs to use semahore for an app.
What happened is my kernel crashed when it called sema_init function. I read that semaphore is used in mutex mode
http://www.makelinux.net/ldd3/chp-5-sect-3
I also read that semaphore is not a mutex as there is no ownership. I have yet to explore that 'ownership' thing, but for now I am not able to make a simple semaphore.
What wrong I am doing here?

There's no actual semaphore.
This line:
static struct semaphore *sem;
creates a pointer to a semaphore, not a semaphore itself. It's almost certain initialized to NULL.
You probably want something like
static struct semaphore sem;
and therefore
sema_init( &sem, 1);
along with
up( &sem );
and
down( &sem );
Note that these calls are taking the address of an actual semaphore.

Related

my machine crashes after inserting the following kernel module

I am a total beginner in kernel module programming. I wanted to create a module which reads input from the proc filesystem. With this you should be able to perform operations in the program. I did that with threading. However my machine crashes after inserting the module. Probably I did something wrong. Here is the source code:
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/proc_fs.h>
#include <linux/uaccess.h>
#include <linux/sched.h>
#include <linux/kthread.h>
#include <linux/wait.h>
#include <linux/string.h>
#define PROCFS_MAX_SIZE 1024
#define PROCFS_NAME "test"
MODULE_LICENSE("GPL");
int pid = 1;
static struct proc_dir_entry *Our_Proc_File;
static char procfs_buffer[PROCFS_MAX_SIZE];
static unsigned long procfs_buffer_size = 0;
struct task_struct *task;
static ssize_t procfile_read(struct file *file, char *buffer, size_t buffer_length, loff_t *offset) {
static int flag = 0;
if(flag) {
printk(KERN_INFO "read : END\n");
flag = 0;
return 0;
}
printk(KERN_INFO "read (/proc/%s) : called\n",PROCFS_NAME);
flag = 1;
return snprintf(buffer, buffer_lengh, procfs_buffer);
}
static ssize_t procfile_write(struct file *file,const char *buffer, size_t count, loff_t *offset) {
procfs_buffer_size = count;
if (copy_from_user(procfs_buffer, buffer, procfs_buffer_size)) {
return -EFAULT;
}
return procfs_buffer_size;
}
static int main_prog(void *data) {
int end = 0;
while(!end) {
while(memcmp(procfs_buffer,"\x00",1)==0);
if(memcmp(procfs_buffer,"test",4)) {
printk(KERN_INFO "Test triggered!\n");
}
if(memcmp(procfs_buffer,"exit",4)) {
end++;
}
memset(procfs_buffer, 0, 1024);
}
kthread_stop(task);
}
static struct file_operations fops_struct = {
.read = procfile_read,
.write = procfile_write,
};
int init_module() {
Our_Proc_File = proc_create(PROCFS_NAME, 0666, NULL, &fops_struct);
if (Our_Proc_File == NULL) {
remove_proc_entry(PROCFS_NAME, NULL);
printk(KERN_ALERT "Error: Could not initialize /proc/%s\n", PROCFS_NAME);
return -ENOMEM;
}
task = kthread_run(&main_prog, NULL, "thread");
wake_up_process(task);
printk(KERN_INFO "/proc/%s created\n", PROCFS_NAME);
return 0;
}
void cleanup_module() {
remove_proc_entry(PROCFS_NAME, NULL);
printk(KERN_INFO "/proc/%s removed\n", PROCFS_NAME);
}
Can someone help me?

Character device I/O across users

I'm learning Linux and I have the task that I can't handle. I have to create character device and make possible to read and write across users. For instance, I open first terminal and I use echo 'test' > /tmp/ringdev (where ringdev is my character device). I also open second terminal and I use cat /tmp/ringdev and I expect that output will be test. I have already read some example snippets, but all of them are just about the basics which I already have.
The question is how to read from / write to character device across users?
#define pr_fmt(fmt) "ringdev: " fmt
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/fs.h>
#include <linux/miscdevice.h>
#include <linux/sched.h>
#include <linux/uaccess.h>
#include <linux/wait.h>
#include <linux/sched.h>
DECLARE_WAIT_QUEUE_HEAD(head);
/*
* mutex used for access synchronization to buffer (ringdev_buf and ringdev_len)
*/
static struct mutex ringdev_lock;
/*
* buffer and number of written bytes in the buffer
*/
static char ringdev_buf[4096];
static size_t ringdev_len;
static int ringdev_open(struct inode *inode, struct file *filp)
{
printk("device_open called \n");
return 0;
}
static ssize_t ringdev_read(struct file *filp, char __user *buf, size_t count,
loff_t *off)
{
ssize_t ret = 0;
printk("device_read called \n");
/*
* access to ringdev_buf i ringdev_len is protected by ringdev_lock,
* take that lock
*/
//wait_event_interruptible(head,ringdev_len!=0);
mutex_lock(&ringdev_lock);
if (*off > ringdev_len)
count = 0;
else if (count >= ringdev_len - *off)
count = ringdev_len - *off;
/*
* for access to user memory special functions must be used,
* to copy to user memory copy_to_user must be used.
*/
ret = -EFAULT;
if (copy_to_user(buf, ringdev_buf + *off, count))
goto out_unlock;
ret = count;
*off += ret;
out_unlock:
mutex_unlock(&ringdev_lock);
ringdev_len=0;
return ret;
}
static ssize_t ringdev_write(struct file *filp, const char __user *buf,
size_t count, loff_t *off)
{
ssize_t ret=0;
ringdev_len=0;
printk("device_write called \n");
mutex_lock(&ringdev_lock);
ret=-EFAULT;
if(copy_from_user(ringdev_buf+ringdev_len ,buf, count)==0){
ringdev_len= ringdev_len + count;
ret=count;
wake_up_interruptible(&head);
goto out_unlock;
}
else{
ret=-ENOSPC;
}
/*
* not supported yet. Do not forget about copy_from_user().
*/
out_unlock:
mutex_unlock(&ringdev_lock);
return ret;
}
static int ringdev_release(struct inode *inode, struct file *filp)
{
mutex_unlock(&ringdev_lock);
printk("device_release called \n");
return 0;
}
static const struct file_operations ringdev_fops = {
.owner = THIS_MODULE,
.open = ringdev_open,
.read = ringdev_read,
.write = ringdev_write,
.release = ringdev_release,
};
static struct miscdevice ringdev_miscdevice = {
.minor = MISC_DYNAMIC_MINOR,
.name = "ringdev",
.fops = &ringdev_fops
};
static int __init ringdev_init(void)
{
int ret;
mutex_init(&ringdev_lock);
ret = misc_register(&ringdev_miscdevice);
if (ret < 0) {
pr_err("can't register miscdevice.\n");
return ret;
}
pr_info("minor %d\n", ringdev_miscdevice.minor);
return 0;
}
static void __exit ringdev_exit(void)
{
misc_deregister(&ringdev_miscdevice);
mutex_destroy(&ringdev_lock);
}
module_init(ringdev_init);
module_exit(ringdev_exit);
MODULE_DESCRIPTION("Device");
MODULE_AUTHOR("xxx");
MODULE_LICENSE("GPL");

How to send signal from Linux kernel space to user space in order to notify about an input hardware event

My kernel module code needs to send signal to a user land program, to transfer its execution to registered signal handler.
In fact, I have developed a C program for my embedded board which make LED turns on and off when I push BUTTON ( the input event ). On the other hand, I have just developed a simple Linux module with its basic functions ( OPEN, CLOSE, READ, WRITE ).
I just don't have any idea how to modify my principal program and my kernel module in order to arrive to my objective.
I share with you my user space program :
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <string.h>
#include <sys/select.h>
#include <sys/time.h>
#include <errno.h>
#include <linux/input.h>
#define BTN_FILE_PATH "/dev/input/event0"
#define LED_PATH "/sys/class/leds"
#define green "green"
void change_led_state(char *led_path, int led_value)
{
char lpath[64];
FILE *led_fd;
strncpy(lpath, led_path, sizeof(lpath) - 1);
lpath[sizeof(lpath) - 1] = '\0';
led_fd = fopen(lpath, "w");
if (led_fd == NULL) {
fprintf(stderr, "simplekey: unable to access led\n");
return;
}
fprintf(led_fd, "%d\n", led_value);
fclose(led_fd);
}
void reset_leds(void)
{
change_led_state(LED_PATH "/" green "/brightness", 0);
}
int configure_leds(void)
{
FILE *r_fd;
char *none_str = "none";
/* Configure leds for hand control */
r_fd = fopen(LED_PATH "/" green "/trigger", "w");
fprintf(r_fd, "%s\n", none_str);
fclose(r_fd);
/* Switch off leds */
reset_leds();
return 0;
}
void eval_keycode(int code)
{
static int green_state = 0;
switch (code) {
case 260:
printf("BTN left pressed\n");
/* figure out green state */
green_state = green_state ? 0 : 1;
change_led_state(LED_PATH "/" green "/brightness", green_state);
break;
}
}
int main(void)
{
int file;
/* how many bytes were read */
size_t rb;
int ret;
int yalv;
/* the events (up to 64 at once) */
struct input_event ev[64];
char *str = BTN_FILE_PATH;
printf("Starting simplekey app\n");
ret = configure_leds();
if (ret < 0)
exit(1);
printf("File Path: %s\n", str);
if((file = open(str, O_RDONLY)) < 0) {
perror("simplekey: File can not open");
exit(1);
}
for (;;) {
/* Blocking read */
rb= read(file, &ev, sizeof(ev));
if (rb < (int) sizeof(struct input_event)) {
perror("simplekey: short read");
exit(1);
}
for (yalv = 0;
yalv < (int) (rb / sizeof(struct input_event));
yalv++) {
if (ev[yalv].type == EV_KEY) {
printf("%ld.%06ld ",
ev[yalv].time.tv_sec,
ev[yalv].time.tv_usec);
printf("type %d code %d value %d\n",
ev[yalv].type,
ev[yalv].code, ev[yalv].value);
/* Change state on button pressed */
if (ev[yalv].value == 0)
eval_keycode(ev[yalv].code);
}
}
}
close(file);
And this is the basic kernel module :
#include <linux/init.h>
#include <linux/module.h>
#include <linux/fs.h>
#include <linux/device.h>
#include <linux/kernel.h>
#include <linux/uaccess.h>
#include <linux/input.h>
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Gaston");
MODULE_DESCRIPTION("A simple Linux char driver");
MODULE_VERSION("0.1");
ssize_t exer_open(struct inode *pinode, struct file *pfile) {
printk(KERN_INFO "Device has been opened\n");
return 0;
}
ssize_t exer_read(struct file *pfile, char __user *buffer, size_t length, loff_t *offset) {
return 0;
}
ssize_t exer_write(struct file *pfile, const char __user *buffer, size_t length, loff_t *offset) {
return 0;
}
ssize_t exer_close(struct inode *pinode, struct file *pfile) {
printk(KERN_INFO "Device successfully closed\n");
return 0;
}
struct file_operations exer_file_operations = {
.owner = THIS_MODULE,
.open = exer_open,
.read = exer_read,
.write = exer_write,
.release = exer_close,
};
int exer_simple_module_init(void) {
printk(KERN_INFO "Initializing the LKM\n");
register_chrdev(240, "Simple Char Drv", &exer_file_operations);
return 0;
}
void exer_simple_module_exit(void) {
unregister_chrdev(240, "Simple Char Drv");
}
module_init(exer_simple_module_init);
module_exit(exer_simple_module_exit);
I hope you will help me. Thank you!
I will concentrate on sending a signal, since that is what you asked for, although sending signals to a process is quite brutal. It would be better to implement poll and read file operations so the user code can wait for events from the device and read them.
Anyway, for sending a signal to the processes that opened the device, the things you need are:
You need a struct fasync_struct * in the private data of your device:
struct fasync_struct *pasync_queue;
It needs to be initialized to NULL by some means during initialization of your device private data. How you do that is up to you.
You need a fasync file operation handler pointed to by the fasync member of your struct file_operations. The implementation of the fasync handler is very simple as it just needs to call fasync_helper() using supplied parameters and a pointer to your device's private struct fasync_struct *:
static int exer_fasync(int fd, struct file *pfile, int mode)
{
// N.B. Change this code to use the pasync_queue member from your device private data.
struct fasync_struct **fapp = &pasync_queue;
return fasync_helper(fd, pfile, mode, fapp);
}
struct file_operations exer_file_operations = {
.owner = THIS_MODULE,
.open = exer_open,
.read = exer_read,
.write = exer_write,
.release = exer_close,
.fasync = exer_fasync,
};
Your device driver can send a SIGIO signal by calling kill_fasync() as follows:
// N.B. Change this code to use the pasync_queue member from your device private data.
struct fasync_struct **fapp = &pasync_queue;
kill_fasync(fapp, SIGIO, POLL_IN);
N.B. The last parameter (value POLL_IN in this case) affects the value of the si_band member of the siginfo_t that your application sees in its signal handler.
Your application needs to set a signal handler for the SIGIO signal. I recommend usingsigaction() to set this up.
Your application needs to set the O_ASYNC flag when it opens the device file, or set it by calling fcntl(fd, F_SETFL, O_ASYNC); after opening the device file.

use copy_to_user fail in timer handler function,why?

If I use copy_to_user in ioctl function, i can copy the data to the user space, but if I put the copy_to_user into the timeout handler function, copy_to_user can not be successful. Why?
#include <linux/init.h>
...
#define GLOBAL_MEMSIZE 0x1000//4K
...
static struct timer_list mytimer;
...
typedef struct globalmem_dev{
struct cdev cdev;
unsigned char mem[GLOBAL_MEMSIZE];
} Glo_dev, *Pglo_dev;
Pglo_dev globalmem_devp;//global pointer
If I put copy_to_user in here, I can not copy the data to user correctly
/*Timeout handler function*/
static void timer_func(unsigned long data)
{
int retc = 0;
retc = copy_to_user((void __user *)data, globalmem_devp->mem, 8);
if(retc)
{
printk("timer_func------->copy_to_user fail\n");
}
mod_timer(&mytimer, jiffies + 2*HZ);
}
/*file open function*/
static int hello_open(struct inode *inode, struct file *file)
{
printk("hello open!\n");
file->private_data = globalmem_devp;
return 0;
}
/*file close function*/
static int hello_release(struct inode *inode, struct file *file)
{
del_timer_sync(&mytimer);
printk("hello closed\n");
return 0;
}
The copy_to_user work fine in the ioctl function
/*ioctl*/
static long int globalmem_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
{
/*if(copy_to_user((void __user *)arg, globlmem_devp->mem, 8))
{
printk("copy_to_user fial\n");
}*/
setup_timer(&mytimer, timer_func, arg);
mytimer.expires = jiffies + HZ;
add_timer(&mytimer);
return 0;
}
static struct file_operations hello_ops = {
...
};
/*init function*/
static int __init hello_init(void)
{
...
globalmem_devp = kmalloc(sizeof(Glo_dev), GFP_KERNEL);//
if(NULL == globalmem_devp)
{
return -ENOMEM;
}
...
return 0;
}
static void __exit hello_exit(void)
{
...
}
MODULE_LICENSE("GPL");
MODULE_AUTHOR("test");
module_init(hello_init);
module_exit(hello_exit);
copy_to_user() copies the data into the memory of the current user-space process, so it can be used only in some code that has been called from such a process.
An interrupt handler can run at any time, so there might be no current process, or worse, the current process is some other process.

Write timer in Linux device driver

I'm newbies with the module linux.
I try to create a counter module where the counter is increment on timer callback.
The result of the counter must be send to an other module (a memory module).
#include <linux/init.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/slab.h>
#include <linux/fs.h>
#include <linux/errno.h>
#include <linux/types.h>
#include <linux/proc_fs.h>
#include <linux/fcntl.h>
#include <asm/system.h>
#include <asm/uaccess.h>
MODULE_AUTHOR("Helene");
MODULE_DESCRIPTION("Module memory");
MODULE_SUPPORTED_DEVICE("none");
MODULE_LICENSE("Dual BSD/GPL");
/* Global variables of the driver */
/* Buffer to store data */
char *memory_buffer;
int result;
struct file_operations memory_fops;
int memory_open(struct inode *inode, struct file *filp) {
// printk(KERN_DEBUG "Opening memory module\n");
return 0;
}
int memory_release(struct inode *inode, struct file *filp) {
// printk(KERN_DEBUG "Releasing of memory module\n");
return 0;
}
ssize_t memory_read(struct file *filp, char *buf, size_t count, loff_t *f_pos){
// printk(KERN_DEBUG "Reading memory module : %s\n", buf);
if (*f_pos > 0)
return 0;
if (count > strlen(memory_buffer))
count = strlen(memory_buffer);
copy_to_user(buf,memory_buffer,count);
*f_pos = *f_pos + count;
return count;
}
ssize_t memory_write( struct file *filp, const char *buf, size_t count, loff_t *f_pos) {
// printk(KERN_DEBUG "Writing memory module : %s\n", buf);
copy_from_user(memory_buffer, buf, count);
return count;
}
static int __init memory_init(void) {
/* Registering device */
result = register_chrdev(0, "memory", &memory_fops);
if (result < 0) {
printk(KERN_DEBUG "memory: cannot obtain major number \n");
return result;
}
/* Allocating memory for the buffer */
memory_buffer = kmalloc(1, GFP_KERNEL);
if (!memory_buffer) {
result = -ENOMEM;
goto fail;
}
memset(memory_buffer, 0, 1);
printk(KERN_ALERT "Inserting memory module : %d\n", result);
return 0;
fail:
//memory_exit();
return result;
}
static void __exit memory_exit(void) {
/* Freeing the major number */
unregister_chrdev(result, "memory");
/* Freeing buffer memory */
if (memory_buffer) {
kfree(memory_buffer);
}
printk(KERN_DEBUG "Removing memory module\n");
}
struct file_operations memory_fops = {
owner: THIS_MODULE,
read: memory_read,
write: memory_write,
open: memory_open,
release: memory_release
};
module_init(memory_init);
module_exit(memory_exit);
The memory module works. My problem is when I call the function : filp_open/fp->f_op->write/filp_close on the function timer callback.
I have test these functions out of the timer callback and it's work.
Why the filp_open function (& co) don't work on timer callback function ?
#include <linux/init.h>
#include <linux/module.h>
#include <linux/kernel.h> /* printk() */
#include <linux/slab.h> /* kmalloc() */
#include <linux/fs.h> /* everything... */
#include <linux/errno.h> /* error codes */
#include <linux/types.h> /* size_t */
#include <linux/proc_fs.h>
#include <linux/fcntl.h> /* O_ACCMODE */
#include <asm/system.h> /* cli(), *_flags */
#include <asm/uaccess.h> /* copy_from/to_user */
MODULE_LICENSE("GPL");
static struct timer_list my_timer;
int cptNbClic ;
int result;
struct file_operations timer_fops;
int write_file_system(struct file *fp, char * buf){
int nb;
mm_segment_t old_fs=get_fs();
set_fs(get_ds());
nb = fp->f_op->write(fp,buf ,10, &fp->f_pos);
set_fs(old_fs);
return nb;
}
void writeInMemory(void){
// printk(KERN_DEBUG "busy %d\n", busy);
int nbwrite;
char buf[3];
int fmemory;
fmemory=filp_open ("/dev/memory", O_WRONLY | O_APPEND | O_CREAT,0); //don't work on this function
if (fmemory==NULL){//verification de l'ouverture
printk(KERN_ALERT "filp_open error input memory!!.\n");
return -1;
}
sprintf(buf, "%d", cptNbClic);
printk(KERN_DEBUG "%d\n", cptNbClic);
nbwrite = write_file_system(fmemory, buf);
filp_close(fmemory, 0);
}
void my_timer_callback( unsigned long data )
{
cptNbClic++;
printk(KERN_DEBUG "cptNbClic %d\n", cptNbClic);
writeInMemory();
setup_timer(&my_timer, my_timer_callback, 0);
mod_timer(&my_timer, jiffies + msecs_to_jiffies(1000));
}
static int timer_open(struct inode *inode, struct file *filp) {
/* setup your timer to call my_timer_callback */
cptNbClic = 0;
setup_timer(&my_timer, my_timer_callback, 0);
/* setup timer interval to 200 msecs */
mod_timer(&my_timer, jiffies + msecs_to_jiffies(1000));
return 0;
}
static int timer_release(struct inode *inode, struct file *filp) {
/* Success */
printk(KERN_DEBUG "Releasing of cpt module\n");
del_timer(&my_timer);
return 0;
}
static int __init timer_init(void) {
/* Registering device */
result = register_chrdev(0, "timer", &timer_fops);
if (result < 0) {
printk(KERN_DEBUG "timer: cannot obtain major number \n");
return result;
}
printk(KERN_ALERT "Inserting timer module : %d\n", result);
return 0;
}
static void __exit timer_exit(void) {
unregister_chrdev(result, "timer");
printk(KERN_DEBUG "Removing timer module\n");
}
struct file_operations timer_fops = {
owner: THIS_MODULE,
open: timer_open,
release: timer_release
};
/* Declaration of the init and exit functions */
module_init(timer_init);
module_exit(timer_exit);
Sorry for my bad english
No need to call setup_timer function in your my_timer_callback().Already timer is setup. If you want a recurring timer then just again call mod_timer() in your handler which will updates your timer expire value and your timer happily runs again and again till del_timer() call.

Resources