Kernel module programming (4): Device attributes and connection with upper-layer applications

Source: Internet
Author: User

This article is the second reading note of chapter 3 Char Drivers in Linux Device Drivers.

This part is difficult to understand. I went online to check and couldn't find the Example in this book, so I decided to rely on myself. I will first write an application layer example to trigger some operations on the kernel module through this example, which is easier to understand.


# Include <stdlib. h>

# Include <stdio. h>

Int main (int argc, char * argv [])

{

FILE * file = NULL;

Printf ("*************** test access driver ***************/n ");

File = fopen ("/dev/scull0", "w ");

If (file = NULL ){

Printf ("Open scull0 error! /N ");

Exit (-1 );

}

Fclose (File );

Return 0;

}


We have allocated a device number to the successful request, a kernel module. We hope the upper layer can use its capabilities or resources. Has the following important data structures.

Struct file_operations, the parameter processing in strcut module is a number of functions. These functions are related to the triggering of upper-layer application operation kernel. The kernel module can provide different communication modes, such as BLOCK and NOBLOCK. Apply the parameter operations of some functions to trigger the operations of the corresponding functions of the kernel module. For example, in the test effect, fopen triggers the open function in the device struct file_operations. File Operations, input and output of upper-layer applications, including the concept that is frequently used in socket. For example, fd: file descripor file description.

Strcut file, indicating the properties of the device, such as whether the device can be written or not. When a user triggers the device, the kernel also sends the user's device operation attributes together.

Struct inode, after the application establishes a connection with the kernel module through open or other methods, it needs further operations. This is an important data that the kernel module receives in the trigger parameter, this allows our kernel module to correspond to the specific device. Generally, we only care about the dev_t I _rdev and struct cdev * I _cdev parameters.

Continue to the scull example. First, we will analyze the use of scull for memory space. As shown in.

[Wei @ Wei ~] $ Cat scull. h

# Ifndef _ wei_scull_h

# DEFINE _ wei_scull_h

# Define scull_major 0

# Define scull_minor_min 0

# Define scull_dev_num 4

/* This is the linked list structure based on Memory Organization */

Struct scull_qset {

Void ** data;

Struct scull_qset * next;

};
/* This is the size of quantum given by the memory structure, and the length of the queue containing quantum in data */

# Define scull_quantum 1024

# Define scull_qset 64

/* This is the structure we provide for the device corresponding to the kernel module ,*/

Struct scull_dev {

Struct scull_qset * data;

Int quantum;/* the quantum size */

Int qset;/* the array size */

Struct cdev;/* Char device structure */

};

Static void scull_setup_cdev (struct scull_dev * Dev, int index );

Int scull_trim (struct scull_dev * Dev );

Int scull_open (struct inode * inode, struct file * file );

Int scull_release (struct inode * inode, struct file * file );

# Endif

In our custom device structure, the last parameter struct cdev is a very important parameter, which is char device struct. Use the following three system functions to initialize it and associate it with a file operation. Add it to and delete it from the kernel.

Void cdev_init (struct cdev * cdev, strcut file_operations * FoPs );

Int cdev_add (strcut cdev * Dev, dev_t num, unsigned int count );

Void cdev_del (strcut cdev * Dev );


The following is scull. c. Let's analyze how to fill in and use the three important data structures

[Wei @ Wei ~] $ Cat scull. c

# Include <Linux/init. h>

# Include <Linux/module. h>

# Include <Linux/fs. h>

# Include <Linux/cdev. h>

# Include "scull. H"

Module_license ("dual BSD/GPL ");

Dev_t dev;

Int is_get_dev =-1;

Static int scull_major = scull_major;

/* This is the file operation structure, our four scull0-3 have the same property, should this can correspond to the same data structure, please note this writing, we listed here, make the program more read and easy to modify. In this example, we simply open and close the function, so we only provide two function ing functions: open and release */

Struct file_operations

Scull_fops

= {

. Owner = THIS_MODULE,

/* This parameter is not an operation to prevent the module from being detached during the operation. */

. Open = scull_open,

. Release = scull_release,

};


/* Strcut scull_dev is all the information we set for each device. Four devices are placed in an array */

Struct scull_dev mydev [scull_dev_num];

Static int _ init scull_init (void)

