1. MODULE_LICENSE ("GPL"); int hello_major = 250; int hello_minor = 0; int number_of_devices = 1; char data[50]="foobar not equal to barfoo"; struct cdev cdev; dev_t dev = 0; static int hello_open (struct inode *inode, struct file *file) { printk (KERN_INFO "Hey! device opened\n"); return 0; } static int hello_release (struct inode *inode, struct file *file) { printk (KERN_INFO "Hmmm... device closed\n"); return 0; } ssize_t hello_read (struct file *filp, char *buff, size_t count, loff_t *offp) { ssize_t result = 0; if (copy_to_user (buff, data, sizeof(data)-1)) // copy_to_user将数据返回给用户 result = -EFAULT; else printk (KERN_INFO "wrote %d bytes\n", count); return result; } ssize_t hello_write (struct file *filp, const char *buf, size_t count, loff_t *f_pos) { ssize_t ret = 0; printk (KERN_INFO "Writing %d bytes\n", count); if (count>127) return -ENOMEM; if (count<0) return -EINVAL; if (copy_from_user (data, buf, count)) { // copy_from_user将用户数据读到本地buffer ret = -EFAULT; } else { data[127]='\0'; printk (KERN_INFO"Received: %s\n", data); ret = count; } return ret; } struct file_operations hello_fops = { //文件操作 .owner = THIS_MODULE, .open = hello_open, .release = hello_release, .read = hello_read, .write = hello_write }; static int __init hello_2_init (void) { int result; dev = MKDEV (hello_major, hello_minor); //拼装设备号,高12位为主设备号,低20位为从设备号。include/linux/kdev_t.h中定义的宏MKDEV。 result = register_chrdev_region (dev, number_of_devices, "hello");// fs/char_dev.c中定义的函数,注册一个范围内的设备号,成功返回0。 if (result<0) { printk (KERN_WARNING "hello: can't get major number %d\n", hello_major); return result; } /* dynamic allocation */ cdev = cdev_alloc(); // fs/char_dev.c中定义的函数,分配一个cdev结构体 cdev_init (cdev, &hello_fops); // fs/char_dev.c中定义的函数,关联cdev结构体和file_operations(在linux/fs.h中定义的结构体,里面为文件的常用操作定义)。 cdev->owner = THIS_MODULE; // cdev->ops = &hello_fops; result = cdev_add (cdev, dev, 1); // fs/char_dev.c中定义的函数,关联cdev结构体和dev(设备号)。 if (result) printk (KERN_INFO "Error %d adding char_device", result); printk (KERN_INFO "Char device registered ...\n"); return 0; } static void __exit hello_2_exit (void) { dev_t devno = MKDEV (hello_major, hello_minor); if (cdev) cdev_del (cdev); // fs/char_dev.c中定义的函数,取消cdev结构体和dev(设备号)的关联 unregister_chrdev_region (devno, number_of_devices); // fs/char_dev.c中定义的函数,释放cdev结构体的空间和dev设备号 printk (KERN_INFO "char device cleaned up :)\n"); } module_init (hello_2_init); module_exit (hello_2_exit); //宏module_init和module_exit都被定义在linux源码的include/linux/init.h中,是为init_module和cleanup_module起别名用的(在静态编译时防止重复定义init_module和cleanup_module)。 2. 当open一个设备节点时,inode中德i_cdev会指向找到的cdev,同时file中的f_op获得已经注册的驱动的file_operations。 cdev---dev (如:250,0) ---ops(mypos)---open,read,write等。<----------------------> file---f_op 3. 用户调用read等系统调用时,系统首先调用sys_read(SYSCALL_DEFINE3),再调用vfs_read,再调用初始化完成的结构体file中的file_operations中的read函数,即为调用了hello_read函数。