Linux驱动模型

一、Linux设备驱动模型基本数据结构

        Linux设备驱动模型有两个基本数据结构:kobject,kset

        kobject是组成设备模型的基本结构,类似于C++中的基类,它嵌入于更大的对象中用来描述设备模型的组件,如bus,devices,drivers,device_driver,bus_type等,这相当于面向对象程序设计语言中的继承机制。每个kobject对象都对应于sysfs(将在后面介绍)中的一个目录。Kobject结构中部分成员如下:

struct kobject
{
  const char *name;  //显示在sysfs中的名称
  struct list_head entry;   //下一个kobject结构
  struct kobject *parent;   //指向父kobject结构体,如果存在
  ……
};
        每个kobject都会有一个属性kobj_type,定义了某种类型的kobejct的公共的属性和操作:

struct kobj_type
{
  struct sysfs_ops *sysfs_ops;      //操作属性的方法
  struct attribute **default_attrs;      //属性数组
  ……
};
        kset是一个kobject集合(或容器),包含了一系列的kobject。kset内部也嵌入了kobject,这表明kset本身也是一个kobject。Kset结构如下:
struct kset
{
  struct list_head list;   //连接所包含的kobject对象的链表首地址
  struct kobject kobj;  //内嵌kobject,说明kset本身也是一个目录
  ……
}; 
        Kset结构体对象和kobject结构体对象是有密切关联的。kset集合包含了属于它的kobject结构体,kset.list链表用来连接第一个和最后一个kobject对象;第一个kobject使用entry连接kset集合和第二个kobject对象;第二个kobject对象使用entry连接第一个kobject对象和第三个kobject对象,依次类推,最终形成了一个kobject对象的链表;所有的kobject结构的parent指针指向kset包含的kobject对象,构成一个父子层次关系;kobject的所有kset指针指向包含它的kset集合,所以通过kobject对象很容易就能找到kset集合;kobject的kobj_type指针指向自身的kobj_type,每一个kobject都有一个单独的kobj_type结构;另外在kset集合中也有一个kobject结构体,该结构体也指向一个kobj_type结构体;kobj_type中定义了一组属性和操作属性的方法。


二、Linux设备驱动模型高层数据结构


        高层主要包括三个结构:device,device_driver,bus_type
        device_driver,device分别表示驱动和设备,且两者需要依附在一种总线上,因此两者的结构体中都包含struct bus_type指针;在Linux中,驱动和设备是可以分开注册的,不需要在对方存在的条件下进行注册;两者通过struct bus_type的成员函数match()进行配对[13]。
        总线、驱动和设备三者的结构中部分成员如下:
总线:
struct bus_type
{
  const char *name;
  struct bus_attribute *bus_attrs;
  struct device_attribute *dev_attrs;
  struct driver_attribute *drv_attrs;
  int (*probe)(struct  device *dev);
  int (*remove)(struct device *dev);
  void (*shutdown)(struct device *dev);
  int (*suspend)(struct device *dev,pm_message_t state);
  ……
};
驱动:
struct device_driver
{
  const char *name;  //设备驱动名字
  struct bus_type *bus;   ///指向驱动属于的总线,总线上有很多设备
  int (*probe)(struct device *dev);
  int (*remove)(struct device *dev);
  void (*shutdown)(struct device *dev);
  int (*suspend)(struct device *dev,pm_message_t state);
  int (*resume)(struct device *dev);
  ……
};

struct driver_private
{
  struct kobject kobj;   //内嵌kobject结构,用来构建设备驱动程序模型
  struct klist_node knode_bus;    //该驱动所属总线
  struct module_kobject *mkobj;   //驱动的模块
  struct device_driver *driver;    //指向驱动本身
  ……
};
设备
struct device
{
  struct klist klist_children;  //连接子设备的链表
  struct device *parent;   //指向父设备的指针
  const char *init_name;   //设备初始名
  struct kobject kobj;  //内嵌的kobject
  struct bus_type *bus;   //指向连接的总线指针
  struct device_driver *driver;   //指向该设备的驱动程序
  dev_t devt;   //设备号
  struct class *class;   //指向设备所属类
  struct attribute_group **groups;   //设备的组属性
  ……
};

