Linux驱动编程 step-by-step (二) 简单字符设备驱动

转载 2012年03月21日 10:12:03
简单字符设备驱动
1、主次设备号
主设备号标识设备连接的的驱动,此设备好由内核使用,标识在相应驱动下得对应的设备
在linux中设备号是一个32位的dev_t类型
typedef __u32    __kernel_dev_t;
typedef __kernel_dev_t    dev_t;


crw------- 1 root  root  101 Apr 11  2011 psaux 
crw------- 1 root  root  4,  1 Oct 2803:04 tty1 
crw-rw-rw- 1 root  tty   464 Apr 11  2011 ttys0 
crw-rw---- 1 root  uucp  465 Apr 11  2011 ttyS
上图是再/dev目录下用$ls -l 命令显示的部分结果可以看到tty driver的主设备号都为4(各个系统版本有差别),次设备号不同

前12位标识主设备号 MAJOR(dev_t dev) 获得主设备号
后20位标识此设备号 MINOR(dev_t dev) 获得此设备号

由主次设备号生成设备号
可以使用宏MKDEV
dev_t  dev_num = MKDEV(dev_t major, dev_t minor);

2、分配与释放设备号

在linux2.6的字符设备中(kernel3.0也是)首先做的事就是申请一个或者多个设备号

  1. /*  静态分配设备号    
  2.  *  parameter:        
  3.  *      first : 分配的第一个设备号  
  4.  *      count: 分配的设备个数  
  5.  *      name : 设备名  
  6.  *  return value:  
  7.  *      0: success  
  8.  *      负值:出现错误,错误码  
  9. */  
  10. int register_chrdev_region(dev_t first, unsigned int count, char *name);   
  11.   
  12. /*  动态分配设备号    
  13.  *  parameter:        
  14.  *      dev : 用来存储分配的设备号值  
  15.  *      firstminor: 次设备号(一般填0)  
  16.  *      count: 分配的设备个数  
  17.  *      name : 设备名  
  18.  *  return value:  
  19.  *      0: success  
  20.  *      负值:出现错误,错误码  
  21. */  
  22. int alloc_chrdev_region(dev_t *dev, unsigned int firstminor, unsigned int count, char *name);   
  23.   
  24. /*  释放设备号  
  25.  *  parameter:        
  26.  *      first: 设备号  
  27.  *      count: 分配的设备个数  
  28. */  
  29. void unregister_chrdev_region(dev_t first, unsigned int count);  

静态分配设备号,是在已经知道一个可用设备号的时候使用,而程序员在编写程序之前大多并知道设备号是否可用,或者现在可用,不能确保在系统升级时候次设备还是可用的
所以linux社区极力推荐使用动态分配,它会去寻找可用的设备号,而不会产生冲突。在次设备卸载的时候需要释放次设备号。

3、一个没有作用的字符设备驱动

  1. #include <linux/init.h>   
  2. #include <linux/module.h>   
  3. #include <linux/types.h>   
  4. #include <linux/fs.h>   
  5.   
  6. #define SIMPLE_DEBUG 1   
  7. #define DEV_COUNT 2   
  8. #define SIMPLE_NAME "simple_char"   
  9.   
  10. static int simple_major = 108;   
  11. static int simple_minor = 0;   
  12.   
  13. static __init int simple_init(void)   
  14. {   
  15.     dev_t dev;   
  16.     int err;   
  17. #if SIMPLE_DEBUG   
  18.     printk(KERN_INFO "In %s\n", __func__);   
  19. #endif   
  20.     dev = MKDEV(simple_major, simple_minor); //求取设备号  
  21.     if(dev > 0)//设备号有效  
  22.     {   
  23. #if SIMPLE_DEBUG   
  24.         printk(KERN_INFO "try to register static char dev  %d \n", dev);   
  25. #endif   
  26.         err = register_chrdev_region(dev,DEV_COUNT, SIMPLE_NAME); //静态分配设备号  
  27.         if(err < 0) //静态分配出错 尝试使用动态分配  
  28.         {   
  29.             printk(KERN_WARNING "register static char dev error\n");   
  30.             err = alloc_chrdev_region(&dev, 0, DEV_COUNT, SIMPLE_NAME); //动态分配设备号  
  31.             if(err < 0)   
  32.             {   
  33.                 printk(KERN_ERR "register char dev error in line %d\n",__LINE__);   
  34.                 goto error;   
  35.             }   
  36.             else  
  37.             {   
  38.                 simple_major = MAJOR(dev);//重新计算主设备号  
  39.                 simple_minor = MINOR(dev);//重新计算此设备号  
  40.             }   
  41.                
  42.         }   
  43.         else{   
  44.            
  45.         }   
  46.     }   
  47.     else //设备号无效使用动态分配  
  48.     {    
  49. #if SIMPLE_DEBUG   
  50.         printk(KERN_INFO "try to register alloc char dev  \n");   
  51. #endif   
  52.         err = alloc_chrdev_region(&dev, 0, DEV_COUNT, SIMPLE_NAME);   
  53.         if(err < 0)   
  54.         {   
  55.             printk(KERN_ERR "register char dev error in line %d\n\n",__LINE__);   
  56.             goto error;   
  57.         }   
  58.         else  
  59.         {   
  60.             simple_major = MAJOR(dev);   
  61.             simple_minor = MINOR(dev);   
  62.         }   
  63.   
  64.     }   
  65.   
  66. #if SIMPLE_DEBUG   
  67.     printk(KERN_INFO "register char dev success major = %d minor = %d \n", simple_major, simple_minor);   
  68. #endif   
  69.   
  70. error:   
  71.     return err;   
  72. }   
  73.   
  74. static __exit void simple_exit(void)   
  75. {   
  76.     dev_t dev;   
  77. #if SIMPLE_DEBUG   
  78.     printk(KERN_INFO "In %s\n", __func__);   
  79. #endif   
  80.     dev = MKDEV(simple_major, simple_minor);   
  81.     unregister_chrdev_region(dev, DEV_COUNT); //释放设备号  
  82. }   
  83.   
  84. module_init(simple_init);   
  85. module_exit(simple_exit);   
  86.   
  87. MODULE_LICENSE("GPL");   
  88. MODULE_AUTHOR("kai_zhang(jsha.zk@163.com)");   
  89. MODULE_DESCRIPTION("simple char driver!");  

