【linux驱动开发】-字符设备驱动高级

1.注册字符设备驱动新接口

        在字符设备驱动基础章节,我们使用的注册字符设备驱动的接口为register_chrdev,在本章节我们要学习一种注册字符设备驱动的新接口register_chrdev_region/alloc_chrdev_region+cdev

因为内核一直在更新,新老设备注册的驱动都有!

在使用新接口注册字符设备驱动的过程中,我们首先要了cdev结构体相关的函数和设备号相关的概念!

使用register_chrdev_region+cdev_init+cdev_add注册

cdev结构体相关的函数有cdev_alloc、cdev_init、cdev_add、cdev_del

dev_t类型中,有需要用到的三个宏,MKDEV(用主设备号和次设备号算出来一个主次设备号)、MAJOR(从主次设备号里提取得到主设备号)、MINOR(从主次设备号里提取得到从设备号)

在驱动开头定义static struct cdev test_cdev(cdev结构体)、static dev_t  mydev(dev_t  型设备号)

/*省略头文件、file_operation结构体、以及动作函数 只保留注册卸载函数*/

#define MYCNT 1;
#define MYMAJOR 200;
static struct cdev test_cdev;
static dev_t mydev;

static int__init chrdev_init(void)
{
   int ret;

/*
    使用新的cdev的接口来注册字符设备驱动
    新的接口注册设备驱动需要两步
*/

  /*第一步:注册字符设备、分配主次设备号*/
   mydev=MKDEV(MYMAJOR,0);//主设备号为200,次设备号为0
 
   ret=register_chrdev_region(mydev,MYCNT,MYNAME);//使用此函数事先必须知道设备号,MYNAME设 
                                                  //  备名字
 
   if(ret)
   {
     printk(KERN_ERR"unable to register minors for%s\n",MYNAME);
     return -EINVAL;
   }
   printk(KERN_ERR"register_chrdev_region success\n");
   printk(KERN_ERR"major=%d\n minor=%d\n",MAJOR(mydev),MINOR(mydev));
  /*通过最后一个函数打印出来我们的主设备号、从设备号*/

 /*静态初始化字符设备*/
   cedv_init(&test_cdev,&test_fops);
   ret=cdev_add(&test_cdev,mydev,MYCNT);//把字符添加到系统中去
   
   if(ret)
   {
     printk(KERN_ERR"unable to cdev_add\n");
     return -EINVAL;
   }
   printk(KERN_ERR"cdev_add success\n");
}

static void__exit chrdev_exit(void)
{
   /*第一步:真正的去注销字符设备驱动用cdev_del*/
    cedv_del(&test_cdev);
   /*第二步:去注销申请的主次设备号*/
    unregister_chrdev_region(mydev,MYCNT);
}

使用register_chrdev_region+cdev_init+cdev_add注册设备驱动,是事先要知道使用的主次设备号时使用的;要先查看cat/proc/devices去查看没有使用的;

更简单、更智能的方法是让内核给我们自动分配一个主设备号!那alloc_chrdev_region就可以实现了!

使用alloc_chrdev_region+cdev_init+cdev_add注册

如上图所示,利用alloc_chrdev_region注册设备,只用改动上述程序的标记部分,因为主设备号是自动分配的,所以就没必要去宏定义主设备号,次设备号一般是从0开始,但不限于从0开始

使用cdev_alloc

注释掉上面这个cdev的结构体,转而用ststic struct cedv *pdev的结构体指针代替!

 

 如此一来,后面使用到cdev结构体相关的test_cdev地址问题都可以用pdev代替!

在使用cdev_init之前,必须调用cdev_alloc()给我们定义的结构体指针pdev申请内存!

pdev=cdev_alloc();给pdev分配内存,指针实例化,调用了内核中的kmalloc等的函数!其他部分不用变,实现的跟上面程序一样的功能!

除此之外,在补充个知识点,为什么说这个呢?就是在分析内核的时候,知道有这两个写法!

 自动创建字符设备驱动的设备文件

       在字符设备基础笔记中,我们知道在向内核注册成功一个字符设备驱动以后,我们是使用mknod命令在/dev目录下生成一个设备文件节点,然后应用层通过这个设备节点进行调用驱动里面的一些动作函数,mknod命令每次都要手动操作实现,这个小节我们讨论如何能让系统自动生成驱动的设备文件!

解决方案:udev(嵌入式中用的是mdev)!

什么是udev:应用层的一个应用程序,是BusyBox中的一个命令,内核源码是找不到的。内核驱动和应用层udev之间有一套信息传输机制(netlink协议),应用层启动udev,内核驱动中使用相应接口。驱动注册和注销时信息会被传给udev,由udev在应用层进行设备文件的创建和删除!

内核驱动设备类相关的函数以及使用

class_create 、 device_create   //创建函数

device_destory()、class_destory()  //销毁函数

这两个函数目的就是发信息给udev,让udev赶紧创建设备文件!

/*此处省略注册函数主体*/

/*注册字符设备驱动完成后,添加设备类的操作,让内核发信息给udev,让udev自动删除和创建设备文件*/

test_class=class_creat(THIS_MODULE,"aston_class");//参数2是类名要和app文件中设备名字保持一致
                                                  //参数1是固定宏,不用动
if(IS_ERR(test_class))
   return -EINVAL;
//最后一个参数就是希望在应用中创建的设备文件的名字,是/dev/aston_test

device_creat(test_class,NULL,mydev,NULL,"aston_test");


/*下面的程序是写在卸载函数中的,当驱动卸载后,自动删除设备文件*/

device_destory(test_class,mydev);
class_destory(test_class);

然后就在app中修改这个设备文件就可以了,    #define FILE "aston_test"

关于设备类

/pros/ /sys/ 这两个都是虚拟的文件系统。写或读这个文件就相当于在读写内核中的一些数据结构。

这些文件系统中有一些设备类,就是按照不同设备驱动的特性去归类,方便我们进行管控。

比如刚才,我们通过class_create建立了一个aston_class的类,我们通过cd/sys/class/就可看到

 然后cd/aston_class 就可以看到aton_test这个设备文件,再进一步,进入到aton_tests

 可以看到,在这个文件里面,有uevent文件,这些文件是内核中自动组织的文件。我们再进一步,查看一下uevent文件。cat uevent!

class文件夹中的每一个文件都是一个类,uevent及class就是内核提供给我们的一个和内核进行交互的一个窗口,通过这个class,我们就可以了解驱动程序安装卸载等过程中内核所发生的事情。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值