Linux Kernel Driver Program: 10_waitqueue_static_Device_driver
neelkanth_surekha#cat Read\ me
This directory contains three files.
1.Driver
2.Make File
3.User Application
Driver is running on kernel space
Makefile is used to build the kernel linux device driver
neelkanth_surekha#cat driver.c
/* When you write a Linux Driver or Module or Kernel Program,* Some process should be wait or sleep for some event. There are
* several ways of handling sleeping and waking up in Linux, each
* suited to different needs.
*
* 'Waitqueue' also one of the method to handle that case.
*
* Whenever a process must wait for an event (such as the arrival of
* data or the termination of a process), it should go to sleep. Sleeping
* causes the process to suspend execution, freeing the processor for other
* uses. After some time, the process will be woken up and will continue with
* its job when the event which we are waiting will be occurred.
*
* Wait queue is a mechanism provided in kernel to implement the wait.
* As the name itself suggests, "wait queue" is the list of processes
* waiting for an event. In other words, A wait queue is used to wait for someone
* to wake you up when a certain condition is true. They must be used carefully
* to ensure there is no race condition.
**************************************************************************************
* There are 3 important steps in Waitqueue.
**************************************************************************************
* 1. Initializing Waitqueue
* 2. Queuing (Put the Task to sleep until the event comes)
* 3. Waking Up Queued Task
*/
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/module.h>
#include <linux/kdev_t.h>
#include <linux/fs.h>
#include <linux/cdev.h>
#include <linux/device.h>
#include <linux/slab.h> //kmalloc()
#include <linux/uaccess.h> //copy_to/from_user()
#include <linux/kthread.h>
#include <linux/wait.h> // Required for the wait queues
uint32_t read_count = 0;
static struct task_struct *wait_thread;
DECLARE_WAIT_QUEUE_HEAD(wait_queue_dummy);
dev_t dev = 0;
static struct class *dev_class;
static struct cdev dummy_cdev;
int wait_queue_flag = 0;
static int __init dummy_driver_init(void);
static void __exit dummy_driver_exit(void);
/*************** Driver Fuctions **********************/
static int dummy_open(struct inode *inode, struct file *file);
static int dummy_release(struct inode *inode, struct file *file);
static ssize_t dummy_read(struct file *filp, char __user *buf, size_t len,loff_t * off);
static ssize_t dummy_write(struct file *filp, const char *buf, size_t len, loff_t * off);
static struct file_operations fops =
{
.owner = THIS_MODULE,
.read = dummy_read,
.write = dummy_write,
.open = dummy_open,
.release = dummy_release,
};
static int wait_function(void *unused)
{
while(1) {
printk(KERN_INFO "Waiting For Event...\n");
wait_event_interruptible(wait_queue_dummy, wait_queue_flag != 0 );
if(wait_queue_flag == 2) {
printk(KERN_INFO "Event Came From Exit Function\n");
return 0;
}
printk(KERN_INFO "Event Came From Read Function - %d\n", ++read_count);
wait_queue_flag = 0;
}
return 0;
}
static int dummy_open(struct inode *inode, struct file *file)
{
printk(KERN_INFO "Device File Opened...!!!\n");
return 0;
}
static int dummy_release(struct inode *inode, struct file *file)
{
printk(KERN_INFO "Device File Closed...!!!\n");
return 0;
}
static ssize_t dummy_read(struct file *filp, char __user *buf, size_t len, loff_t *off)
{
printk(KERN_INFO "Read Function\n");
wait_queue_flag = 1;
wake_up_interruptible(&wait_queue_dummy);
return 0;
}
static ssize_t dummy_write(struct file *filp, const char __user *buf, size_t len, loff_t *off)
{
printk(KERN_INFO "Write function\n");
return 0;
}
static int __init dummy_driver_init(void)
{
/*Allocating Major number*/
if((alloc_chrdev_region(&dev, 0, 1, "dummy_Dev")) <0){
printk(KERN_INFO "Cannot allocate major number\n");
return -1;
}
printk(KERN_INFO "Major = %d Minor = %d \n",MAJOR(dev), MINOR(dev));
/*Creating cdev structure*/
cdev_init(&dummy_cdev,&fops);
dummy_cdev.owner = THIS_MODULE;
dummy_cdev.ops = &fops;
/*Adding character device to the system*/
if((cdev_add(&dummy_cdev,dev,1)) < 0){
printk(KERN_INFO "Cannot add the device to the system\n");
goto r_class;
}
/*Creating struct class*/
if((dev_class = class_create(THIS_MODULE,"dummy_class")) == NULL){
printk(KERN_INFO "Cannot create the struct class\n");
goto r_class;
}
/*Creating device*/
if((device_create(dev_class,NULL,dev,NULL,"dummy_device")) == NULL){
printk(KERN_INFO "Cannot create the Device 1\n");
goto r_device;
}
//Initialize wait queue
init_waitqueue_head(&wait_queue_dummy);
//Create the kernel thread with name 'mythread'
wait_thread = kthread_create(wait_function, NULL, "Neel_Wt_Thr");
if (wait_thread) {
printk("Thread Created successfully\n");
wake_up_process(wait_thread);
} else
printk(KERN_INFO "Thread creation failed\n");
printk(KERN_INFO "Device Driver Insert...Done!!!\n");
return 0;
r_device:
class_destroy(dev_class);
r_class:
unregister_chrdev_region(dev,1);
return -1;
}
void __exit dummy_driver_exit(void)
{
wait_queue_flag = 2;
wake_up_interruptible(&wait_queue_dummy);
device_destroy(dev_class,dev);
class_destroy(dev_class);
cdev_del(&dummy_cdev);
unregister_chrdev_region(dev, 1);
printk(KERN_INFO "Device Driver Remove...Done!!!\n");
}
module_init(dummy_driver_init);
module_exit(dummy_driver_exit);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Neelkanth Reddy <www.neelkanth.13@gmail.com>");
MODULE_DESCRIPTION("A simple device driver");
MODULE_VERSION("1.7");
neelkanth_surekha#cat Makefile
obj-m += driver.oKDIR = /lib/modules/$(shell uname -r)/build
#e.g. : make -C /lib/modules/4.4.0-93-generic/build M=/home/neelkanth_surekha/Device_Driver/8_IOCTL_Driver_code modules
all:
make -C $(KDIR) M=$(shell pwd) modules
clean:
make -C $(KDIR) M=$(shell pwd) clean