{

Int I = 0;

Printk ("scull module init enter/N ");

If (scull_major ){

Dev = MKDEV (scull_major, SCULL_MINOR_MIN );

Is_get_dev = register_chrdev_region (dev, SCULL_DEV_NUM, "scull ");

} Else {

Is_get_dev = alloc_chrdev_region (& dev, SCULL_MINOR_MIN, SCULL_DEV_NUM, "scull ");

Scull_major = MAJOR (dev );

}

If (is_get_dev <0 ){

Printk (KERN_WARNING "scull: can't get device major number % d/n", scull_major );

Return is_get_dev;

}

/* Initialize the four devices respectively */

For (I = 0; I <SCULL_DEV_NUM; I ++ ){

Scull_setup_cdev (& mydev [I], I );

}
Return 0;

}

Static void _ exit scull_exit (void)

{

If (is_get_dev <0 ){

Return;

} Else {

Int I = 0;

/* For any device that performs the cdev_add operation, perform cdev_del when uninstalling the module and delete it from the kernel. */

For (I = 0; I <SCULL_DEV_NUM; I ++ ){

Cdev_del (& Mydev [I]. cdev

);

}

Unregister_chrdev_region (dev, SCULL_DEV_NUM );

Printk ("Scull module exit/n ");

}

}

Module_init (scull_init );

Module_exit (scull_exit );

/* Initialize the device according to the structure defined for the device */

Static void scull_setup_cdev (struct scull_dev * dev, int index)

{

Int err;

/* Through the second index parameter, we can know the specific scullx, which can correspond to the corresponding device. */

Int devno = MKDEV (scull_major, SCULL_MINOR_MIN + index );

Printk ("scull % d, % d is % d/n", index, scull_major, SCULL_MINOR_MIN + index, devno );

/* Initialize the char device, associate it with file operation, set its properties, and add it to the kernel through the corresponding device */

Cdev_init (& Dev-> cdev, & scull_fops

);

Dev-> cdev. owner = THIS_MODULE;

Dev-> cdev. ops = & scull_fops;

Err =Cdev_add (& Dev-> cdev, devno, 1

);

If (err ){

Printk (KERN_NOTICE "scull: Err % d adding scull % d/n", err, index );

}

}

/* When a user program opens a device, such as fopen () in the test applet, the kernel will send inode and the user's file attributes. Different users have different operation permissions. */

Int scull_open (struct inode * inode, struct file * filp)

{

Struct scull_dev * dev;


/* The method for obtaining the corresponding device through inode is provided here. The first method is to retrieve the device number. The second method is an interesting function contianer_of, according to the ldd3 book, this is provided by kernel hackers. Container_of (pointer, container_type, container_field) is too convenient. It is convenient to have some questions about whether or not to be insured. */

Printk ("scull_open is called, node % d/n ",Imajor (Inode

)

,Iminor (Inode

)

);

Dev =Container_of (Inode-> I _cdev, struct scull_dev, cdev

);

/* We store dev as filp and private_data to avoid any query in any operation.

*/

Filp-> private_data = dev;

/* View the user permissions. We can use "r" and "w" in fopen to view them separately. If a write-only operation is provided, all the original data (scull_trim () will be cleared ()). */

Printk ("scull: open mode is % x/N", filp-> f_mode );

If (filp-> f_flags & o_accmode) = o_wronly ){

Printk ("scull: only write: free all data/N ");

Scull_trim (Dev );

}

Return 0;

}
/* We call it when the user program fclose. */

Int scull_release (struct inode * inode, struct file * filp)

{

Printk ("scull: release is called./N ");

Return 0;

}

/* Clear all data */

Int scull_trim (struct scull_dev * dev)

{

Struct scull_qset * next, * dptr;

Int qset = dev-> qset;

Int I;

For (dptr = dev-> data; dptr! = NULL; dptr = next ){

If (dptr-> data ){

For (I = 0; I <qset; I ++)

Kfree (dptr-> data [I]);

Kfree (dptr-> data );

Dptr-> data = NULL;

}

Next = dptr-> next;

Kfree (dptr );

}

Dev-> size = 0;

Dev-> quantum = SCULL_QUANTUM;

Dev-> qset = SCULL_QSET;

Dev-> data = NULL;

Return 0;

}

Link: My articles related to the kernel module

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.