Linux Device Driver Development Cookbook
上QQ阅读APP看书,第一时间看更新

Working with Char Drivers

A device driver is special code (running in kernel space) that interfaces a physical device to the system and exports it to the user space processes using a well-defined API, that is, by implementing some system calls on a special file. This is due to the fact that, in a Unix-like OS, everything is a file and physical devices are represented as special files (usually placed in the /dev directory), each one connected to a particular device (so, for instance, the keyboard can be a file named /dev/input0, a serial port can be a file named /dev/ttyS1, and a real-time clock can be /dev/rtc2).

We can expect that network devices belong to a particular set of devices not respecting this rule because we have no /dev/eth0 file for the  eth0 interface. This is true, since network devices are the only devices class that doesn't respect this rule because network-related applications don't care about individual network interfaces; they work at a higher level by referring sockets instead. That's why Linux doesn't provide direct access to network devices, as for other devices classes.

Looking at the next diagram, we see that the kernel space is used to abstract hardware to user space, so that every process uses the same interface to get access to peripherals, and this interface is composed by a set of system calls:

The diagram also shows that it is possible to get access to peripherals not only by using device drivers but also by using another interface such as sysfs or by implementing a user space driver.

Since our peripherals are just (special) files, our drivers should implement the system calls we need to manipulate these files and especially the ones useful to exchange data. For example, we need open() and close() system calls to start and stop the communication with the peripheral and read() and write() system calls to exchange data with it.

The main difference between a normal C function and a system call is just the fact that the latter is mainly executed into the kernel, while a function executes into the user space only. For example, printf() is a function, while write() is a system call. The latter (except for the prologue and epilogue part of a C function) executes in the kernel space, while the former executes predominantly in the user space even if, at the and, it calls write() to actually write its data to the output stream (this is because all input/output data flows must pass through the kernel anyway).

For more information check this book out: https://prod.packtpub.com/hardware-and-creative/gnulinux-rapid-embedded-programming

Well, this chapter will show us how to implement at least the open(), close(), read(), and write() system calls in order to introduce device drivers programming and the first steps into char drivers development.

Now it's time to write our first device driver! In this chapter, we will start with a very simple character (or char) driver in order to cover the following recipes:

  • Creating the simplest char driver
  • Exchanging data with a char driver
  • Using the ''Everything Is a File" abstraction