Android is essentially a Linux kernel-based system, that is, Android is a Linux operating system. Most of the time, however, they run on ARM-based devices, such as Android phones and tablets. The Android driver is actually a Linux driver. Therefore, the driver can be installed on the Android simulator, Android mobile phone (root required), or tablet (these devices must use the CPU allocated to the ARM architecture). Of course, using traditional GCC, you can also compile it into a X86 Driver (without modifying the Code). In this way, you can install the Linux driver on Ubuntu Linux. This article and later articles mainly introduce how to develop a Linux driver for the ARM architecture using the Android simulator and the cloud6410 Development Board. Of course, the testing environment is Android, instead of X86 architecture systems such as Ubuntu Linux. Finally, we will introduce how to test the driver in multiple ways, including the command line, NDK, and Android Program (Java code). Of course, at the end of the article, we will also introduce how to embed the driver into the Linux kernel so that Android will automatically own the driver at startup. If you want to learn about Android underlying development, you can use this article to fully master the complete steps for Android-based LInux driver development. There is a complete experimental environment (VMWare Ubuntu Linux12.04LTS) on the CD of "Android Deep Exploration (Volume 1): HAL and driver development, you can copy the virtual environment from the CD. The virtual file is too large (3.6 GB) and cannot be uploaded. You can only send an article! 1. What is a Linux driver? For programmers who have never been familiar with driver development, the Linux driver may feel mysterious. It feels complicated to develop. In fact, this is completely a misunderstanding. In fact, there is no essential difference between a Linux driver and a common LinuxAPI. The method for using the Linux driver is different from that for using the Linux API. Before learning the Linux driver, let's first introduce how the Linux driver works. If you have been familiar with Windows or other non-Unix operating systems before, it is best to forget the way they work, because these memories will disturb our understanding of some details of the Linux underlying layer. The work and access methods of the Linux driver are one of the highlights of Linux and have won wide acclaim in the industry. In Linux, each driver is mapped into a file. These files are called device files or driver files and are stored in the/dev directory. This design concept makes interaction with the Linux driver as easy as interaction with common files. Of course, it is easier than accessing the LinuxAPI. Because most Linux drivers have their corresponding device files, switching data with the Linux driver becomes a data exchange with the device files. For example, to send a print command to the Linux printer driver, you can directly use the C language function open to open the device file, and then use the C language function ioctl to send a print command to the driver's device file. Of course, more advanced functions are required to write Linux drivers. For example, when writing data to a printer driver, the printer driver needs to receive the written data and send them to the printer through ports such as the parallel port and USB of the PC. To implement this process, the Linux driver must be able to respond to the data transmitted by the application. This is a Linux-driven event. Although there is no event concept in the C language, there is a similar concept with the event, which is the callback function. Therefore, the most important step to write a Linux driver is to write a callback function. Otherwise, the data that interacts with the device file cannot be processed. Figure 6-1 shows the relationship between application software, device files, drivers, and hardware. 2. Procedures for compiling a Linux driver the Linux driver has its own rules, just like other types of Linux programs. Readers who are new to Linux driver development may not be familiar with how to develop a LInux driver. To solve the reader's confusion, this section provides a general step for compiling a basic Linux driver. Readers can follow these steps to learn about Linux driver development step by step. Step 2: Create a Linux driver skeleton (load and uninstall the Linux driver). All types of programs have a basic structure. For example, the C language requires an entry function main. The Linux driver is no exception. The Linux kernel must first load the driver when using the driver. Initialization is required during the loading process, such as creating device files and allocating memory addresses. When the Linux system exits, You Need To uninstall the Linux driver. During the uninstallation process, you need to release resources occupied by the Linux driver, such as deleting device files and releasing memory address space. In the Linux driver, two functions are required to process the initialization and exit of the driver respectively. The two functions are specified by the module_init and module_exit macros respectively. Linux drivers generally need to specify these two functions. Therefore, the C program file that contains these two functions and the two macros that specify these two functions can also be seen as the skeleton of the Linux driver. Step 2: Register and unregister the device file any Linux driver requires a device file. Otherwise, the application cannot interact with the driver. The creation of device files is generally completed in the functions written in step 1 to process Linux Initialization. Deleting a device file is generally completed in the function written in step 1 to process the Linux exit. You can use the misc_register and misc_deregister functions to create and remove device files. Step 2: specify that the driver-related information driver is self-described. For example, you can use the modinfo command to obtain the name of the driver, the open-source protocol used, the alias, and the driver description. This information must be specified in the driver source code. You can use MODULE_AUTHOR, MODULE_LICENSE, MODULE_ALIAS, MODULE_DESCRIPTION, and other macros to specify Driver-related information. Step 2: Specify the callback function. The Linux driver contains multiple actions, also known as events. For example, when writing data to a device file, a "write" event is triggered. the Linux system calls the write callback function of the corresponding driver to trigger a "read" event when reading data from the device file, in Linux, the read callback function of the corresponding driver is called. A driver does not have to specify all callback functions. Callback functions are registered through relevant mechanisms. For example, callback functions related to device files are registered using the misc_register function. Step 2: Compile the business logic. This step is the core part of the Linux driver. Linux drivers with skeleton and callback functions alone have no significance. Any complete Linux driver will do some work related to its functions. For example, the printer driver will send a print command to the printer. The COM driver interacts with each other based on the transmission rate. The specific business logic is related to the driver's functions. The business logic may consist of multiple functions, multiple files, or even multiple Linux driver modules. The specific implementation can be determined by the actual situation. Step 2: Compile the Makefile file. the Linux kernel source code compilation rules are defined by the Makefile file. Therefore, to write a new Linux driver, you must have a Makefile file. Step 2: Compile the Linux driver. The Linux driver can be directly compiled into the kernel or compiled separately as a module. Step 2: Install and uninstall the Linux driver. If you compile the Linux driver into the kernel, the driver will be automatically loaded as long as Linux uses the kernel. If the Linux driver exists separately as a module, run the insmod or modprobe command to load the Linux driver module and run the rmmod command to uninstall the Linux driver module. The first five steps in the above eight steps are about how to write the Linux driver. The next three steps can make the Linux driver work normally. Iii. Preparations before writing the Linux driver source code in this example is not put together with the Linux kernel source code, but in a separate directory. First, use the following command to create a directory for storing the Linux driver. # Mkdir-p/root/drivers/ch06/word_count # cd/root/drivers/ch06/word_count and then use the following command to create the driver source code file (word_count.c) # echo ''> word_count.c finally writes a Makefile file. In fact, this is step 1 of writing the Linux driver described in section 6.2. After you are familiar with the steps for compiling the Linux driver, you can write the Linux driver in the order described in section 6.2. # Echo 'obj-m: = word_count.o '> Makefile where obj-m indicates that the Linux driver is compiled as a module (. ko file. If obj-y is used, the Linux driver is compiled into the Linux kernel. Obj-m or obj-y must be assigned a value of ": =. If the obj-m or obj-y value is word_count.o, The make command will compile the word_count.c or word_count.s file in the Linux driver source code Directory into the word_count.o file. If you use obj-m, word_count.o will be connected to the word_count.ko file, and then use the insmod or modprobe command to load word_count.ko. If obj-y is used, word_count.o is connected to the built-in.o file and eventually to the kernel. Where the built-in.o file is an intermediate target file generated by the. o file that connects to the same class program. For example, all character device drivers generate a built-in.o file. You can find a built-in.o file in the <Linux kernel source code directory>/drivers/char directory. The target file contains all the character drivers that can be connected to the Linux kernel. (You can use the make menuconfig command to configure whether each driver and other kernel programs can be compiled into the kernel, for more information about Linux Kernel configuration, see section 4.2.4 ). If the Linux driver depends on other programs, such as process. c and data. c. You need to compile the Makefile file as follows. Obj-m: = word_count.oword_count-y: = process. o data. o where dependency files are specified using module-y or module-objs. Module indicates the module name, such as word_count. 4. Compile the skeleton of the Linux driver. Now, compile the skeleton of the Linux driver, that is, step 1 described above. The skeleton part mainly refers to the initialization and exit functions of the Linux driver. The Code is as follows: [cpp] # include <linux/module. h> # include <linux/init. h> # include <linux/kernel. h> # include <linux/fs. h> # include <linux/miscdevice. h> # include <asm/uaccess. h >/// initialize the Linux driver static int word_count_init (void) {// output log information printk ("word_count_init_success \ n"); return 0 ;} // exit the Linux driver static void word_count_exit (void) {// output the log information printk ("word_count_init_exit_success \ n ");}// Register the module_init (word_count_init) function to initialize the Linux driver; // register the Linux le_exit (word_count_exit) function to exit the Linux driver; the printk function is used in the above Code. This function is used to output log information (detailed usage of the printk function is described in section 10.1 ). The usage of the printk function is similar to that of the printf function. Some readers may have doubts. Why not use the printf function? This involves the question of what a Linux kernel program can call or cannot call. In Linux, memory is divided into user space and kernel space, which cannot be accessed directly by programs in these two spaces. The printf function runs in the user space, and the printk function runs in the kernel space. Therefore, Linux drivers of kernel programs cannot directly access the printf function. Even if the stdio. h header file is included, an error not found in the stdio. h file will be thrown during Linux driver compilation. Of course, a program running in a user space cannot directly call the printk function. So is the user space and the kernel space programs unable to interact? The answer is no. Otherwise, will the two memories become isolated islands. There are many ways to interact between programs running in the two memories. The device file is a major interaction method (the interaction method of the/proc virtual file will be introduced later ). If a program in the user space needs to access the kernel space, you only need to create a driver that can access the kernel space, and then the program in the user space can interact with the driver through the device file. Readers may have more doubts. The Linux driver cannot directly access the programs running in the user space. Therefore, you have to implement many functions on your own. For example, in C language, the malloc function is often used to dynamically allocate memory space, which cannot be used in Linux drivers. So how to dynamically allocate memory space in the Linux driver? It is easy to solve similar problems. Since the Linux driver cannot directly call functions running in the user space, a replacement must be provided in the Linux kernel. You can enter the <Linux kernel source code>/include directory. Each subdirectory contains a large number of C header files. The functions, macros, and other resources defined in these header files are substitutes for programs running in the user space. The header file corresponding to the function library running in the user space is in the/usr/include directory. The replacement of the previously mentioned malloc function in the kernel space is kmalloc (it must contain the slab. h header file, # include <linux/slab. h> ). Note: The names of functions, macros, and other resources in the user space and the kernel space that have completed the same or similar functions are not necessarily the same. Some names are similar, such as malloc and kmalloc, there are two different names: atoi (user space), simple_strtol (kernel space), itoa (user space), and snprintf (kernel space ). When using kernel-related resources, you should pay attention to the following points. If you want to see the effects of the previously written program, you can use the following command to compile the Linux driver source code (X86 architecture ). # Make-C/usr/src/linux-headers-3.0.0-15-generic M =/root/drivers/ch06/word_count in the test Linux driver may not be completed on Android devices. Because Android, Ubuntu Linux, and other Linux versions are based on the Linux kernel, most Linux drivers can be tested on Ubuntu Linux or other Linux distributions, and then compiled into the target file based on the ARM architecture with the cross compiler again, and then installed on Android to run normally. To compile the Linux kernel source code, use the Linux kernel header file. To test the driver on Ubuntu Linux, you need to use the-C command line parameter to specify the directory (/usr/src/linux-headers-3.0.0-15-generic) of the Linux kernel header file ). The linux-headers-3.0.0-15-generic directory is the Linux kernel source code directory, in which only the include subdirectory has the actual header file, other directories only Makefile and some other configuration files, does not contain the Linux kernel source code. This directory is provided to develop drivers of the current Linux kernel version and other kernel programs (because only header files are required to generate the target file when compiling the Linux driver, when linking the target file, you only need to have the relevant target file, and do not need the source code file ). To compile the Linux driver as a module, use M to specify the directory where the driver is located (M = root/drivers/ch06/word_count ). Note: If you use another Linux kernel in the Linux release, you must set the correct path for the-C command line parameter. After the preceding command is executed, the information shown in 6-2 is output. From this information, we can see that the word_count.c file has been compiled into the Linux driver module File word_count.ko. After using the ls command to list the files in the/root/drivers/ch06/word_count directory, we found that there were a few more. o and. ko files and other files, as shown in 6-3. These files are automatically generated by the compiler and do not need to be taken into account. Although the Linux driver compiled in this article does not have any practical functions, it can be installed in Linux kernel space as a driver. You can use the following command to install, view, and uninstall the Linux driver, or view the log information output by the driver (enter the word_count directory before executing the following command ). Install the Linux driver # insmod word_count.ko check whether word_count is successfully installed # lsmod | grep word_count uninstall the Linux driver # rmmod word_count view the log information output by the Linux driver # dmesg | grep word_count | tail-n 2 after executing the preceding command, if the information shown in 6-4 shows that the reader has successfully completed the learning in this section, you can continue to read the next section. The dmesg command is actually the log information read from the/var/log/messages (Ubuntu Linux 10.04) or/var/log/syslog (Ubuntu Linux11.10) file, therefore, you can run the following command to obtain the log information output by the Linux driver. # Cat/var/log/syslog | grep word_count | tail-n 2 will output more information after executing the preceding Command, as shown in 6-5.