Linux Kernel Driver Program:12_sysfs_kernel_driver

Linux Kernel Driver Program:

12_sysfs_kernel_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 

/* 
 * Sysfs is a virtual filesystem exported by the kernel, similar to /proc. 
 * The files in Sysfs contain information about devices and drivers. Some 
 * files in Sysfs are even writable, for configuration and control of devices 
 * attached to the system. Sysfs is always mounted on /sys.
 * 
 * The directories in Sysfs contain the hierarchy of devices, 
 * as they are attached to the computer. 
 *
 * "Sysfs" is the commonly used method to export system information 
 * from the kernel space to the user space for specific devices. 
 * The "sysfs" is tied to the device driver model of the kernel. 
 * The "procfs" is used to export the process specific information 
 * and the "debugfs" is used to used for exporting the debug information 
 * by the developer.
 ******************************************************************************************
 * 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*
 */

#if 0
#############################################################################
 Heart of the sysfs model is the Kobject. 
 Kobject is the glue that binds the sysfs and the kernel, 
 which is represented by struct kobject.
 A struct kobject represents a kernel object, maybe a device or so, 
 such as the things that show up as directory in the sysfs filesystem.
#############################################################################
#endif


/*********************************************************************** 
 *                         OUTPUT
 ***********************************************************************  
neelkanth_surekha#pwd
/sys/kernel
neelkanth_surekha#cd dummy_sysfs/
neelkanth_surekha#ls
dummy_value
neelkanth_surekha#sudo cat dummy_value 
[sudo] password for neelkanth_surekha: 
0

neelkanth_surekha#sudo chmod 777 dummy_value 
neelkanth_surekha#sudo echo 1 > dummy_value 
neelkanth_surekha#cat dummy_value 
1
************************************************************************/

#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/sysfs.h> 
#include<linux/kobject.h> 


volatile int dummy_value = 0;


dev_t dev = 0;
static struct class *dev_class;
static struct cdev dummy_cdev;
struct kobject *kobj_ref;

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);

/*************** Sysfs Fuctions **********************/
static ssize_t sysfs_show(struct kobject *kobj, 
                struct kobj_attribute *attr, char *buf);
static ssize_t sysfs_store(struct kobject *kobj, 
                struct kobj_attribute *attr, char *buf, size_t count);

struct kobj_attribute dummy_attr = __ATTR(dummy_value, 0660, sysfs_show, sysfs_store);

static struct file_operations fops =
{
        .owner          = THIS_MODULE,
        .read           = dummy_read,
        .write          = dummy_write,
        .open           = dummy_open,
        .release        = dummy_release,
};

static ssize_t sysfs_show(struct kobject *kobj, 
                struct kobj_attribute *attr, char *buf)
{
        printk(KERN_INFO "Sysfs - Read!!!\n");
        return sprintf(buf, "%d", dummy_value);
}

static ssize_t sysfs_store(struct kobject *kobj, 
                struct kobj_attribute *attr, char *buf, size_t count)
{
        printk(KERN_INFO "Sysfs - Write!!!\n");
        sscanf(buf,"%d",&dummy_value);
        return count;
}

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 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;
        }

        /*Creating a directory in /sys/kernel/ */
        kobj_ref = kobject_create_and_add("dummy_sysfs", kernel_kobj);

        /*Creating sysfs file for dummy_value*/
        if(sysfs_create_file(kobj_ref, &dummy_attr.attr)){
                printk(KERN_INFO"Cannot create sysfs file......\n");
                goto r_sysfs;
    }
        printk(KERN_INFO "Device Driver Insert...Done!!!\n");
    return 0;

r_sysfs:
        kobject_put(kobj_ref); 
        sysfs_remove_file(kernel_kobj, &dummy_attr.attr);

r_device:
        class_destroy(dev_class);
r_class:
        unregister_chrdev_region(dev,1);
        cdev_del(&dummy_cdev);
        return -1;
}

void __exit dummy_driver_exit(void)
{
        kobject_put(kobj_ref); 
        sysfs_remove_file(kernel_kobj, &dummy_attr.attr);
        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 - SysFs");
MODULE_VERSION("1: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