What is device driver?
From this article onwards, let’s explore about Device drivers.
What is a device driver?
A device driver is a piece of code that configures and manages a device. The device driver code knows how to configure the device sending data to the device, and it knows how to process requests which originate from the device.
When the device driver code is loaded into an operating system such as Linux, it exposes interfaces to the user space so that the user application can communicate with the device. Without the device driver, the OS or the application will not have a clear picture of how to deal with a device.
Basically, a device driver is a code which knows how to handle a particular device. It gives the right interfaces for the user-space to access that device and the device driver code also abstracts various hardware details from the user-space applications. The user applications can just use traditional write, open, read, system calls to talk to the device.
But those system calls are carefully handled by the driver code to touch various registers of the device. The kernel’s job here is to connect the system calls to the driver’s system called implementation methods.
Let’s say there is a device xyz(shown in Figure 1) and when you load a driver of that device, then that device driver exposes the interfaces to the user-space.o that the user-space applications can communicate with the device.
The device driver takes the burden of interacting with the hardware devices and export interfaces that applications and other kernel modules can use to access the device.
Let’s say you have a device xyz. And the kernel or the operating system doesn’t know how to handle a device. Because a device has various configuration registers, it has various configuration values which needs to be program to the hardware. A before using that hardware and the kernel doesn’t know how to handle the interrupts generated by the hardware. That’s a reason why you should load a device driver.
A driver knows what are the configuration values which needs to be programmed to the hardware, what are its register address is, and how to handle the interrupts which originate from the hardware.
When you load a device driver, it connects to the kernel, and it utilizes kernel services to talk0 to the userspace. A driver should give an interface to the user-level programs to communicate with the hardware.
In Linux, we access the device by using a file access technique.
For example, let’s consider this is an RTC device.
What you do with an RTC device?
So, you read data and time information from the RTC device. or you write into the RTC if you want to configure it.
Basically, we do read-write operations on a device. That’s why the device driver has to create a device file interface at the user’s space, so that user-level programs can communicate with the hardware, using traditional file access system calls such as open, close, read, write, etc.
So, here the kernel’s job is to connect system call execution from the user-space to the driver’s system call handler methods. That will be taken care by the kernel. And we are going to understand that as we make progress in the section.
There are various categories of Linux device drivers(as shown in Figure 2). There are character drivers which take care of character devices, there are block drivers which take care of block devices such as storage devices, and there are network device drivers which take care of network devices.
In this article, we’ll be learning and writing character device drivers.
What’s a character device driver or char driver?
Character driver accesses data from the device sequentially. i.e., byte by byte (like a stream of characters), not as a chunk of data. Sophisticated buffering strategies are usually not involved in char drivers. Because when you write 1 byte, it directly goes to the device without any intermediate buffering or delayed write back, or there is no dirty buffer management as in block drivers.
Some of the examples of char devices are sensors, RTC, keyboard, serial port, parallel port. All these are character devices, and you need character drivers to manage these devices.
For example(shown in Figure 3), let’s say you have an RTC hardware or RTC device. And to take care of that RTC device, you have an RTC driver in the kernel space. In the user-space, you just use your traditional read-write APIs or system calls to talk to the RTC device.
For example, when you use a write system call to write 1 byte of data, it directly goes to the hardware via the driver. The driver knows how to forward that data to the RTC device. But this is not the case in block drivers.
For example, let’s say you have a memory device such as an SDMMC card. So, the SDMMC specification or the design doesn’t allow you to a write data byte by byte. You either have to write in chunks such as 512 bytes or 1024 bytes. But in the character device, you can write byte by byte.
What are block drivers?
The device which handles data in chunks or blocks is called a block device. Block drivers are more complicated than char drivers because the block drivers should implement advanced buffering strategies to read and write to the block drivers, and the disk caches are also involved.
Examples are mass storage devices such as hard disks, SDMMC, Nand flash, USB camera, etc.
As I said, the driver has to create some interface at the userspace (as shown in Figure 4). So, the user-level programs can use that interface to communicate with the hardware. Those are called device files. Most of the devices are accessed as a file in Unix/Linux system.
A device file is a special file or a node that gets populated in /dev directory during kernel boot time or device/driver hotplug events. When you boot your Linux kernel, the /dev directory is automatically it will get populated with device files, which are generated from various drivers of the kernel.
There is a special program in the user level called Udev, which actually populates this /dev directory with various device files as shown in Figure 5.
By using a device file, user application and drivers communicate with each other Device files are managed as a part of VFS subsystem of the kernel, where VFS stands for virtual file system. Because this is also like a file access. So, the device files are also managed by the VFS subsystem of the kernel.
In summary, The device file is a special file, and by using a device file, user application drivers communicate with each other.
And if you are wondering who creates this device file, the creation of this device file has to be triggered from your driver. If you just go to the /dev directory as shown in Figure 6.
You can see here various device files are already populated in your system. You can see that all the entries with a character c are called as character device files.
And here, the ‘d’ stands for the directory. And all the entries with the letter ‘b’ are block devices. These are handled by block drivers. For example, sda is my harddisk and sda1 is one of the partition, and there are some numbers; these are called major and minor numbers.
In the following article, let’s learn how to write a character driver, and we are going to understand about character driver, how to implement its methods, how to register with the kernel, and how to connect the user-level system call to our driver’s system call implementation.
Everything we have to understand to write a character driver . We will understand all of these things by doing one exercise. That would be the best way to learn.
FastBit Embedded Brain Academy Courses