字符设备驱动框架

字符设备驱动框架


一、linux软件系统的层次关系




一个应用程序操作底层驱动程序的过程:


         1 . 应用程序使用库提供的open函数打开某一个设备文件。

         2. 库根据open函数传入的参数执行swi(软件中断)指令,这会引起CPU异常,进入内核。

         3 . 内核的异常处理函数根据这些参数找到相应的驱动程序,返回一个文件句柄给库,进而返回给应用程序。

         4. 应用程序的到文件句柄后,使用库函数提供的writeioctl函数发出控制命令。

         5. 库根据writeioctl函数传入的参数执行swi(软件中断)指令,这会引起CPU异常,进入内核。

         6. 内核的异常处理函数根据这些参数调用驱动程序的相应函数,实现对设备的控制。

          

        以上内容参照《嵌入式linux应用开发完全手册 韦东山编著》



二、编写字符设备驱动程序的步骤


1. 定义相应file_operation结构类型的变量,并实现结构中的函数(驱动作者的的主要任务就在于此),如read, write    ,ioctl等。


2. 定义变量(以led驱动为例):

/*led_major0时,led_init采取动态分配设备号。在此默认采用动态分配,第一个次设备号为0,所请求设备个数DEV_NUM1*/


static int led_major = 0; //保存主设备号

  • static int led_minor = 0; //保存次设备号

    static int DEV_NUM = 1; //请求设备数量


  • static struct cdev led_cdev; //定义一个cdev结构表示字符设备

    static struct class_simple*led_class; //创建相应的类,用于自动创建节点

    static struct class_device*led_class_dev; /*定义一个类中的设备*/


  • dev_t led_id; //dev_t变量保存设备编号


    3.获得一个或多个设备编号(包括主设备号和次设备号),分为静态分配和动态分配:


    静态分配

    int register_chrdev_region(dev_tfirst, unsigned int count, char *name)

    first:要分配的设备编号范围的起始值,其次设备号常被置为0

    count:所请求连续设备编号的个数。

    name:和编号范围关联的设备名称,将出现在/proc/deviecssysfs中。

    分配成功,返回0,失败时,返回负的错误码。


    动态分配

    intalloc_chrdev_region(dev_t *dev, unsigned int firstminor, unsigned intcount, char *name)

    dev :仅用于输出的参数,成功分配后保存以分配范围的第一个编号。

    firstminor:要使用的被请求的第一个次设备号,通常为0


            为了避免静态分配设备编号带来的冲突和麻烦,我们应当使用动态分配机制获取主设备号。即使用

    alloc_chrdev_region。也可以同时保留静态分配设备号的余地。

    if(led_major) // 如果led_major=0,采取静态分配。

    {

          led_id = MKDEV(led_major,led_minor);

          ret = register_chrdev_region(led_id,DEV_NUM, "led");

    }

    else         //led_major = 0动态分配

    {

          ret =alloc_chrdev_region(&led_id,0,1,"led");

         led_major = MAJOR(led_id);

    }

    if ( ret < 0 )

    {

         printk(KERN_WARNING "led : can'tget major %d\n", led_major);

         return ret;

    }

    else

    {

          printk(KERN_WARNING"alloc_chrdev_region succeed .\n"); printk(KERN_WARNING "led major = %d ,minor = %d .\n",MAJOR(led_id),MINOR(led_id));

    }

    4.注册设备

    cdev_init(&led_cdev,&led_fops);//初始化设备cdev结构

    err = cdev_add(&led_cdev, led_id,1);//向内核注册cdev结构

    if(err<0)

             printk(KERN_WARNING "Error%d,cdev_addfailed .\n", err);

    else

           printk(KERN_WARNING "cdev_add succeed .\n");


    5.创建类并给类中添加设备

    led_class =class_simple_create(THIS_MODULE, "led_clss_drv"); /*创建led_class_drv的类*/

    led_class_dev =class_simple_device_add(led_class, led_id, NULL, "led");/*创建类的设备/dev/led*/


    6.设备不用时,做一系列撤销动作

    class_simple_device_remove(led_id);/*删除类中的设备 这里提供设备号就足够了,不许要用class_simple_device_add返回的结构*/

    class_simple_destroy(led_class); //销毁一个简单的类

    cdev_del(&led_cdev); //从系统中移除字符设备

    unregister_chrdev_region(led_id, 1); //释放设备编号




    步骤3到步骤5,放在init函数中,insmod时调用;

    步骤6,放在exit函数中,rmmod时调用。


    参考书籍:LDD3《嵌入式linux应用开发完全手册 韦东山编著》         

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值