How to compile a Linux Device Driver

Source: Internet
Author: User
Article Title: how to compile a Linux Device Driver. Linux is a technology channel of the IT lab in China. Includes basic categories such as desktop applications, Linux system management, kernel research, embedded systems, and open source.
   Preface
Linux is a variant of the Unix operating system. The principle and
  
The idea is similar to other Unix systems, but the drivers in the dos or window environment are very different. in a Linux environment, the driver is designed with simple ideas, convenient operations, and powerful functions. However, it only supports a small number of functions and can only rely on functions in the kernel. Some common operations should be compiled by yourself, debugging is not convenient. I have developed a driver for a multi-media card developed by the lab over the past few weeks and gained some experience. I hope to share it with Linux fans. please correct me if there are any improper problems.
  
The following text mainly comes from khg, johnsonm Write linux device driver, Brennan's Guide to Inline Assembly, The Linux A-Z, and some information about device driver on Tsinghua BBS. some of these materials are outdated and some are incorrect. I have corrected them based on my own test results.
  
   I. Concepts of Linux device driver
A system call is an interface between the operating system kernel and applications, and a device driver is an interface between the operating system kernel and machine hardware. the device driver shields the application from hardware details. In this way, the hardware device is only a device file, and the application can operate the hardware device like a common file. the device driver is part of the kernel and implements the following functions:
  
1. initialize and release the device.
  
2. Transmit data from the kernel to the hardware and read data from the hardware.
  
3. Read the data that the application sends to the device file and send back the data requested by the application.
  
4. Detect and handle device errors.
  
In Linux, there are two main types of device files: character devices and Block devices. the main difference between a character device and a block device is that when a read/write request is sent to a character device, the actual hardware I/O usually happens immediately after it is sent, it uses a piece of system memory as a buffer. When a user's process can meet the user's requirements for device requests, it will return the requested data. If not, you can call the request function to perform actual I/O operations. block devices are designed for disks and other slow devices to avoid excessive CPU time consumption.
  
It has been mentioned that a user process deals with the actual hardware through a device file. Each device file has its File Attribute (c/B), indicating whether it is a character device or not? Strong? In addition, each file has two device numbers. The first is the master device number, which identifies the driver, and the second is the slave device number, which identifies different hardware devices that use the same device driver, for example, if there are two floppy disks, you can use the device number to distinguish them. the master device ID of the device file must be the same as the master device ID applied by the device driver during registration. Otherwise, the user process will not be able to access the driver.
  
It must be mentioned that when a user's process calls the driver, the system enters the core State and is no longer preemptive scheduling. that is to say, the system must perform other work only after the sub-functions of your driver are returned. if your driver is in an endless loop, unfortunately you only have to restart the machine, and then there is a long fsck. // hehe
  
   Ii. instance profiling
Let's write a simple character device driver. although it does not do anything, it can be used to understand the operating principle of the Linux Device Driver. input the following C code into the machine and you will get a real device driver. however, my kernel is 2.0.34, which may cause problems in earlier versions. I have not tested it yet. // xixi
  
# Define _ NO_VERSION __
  
# Include
  
# Include
  
Char kernel_version [] = UTS_RELEASE;
  
This section defines some version information. Although it is not very useful, it is also essential. Johnsonm said that all the drivers must start with, but I don't think so.
  
Because a user process deals with hardware through a device file, the operation on the device file is similar to some system calls, such as open, read, write, close ...., note: Not fopen, fread ., but how can we associate system calls with drivers? This requires an understanding of a very critical data structure:
  
