9、Linux驱动的杂项设备

杂项设备,是字符设备中的特殊,它的主设备号,是 10,不同的杂项设备,通过次设备号进行区分。

1、注册与注销

int misc_register(struct miscdevice * misc)

完成杂项设备的注册,

int misc_deregister(struct miscdevice *misc)

可见,设备的注册和注销,都是设置到 struct miscdevice  结构体

2、struct miscdevice  结构体

struct miscdevice  {
    int minor;
    const char *name;      // 名字
    const struct file_operations *fops;  // 文件操作结构体
    struct list_head list;
    struct device *parent;
    struct device *this_device;
    const char *nodename;
    mode_t mode;
};

结构体中,name 是注册的名字,以后将会在 /dev 目录下,进行显示的 name,里面最主要的是 struct file_operations ,在注册杂项设备的时候,字符设备的结构体与杂项设备进行绑定,

minor 为 MISC_DYNAMIC_MINOR 的时候,miscdevice 核心层会自动寻找一个空闲的次设备号,

3、杂项设备与字符设备驱动

杂项设备,本质上就是字符设备驱动,只不过是一个特殊一点的。杂项设备的主设备号,被固定在 10,通过次设备号进行区分设备。杂项设备注册之后,在 /dev/ 目录下就有 name 设备节点,在 /sys/clas/misc 下面,也会自动生成的类信息,因此,一定程度上,比标准的的字符设备驱动简单了一丢丢。

4、流程

    struct const file_operations xxxx_fops = {

    .unlock_ioctl = xxx_ioctl,

     xxxx

};

    struct miscdevice xxx_dev = {

    .minor = MISC_DYNAMIC_MINOR,

    .name = “xxx”,

    .fops = xxxx_fops

};

static int __init xxx_init()

{

    return misc_register(&xxx_dev );

}

void __exit xxx_exit()

{

    return misc_deregister(&xxx_dev) ;

}

当调用 misc_register(&xxx_dev ); 的时候,会在 misc_open 的帮助下,实现将 xxx_dev 成为 file 的private_data,也就是 系统会帮助我们实现 file->private_data = xxx_dev .

二、总线平、设备、驱动

在实际的编程中,最希望的是,一套支持,可以支持一类所有的设备,比如 同一套 DM9000 驱动,可最好是满足在不同板子上运行,所以为了达到目标,就提出了总线、设备、驱动软件架构。

驱动编写代码中,有一些信息是关于设备的相关信息,比如 IO 地址,内存资源地址,其余的是对这些设备的操作,所以,就将这些对应的设备的信息进行提取到一个文件,设备文件,它只做对不同设备的资源进行定义,不同的平台就单独设置不同的设备文件。

驱动则只管对设备的操作。

总线,主要是完成 设备 与 驱动的配合。总线、设备、驱动 的 软件架构,就可以使得驱动四海皆准了。

在系统注册设备的时候,总线就会根据设备的信息去匹配对应的设备;同理,驱动注册的时候,总线也会根据驱动的信息进行运行匹配的设备,当找到对应的驱动或者设备的时候,就会调用驱动文件的 probe 函数。

2.1、platform_device 与 platform_driver

因为提出了总线、设备、驱动这种软件架构,Linux就虚构了虚拟的总线,称之为 platform 总线,设备称之为 platform_device,驱动则成为 platform_driver。

platform_device  有对应的结构体,

struct platform_device {
    const char    * name;     // 设备名字
    int        id;
    struct device    dev;    // 设备
    u32        num_resources;
    struct resource    * resource;   // 资源

    const struct platform_device_id    *id_entry;

    /* MFD cell pointer */
    struct mfd_cell *mfd_cell;

    /* arch specific additions */
    struct pdev_archdata    archdata;
};

platform_driver  结构体,我们只需要注意的是 设备的名字,以及设备的资源。

struct platform_driver {
    int (*probe)(struct platform_device *);     // probe
    int (*remove)(struct platform_device *);   // 删除
    void (*shutdown)(struct platform_device *);
    int (*suspend)(struct platform_device *, pm_message_t state);
    int (*resume)(struct platform_device *);
    struct device_driver driver;
    const struct platform_device_id *id_table;     // 平台设备的 ID,
};

