Simple character Device Driver
1. Primary and secondary device numbers
The main device ID identifies the driver connected to the device. This device ID is used by the kernel and identifies the device under the corresponding driver.
In Linux, the slave number is a 32-bit dev_t type.
Typedef _ u32 _ kernel_dev_t;
Typedef _ kernel_dev_t dev_t; CrW ------- 1 Root 10, 1 Apr 11
2011 psaux
CrW ------- 1 Root 4, 1 Oct 2803: 04
Tty1
CrW-RW-1 root tty 4, 64 Apr 11
2011 ttys0
CrW-RW ---- 1 root uucp4, 65 Apr 11 2011
TTYs
Yes. In the/dev directory, use the $ LS-l command to display some results. We can see that the master device number of the tty driver is 4 (different system versions), and the secondary device number is different.
The first 12 digits identify the master device number |
Major (dev_t Dev) |
Obtain the master device number |
The last 20 digits identify the device number |
Minor (dev_t Dev) |
Get this device number |
The device number is generated by the Primary and Secondary device numbers.
Macro mkdev can be used.
Dev_t dev_num = mkdev (dev_t major, dev_t minor );
2. Allocate and release device numbers
In the character device of linux2.6 (as well as kernel3.0), the first thing to do is to apply for one or more device numbers.
- /* Statically allocate the device number
- * Parameter:
- * First: the first device number allocated.
- * Count: Number of allocated Devices
- * Name: Device Name
- * Return value:
- * 0: Success
- * Negative value: error, error code
- */
- Int register_chrdev_region (dev_t first, unsigned int count, char * Name );
- /* Dynamically allocate device numbers
- * Parameter:
- * Dev: used to store the assigned device number value.
- * Firstminor: Device number (usually 0)
- * Count: Number of allocated Devices
- * Name: Device Name
- * Return value:
- * 0: Success
- * Negative value: error, error code
- */
- Int alloc_chrdev_region (dev_t * Dev, unsigned int firstminor, unsigned int count, char * Name );
- /* Release the device number
- * Parameter:
- * First: Device number
- * Count: Number of allocated Devices
- */
- Void unregister_chrdev_region (dev_t first, unsigned int count );
Static allocation of device numbers is used when an available device number is known. Before programming, programmers mostly know whether the device number is available or not, it cannot be ensured that the device is still available during system upgrade.
Therefore, dynamic allocation is strongly recommended in the Linux community. It will find available device numbers without conflict. You must release the device number when detaching the device.
3. An ineffective character Device Driver
- # Include <Linux/init. h>
- # Include <Linux/module. h>
- # Include <Linux/types. h>
- # Include <Linux/fs. h>
- # Define simple_debug 1
- # Define dev_count 2
- # Define simple_name "simple_char"
- Static int simple_major= 108;
- Static int simple_minor = 0;
- Static _ init int simple_init (void)
- {
- Dev_t dev;
- Int err;
- # If simple_debug
- Printk (kern_info "in % s \ n", _ FUNC __);
- # Endif
- Dev = mkdev (simple_major, simple_minor); // obtain the device ID.
- If (Dev> 0) // The device number is valid.
- {
- # If simple_debug
- Printk (kern_info "try to register static char Dev % d \ n", Dev );
- # Endif
- Err = register_chrdev_region (Dev, dev_count, simple_name); // statically allocate the device number
- If (ERR <0) // static Allocation Error try to use Dynamic Allocation
- {
- Printk (kern_warning "register static char Dev error \ n ");
- Err = alloc_chrdev_region (& Dev, 0, dev_count, simple_name); // dynamically allocate device numbers
- If (ERR <0)
- {
- Printk (kern_err "register char Dev error in line % d \ n" ,__ line __);
- Goto error;
- }
- Else
- {
- Simple_major = major (Dev); // recalculate the master device number
- Simple_minor = minor (Dev); // recalculate the device number
- }
- }
- Else {
- }
- }
- Else // The device number cannot be dynamically allocated
- {
- # If simple_debug
- Printk (kern_info "try to register alloc char Dev \ n ");
- # Endif
- Err = alloc_chrdev_region (& Dev, 0, dev_count, simple_name );
- If (ERR <0)
- {
- Printk (kern_err "register char Dev error in line % d \ n" ,__ line __);
- Goto error;
- }
- Else
- {
- Simple_major = major (Dev );
- Simple_minor = minor (Dev );
- }
- }
- # If simple_debug
- Printk (kern_info "register char Dev success major = % d Minor = % d \ n", simple_major, simple_minor );
- # Endif
- Error:
- Return err;
- }
- Static _ exit void simple_exit (void)
- {
- Dev_t dev;
- # If simple_debug
- Printk (kern_info "in % s \ n", _ FUNC __);
- # Endif
- Dev = mkdev (simple_major, simple_minor );
- Unregister_chrdev_region (Dev, dev_count); // release the device number.
- }
- Module_init (simple_init );
- Module_exit (simple_exit );
- Module_license ("GPL ");
- Module_author ("kai_zhang (jsha.zk@163.com )");
- Module_description ("simple char driver! ");
In this example, only the device number is assigned during module initialization, and the device Number of the driver is released when the module is canceled.
In the function, we can see the notorious goto function in application programming. In Linux-driven programming, the Goto function makes our programming more organized, it can be processed more quickly when an error occurs.
If errors are handled by the caller of the Function check, the module functions are bloated and huge. Therefore, we recommend that you use the Goto function properly.
After the module is loaded
Run $ CAT/proc/devices to view the device and master device Number of simple_char.
Here we can see that the original primary device number is not available, so we use the Dynamic Allocation of the device number, so we apply to the primary device number 249, we can add our device above, the specific operation will be discussed in the next section. Leave some suspense first.