Linux Kernel Driver Program: 8_IOCTL_Driver_code
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
User application will running on the user space and communicate to driver on kernel space.
neelkanth_surekha#cat driver.c
/** IOCTL is referred as Input and Output Control, which is used to talking to device drivers.
* This system call, available in most driver categories. The major use of this is in case
* of handling some specific operations of a device for which the kernel does not have a system
* call by default.
*
* Some real time applications of ioctl is Ejecting the media from a “cd” drive, to change the
* Baud Rate of Serial port, Adjust the Volume, Reading or Writing device registers, etc. We
* already have write and read function in our device driver. But it is not enough for all cases.
*/
#if 0
############################################################################################
There are many ways to Communicate between the User space and Kernel Space, they are:
############################################################################################
1. IOCTL
2. Procfs
3. Sysfs
4. Configfs
5. Debugfs
6. Sysctl
7. UDP Sockets
8. Netlink Sockets
#endif
/*****************************************************************************
* Steps involved in IOCTL
****************************************************************************
* 1. Create IOCTL command in driver
* 2. Write IOCTL function in driver
* 3. Create IOCTL command in User space application
* 4. Use IOCTL system call in User space
*/
#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/ioctl.h>
#define WR_VALUE _IOW('a','a',int32_t*)
#define RD_VALUE _IOR('a','b',int32_t*)
int32_t value = 0;
dev_t dev = 0;
static struct class *dev_class;
static struct cdev dummy_cdev;
static int __init dummy_driver_init(void);
static void __exit dummy_driver_exit(void);
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 long dummy_ioctl(struct file *file, unsigned int cmd, unsigned long arg);
static struct file_operations fops =
{
.owner = THIS_MODULE,
.read = dummy_read,
.write = dummy_write,
.open = dummy_open,
.unlocked_ioctl = dummy_ioctl,
.release = dummy_release,
};
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");
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 long dummy_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
{
switch(cmd) {
case WR_VALUE:
copy_from_user(&value ,(int32_t*) arg, sizeof(value));
printk(KERN_INFO "Value = %d\n", value);
break;
case RD_VALUE:
copy_to_user((int32_t*) arg, &value, sizeof(value));
break;
}
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;
}
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)
{
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.5");
neelkanth_surekha#cat test_app.c
#include <stdio.h>#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include<sys/ioctl.h>
#define WR_VALUE _IOW('a','a',int32_t*)
#define RD_VALUE _IOR('a','b',int32_t*)
int main()
{
int fd;
int32_t value, number;
printf("*********************************\n");
printf("\nOpening Driver\n");
fd = open("/dev/dummy_device", O_RDWR);
if(fd < 0) {
printf("Cannot open device file '/dev/dummy_device'\n");
return 0;
}
printf("Enter the Value to send\n");
scanf("%d",&number);
printf("Writing Value to Driver\n");
ioctl(fd, WR_VALUE, (int32_t*) &number);
printf("Reading Value from Driver\n");
ioctl(fd, RD_VALUE, (int32_t*) &value);
printf("Value is %d\n", value);
printf("Closing Driver\n");
close(fd);
}
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