Linux Device Driver Learning (3)

Source: Internet
Author: User

1. scull Memory Management

Two basic functions: void * kmalloc (siez_t size, int flags );

Void kfree (void * PTR );

 

In memory, a policy rather than a mechanism is used to select appropriate values for quantum and quantum sets, and the most important values depend on how devices are used. Therefore, device drivers do not need to force specific values to be used for the size of quantum and quantum sets. In the scull device, you can modify these values in the following way: you can modify scull during compilation. macro scull_quantum and scull_qset in H: the value of scull_quantum and scull_qset can also be set in the loading module. This is similar to the method for selecting the master device number on the front.

It indicates that the scull_dev structure of the scull device is important:

Struct scull_dev {

Struct scull_qest * data;/* points to the First Quantum set pointer

Int quantum;/* The current quantum size, which refers to the size of data items in scull_qset.

Int Qest;/* the size of the current array. From scull_trim, we can see that qset refers to the amount of data in scull_qset.

The two items describe the size of the quantum in data, and the amount of the quantum, so that the understanding can correspond to the scull_trim behind.

Unsigned long size;/* The amount of data stored in it

Unsigned int access_key;/* use sculluid and scullpriv

Struct semaphore SEM;/* mutex semaphores

Struct cdev;/* character device structure

};

The quantum and qset fields of this structure respectively store the device's ele. Me quantum and quantum set, but the actual data is processed by another data structure, which is scull_qest"

Struct scull_qest {

Void ** data;

Struct scull_qest * next;

};

The reason why data is a 2-level pointer is that it points to an array, which encapsulates various quantum.

 

The scull_trim function releases the entire data zone and is called by scull_open when the file is opened in writing mode. It simply calls the linked list and releases all the found quantum and quantum sets.

Int scull_trim (struct scull_dev * Dev)

{

Struct scull_qset * Next, * dptr;

Int qset = Dev-> qset;

Int I;

For (dptr = Dev-> data; dptr = NEXT) {// outer loop, traversing scull_qset through dptr and next

If (dptr-> data ){

For (I = 0; I <Qest; I ++) {// The inner layer loop. As analyzed by scull_dev, qset is used to traverse the number of quantum numbers in data in each scull_qset.

Kfree (dptr-> data [I]);

}

Kfree (data );

Dptr-> DATA = NULL;

}

Next = dptr-> next;

Kfree (dptr );

}

Dev-> size = 0;

Dev-> quantum = scull_quantum;

Dev-> DATA = NULL;

Return 0;

}

The module's clearing function also calls scull_trim and returns the memory used by the scull lock to the system.

This function can be combined with Figure 3-1 for better understanding.

 

Here we will first introduce the use of read/write

Struct scull_qset * scull_follow (strcut scull_dev * Dev, int N)

{

Struct scull_qset * Qs = Dev-> data; // assign the First Quantum pointer.

If (! Qs) {// if the data field in Dev is empty, a new space will be opened for it.

Qs = Dev-> DATA = kmalloc (sizeof (struct scull_qset), gfp_kernel );

If (Qs = NULL)

Return NULL; // null if not opened

Memset (QS, 0, sizeof (struct scull_qset); // The opened space is cleared.

}

While (n --){

If (! QS-> next ){

QS-> next = kmalloc (sizeof (struct scull_qset), gfp_kernel );

If (QS-> next = NULL)

Return NULL;

Memset (QS, 0, sizeof (struct scull_qset ));

}

Qs = QS-> next;

Continue;

}

Return QS;

}

The essence of this function is: if it is already in this scull_qset, the pointer to this scull_qset will be returned. If the scull_qset parameter does not exist, the scull_qset pointer is returned when the scull_qset parameter is allocated along the linked list and the scull_qset parameter moves forward along the linked list until the required scull_qset is allocated to the space and initialized.

2. read/write

Ssize_t read (struct file * filp, char _ User * buff, size_t count, loff_t * OFFP );

Ssize_t write (struct file * filp, char _ User * buff, size_t count, loff_t * OFFP );

For the buff parameter, the _ User flag indicates that the buff is the cache of the user space, so it cannot be accessed at will in the kernel space, or it should not be allowed to access user space pointers. However, the preceding two functions need to access the user space to complete the task. Several functions are provided to access the Secure Kernel for data exchange.

Unsigned long copy_to_user (void _ User * To, const void * From, unsigned Long Count );

Unsigned long copy_from_user (void * To, const void _ User * From, unsigned Long Count );

The Read and Write Functions encapsulate the above two functions.

Copy_to_user and copy_from_user functions. If the copy is successful, zero is returned. If the copy fails, no Bytes are returned. When writing a character device driver, you must include the header file <ASM/uaccess. h>.

Be careful when the code running in the kernel space accesses the user space. Because the virtual memory paging mechanism is used, the address user space page may not be in the memory, so the virtual memory system transfers the current process to the sleep state, know where the page is delivered. In addition to copying data, the above two functions also check whether the user space pointer is valid. If the pointer is invalid, it will not be copied.

If process a is reading the device, and process B opens the device as a write, the device is truncated to 0. In this case, process a suddenly finds that it exceeds the end of the file, in addition, it is returned when read is called next time.

Ssize_t scull_read (struct file * filp, char _ User & Buf, size_t count, loff_t * OFFP)

{

Struct scull_dev * Dev = filp-> private_data;

Struct scull_qset * dptr;

Int quantum = Dev-> quantum, qset = Dev-> qset;

Int itemsize = quantum * qset;

Int item, s_pos, q_pos, rest;

Ssize_t retval = 0;

If (down_intertuptible (& Dev-> SEM ){

Return-erestartsys;

If (* f_pos> = Dev-> size)

Goto out;

If (* f_pos + count> Dev-> size)

Count = Dev-> size-* f_ops;

Item = (long) * f_pos/itemsize;

Rest = (long) * f_ops % itemsize;

S_pos = rest/quantum; q_pos = rest % quantum;

Dptr = scull_follow (Dev, item );

If (dptr = NULL |! Dptr-> data |! Dptr-> data [s_pos]) {

Goto out;

If (count> quantum-q_pos)

Count = quantum-q_pos;

If (copy_to_user (BUF, dptr-> data [s_pos] + q_pos, count )){

Retval =-efault;

Goto out;

}

* F_pos + = count;

Retval = count;

 

Out:

Up (& Dev-> SEM );

Return retval;

}

The Write function is roughly the same as the READ function. Only codes that are not the same are listed:

Dptr = scull_follow (Dev, item );

If (dptr = NULL)

Goto out;

If (! Dptr-> data ){

Dptr-> DATA = kmalloc (qset * sizeof (char *), gfp_kernel );

If (! Dptr-> data)

Goto out;

Memset (dptr-> data, 0, qset * sizeof (char *));

}

If (! Dptr-> data [s_pos]) {

Dptr-> data [s_pos] = kmalloc (quantum, gfp_kernel );

If (! Dptr-> data [s_pos])

Goto out;

}

If (count> quantum-q_pos)

Count = quantum-q_pos;

 

 

 

 

 

 

 

 

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.