linux驱动学习

  1. Linux设备驱动开发学习笔记   
  2. 内核版本:2.6.x   
  3.   
  4.      
  5.   Major and Minor Numbers   
  6. 内核通过major号来识别设备,下面的命令列出的是系统上所连接的设备及其major number,第一列就是设备的major number.   
  7. $ cat /proc/devices    
  8. Character devices:   
  9.   1 mem   
  10.   4 /dev/vc/0  
  11.   4 tty   
  12.   5 /dev/tty   
  13.   5 /dev/console   
  14.   5 /dev/ptmx   
  15.   7 vcs   
  16.  10 misc   
  17.  13 input   
  18.  14 sound   
  19. 116 alsa   
  20. 128 ptm   
  21. 136 pts   
  22. 180 usb   
  23. 195 nvidia   
  24. 226 drm   
  25. 254 devfs   
  26.   
  27. Block devices:   
  28.   3 ide0   
  29.  22 ide1   
  30. $ls -l /dev   
  31. ..............   
  32. crw-------  1 root root 119,   0 Apr 24 11:34 vmnet0   
  33. crw-------  1 root root 119,   1 Apr 24 11:34 vmnet1   
  34. crw-------  1 root root 119,   2 Apr 24 11:34 vmnet2   
  35. crw-------  1 root root 119,   3 Apr 24 11:34 vmnet3   
  36. crw-------  1 root root 119,   4 Apr 24 11:34 vmnet4   
  37. crw-------  1 root root 119,   5 Apr 24 11:34 vmnet5   
  38. crw-------  1 root root 119,   6 Apr 24 11:34 vmnet6   
  39. crw-------  1 root root 119,   7 Apr 24 11:34 vmnet7   
  40. crw-------  1 root root 119,   8 Apr 24 11:34 vmnet8   
  41. ..............   
  42. 可以看到他们的major number 是119,但他们的minor number不同.分别是0~8.   
  43. 内核只关心major number,而minor number 是由设备驱动来区别的.   
  44. 内核内部,类型dev_t存储着设备号,且定义了一组宏来维护它.   
  45.     MKDEV(int major,int minor);//return dev_t   
  46.     MAJOR( dev_t dev);   
  47.     MINOR (dev_t dev);   
  48. 比如,我们用mknod建立一个新的设备文件   
  49.     #mknod /dev/newchr c 50 0  
  50. 建立/dev/newchr设备文件,类型是c(char,字符型),major number 是50,minor number 是0.mknod的用法可以用man来查看.   
  51. 在内核内部,我们用上面的宏来维护:   
  52.     dev_t mydev;   
  53.     mydev=MKDEV(50,0);   
  54. 我们也可以由mydev得到major 和minor number.   
  55.     int major,minor;   
  56.     major=MAJOR(mydev);   
  57.     minor=MINOR(mydev);   
  58.   
  59.   
  60.   注册设备号   
  61. 我们定义好major和minor number 后就可以在内核中注册一个设备了.注册一个字符设备需要用到下面几个函数:   
  62.     int register_chrdev_region(dev_t first,unsigned int count,   
  63.                         char *name);   
  64. first是你要注册的设备号范围的开始(其中minor号一般设置为0),count是你所申请的连续设备号的总数.name是设备的名称.它会在/proc/devices中出现.   
  65.     int alloc_chrdev_region(dev_t *dev,unsigned int firstminor,   
  66.                 unsigned int count,char *name);   
  67. 这个函数是用来动态分配设备号的.有余开发者不知道所要用的major号是多少,便让内核动态分配一个.参数dev是个output-only参数.   
  68.     void unregister_chrdev_region(dev_t first,unsigned int count);   
  69. 一般在模块清除函数中调用.   
  70.   
  71. 重要的数据结构   
  72. 正如你所想象的,注册只是第一步,后面还有更重要的部分,其中一个就是我们一开始提到的如何实现open/read/write/ioctl等用户接口.   
  73. 首先看一下几个重要的数据结构:   
  74.     file_operations,file,inode   
  75. <linux/fs.h>中定义了这三个结构.   
  76. struct file_operations {   
  77.         struct module *owner;   
  78.         loff_t (*llseek) (struct file *, loff_t, int);   
  79.         ssize_t (*read) (struct file *, char __user *, size_t, loff_t *);   
  80.         ssize_t (*aio_read) (struct kiocb *, char __user *, size_t, loff_t);   
  81.         ssize_t (*write) (struct file *, const char __user *, size_t, loff_t *);   
  82.         ssize_t (*aio_write) (struct kiocb *, const char __user *, size_t, loff_t);   
  83.         int (*readdir) (struct file *, void *, filldir_t);   
  84.         unsigned int (*poll) (struct file *, struct poll_table_struct *);   
  85.         int (*ioctl) (struct inode *, struct file *, unsigned int, unsigned long);   
  86.         int (*mmap) (struct file *, struct vm_area_struct *);   
  87.         int (*open) (struct inode *, struct file *);   
  88.         int (*flush) (struct file *);   
  89.         int (*release) (struct inode *, struct file *);   
  90.         int (*fsync) (struct file *, struct dentry *, int datasync);   
  91.         int (*aio_fsync) (struct kiocb *, int datasync);   
  92.         int (*fasync) (int, struct file *, int);   
  93.         int (*lock) (struct file *, int, struct file_lock *);   
  94.         ssize_t (*readv) (struct file *, const struct iovec *, unsigned long, loff_t *);   
  95.         ssize_t (*writev) (struct file *, const struct iovec *, unsigned long, loff_t *);   
  96.         ssize_t (*sendfile) (struct file *, loff_t *, size_t, read_actor_t, void *);   
  97.         ssize_t (*sendpage) (struct file *, struct page *, int, size_t, loff_t *, int);   
  98.         unsigned long (*get_unmapped_area)(struct file *, unsigned long, unsigned long, unsigned long, unsigned long);   
  99.         int (*check_flags)(int);   
  100.         int (*dir_notify)(struct file *filp, unsigned long arg);   
  101. }   
  102. file_operations结构定义了一组函数指针,每一个打开的文件(用struct file表示)和他自己的一组函数(包含在一个叫f_op的域中,它指向一个struct file_operations结构)相联系.这些操作都是来实现系统调用的,所以才被命名为open,read,等等.对于那些不需要的功能(比如你的设备不需要write功能,即不需要向设备写数据),可以给write指针付NULL.   
  103.   
  104. struct file {   
  105.         struct list_head        f_list;   
  106.         struct dentry           *f_dentry;   
  107.         struct vfsmount         *f_vfsmnt;   
  108.         struct file_operations  *f_op;   
  109.         atomic_t                f_count;   
  110.         unsigned int            f_flags;   
  111.         mode_t                  f_mode;   
  112.         int                     f_error;   
  113.         loff_t                  f_pos;   
  114.         struct fown_struct      f_owner;   
  115.         unsigned int            f_uid, f_gid;   
  116.         struct file_ra_state    f_ra;   
  117.   
  118.         unsigned long           f_version;   
  119.         void                    *f_security;   
  120.   
  121.         /* needed for tty driver, and maybe others */   
  122.         void                    *private_data;   
  123.   
  124. #ifdef CONFIG_EPOLL   
  125.         /* Used by fs/eventpoll.c to link all the hooks to this file */   
  126.         struct list_head        f_ep_links;   
  127.         spinlock_t              f_ep_lock;   
  128. #endif /* #ifdef CONFIG_EPOLL */   
  129.         struct address_space    *f_mapping;   
  130. };   
  131. 每个打开的文件对应一个struct file.它在被打开时由内核创建,并传给它所有可以操作该文件的函数,到文件被关闭时才被删除.   
  132.   
  133. The inode Structure.   
  134. Inode结构是用来在内核内部表示文件的.同一个文件可以被打开好多次,所以可以对应很多struct file,但是只对应一个struct inode.该结构里面包含了很多信息,但是,驱动开发者只关心里面两个重要的域:   
  135.     dev_t i_rdev;//含有真正的设备号   
  136.     struct cdev *i_cdev;//struct cdev是内核内部表示字符设备的结构.   
  137.   
  138. 注册字符设备   
  139.   
  140. <linux/cdev.h>   
  141. 可以有两种方法注册   
  142.     struct cdev *my_cdev=cdev_alloc();   
  143.     my_cdev->ops=&my_fops;   
  144. 或   
  145.     void cdev_init(struct cdev *cdev,struct file_operations *fops);   
  146.   
  147. 注册完后还要通知内核一声,通过调用   
  148.     int cdev_add(struct cdev *dev,dev_t num,unsigned int count);   
  149. count 一般是 1.   
  150.   
  151. 删除字符设备,调用   
  152.     void cdev_del(struct cdev *dev);   
  153.   
  154.   
  155. 说了那么多,现在可以来个例子了.   
  156. #include <linux/kernel.h>   
  157. #include <linux/fs.h>   
  158. #include <linux/module.h>   
  159. #include <asm/uaccess.h>   
  160. #include <linux/cdev.h>   
  161. #include <asm/uaccess.h>   
  162.   
  163.   
  164. #define DP_MAJOR 50  
  165. #define DP_MINOR 0  
  166. static int char_read(struct file *filp,char __user *buffer,size_t,loff_t *);   
  167. static int char_open(struct inode *,struct file *);   
  168. static int char_write(struct file *filp,const char __user *buffer,size_t ,loff_t*);   
  169. static int char_release(struct inode *,struct file *);    
  170. static char *arr,*p;   
  171. static int chropen;   
  172. struct cdev *my_cdev;   
  173. static int len;   
  174. struct file_operations Fops = {   
  175.     .read = char_read,   
  176.     .write = char_write,   
  177.     .open = char_open,   
  178.     .release = char_release,    /* a.k.a. close */   
  179. };   
  180. static int __init char_init(void)   
  181. {   
  182.     printk(KERN_ALERT"Initing......\n");   
  183.     dev_t dev;   
  184.     dev=MKDEV(DP_MAJOR,DP_MINOR);   
  185.     my_cdev = cdev_alloc( );   
  186.     arr=kmalloc(1024,GFP_KERNEL);   
  187.     if(arr==NULL){   
  188.         printk(KERN_ALERT"kmalloc error\n");   
  189.     }   
  190.     sprintf(arr,"Hello,Pid=%d\n",current->pid);   
  191.     if(my_cdev==NULL){   
  192.         return -1;   
  193.     }   
  194.     if(register_chrdev_region(dev,10,"dpchr")<0){   
  195.         printk(KERN_ALERT"Register char dev error\n");   
  196.         return -1;   
  197.     }   
  198.     chropen=0;   
  199.     len=0;   
  200.     my_cdev->ops = &Fops;   
  201.     cdev_init(my_cdev,&Fops);   
  202.     cdev_add(my_cdev,dev,1);   
  203.   
  204.     return 0;   
  205. }   
  206.   
  207. static int char_open(struct inode *inode,struct file *file)   
  208. {   
  209.     if(chropen==0)   
  210.         chropen++;   
  211.     else{   
  212.         printk(KERN_ALERT"Another process open the char device\n");   
  213.         return -1;   
  214.     }   
  215.     p=arr;   
  216.     try_module_get(THIS_MODULE);   
  217.     return 0;   
  218. }   
  219.   
  220. static int char_release(struct inode *inode,struct file *file)   
  221. {   
  222.     chropen--;   
  223.     module_put(THIS_MODULE);   
  224.     return 0;   
  225. }   
  226.   
  227. static int char_read(struct file *filp,char __user *buffer,size_t length,loff_t *offset)   
  228. {   
  229.     int i=0;   
  230.     if(*p=='\0')   
  231.         return 0;   
  232.     while(length&&*p){   
  233.         put_user(*(p++),buffer++);   
  234.         length--;   
  235.         i++;   
  236.     }   
  237.     return i;   
  238. }   
  239.   
  240. static int char_write(struct file *filp,const char __user  *buffer,size_t length,loff_t *offset)   
  241. {   
  242.   
  243.     int i;   
  244.     for(i=0;i<length&&i<1024;i++)   
  245.         get_user(p[i],buffer+i);   
  246.   
  247.     p[i]=0;   
  248.     len=i;   
  249.     return i;   
  250. }   
  251.        
  252.   
  253. static void module_close()   
  254. {   
  255.     len=0;   
  256.     printk(KERN_ALERT"Unloading..........\n");   
  257.     kfree(arr);   
  258.     unregister_chrdev_region(MKDEV(DP_MAJOR,DP_MINOR),10);   
  259.     cdev_del(my_cdev);   
  260. }   
  261.   
  262. module_init(char_init);   
  263. module_exit(module_close);   
  264.   
  265. 需要注意的是,用户调用read/write时返回的值便是我们实现的函数(char_read,char_write)返回的值,所以我们不能随便的返回一个值(比如,0,用户的read/write返回0,所以会认为出错了,然后并没有出错,只是我们返回了一个错误的值而已.   
  266.   
  267.   
  268. 参考资料   
  269. 内核模块的编程http://www.tldp.org/LDP/lkmpg/2.6/html/index.html   
  270. Linux Device Driver 3rd Edition   
  271. Linux Kernel Development 2nd Edition  
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值