Chinaunix首页 | 论坛 | 博客
  • 博客访问: 159895
  • 博文数量: 118
  • 博客积分: 0
  • 博客等级: 民兵
  • 技术积分: 12
  • 用 户 组: 普通用户
  • 注册时间: 2013-06-21 16:38
文章分类

全部博文(118)

文章存档

2013年(118)

我的朋友

分类: 嵌入式

2013-12-06 12:33:13

设备驱动:为应用层提供了访问设备的接口

字符设备:mouse/keyboard/串口/帧缓存...        以字节为单位访问,一般只支持顺序访问,无缓冲
块设备:disk/flash...        以固定大小为单位访问 支持随机访问 ,有缓冲
网络设备:无设备文件 通过socket访问

虚拟文件系统(VFS):为应用层提供了统一的文件访问接口

设备驱动编写步骤:

一、申请设备号
设备号作用:识别设备
设备号 为32位无符号整形数  
低20位为次设备号,高12位为主设备号
主设备号(major) 次设备号(minor)
区别不同类型的设备         区分同一类型的不同设备

获取设备号用MKDEV 函数:
    

点击(此处)折叠或打开

  1. int hello_major = 250;
  2. int hello_minor = 0;
  3. dev_t dev = 0;

  4. dev = MKDEV (hello_major, hello_minor);
查看当前版本内核中设备号的使用情况:内核/Document 下 devices.txt 文本中

申请设备号:
1、静态申请

点击(此处)折叠或打开

  1. 申请设备号:
  2.   result = register_chrdev_region (dev, number_of_devices, "hello");
  3.   if (result<0) {
  4.     printk (KERN_WARNING "hello: can't get major number %d\n", hello_major);
  5.     return result;
  6.   }
  7. 释放设备号:
  8.   unregister_chrdev_region (dev, number_of_devices);


/proc/devices 存放系统中当前已经申请的设备号

2.动态申请
    int alloc_chrdev_region(dev_t *dev,unsigned baseminor,unsigned count,const char *name)

静态申请和动态申请比较:
    静态申请可以提前创建设备文件,动态申请不会设备号冲突

二、定义操作集合:
设备操作:打开,关闭,读,写

struct file_operations 字符设备操作集合结构体
成员    .owner = THIS_MODULE ;只有这一种复制

三、注册字符设备
    通过cdev 把设备号和操作集合相关联,并且添加到内核cdev链表中,
如:struct cdev cdev;
        cdev.owner = THIS_MODULE;
        cdev_init(&cdev,&hello_ops);
        cdev_add(&cdev,dev,1);

创建设备节点:mknod /dev/hello c 250 0
删除设备节点:rmmod /dev/hello

常见错误:
mknod /dev/hello c 250 0
mknod /dev/hello c 251 0
创建第二个设备节点时错误,因为linux下不能有同名文件。

下面这个用法则可以:
mknod /dev/hello c 250 0
mknod /dev/hi     c 250 0
这样创建节点 ,无论打开哪个,只要设备号一样 打开的是同一个设备

驱动源码:

点击(此处)折叠或打开

  1. #include <linux/module.h>
  2. #include <linux/kernel.h>
  3. #include <linux/init.h>
  4. #include <linux/cdev.h>
  5. #include <linux/fs.h>

  6. MODULE_LICENSE ("GPL");         //必须遵循GPL协议

  7. int hello_major = 250;        //主设备号
  8. int hello_minor = 0;            //次设备号
  9. int number_of_devices = 1;        //设备数

  10. struct cdev cdev;    

  11. struct file_operations hello_ops =
  12. {
  13.     .owner = THIS_MODULE
  14. };

  15. static void char_reg_setup_cdev(void)      //注册设备
  16. {
  17.     dev_t dev = MKDEV (hello_major,hello_minor);
  18.     int error;

  19.     cdev_init(&cdev,&hello_ops);
  20.     error = cdev_add(&cdev,dev,1);
  21.     if(error)
  22.         printk("Error %d cdev_add",error);

  23. }

  24. static int __init hello_2_init (void)    //初始化函数
  25. {
  26.   int result;
  27.   dev_t dev = 0;

  28.   dev = MKDEV (hello_major, hello_minor);    
  29.   result = register_chrdev_region (dev, number_of_devices, "hello");        //申请设备号
  30.   if (result<0) {
  31.     printk (KERN_WARNING "hello: can't get major number %d\n", hello_major);//错误打印
  32.     return result;
  33.   }

  34.   char_reg_setup_cdev();    //执行注册设备函数

  35.   printk (KERN_INFO "Registered character driver\n");    

  36.   return 0;
  37. }

  38. static void __exit hello_2_exit (void)
  39. {
  40.   dev_t dev = MKDEV (hello_major, hello_minor);

  41.   cdev_del(&cdev);    //接触关联

  42.   unregister_chrdev_region (dev, number_of_devices);    //释放设备号

  43.   printk (KERN_INFO "Char driver cleaned up\n");
  44. }

  45. module_init (hello_2_init);
  46. module_exit (hello_2_exit);




阅读(1074) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~