Summary and analysis of Linux character device drivers

Source: Internet
Author: User
Recently, I have been reading books and learning about Linux device drivers. I am getting started with the simplest character device drivers and can have a macro understanding of the driver framework and functions of various elements. The following is a detailed analysis of the device driver with the first character I have written. I will sort out some basic driver knowledge to deepen my impression. First, some macro definitions and global variables are given:
#define GLB_MEM_SIZE 0x1000
#define HELLO_MAJOR 250
#define MEM_CLEAR 0x1
int hello_major = HELLO_MAJOR;
struct globalmem_dev
{
    struct cdev cdev;    unsigned char mem[GLB_MEM_SIZE];};               
// A global variable is defined here to construct a virtual character device.
struct globalmem_dev *devp;
First, Linux device drivers are part of the kernel and have obvious module features. Character device drivers include the following parts:
(1) driver loading and unloading Module
module_init(hello_drv_init);
module_exit(hello_drv_exit);
Module_init and module_exit are kernel-defined macros used to load self-written modules to or from the kernel. Hello_drv_init and hello_drv_exit are
The self-defined function hello_drv_init is the initialization function of the driver. It mainly completes the following work:
1. Apply for a device number from the system for character Devices
dev_t devno = MKDEV(hello_major, 0); 
If the primary device number hello_major is manually assigned, the mkdev macro can generate a device number. The secondary device number is 0, and the primary device number is 12 digits, and the secondary device number is 20 digits.
register_chrdev_region(devno, 1, "helloworld");
The above function is to manually apply for a device number to record it to the chardevs array. The device name is "helloworld", provided that the device number is not used.
alloc_chrdev_region(devno, 0, 1, "helloworld");
The above function indicates dynamically applying for unused device numbers from the system. The first parameter devno is used to store the acquired device numbers. The second parameter 0 indicates the second device number, and the third parameter
Parameter 1 indicates only one request.
hello_major = MAJOR(devno);
hello_minor = MINOR(devno);
The preceding two macros indicate that the master device number hello_major and the secondary device number hello_major are extracted from the device number devno.
2. allocate memory and initialize the struct of the character device
devp = kmalloc(sizeof(struct globalmem_dev), GFP_KERNEL);
memset(devp, 0, sizeof(struct globalmem_dev));
The above gfp_kernel is an identifier of the memory space allocated by the kernel, indicating that it enters sleep state when no memory is available.
3. initialize cdev
devno = MKDEV(hello_major, 0);
Cdev_init (& devp-> cdev, & FOPS); this function is used to initialize cdev members and establish the connection between cdev and file_operations.
devp->cdev.owner = THIS_MODULE;
4. Register cdev
Cdev_add (& devp-> cdev, devno, 1); add a cdev to the system to register the character device.
Similarly, when the module is uninstalled, it performs three operations that correspond to the registration.
Cdev_del (& devp-> cdev); // cancel cdevkfree (devp); // release the struct memory unregister_chrdev_region (mkdev (hello_major, 0), 1); // release the device number.
(2) filling of the file_operations Data Structure
I simply understand that applications access underlying devices through functions such as open, close, and ioctl, and these functions at the application layer serve as a bridge between system calls and file systems, the final call is the corresponding function in file_operations. Therefore, the function implementation in the file_operations struct needs to be implemented by the driver engineer.
static struct file_operations fops ={.owner                = THIS_MODULE,.llseek                  = hello_llseek,.read                   = hello_read,.write                   = hello_write,.ioctl                    = hello_ioctl,.release              = hello_release,}
(3) Implementation of functions in the file_operations struct The following describes the most common read and write functions as an example,
Static int hello_read (struct file * file, char _ User * Buf, size_t size, loff_t * PPOs) {unsigned long P = * PPOs; // The offset of the read position to the beginning of the file int ret = 0; // determine whether the read offset is out of bounds or whether the number of bytes is too large
If (P> = glb_mem_size) return 0; If (size> glb_mem_size-p) size = glb_mem_size-P; // start reading
if(copy_to_user(buf, (void*)(devp->mem+p), size))    ret = -EFAULT;else{    *ppos += size;    ret = size;    printk(KERN_INFO "read %d bytes from %d\n", size, p);}    return ret;}
File is the object structure pointer, Buf is the memory of the user space, and size is the number of bytes to be read, because the kernel space and the user space memory cannot access each other, you need to use the copy_to_user function to map the kernel space to the user space (that is, copy). Similarly, when writing, you need copy_from_user to map the user space to the memory space, the two functions return the number of bytes that cannot be copied. Therefore, if the full ing (replication) succeeds, 0 is returned.
static int hello_write(struct file *file, const char __user *buf, size_t count, loff_t *offset){    int ret;    unsigned long p = *offset;    if(p >= GLB_MEM_SIZE)        return 0;    if(count> GLB_MEM_SIZE - p)        count = GLB_MEM_SIZE - p;    if(copy_from_user((devp->mem+p), buf, count))        ret = -EFAULT;    else    {        *ppos += count;        ret = count;        printk(KERN_INFO "write %d bytes to %d\n", count, p);    }    return ret;}
(4) header files and macros
For the header files that are often used in the driver module, refer to an article I have reproduced on the Linux driver header files. In addition, there are some macros, such:
Module_author ("W. yihong <a5131wyh@163.com> "); // some information declaration of the module author module_description (" Hello World Driver "); // some descriptions of the module function module_license (" GPL "); // module license statement. If the license is not declared, the module will receive a kernel contaminated warning module_alias ("Platform: myfirst_driver") when loading the module "); // The module can call this macro to define one or more specific terms for itself.
The above is a simple understanding of character device drivers. There are still many driver mechanisms and meanings that are unclear. We need to explore and summarize them in future practical projects. I am getting started, I hope you can point out the shortcomings and make progress together.
 
 
 

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.