6/26/2011 7:27:13 PM

 

6/26/2011 7:27:13 PM

DMA engine

static int __init dma_bus_init(void)
{
 mutex_init(&dma_list_mutex);
 return class_register(&dma_devclass);


struct class_device_attribute {
 struct attribute attr;
 ssize_t (*show)(struct class_device *, char * buf);
 ssize_t (*store)(struct class_device *, const char * buf, size_t count);
};

类设备属性

static struct class_device_attribute dma_class_attrs[] = {
 __ATTR(memcpy_count, S_IRUGO, show_memcpy_count, NULL),
 __ATTR(bytes_transferred, S_IRUGO, show_bytes_transferred, NULL),
 __ATTR(in_use, S_IRUGO, show_in_use, NULL),
 __ATTR_NULL
};

拷贝计数和字节传输

Linux驱动模型从面向对象的观点,提供了通用的、一致性的数据模型,用来描述总线和设备以及它们的层次结构。

Linux驱动模型抽象出统一的总线、设备接口、桥接口、驱动程序等模型,形成驱动程序的基类。这些基类抽象出共有特性和方法函数,

具体的设备驱动程序从基类继承产生派生类。例如:PCI设备结构从基类device继承,继承方法如下:

struct pci_dev {
 ...
 struct device device;
};

通过对象化处理后,设备驱动程序之间层次结构关系转换成类对象之间的层次关系,驱动程序的基类从kobject继承,这样,驱动程序类对象之间的层次关系反映到文件系统sysfs中,用户空间的应用程序通过sysfs可以查看或操作类对象的数据。


通常,计算机的周边设备都是通过总线与处理器连接。在Linux内核中,每个总线类型(如:PCI、USB等)应该声明一个静态的总线类型对象实例,并初始化该对象的部分成员,这些成员一般在驱动程序的运行过程中无变化。总线类型对象也简称总线对象。

当总线驱动程序初始化时,它调用函数bus_register注册总线类型实例:初始化总线类型实例中的易变化的成员,将对象插入总线类型对象的全局链表中。一旦注册了总线对象,总线驱动程序就可以使用该对象的成员。

每一种总线类型都用一个总线类型对象结构bust_type进行描述,它包括了一类总线的通用操作函数、总线属性、总线类型私有数据等。其列出如下(在include/linux/device.h中):

注册总线类型实例

struct bus_type {
 const char  *name;
    /*总线属性,用于在文件系统sysfs显示总线的属性*/
 struct bus_attribute *bus_attrs;
 struct device_attribute *dev_attrs; /*设备属性,用于在sysfs中显示*/
 struct driver_attribute *drv_attrs;/*驱动程序属性,用于在sysfs中显示*/
 
     /*通过把总线驱动程序支持的设备ID与特定设备ID进行比较,来决定总线是否支持这个设备。当总线注册了驱动程序时,系统遍历总线的设备链表,并且每个没有相关设备驱动程序的设备会调用match回调函数*/
 int (*match)(struct device *dev, struct device_driver *drv);
 int (*uevent)(struct device *dev, struct kobj_uevent_env *env);
 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 (*suspend_late)(struct device *dev, pm_message_t state); /*挂起设备后的操作*/
 int (*resume_early)(struct device *dev); /*恢复设备早期的操作*/
 int (*resume)(struct device *dev);   /*恢复设备时的操作*/
 
 struct pm_ext_ops *pm;    /*电源管理其他的操作*/
 
 struct bus_type_private *p;  /*总线类型私有数据*/
};


结构bus_type_private含有总线类型对象的私有数据,含有实际的内核对象信息,允许静态分配结构bus_type。驱动程序核心代码使用该结构,用户编写的驱动程序不许使用该结构。

总线属性 设备属性 驱动属性

struct bus_type_private {
 struct kset subsys;   /*主kobject,定义此总线的kset*/
 struct kset *drivers_kset; /*与此总线相关的驱动程序的链表*/
 struct kset *devices_kset; /*与此总线相关的设备的链表*/
 struct klist klist_devices; /*用于在devices_kset上遍历的klist*/
 struct klist klist_drivers; /*用于在drivers_kset上遍历的klist*/
 struct blocking_notifier_head bus_notifier; /*总线通知链表,用于总线所关心的事件*/
 unsigned int drivers_autoprobe:1;
 struct bus_type *bus;    /*用于回指总线类型对象*/
};

bus_type_private 描述了挂载在bus上的设备和驱动等

当一个总线驱动程序被初始化时,它调用函数bus_register初始化了总线类型对象,并将对象插入到内核对象树中。函数bus_unregister用来注销bus。两个函数原型列出如下:

int bus_register(struct bus_type * bus);
extern void bus_unregister(struct bus_type *bus);

总线注册和取消注册


内核分别存在结构devices的链表和结构device_drivers的链表,利用下面的辅助函数可以遍历这两个链表,这两个函数遍历链表,并调用每个设备或驱动程序的回调函数。在回调函数调用之前,链表中的对象的引用计数加1,在下一个对象已获得之后,它个计数减1。

int bus_for_each_dev(struct bus_type * bus, struct device * start, void * data,
       int (*fn)(struct device *, void *));
 
int bus_for_each_drv(struct bus_type * bus, struct device_driver * start,
       void * data, int (*fn)(struct device_driver *, void *));
      
遍历总线上的所有设备和驱动

在sysfs文件系统的bus目录下,每个总线获得一个目录。在总线驱动程序目录drivers里,每个与总线注册在一起的驱动程序有一个目录。在总线中发现的每个设备在bus/devices目录里有一个符号链接指向物体体系中的设备的目录。

PCI总线在文件系统sysfs中显示的内容列出如下:

^-^$ tree /sys/bus/pci
/sys/bus/pci               /*对应总线属性结构*/
|-- devices               /*对应设备属性结构*/
|   |-- 0000:00:00.0 -> ../../../devices/pci0000:00/0000:00:00.0
|   |-- 0000:00:00.1 -> ../../../devices/pci0000:00/0000:00:00.1
|   ……
|   `-- 0000:04:09.0 -> ../../../devices/pci0000:00/0000:00:10.0/0000:04:09.0
|-- drivers              /*对应驱动程序属性结构*/
|   |-- 8139cp
|   |   |-- bind
|   |   |-- module -> ../../../../module/8139cp
|   |   |-- new_id
|   |   |-- uevent
|   |   `-- unbind
|   ……
|   `-- yenta_cardbus
|       |-- bind
|       |-- module -> ../../../../module/yenta_socket
|       |-- new_id
|       |-- uevent
|       `-- unbind
|-- drivers_autoprobe
|-- drivers_probe
|-- slots
`-- uevent

查看总线和总线上的设备

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值