Before reading this article, you must read Stage 1 of this article series.
The stage is going to contain:
1. How to register the driver with the kernel. I will also talk about what is the difference between registering a driver and loading or inserting a driver.
2. How to call registered functions
3. How to access device file from user space
Please look at the code below:
/* File name is fld.c.
* The file has four key concepts here:
* 1. Registering the driver with kernel. For that we have used alloc_chrdev_region.
* This API gives us device id which have a major number and minor number of devices.
* There are many times where we need more than one device file and using this API we have.
* i.e. tty. We will use the device ID to create 3 device file which we can see using
* $ ls -l /dev/
* 2. class_create - create class for all devices under /sys/class
* 3. device_create - create all device under /sys/class/[our class]
* 4. cdev_init and cdev_add : VFS s reponsible to handle all our device file operation.
* the api help to register all functions under file_operations and
* cdev_init initialize the device structure while hand over this structure to
* VFS by calling cdev_add */
#include /* All module related APIs are declared */
#include /* declares all character device related functions*/
#include /* for copy_to_user and copy_from_user*/
#include /* kmalloc() */
static dev_t device_id;
static struct class *device_class;
static struct cdev c_dev;
/* Buffer to store data */
static int fld_open(struct inode *inodePtr, struct file *filePtr)
printk(KERN_INFO "FLD Driver: open()\n");
static int fld_close(struct inode *inodePtr, struct file *filePtr)
printk(KERN_INFO "FLD Driver: close()\n");
static ssize_t fld_read(struct file *filePtr, char __user *buf, size_t length, loff_t *f_pos)
/* Transfering data to user space */
copy_to_user(buf, memory_buffer, 1)
if (*f_pos == 0) /* Changing reading position as best suits */
*f_pos += 1;
static ssize_t fld_write(struct file *filePtr, const char __user *buf, size_t length, loff_t *off)
const char *tmp;
tmp = buf + length - 1;
copy_from_user(memory_buffer, tmp, 1);
static void __exit fld_exit(void)
printk(KERN_INFO "FLD Exit Called");
static struct file_operations fld_fops =
.owner = THIS_MODULE,
.open = fld_open,
.release = fld_close,
.read = fld_read,
.write = fld_write};
/* for '__init'/'__exit' - find info in stage 1 article*/
static int __init fld_init(void)
int ret = 0;
printk(KERN_INFO "FLD Init Called");
/* The below API dynamically figures out a free major number and
* registers the cnt number of device file numbers starting from
* , with the name. */
/* Registers a range of char device numbers */
/* When you load driver and run the command 'cat /proc/devices'
* you can see the device file name as 'fld_device' for the driver */
if ((ret = alloc_chrdev_region(&device_id, 0, 1, "fld_device")) < 0)
/* Allocating memory for the buffer */
memory_buffer = kmalloc(1, GFP_KERNEL);
ret = -ENOMEM;
memset(memory_buffer, 0, 1);
/* Kernel populates the appropriate device class & device info into
* the '$ ls -l /sys/class/' you could see 'fld_class' */
/* Create device class */
if ((device_class = class_create(THIS_MODULE, "fld_class")) == NULL)
/* Create device info */
/* when you execute $ ls -l /sys/class/fld_class/', you can see device 'fld_dev' */
if (device_create(device_class, NULL, device_id, NULL, "fld_dev") == NULL)
/* Initialize the character device structure (struct cdev c_dev)
* with that, using cdev_init()*/
/* to hand this structure to the VFS using the call cdev_add() */
if (cdev_add(&c_dev, device_id, 1) == -1)
/* Find info about module_init and module_exit in Stage 1 article code*/
/* Refer stage 1 article for explanation below. */
MODULE_DESCRIPTION("For self-learning LDD");
Refer to stage 1 article.
Refer to stage 1 article.
cat is a command which opens a file, reads it,and then closes the file.
We will use this command to open and read our driver which is a device file.
To see the major and minor number, run the following command:
$ cat /sys/class/fld_class/fld_dev/uevent
$ cat /dev/fld_dev
echo -n First > /dev/fld_dev
See all class file i.e. fld_class
$ ls -l /sys/class/
See device file i.e. fld_dev
$ ls -l /sys/class/fld_class/
$ ls -l /dev/
See Loaded driver