Linux驱动之杂项设备(张栖银详谈)

一、杂项设备驱动介绍

1.1 系统介绍

本文是基于linux-2.6.32内核进行分析的,如果使用的是其他版本的内核,其内核调用的函数可能有所不同,但是其实现原理是相通的。

1.2 杂项设备驱动的引入

在前面一小节里面,我们详细介绍了字符设备驱动程序,知道字符设备指那些必须以串行顺序依次进行访问,且没有经过系统快速缓冲的设备,了解了Linux内核中驱动的框架和组成,以及编写的步骤等。但是,当我们写的驱动程序多了之后,就会发现:部分硬件并不符合预先定义的字符设备的范畴,而且普通字符设备的主设备号不管是静态分配还是动态分配,都会消耗一个主设备号(目前一个系统最多只能有255个字符设备),比较浪费主设备号资源。因此,而引入了杂项设备驱动。

在Linux里面,把无法归类的五花八门的设备定义为混杂设备(用miscdevice结构体描述)。杂项设备是一个典型的字符设备(与接下来要介绍的输入子系统一样,呵呵),其主设备号固定为10。其内部实现就是用主设备号10来调用register_chrdev()实现的;并且在内部还调用了class_create()和device_create ()为每个杂项设备创建设备节点,从而避免了我们通过mknod命令或自行调用该两个函数来创建设备节点的麻烦。

从以上这点来说,杂项设备就是将我们平常编写字符设备的驱动进行了再次封装,降低了我们编写字符设备驱动的难度,同时节约了主设备号资源

1.3 杂项设备与字符设备实现比较

在进行字符设备驱动程序开发的过程中,我们的实现步骤如下:

  • 申请一个字符设备号:可以自己指定,也可系统自动分配;
  • 构造一个file_operations结构体,其包含对硬件的所有操作;
  • 实现file_operations结构体中的成员函数;
  • 将字符设备注册进系统中:register_chrdev();
  • 创建设备类和设备节点:class_create()、device_create();
  • 告诉内核入口与出口函数:module_init()、module_exit();

杂项设备驱动也是字符设备驱动,那么其注册的过程与字符设备驱动一样,也必须经过上面的这些步骤,只是杂项设备驱动中的对申请字符设备号、注册字符设备到系统、创建设备类和设备节点进行了封装,我们只需要完成如下几步开发即可:

  • 构造一个file_operations结构体,其中包含对硬件的所有操作;
  • 实现file_operations结构体中的成员函数;
  • 构造一个杂项设备驱动(struct miscdevice)实体,并赋值前面定义的file_operations实体;
  • 在入口函数处调用misc_register()向系统注册杂项设备;
  • 在出口函数处调用misc_deregister()从系统注销杂项设备;
  • 告诉内核入口与出口函数:module_init()、module_exit();

从中也可以得出一个结论:无论Linux内核对驱动框架设计的如何好,内核实现了多少的代码,与硬件相关部分的代码还是需要我们去实现

本文的重点内容就是讲解如上几点内容:

  • 杂项子系统如何向内核注册;
  • 杂项子系统如何实现字符设备注册;
  • 杂项子系统如何创建设备类和设备文件;
  • 如何编写一个杂项设备驱动程序;

1.4 杂项设备和字符设备与应用层数据交互比较

编写过字符设备驱动的人都知道,应用程序与驱动之间实现数据交互就是通过应用API的read()、write()调用,从而产生一个SWI软件中断,然后通过主设备号找到对应的struct cdev结构体实体,从而找到具体硬件设备的struct file_operations结构体,然后具体调用底层的drv_read()、drv_write(),我们就是在具体的drv_read()和drv_write()中实现对硬件的操作的,其过程如下:

read()—>swi_read()—>drv_read()—>硬件操作

那么对于杂项设备驱动呢?前面已经说了,杂项设备也是字符设备,那么它也必须经历上面的这些步骤,只是中间穿插了几个通过次设备号找到对应struct file_operation结构体的过程而已而已。那么是如何穿插的呢:

首先在mist.c(杂项子系统的核心)文件的打开函数中获取此设备号,然后次设备号找到对应的fops(也即struct file_operations结构体)填充struct file中的f_op成员,那么之后应用调用read()、write()函数就是调用具体次设备号对应的struct file_operations结构体中的成员了;最后再调用fops中的open()函数打开具体的函数:

open()—>
    swi_open()—>
        misc_open()
        {
            int minor = iminor(inode); //获取次设备号
            new_fops = fops_get(c->fops);
            old_fops = file->f_op;
            file->f_op = new_fops;
            file->f_op = fops_get(old_fops);
        }
read()/write()—>
    swi_read()/swi_write()—>
        new_fops->drv_read()/drv_write()

这里说明一下:misc.c是杂项子系统的核心,内核已经实现,我们只需要实现底层的硬件操作函数集合,然后调用misc_register()告诉杂项子系统就好了。

通过前面的介绍,不太理解也没有关系。你只需要记住,其实杂项子系统就是一个典型的字符设备系统,它也逃不过字符设备的框架,其应用与驱动交互的流程也和字符设备驱动一样,没有什么不同就是了(要从心里小瞧它)。

要想搞明白杂项子系统的框架,只需要弄明白应用程序是如何与具体的硬件设备驱动进行交互的就行了。本文的重点就是对杂项子系统的注册、杂项子系统中驱动与应用数据交互过程,以及如何编写杂项子系统进行分析的。

二、杂项子系统实现

2.1 杂项子系统

杂项设备是主设备号为10的驱动设备,比较适用于功能简单的设备。它有自己的设备结构体(/include/linux/miscdevice.h):

struct miscdevice  {
    int minor;                      //次设备号
    const char *name;               //设备名字
    const struct file_operations *fops;  //文件操作集合
    struct list_head list;              //连接到misc_list的链表
    struct device *parent;            //父设备
    struct device *this_device;        //当前设备,是device_create的返回值
    const char *nodename;
    mode_t mode;
};

miscdevice在本质上仍然属于字符设备,只是被增加了一层封装而已,因此其驱动的主体工作还是file_operations的成员函数。

其中minor是次设备号,杂项子系统主要是依赖minor来对不同的杂项设备驱动进行管理,如果该项设置为MISC_DYNAMIC_MINOR,表示由系统自行分配次设备号。name是调用misc_register()注册杂项设备时创建节点文件的名字;list是双向链表,用于将要注册的杂项设备注册进misc_list链表中。如下图所示:


image
image

接下来的内容,将详细介绍misc.c杂项子系统的实现过程,主要包括:

  1. 杂项子系统的注册;
  2. 杂项子系统之设备注册;
  3. 杂项子系统之设备注销;
  4. 杂项子系统之设备使用;

2.2 杂项子系统实现

2.2.1 杂项子系统的注册

还有 79% 的精彩内容
©著作权归作者所有,转载或内容合作请联系作者
支付 ¥2.99 继续阅读
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 204,293评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,604评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,958评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,729评论 1 277
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,719评论 5 366
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,630评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,000评论 3 397
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,665评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,909评论 1 299
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,646评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,726评论 1 330
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,400评论 4 321
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,986评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,959评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,197评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 44,996评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,481评论 2 342

推荐阅读更多精彩内容