三、Sysfs文件系统


        为了方便调试,设备模型的开发者决定将设备结构树导出为一个文件系统,这就是sysfs文件系统,它可以帮助用户能以一个简单文件系统的方式来观察系统中各种设备的拓扑结构。sysfs代替了先前处于/proc下的设备相关文件,另外它为系统对象提供了一个很有效的视图。sysfs是对一个全新的对象模型非常有利于系统。Sysfs与kobject联系紧密,在sysfs文件系统下,一个目录也就对应着一个kobject。启动时,系统将sysfs挂载到/sys目录下。
        Sysfs 下的文件可分为三种:目录,普通文件,符号连接;通过命令tree -a /sys可查看sysfs的目录结构,部分结果如下:
|--block
|--bus
|  |--pci
|  |  |--device
|  |  |  |--0000:00:00.0 -> ../../../device/pci0000:00/ 0000:00:00.0
|  |  |  |--0000:00:01.0 -> ../../../device/pci0000:00/ 0000:00:01.0
|  |  |  `--0000:00:07.0 -> ../../../device/pci0000:00/ 0000:00:07.0
|  |  `--drivers
|  `--usb
|     |--devices
|     `--drivers
|        `--usb-storage
|--class
|  |--pci_bus
|  |  |--0000:00
|  |  |  `--bridge -> ../../../devices/pci0000:00
|  |  `--0000:01
|  |     `-- bridge -> ../../../devices/pci0000:00/0000:00:01.0
|  `--…
|--devices
|  |--pci0000:00
|  |  |--0000:00:00.0
|  |  `--0000:00:01.0
|--kernel
|  `--hotplug_seqnum
|--module
|  |--usb_storage
|  |--usbcore
|  |  |--parameters
|  |  `--…
|  `--…
`--power
        block目录包含所有的块设备;devices目录包含系统所有的设备,并根据设备挂接的总线类型组织成层次结构;drivers目录包含内核中所有已注册的设备驱动程序;bus目录包含系统在所有的总线类型,如PCI、USB总线,而每个总线类型子目录下又有drivers和devices目录,devices目录中的额外那就是对/sys/devices目录中文件的符号连接。
特别需要注意class目录。Linux中设备根据不同的用途被分为不同的类(class),同一个类下面有不同的接口(interface),如输入(input)类中有键盘接口。/sys/class目录中最终也是一个个的文件,而这些文件依然是对/sys/devices目录中相应文件的符号链接。

        Sysfs文件系统中,总线、设备、驱动和类的关系如图2.2所示:


        总线、驱动和设备最终会落实成为sysfs中的一个目录,查看它们的声明结构体可知,每个类型都直接或间接包含了kobject对象,一个kobject对象对应sysfs中的一个目录,kobject的每个属性(attribute)对应sysfs文件系统中的文件。属性伴随着show()和store()两个函数,这两个函数用来读和写属性对应的文件。
        Sysfs文件系统提供了一套方法建立文件与对应的show()和store()函数的映射。首先是一系列宏定义,主要的有对设备的使用DEVICE_ATTR(),对总线使用的BUS_ATTR(),对驱动使用的DRIVER_ATTR(),对类别(class)使用的CLASS_ATTR()。以DEVICE_ATTR()为例,其定义如下:

#define DEVICE_ATTR(_name, _mode, _show, _store) \
struct device_attribute dev_attr_##_name = __ATTR(_name, _mode, _show, _store)
在宏定义中填入如下内容:
static DEVICE_ATTR(polling, S_IRUGO | S_IWUSR, show_polling, set_polling);
会得到如下格式的结构体对象:
static struct device_attribute device_attribute_ polling {
.attr = {.name = polling,.mode = S_IRUGO | S_IWUSR.owner = THIS_MODULE },
.show = show_ polling,.store = store_ polling }
在创建、移除文件时分别需要调用如下两个函数:
int device_create_file(struct device *device, struct device_attribute * entry);
void device_remove_file(struct device * dev, struct device_attribute * attr);
这两个函数的第二个参数为struct device_attribute类型的结构体,这样便建立了设备和对其进行读写操作的函数之间的关联。

(本文是将相关材料整理后写出的,来源:宋宝华.Linux设备驱动开发详解[M].北京:人民邮电出版社,2010)

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值