The biggest feature of Linux devices is that device operations are like file operations. In the application layer, a hardware device is just a device file. Applications can operate hardware devices like operating files, such as open (), close (), read (), and write.
Below is a simple implementation of the character device driver test. c
# Include <Linux/types. h> <br/> # include <Linux/Fs. h> <br/> # include <Linux/mm. h> <br/> # include <Linux/errno. h> <br/> # include <Linux/module. h> <br/> # include <Linux/moduleparam. h> <br/> # include <Linux/kernel. h> <br/> # include <ASM/uaccess. h> <br/> # include <Linux/cdev. h> <br/> # include <Linux/IOCTL. h> <br/> # include <Linux/slab. h> <br/> # include <Linux/fcntl. h> <br/> # include <ASM/segment. h> <br/> # include <ASM/Io. h> <br/> # include <ASM/ARCH/regs-gpio.h> <br/> unsigned int test_major = 253; <br/> unsigned int test_minor = 0; <br/> struct cdev cdevc; <br/> module_license ("dual BSD/GPL"); <br/> static int read_test (struct file * file, char * Buf, int count, loff_t * f_pos) <br/>{< br/> printk ("/n read_test"); <br/> printk ("/n % d ", count); <br/> return count; <br/>}< br/> static int write_test (struct file * file, const char * Buf, int count, loff_t * f_pos) <br/>{< br/> printk ("/n write_test"); <br/> return count; <br/>}< br/> static int open_test (struct inode * inode, struct file * file) <br/>{< br/> printk ("/n open_test"); <br/> return 0; <br/>}< br/> static void release_test (struct inode * inode, struct file * file) <br/>{< br/> printk ("/n release_test"); <br/>}< br/> struct file_operations test_fops ={ <br/>. owner = this_module, <br/>. read = read_test, <br/>. write = write_test, <br/>. open = open_test, <br/>. release = release_test, <br/>}; <br/> int simple_c_init_module (void) <br/>{< br/> int result; <br/> dev_t Dev = 0; </P> <p> Dev = mkdev (test_major, test_minor); <br/> result = register_chrdev_region (Dev, 1, "test "); </P> <p> printk ("Major = % d, minor = % d/N", test_major, test_minor ); </P> <p> If (result <0) <br/> {<br/> printk (kern_info "test: Can't Get Major number/N "); <br/> return result; <br/>}</P> <p> cdev_init (& cdevc, & test_fops); <br/> cdevc. owner = this_module; <br/> cdevc. ops = & test_fops; <br/> result = cdev_add (& cdevc, Dev, 1); <br/> If (result) <br/> printk ("error % d adding test", result); <br/> return 0; <br/>}< br/> void simple_c_cleanup_module (void) <br/>{ <br/> dev_t Dev = 0; <br/> Dev = mkdev (test_major, test_minor); <br/> cdev_del (& cdevc ); <br/> unregister_chrdev_region (Dev, 1); <br/>}< br/> module_init (simple_c_init_module); <br/> module_exit (simple_c_cleanup_module );
Module Analysis
1. initialize the device driver struct
Struct file_operations test_fops = {
. Owner = this_module,
. Read = read_test,
. Write = write_test,
. Open = open_test,
. Release = release_test,
};
Defines the function called during device Io. In this module, the upper-layer read calls the underlying read_test, the write calls write_test, the open calls open_test, and the close calls release_test.
2. module_init Function
Int simple_c_init_module (void)
{
Int result;
Dev_t Dev = 0;
Dev = mkdev (test_major, test_minor );
Result = register_chrdev_region (Dev, 1, "test ");
Printk ("Major = % d, minor = % d/N", test_major, test_minor );
If (result <0)
{
Printk (kern_info "test: Can't Get Major number/N ");
Return result;
}
Cdev_init (& cdevc, & test_fops );
Cdevc. Owner = this_module;
Cdevc. Ops = & test_fops;
Result = cdev_add (& cdevc, Dev, 1 );
If (result)
Printk ("error % d adding test", result );
Return 0;
}
(1) first, mkdev is a device. test_major and test_minor are defined before the file respectively.
Unsigned int maid = 253;
Unsigned int test_minor = 0;
(2) register a device number in the specified range,
Result = register_chrdev_region (Dev, 1, "test ");
The function prototype is
Int register_chrdev_region (dev_t from, unsigned count, <br/> const char * Name );
The three parameters indicate the device number in the expected range for the first time, the number of devices required for the number of consecutive devices, the device or driver in this name, respectively.
(3) printk prints two device numbers in the kernel, similar to the printf function.
(4) initialize the character device structure cdev_init (& cdevc, & test_fops );
The two parameters indicate: the initialization of the structure, the file_operations of the device,
The function is used to remember to initialize the FoPs cdev so that it can be added to the system and cdev_add.
(5) assign a value to the structure cdevc of the character device
(6) Call int cdev_add (struct cdev * P, dev_t Dev, unsigned count );
Function: cdev_add adds the P struct to the system device so that it takes effect immediately. A negative error code returns an error.
3. module_exit (); Function
Void simple_c_cleanup_module (void)
{
Dev_t Dev = 0;
Dev = mkdev (test_major, test_minor );
Cdev_del (& cdevc );
Unregister_chrdev_region (Dev, 1 );
}
Function cdev_del-remove a character device from the system
The range of device numbers returned by the function unregister_chrdev_region.
4. Underlying Function Design
Static int read_test (struct file * file, char * Buf, int count, loff_t * f_pos) <br/>{< br/> printk ("/n read_test "); <br/> printk ("/n % d", count); <br/> return count; <br/>}< br/> static int write_test (struct file * file, const char * Buf, int count, loff_t * f_pos) <br/>{< br/> printk ("/n write_test"); <br/> return count; <br/>}< br/> static int open_test (struct inode * inode, struct file * file) <br/>{< br/> printk ("/n open_test"); <br/> return 0; <br/>}< br/> static void release_test (struct inode * inode, struct file * file) <br/>{< br/> printk ("/n release_test"); <br/>}
Demo:
Compile, make (makefile see http://blog.csdn.net/wanxiao009/archive/2010/06/13/5669665.aspx)
Generate Test. Ko
Minicom logon to the Development Board,
Sent to the Development Board,
Chmod + X test. Ko
Create a device node mknod/dev/test C 253 0 (253 0 is test_major, test_minor)
Insmod test. Ko
As shown in
Description: The character driver can be added to the kernel module. ^_^!