Linux Kernel Driver Program: 11_waitqueue_dynamic_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;

dev_t dev = 0;
static struct class *dev_class;
static struct cdev dummy_cdev;
wait_queue_head_t wait_queue_dummy;
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 'neel_WtThread' */
        wait_thread = kthread_create(wait_function, NULL, "neel_WtThread");
        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("0:1.0");

neelkanth_surekha#cat Makefile 

obj-m += driver.o

KDIR = /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