platform_driver  结构体的地位 和 i2c_driver、spi_driver 、usb_driver, pci_driver 相等。所以说,在实现 I2C 驱动的时候,就可以使用 i2c_driver,当然可以是 platform_driver 。

设备与驱动的匹配主要是通过设备名字的方式实现的:

struct platform_device  里面的注册一个 一个 name,指定的是 device 的名字;struct platform_driver 里面的const struct platform_device_id *id_table 表,则是注册了驱动支持的不同设备的名字,正是对两个名字进行了匹配,匹配成功之后,就会调用 driver 端 的probe 函数。一般是在里面是  probe 里面,完成新的字符设备驱动的操作。

2.2、device 的注册

当 新建了platform_device  结构体(也可以是新建了一个指针, 再通过platform_device_alloc 接口实现 ),完成了资源和名字的设置之后,需要将这个 device 注册到内核。

设备注册进内核:

platform_device_add(struct platform_device *pdev)

设备从内核取消:

 platform_device_unregister(struct platform_device * pdev)

2.3、driver 的注册

struct platform_driver  里面的 id_table 指定了设备的名字,当总线完成名字的匹配之后,就会调用 driver 端的 probe 函数,一般是在 probe 函数里面完成注册,注册的实现,一般也是注册为字符设备驱动,或者杂项设备。

3.、device 资源、driver 获取资源

struct resource {
    resource_size_t start;
    resource_size_t end;
    const char *name;
    unsigned long flags;
    struct resource *parent, *sibling, *child;
};

device 结构体 里面,的resource 结构体实现了对设备资源的描述。一般上,只需要关心 start、end、flags。

start: 设备资源的开始值

end : 设备资源的结束值

flags : 设备资源类型的标志。IORESOURCE_IO   IORESOURCE_MEM IORESOURCE_IRQ IORESOURCE_DMA

当 flag 是 IORESOURCE_MEM  的时候,start 就是内存的开始地址,end 就是内存资源的结束地址。

flag 是 IORESOURCE_IRQ  的时候,start 和 end 就是中断号的开始值和结束值。如果只是一个中断的话,那么开始值和结束值就是相同的。

device 定了硬件相关的板级资源,所以 driver 端,就应该在需要获取板级资源的时候,去获取相关的设备资源,driver 是通过这个接口去实现 相匹配的 device 端的资源:

 platform_get_resource(struct platform_device * dev,unsigned int type,unsigned int num)

去 device 获取 type 类型指定的资源。

如果是获取 irq 的资源的话,也可以使用直接封装的接口:

  platform_get_irq(struct platform_device * dev,unsigned int num) 

4、代码

借助宋宝华的 Linux设备驱动开发详解的代码,

4.1、device

static struct platform_device *globalfifo_pdev;     // 指针

static int __init globalfifodev_init(void)
{
    int ret;

    globalfifo_pdev = platform_device_alloc("globalfifo", -1);   // 分配一个  device ,指定了名字
    if (!globalfifo_pdev)
        return -ENOMEM;

    ret = platform_device_add(globalfifo_pdev);   // 将 device 注册进 总线
    if (ret) {
        platform_device_put(globalfifo_pdev);
        return ret;
    }

    return 0;

}
module_init(globalfifodev_init);

static void __exit globalfifodev_exit(void)
{
    platform_device_unregister(globalfifo_pdev);      // 将 device 从总线进行注销

}
module_exit(globalfifodev_exit);

4.3、driver

static int globalfifo_probe(struct platform_device *pdev)
{

    ret = misc_register(miscdev);    // 杂项设备的注册
    if (ret < 0)
        goto err;
}

static int globalfifo_remove(struct platform_device *pdev)
{ 

    misc_deregister(miscdev);   // 注销

    return 0;
}

static struct platform_driver globalfifo_driver = {
    .driver = {
        .name = "globalfifo",   // 名字
        .owner = THIS_MODULE,
    },
    .probe = globalfifo_probe,   // 名字匹配成功,就调用 probe 函数
    .remove = globalfifo_remove,
};

module_platform_driver(globalfifo_driver);   // 平台设备 driver 入口
时间: 2024-10-25 12:58:28

9、Linux驱动的杂项设备的相关文章

Linux 驱动之块设备 (一)

