How to Create a Linux Character Device Driver

Beaglebone black board






In this article, we show how to create a linux character device driver.

We won't actually use a hardware device.

We will create a pseudo character device in software only. This way, you can see how a character device works without actually needing a hardware device.

We will replicate in software a simple memory buffer device that can hold 512 bytes of data.

This is achieved through a simple line of code, char device_buffer[DEV_MEM_SIZE];

DEV_MEM_SIZE is defined with teh #define statement as 512 in a separate line.

Thus, through this simple line of code, we replicate a 512-byte memory device buffer which acts as our character device that we will create.

Okay, so let's start.

The first thing that you want to do is create a directory on your computer where you will store your device drivers.

This can be in any directory.

I created mine my home directory on my linux operating system.

On the home directory, I created the pcd.c file (which is the character device driver source code) in the /custom_drivers/character_drivers/ directory.

You are free to create this wherever you want (you can do exactly as I have done).

Within this directory, you need 2 files.

The first is a Makefile, which will act to build our character device driver source code. You can download or check out this file at the following link: Makefile for Pseudo Character Device Driver

The next file that is necessary is the source code for the pseudo character device driver.

To create this file, go to the linux terminal and type in, touch pcd.c

This creates a file, pcd.c

Now go into this file such as by using vim with the line, vim pcd.c

So below is the full code for this character device.

You can copy and paste this code into the pcd.c file and if you build it with make, you should see that it should work correctly.





Though this code may seem long and at least somewhat intimidating, it really isn't, and we'll now go through it to facilitate you understanding it.

So the first few lines are necessary headers that you need in order to run various functions throughout the code. Otherwise, there would be multiple errors if they are not included.

We then create a character device buffer of 512 bytes.

We then create a variable of type dev_t named device_number. This variable will store the device number when this is created later in code in the alloc_chrdev_region() function. The line that this is done is the following, alloc_chrdev_region(&device_number, 0,1,"pcd_devices");

Each character device needs a device number. Each device in a linux operating system must be assigned a device number, which uniquely identifies this device (separating it from all others on the linux operating system). Each device has a major and minor number. First the number is assigned. Then later, it must be registered with the Virtual File System in the kernel space, which allows the operating system to then connect the device to the device driver.

Next we have the line, struct cdev pcd_cdev;

Every character device needs a cdev structure.

This structure must be intialized with the file operations and the owner.

We then register the device with VFS. This is done through the line, cdev_add(&pcd_cdev,device_number,1);

Next, we have our file operations.

With this character device driver, we define 5 file operations methods. Of course, you can have more depending on the needs and complexity of your particular character device and what is required.

A file operation is a task that is run which originates from the user that allows the user to interact with the device. The open() method opens the device up for use on the computer. The close() method closes the device. The read() method allows us to read data from the device. The write() method allows us to write data to the device. The lseek() method allows us to change the file location pointer to where on a file we begin reading from or writing to.

The first method we define is the lseek() method. This method can change the file position offset of the pointer, which is where the file begins various operations such as read() and write(). The lseek() method can change from where a file begins the reading from or writing to.

For a complete article on the lseek() method, see How to Implement the lseek File Operation Method in a Linux Device Driver

Next, we define the read() method.

This allows us to read a specified number of bytes from a file.

For a complete article on the read() method, see How to Implement the Read File Operation Method in a Linux Device Driver

Next, we define the write() method.

This allows us to write a specified number of bytes to a file.

For a complete article on the write() method, see How to Implement the Write File Operation Method in a Linux Device Driver

Next, we define the open() method.

This allows us access to the device.

Lastly, we have the close() or (release) method, which allows us to close the device.

All of these file operation methods must then be placed into a structure, along with the owner, which you see done in the pcd_fops variable.

Next, we define the *class_pcd class variable and the *device_pcd device variable.

We will go over their uses later.

We then go into the heart of ource, which is the pcd_driver_init() function.

So the first function within this function is the alloc_chrdev_region() function, which dynamically allocates a device number for our character device. Remember that every character device (or any other device such as block) requires a device number.

The first parameter, &device_number represents the address of the device.

The second parameter, 0 represents the base minor number.

The third parameter, 1 represents we are working with a singular device.

The fourth parameter, "pcd_device" signifies the name of the device.

Next, we initialize the cdev structure with the file operation methods. We also specify the owner of the structure, which is THIS_MODULE

For a complete article on assigning a character device number in linux, see How to Assign a Character Device Number to a Linux Character Device

Next, we must register the device with the Virtual File System, so that the kernel space can link a user system call to the file operation method in the device driver code.

We register the device with the VFS using the cdev_add() function. This is done with the line, cdev_add(cdev_add(&pcd_cdev,device_number,1);,device_number,1);

The first parameter, &pcd_cdev is the address of the cdev structure.

The second parameter, device_number is the device number of the character device.

The third parameter, 1 is the number of device(s) that you are registering.

For a complete article on assigning a character device number in linux, see How to Perform Character Device Registration for a Linux Character Device

Next, we need to create a device file.

In the linux operating system, each device has its own file within the /dev directory (devices directory).

To create a device file, we must first create a device class under the /sys/class directory. This is done by the line, class_pcd= class_create(THIS_MODULE,"pcd_class");

We next create the device file through the line, device_pcd= device_create(class_pcd, NULL, device_number, NULL,"pcd");

The first parameter, class_pcd is the class we previously created.

The second parameter is NULL because this device does not have a parent element.

The third parameter, the device_number is the device number of the character device.

The fourth parameter is NULL because this device has no private data that we give it.

The fifth parameter is the name of the device. This is the name which will appear in the /dev directory for the device.

For a complete article on creating a device file dynamically in the device driver code in linux, see How to Create a Device File Dynamically in the Device Driver Code in Linux

After this, we must have our pcd_driver_cleanup() function, which is run when we run rmmod, when we're removing the linux kernel module from the linux kernel.

Basically, it's reversing all the creation that we have done.

We destroy the device, destroy the class, delete the cdev structure, and unregister the character device from the VFS.

So this is how to create a linux character device driver.

The next step is now to test your character device driver. Learning this can be found at the following article, How to Test a Linux Character Device Driver




Related Resources





HTML Comment Box is loading comments...