1. Call module_init (scull_init_module) in the insmod module. Let's take a look at this function: int scull_init_module (void)
II,
Int scull_init_module (void) <br/>{< br/> int result, I; // declare two integer variables result, I <br/> dev_t Dev = 0; // declare a dev_t type object Dev. The default initial value is 0 </P> <p> // the following code calls the alloc_chrdev_region method to dynamically generate the device number to Dev, the device name is "scull" and the master device number in Dev is extracted and paid to scull_major by calling the macro major (dev_t Dev) </P> <p> // the prototype of the alloc_chrdev_region function is: int alloc_chrdev_region (dev_t * Dev, unsigned int firstminor, unsigned int count, char * Name); </P> <p> // each parameter has the following meanings: </P> <p> // Dev _ T * Dev: dev_t pointer, which is the address of the variable (storing the generated device number) </P> <p> // firstminor: the first device number to be requested, usually 0. This document defines int scull_minor = 0; </P> <p> // count: the number of consecutive device numbers requested. Here is scull_nr_devs. This document defines: int scull_nr_devs = scull_nr_devs; </P> <p> // scull_nr_devs in the header file scull. </P> <p> // # ifndef scull_nr_devs <br/> // # define scull_nr_devs 4/* scull0 through scull3 */<br/> // # endif </P> <p> // Name: char pointer. Is the name of the device associated with the specified range. The "scull" name will appear in the/proc/devices and sysfs files </P> <p> If (scull_major) {<br/> Dev = mkdev (scull_major, scull_minor); <br/> result = register_chrdev_region (Dev, scull_nr_devs, "scull"); <br/>} else {// The default scull_major = 0; therefore, use the Dynamic Allocation Method <br/> result = alloc_chrdev_region (& Dev, scull_minor, scull_nr_devs, <br/> "scull "); <br/> scull_major = major (Dev); <br/>}< br/> If (result <0) {<br/> printk (kern_warnin G "scull: Can't Get Major % d/N", scull_major); <br/> return result; <br/>}</P> <p> // scull_devices: A pointer variable declared in the scull_dev structure: struct scull_dev * scull_devices; </P> <p> // The scull_dev structure is customized. Each scull device has a corresponding scull_dev structure. In scull. statement in H. </P> <p> // struct scull_dev {<br/> // struct scull_qset * data; /* pointer to the First Quantum set <br/> // int quantum;/* quantum size <br/> // int qset; /* large and small quantum set <br/> // unsigned long size;/* Total Amount of stored data */<br/> // unsigned int access_key; /* used by sculluid and scullpriv */<br/> // struct semaphore SEM;/* Mutual Exclusion semaphore */<br/> // struct cdev; /* character device structure */<br/> //}; <br/> // the prototype of the kmalloc function is void * kmalloc. (Size_t size, int flags); its function is to dynamically open up memory in the device driver or kernel module. each parameter has the following meanings: </P> <p> // size: the size of the memory to be allocated. in bytes. here is (the size of a scull_dev structure) * Number of devices. The number of devices is determined by scull_nr_devs as four </P> <p> // flags: the type of memory to be allocated. the most common gfp_kernel flag is used here. Green = get free page. </P> <p> // This function returns the first address of the allocated memory. The address is paid to scull_dev's pointer variable scull_devices </P> <p> // if the allocation is not successful, then goto fail </P> <p> // because kmalloc does not clear the acquired memory space, therefore, the memset function is called to clear the memory </P> <p> // the prototype of the memset function is void * memset (void * s, int C, size_t N ); the general function is to set the value of the first n Bytes of the memory space S to the value c. </P> <p> scull_devices = kmalloc (scull_nr_devs * sizeof (struct scull_dev), gfp_kernel); <br/> If (! Scull_devices) {<br/> result =-enomem; <br/> goto fail; /* make this more graceful */<br/>}</P> <p> memset (scull_devices, 0, scull_nr_devs * sizeof (struct scull_dev )); // reset the opened memory </P> <p> // initialize and register each device </P> <p> // 1. set the quantum size of each device to 4000 </P> <p> // 2. set the array size of each device to 1000 </P> <p> // 3. set the mutex semaphores of each device to 1. the prototype of the function is void init_mutex (struct semaphore * SEM); </P> <p> // This function is used to initialize a mutex lock, that is, it sets the semaphores SEM value to 1. </P> <p> // 4. Use the custom function scull_setup_cdev to initialize the character device structure and add it to the system (register the device). A total of four devices are added. The function is defined as follows: </P> <p> // static void scull_setup_cdev (struct scull_dev * Dev, int index) <br/> // {<br/> // int err, devno = mkdev (scull_major, scull_minor + index ); // scull_major that has been dynamically allocated is used here <br/> // The following steps are very important !!! Is the basic process of registering an independent cdev device !!! <Br/> // cdev_init (& Dev-> cdev, & scull_fops); // initialize struct cdev <br/> // Dev-> cdev. owner = this_module; // initialize cdev. owner <br/> // Dev-> cdev. ops = & scull_fops; // initialize cdev. ops <br/> // err = cdev_add (& Dev-> cdev, devno, 1); // After the cdev structure is set, inform the kernel of the structure <br/> /// * fail gracefully if need be */<br/> // If (ERR) <br/> // printk (kern_notice "error % d adding scull % d", err, index ); <br/> //} </P> <p> for (I = 0; I <scull_nr_devs; I ++) {<br/> scull_devices [I]. quantum = scull_quantum; <br/> scull_devices [I]. qset = scull_qset; <br/> init_mutex (& scull_devices [I]. SEM); <br/> scull_setup_cdev (& scull_devices [I], I ); <br/>}</P> <p>/* at this point call the init function for any friend device */</P> <p> // not considered here other devices </P> <p> Dev = mkdev (scull_major, scull_minor + scull_nr_devs); </P> <p> Dev + = scull_p_init (Dev); </P> <p> Dev + = scull_access_init (Dev); <br/>
The device has been initialized.
Summarize the initialization steps of the module (only the general situation is taken into account, not the special case of Scull ).
Step 1: dynamically generate the device ID. The key functions of this step are as follows:
Int alloc_chrdev_region (dev_t * Dev, unsigned int firstminor, unsigned int count, char * Name );
Step 2: assign a character device structure. The key functions of this step are as follows:
Struct cdev * cdev_alloc (void );
(In scull, kmalloc is used to open up memory for the device)
Step 3: Initialize and add the device. The key functions of this step are as follows:
Void cdev_init (struct cdev * cdev, struct file_operations * FoPs );
Int cdev_add (struct cdev * Dev, dev_t num, unsigned int count );
Step 2 and Step 3 are collectively referred to as "Registration of character devices"