Struct file_operations {
  
Int (* seek) (struct inode *, struct file *, off_t, int );
  
Int (* read) (struct inode *, struct file *, char, int );
  
Int (* write) (struct inode *, struct file *, off_t, int );
  
Int (* readdir) (struct inode *, struct file *, struct dirent *, int );
  
Int (* select) (struct inode *, struct file *, int, select_table *);
  
Int (* ioctl) (struct inode *, struct file *, unsined int, unsigned long
  
Int (* mmap) (struct inode *, struct file *, struct vm_area_struct *);
  
Int (* open) (struct inode *, struct file *);
  
Int (* release) (struct inode *, struct file *);
  
Int (* fsync) (struct inode *, struct file *);
  
Int (* fasync) (struct inode *, struct file *, int );
  
Int (* check_media_change) (struct inode *, struct file *);
  
Int (* revalidate) (dev_t dev );
  
}
  
The name of each member in this structure corresponds to a system call. when a user process uses a system call to perform read/write operations on device files, the system calls the system to find the corresponding device driver through the master device number of the device file, then read the corresponding function pointer of the data structure, and then give the control to the function. this is the basic principle of linux device drivers. in this case, the main task of writing a device driver is to write a sub-function and fill in the fields of file_operations. it's quite simple, isn't it?
  
The following describes the subprogram.
  
# Include
  
# Include
  
# Include
  
# Include
  
# Include
  
Unsigned int test_major = 0;
  
Static int read_test (struct inode * node, struct file * file,
  
Char * buf, int count)
  
{
  
Int left;
  
  
If (verify_area (VERIFY_WRITE, buf, count) =-EFAULT)
  
Return-EFAULT;
  
For (left = count; left> 0; left --)
  
{
  
_ Put_user (1, buf, 1 );
  
Buf ++;
  
}
  
Return count;
  
}
  
This function is prepared for read calls. When read is called, read_test () is called, which writes all the user's buffer.
  
Buf is a parameter called by read. it is an address of the user's process space. however, when read_test is called, The system enters the core state. therefore, you cannot use the buf address. You must use _ put_user (). This is a function provided by kernel to transmit data to users. there are also many functions with similar functions. see. before copying data to a user space, you must verify whether the buf is available. the verify_area function is used.
  
Static int write_tibet (struct inode * inode, struct file * file,
  
Const char * buf, int count)
  
{
  
Return count;
  
}
  
Static int open_tibet (struct inode * inode, struct file * file)
  
{
  
MOD_INC_USE_COUNT;
  
Return 0;
  
} Static void release_tibet (struct inode * inode, struct file * file)
  
{
  
MOD_DEC_USE_COUNT;
  
}
  
These functions are all empty operations. When the actual call happens, nothing is done. They only provide function pointers for the following structure.
  
Struct file_operations test_fops = {
  
NULL,
  
Read_test,
  
Write_test,
  
NULL,/* test_readdir */
  
NULL,
  
NULL,/* test_ioctl */
  
NULL,/* test_mmap */
  
Open_test,
  
Release_test, NULL,/* test_fsync */
  
NULL,/* test_fasync */
  
/* Nothing more, fill with NULLs */
  
};
  
The main body of the device driver can be said to be written. Now we need to embed the driver into the kernel. The driver can be compiled in two ways. One is to compile into the kernel, and the other is to compile into the module. If compiled into the kernel, it will increase the size of the kernel and change the source file of the kernel, it cannot be dynamically uninstalled, which is not conducive to debugging. Therefore, we recommend that you use the module method.
  
Int init_module (void)
  
{
  
Int result;
  
  
Result = register_chrdev (0, "test", & test_fops );
  
If (result <0 ){
  
Printk (KERN_INFO "test: can't get major number ");
  
Return result;
  
}
  
If (test_major = 0) test_major = result;/* dynamic */
  
Return 0;
  
}
  
The init_module function is called when compiled modules are transferred to the memory using the insmod command. Here, init_module only registers a character device to the system's character device table. Register_chrdev requires three parameters. The first parameter is the device number to be obtained. If it is zero, the system selects an unused device number and returns it. The second parameter is the device file name. The third parameter is used to register the pointer of the function in which the driver actually performs the operation. If the registration is successful, the system returns the device's master device number. If the registration fails, a negative value is returned.
  
Void cleanup_module (void)
  
{
  
Unregister_chrdev (test_major, "test ");
  
}
  
When you use rmmod to uninstall a module, the cleanup_module function is called, which releases the table items that the character device test occupies in the system character device table.
  
  
A simple character device can be written. The file name is test. c.
  
Compile the following code
  
$ Gcc-O2-DMODULE-d1_kernel _-c test. c. The file test. o is a device driver.
  
If the device driver has multiple files, compile each file according to the command line above, and then ld-r file1.
Related Article

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.