这里只在模块初始化的时候去分配设备号,在模块注销的时候去释放次驱动拥有的设备号
在函数里边我们看到用到了在应用编程里边声名狼藉的goto函数,在linux驱动编程时 goto 函数可以让我们的编程更加有条理性,在出现错误时候能更快的去处理。
如果在调用函数检查返回者都去做错误处理则模块函数就显得臃肿,庞大。所以还是建议合理使用goto函数的。
加载次模块后 
运行 $cat /proc/devices可以看到 simple_char 的设备以及主设备号。

这里我们看到原来假设的主设备号是不可用的,所以使用的动态分配设备号,由此我们申请到主设备号为249,我们可以在上边添加我们的设备,具体操作下一节会讲到。呵呵留点悬念先。

linux设备驱动第三篇:写一个简单的字符设备驱动

在linux设备驱动第一篇:设备驱动程序简介中简单介绍了字符驱动,本篇简单介绍如何写一个简单的字符设备驱动。本篇借鉴LDD中的源码,实现一个与硬件设备无关的字符设备驱动,仅仅操作从内核中分配的一些内存...
  • HAOMCU
  • HAOMCU
  • 2015年03月28日 19:05
  • 23761

教你写Linux设备驱动程序:一个简短的教程

摘自:http://blog.chinaunix.net/uid-20799298-id-99675.html 原文为 Writing device driver in Linux:A brief ...
  • chinaclock
  • chinaclock
  • 2015年11月18日 11:16
  • 5914

Linux设备驱动之字符设备驱动

一、linux系统将设备分为3类:字符设备、块设备、网络设备。 应用程序调用的流程框图: 三种设备的定义分别如下, 字符设备:只能一个字节一个字节的读写的设备,不能随机读取设备内...
  • andylauren
  • andylauren
  • 2016年07月01日 19:36
  • 4677

Linux驱动编程 step-by-step (九)字符设备模拟pipe的驱动程序

字符设备模拟pipe的驱动程序 让我们用一个”pipe“的设备驱动去结束简单字符设备吧(这里所说的pipe并非标准的pipe只是模拟了一个从一端写入从另一端写入的设备) 测试代码1      测试...
  • chuanshaoke
  • chuanshaoke
  • 2012年03月21日 10:25
  • 278

Linux驱动编程 step-by-step (九)字符设备模拟pipe的驱动程序

字符设备模拟pipe的驱动程序 让我们用一个”pipe“的设备驱动去结束简单字符设备吧(这里所说的pipe并非标准的pipe只是模拟了一个从一端写入从另一端写入的设备) 测试代码1    ...
  • a8039974
  • a8039974
  • 2014年11月14日 22:48
  • 335

操作系统课设 linux简单字符设备驱动

  • 2012年02月25日 18:59
  • 1.02MB
  • 下载

linux下简单字符设备驱动

  • 2014年04月07日 22:27
  • 3KB
  • 下载

最简单的linux字符设备驱动

  • 2012年11月25日 16:01
  • 12KB
  • 下载

linux驱动模块开发(二)----字符设备驱动

字符设备驱动(Linux的模块)开发流程一、字符设备字符设备指的是在I/O传输过程中以字符为单位进行传输的设备,例如键盘、打印机等。注意,以字符为单位并不一定意味着以字节为单位,因为编码有不同规定,有...
  • u010460406
  • u010460406
  • 2016年12月21日 16:46
  • 155

[Linux驱动]字符设备驱动学习笔记(二)———实例

一,注册字符设备 #define GLOBALMEM_MAJOR 256 #define GLOBALMEM_SIZE 0X1000 //4k static int char_major=GLOBA...
  • u013686805
  • u013686805
  • 2014年10月13日 15:55
  • 483
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:Linux驱动编程 step-by-step (二) 简单字符设备驱动
举报原因:
原因补充:

(最多只允许输入30个字)