1.引言 块设备的驱动比字符设备的难,这是因为块设备的驱动和内核的联系进一步增大,但是同时块设备的访问的几个基本结构和字符还是有相似之处的. 有一句话必须记住:对于存储设备(硬盘~~带有机械的操作)而言,调整读写的顺序作用巨大,因为读写连续的扇区比分离的扇区快. 但是同时:SD卡和U盘这类设备没有机械上的限制,所以像上面说的进行连续扇区的调整显得就没有必要了 2.块设备概念 块设备(blockdevice) --- 是一种具有一定结构的随机存取设备,对这种设备的读写是按块进行的,他使用缓冲区来存

Linux驱动之混杂设备(misc)

字符设备之混杂设备: 定义混杂设备: struct misdevice{ int  minor; //为什么这里只有次设备号,因为混杂设备是一种在                          /////////////////////////Linux系统默认主设备号为10 的特殊字符设备. const char  *name; const struct  file_operation *fops; struct list_head list; struct device  *parent

Linux驱动之平台设备驱动模型简析(驱动分离分层概念的建立)

Linux设备模型的目的:为内核建立一个统一的设备模型,从而有一个对系统结构的一般性抽象描述.换句话说,Linux设备模型提取了设备操作的共同属性,进行抽象,并将这部分共同的属性在内核中实现,而为需要新添加设备或驱动提供一般性的统一接口,这使得驱动程序的开发变得更简单了,而程序员只需要去学习接口就行了. 对于整个设备总线驱动模型的样子,如下图.简单来说,bus 负责维护注册进来的devcie 与 driver,每注册进来一个device 或者 driver 都会调用 Bus->match 函数

linux驱动之字符设备

第一部分:字符设备工作过程1.系统调用和驱动程序的关联关键结构体:struct file_operation:file_operation结构体的每一个成员的名字都对应着一个系统调用.用户进程利用系统调用在对设备文件进行诸如read/write操作时,系统调用通过设备文件的主设备号找到相应的设备驱动程序,然后读取这个数据结构相应的函数指针,接着把控制权交给该函数.这是linux的设备驱动程序工作的基本原理.编写设备驱动程序的主要工作就是编写子函数,并填充file_operations的各个域.

Linux驱动之平台设备

<平台设备设备驱动> a:背景: 平台总线是Linux2.6的设备驱动模型中,关心总线,设备和驱动这3个实体.一个现实的Linux设备和驱动通常需要挂接在一种总线上(比如本身依附于PCI,USB,IIC,SPI等设备而言).但是在嵌入式系统里面,SoC系统即集成的独立外设控制器,挂接在SoC内存空间的外设却没有这样的总线依附,为了和Linux设备驱动模型理论相互统一,Linux系统开发了Platform_bus这种虚拟总线,相应的设备叫做platform_device ,相应的驱动叫platf

13 Linux驱动之平台设备

一 platform子系统 1.对平台设备描述 struct platform_device { const char * name; //设备名字 int id; // -1 struct device dev; //通用设备描述 u32 num_resources; //资源的个数 struct resource * resource;//资源 //如果是在driver的id_table中匹配成功,id_entry就会记录id_table匹配的项 const struct platform_

Linux杂项设备与字符设备

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

浅谈 MISC杂项设备

在虚拟机的 Ubuntu 系统上,如下图所示,使用命令"cat /proc/misc",可以查看到 PC 机 Ubuntu 系统的杂项设备. 启动开发板,在超级终端中输入命令"cat /proc/misc"也可以查看对应的杂项设备. 前面介绍过主设备号只有 256 个,设备又非常多,所以引入了子设备号. 其中杂项设备的主设备号是 10,在任何 Linux 系统中它都是固定的. 一般将 Linux 驱动分为字符设备.块设备.网络设备,但是这个分类不能包含所有的设备,

linux驱动面试题整理

资料来自网上,简单整理,答案后续补充...... 1.字符型驱动设备你是怎么创建设备文件的,就是/dev/下面的设备文件,供上层应用程序打开使用的文件? 答:mknod命令结合设备的主设备号和次设备号,可创建一个设备文件. 评:这只是其中一种方式,也叫手动创建设备文件.还有UDEV/MDEV自动创建设备文件的方式,UDEV/MDEV是运行在用户态的程序,可以动态管理设备文件,包括创建和删除设备文件,运行在用户态意味着系统要运行之后.那么在系统启动期间还有devfs创建了设备文件.一共有三种方式可