您的位置:首页 > 运维架构 > Linux

Linux驱动编程 step-by-step (二)

2011-11-26 21:43 465 查看
 
简单字符设备驱动
1、主次设备号

主设备号标识设备连接的的驱动,此设备好由内核使用,标识在相应驱动下得对应的设备

在linux中设备号是一个32位的dev_t类型

typedef __u32    __kernel_dev_t;
typedef __kernel_dev_t    dev_t;

crw------- 1 root  root  10, 1 Apr 11
 2011 psaux 

crw------- 1 root  root  4,  1 Oct 2803:04
tty1 

crw-rw-rw- 1 root  tty   4, 64 Apr 11
 2011 ttys0 

crw-rw---- 1 root  uucp  4, 65 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也是)首先做的事就是申请一个或者多个设备号

/*  静态分配设备号    
 *  parameter:        
 *      first : 分配的第一个设备号  
 *      count: 分配的设备个数  
 *      name : 设备名  
 *  return value:  
 *      0: success  
 *      负值:出现错误,错误码  
*/  
int register_chrdev_region(dev_t first, unsigned int count, char *name);   
  
/*  动态分配设备号    
 *  parameter:        
 *      dev : 用来存储分配的设备号值  
 *      firstminor: 次设备号(一般填0)
 
 *      count: 分配的设备个数  
 *      name : 设备名  
 *  return value:  
 *      0: success  
 *      负值:出现错误,错误码  
*/  
int alloc_chrdev_region(dev_t *dev, unsigned int firstminor, unsigned int count, char *name);
  
  
/*  释放设备号  
 *  parameter:        
 *      first: 设备号  
 *      count: 分配的设备个数  
*/  
void unregister_chrdev_region(dev_t first, unsigned int count);  

静态分配设备号,是在已经知道一个可用设备号的时候使用,而程序员在编写程序之前大多并知道设备号是否可用,或者现在可用,不能确保在系统升级时候次设备还是可用的

所以linux社区极力推荐使用动态分配,它会去寻找可用的设备号,而不会产生冲突。在次设备卸载的时候需要释放次设备号。

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

#include <linux/init.h>   
#include <linux/module.h>   
#include <linux/types.h>
  
#include <linux/fs.h>   
  
#define SIMPLE_DEBUG 1   
#define DEV_COUNT 2
  
#define SIMPLE_NAME "simple_char"
  
  
static int simple_major = 108;   
static int simple_minor = 0;   
  
static __init int simple_init(void)   
{   
    dev_t dev;   
    int err;   
#if SIMPLE_DEBUG   
    printk(KERN_INFO "In %s\n", __func__);   
#endif   
    dev = MKDEV(simple_major, simple_minor); //求取设备号  
    if(dev > 0)//设备号有效  
    {   
#if SIMPLE_DEBUG   
        printk(KERN_INFO "try to register static char dev  %d \n", dev);   
#endif   
        err = register_chrdev_region(dev,DEV_COUNT, SIMPLE_NAME
c031
); //静态分配设备号  
        if(err < 0) //静态分配出错 尝试使用动态分配  
        {   
            printk(KERN_WARNING "register static char dev error\n");   
            err = alloc_chrdev_region(&dev, 0, DEV_COUNT, SIMPLE_NAME); //动态分配设备号  
            if(err < 0)   
            {   
                printk(KERN_ERR "register char dev error in line %d\n",__LINE__);   
                goto error;   
            }   
            else  
            {   
                simple_major = MAJOR(dev);//重新计算主设备号  
                simple_minor = MINOR(dev);//重新计算此设备号  
            }   
               
        }   
        else{   
           
        }   
    }   
    else //设备号无效使用动态分配  
    {    
#if SIMPLE_DEBUG   
        printk(KERN_INFO "try to register alloc char dev  \n");   
#endif   
        err = alloc_chrdev_region(&dev, 0, DEV_COUNT, SIMPLE_NAME);   
        if(err < 0)   
        {   
            printk(KERN_ERR "register char dev error in line %d\n\n",__LINE__);   
            goto error;   
        }   
        else  
        {   
            simple_major = MAJOR(dev);   
            simple_minor = MINOR(dev);   
        }   
  
    }   
  
#if SIMPLE_DEBUG   
    printk(KERN_INFO "register char dev success major = %d minor = %d \n", simple_major, simple_minor);   
#endif   
  
error:   
    return err;   
}   
  
static __exit void simple_exit(void)   
{   
    dev_t dev;   
#if SIMPLE_DEBUG   
    printk(KERN_INFO "In %s\n", __func__);   
#endif   
    dev = MKDEV(simple_major, simple_minor);   
    unregister_chrdev_region(dev, DEV_COUNT); //释放设备号  
}   
  
module_init(simple_init);   
module_exit(simple_exit);   
  
MODULE_LICENSE("GPL");   
MODULE_AUTHOR("kai_zhang(jsha.zk@163.com)");   
MODULE_DESCRIPTION("simple char driver!");  

这里只在模块初始化的时候去分配设备号,在模块注销的时候去释放次驱动拥有的设备号

在函数里边我们看到用到了在应用编程里边声名狼藉的goto函数,在linux驱动编程时 goto 函数可以让我们的编程更加有条理性,在出现错误时候能更快的去处理。

如果在调用函数检查返回者都去做错误处理则模块函数就显得臃肿,庞大。所以还是建议合理使用goto函数的。

加载次模块后 

运行 $cat /proc/devices可以看到 simple_char 的设备以及主设备号。



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

 

转自:http://blog.csdn.net/jshazk1989/article/details/6918828

 
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  linux 编程 module 存储