Chinaunix首页 | 论坛 | 博客
  • 博客访问: 48840
  • 博文数量: 13
  • 博客积分: 25
  • 博客等级: 民兵
  • 技术积分: 20
  • 用 户 组: 普通用户
  • 注册时间: 2012-08-08 19:06
文章分类
文章存档

2013年(13)

我的朋友

分类: LINUX

2013-07-11 14:59:32

Device Drivers
设备驱动

See the kerneldoc for the struct device_driver.


Allocation
内存分配
~~~~~~~~~~

Device drivers are statically allocated structures. Though there may
be multiple devices in a system that a driver supports, struct
device_driver represents the driver as a whole (not a particular
device instance).
设备驱动应该是静态分配的结构体。虽然系统中一个 driver 可能会支持多
设备,但 struct device_driver 仍将 driver 做为一个单独的整体(而不是某
实例的一部分)。

Initialization
初始化
~~~~~~~~~~~~~~

The driver must initialize at least the name and bus fields. It should
also initialize the devclass field (when it arrives), so it may obtain
the proper linkage internally. It should also initialize as many of
the callbacks as possible, though each is optional.
driver 至少应该初始化两个字段:name 和 bus。当然也应该初始化 devclass
字段,这样它可以在内部获得适当的链接。同时它也应该尽可能多的初始化回
函数,尽管这些回调函数是可选的。

Declaration
声明
~~~~~~~~~~~

As stated above, struct device_driver objects are statically
allocated. Below is an example declaration of the eepro100
driver. This declaration is hypothetical only; it relies on the driver
being converted completely to the new model. 
如上所述,struct device_driver 对象是静态分配的。以下是一个 eepro100
driver 的声明的小例子。这个声明仅仅是个假设,它依赖于被完全转换成新模型
的 driver。

  1. static struct device_driver eepro100_driver = {
  2.     .name = "eepro100",
  3.     .bus = &pci_bus_type,
  4.        
  5.     .probe = eepro100_probe,
  6.     .remove = eepro100_remove,
  7.     .suspend = eepro100_suspend,
  8.     .resume = eepro100_resume,
  9. };

Most drivers will not be able to be converted completely to the new
model because the bus they belong to has a bus-specific structure with
bus-specific fields that cannot be generalized. 
但大多数 driver 不能够被完全转换成新模型,这是因为这些 driver 所依附的
总线都有一个该总线定制字段的数据结构,而这些字段不能一概而论。

The most common example of this are device ID structures. A driver
typically defines an array of device IDs that it supports. The format
of these structures and the semantics for comparing device IDs are
completely bus-specific. Defining them as bus-specific entities would
sacrifice type-safety, so we keep bus-specific structures around. 
最常见的例子就是设备的 ID 结构。通常是一个驱动会定义一组它支持的设备 ID。
而这些结构的数据格式和与设备 ID 进行比较时的算法都完全是总线定制的。因为
将它们定义成总线定制的实体会牺牲类型安全,所以我们将保留总线定制的数据结构。

Bus-specific drivers should include a generic struct device_driver in
the definition of the bus-specific driver. Like this:
总线定制的驱动应该包含一个通用的结构体 struct device_driver,就像这样:

  1. struct pci_driver {
  2.     const struct pci_device_id *id_table;
  3.     struct device_driver driver;
  4. };

A definition that included bus-specific fields would look like
(using the eepro100 driver again):
一个包含了总线定制字段的驱动应该像这样定义(还是用 eepro100 driver):

  1. static struct pci_driver eepro100_driver = {
  2.     .id_table = eepro100_pci_tbl,
  3.     .driver = {
  4.         .name = "eepro100",
  5.         .bus = &pci_bus_type,
  6.         .probe = eepro100_probe,
  7.         .remove = eepro100_remove,
  8.         .suspend = eepro100_suspend,
  9.         .resume = eepro100_resume,
  10.     },
  11. };

Some may find the syntax of embedded struct initialization awkward or
even a bit ugly. So far, it's the best way we've found to do what we want...
可能有些人会觉得这样的内嵌结构体有些别扭甚至比较丑陋。但目前为止,这是
能够满足我们需要的最好的方法了...

Registration
注册
~~~~~~~~~~~~

  1. int driver_register(struct device_driver * drv);

The driver registers the structure on startup. For drivers that have
no bus-specific fields (i.e. don't have a bus-specific driver
structure), they would use driver_register and pass a pointer to their
struct device_driver object. 
驱动程序将会在启动时注册该结构体。对于那些没有总线定制字段的 driver
(即没有一个总线定制的 driver 结构体),应该使用 driver_register 并传递
给这个函数指向该驱动的 struct device_driver 对象的指针。

Most drivers, however, will have a bus-specific structure and will
need to register with the bus using something like pci_driver_register.
然而大部分 driver 拥有一个总线定制结构并需要一个像 pci_driver_register
这样的函数去这个总线上完成注册。

It is important that drivers register their driver structure as early as
possible. Registration with the core initializes several fields in the
struct device_driver object, including the reference count and the
lock. These fields are assumed to be valid at all times and may be
used by the device model core or the bus driver.
重要的是驱动程序应该尽早的注册他们的 driver 结构。在向核心的注册过程
中,struct device_driver 对象中的几个字段会被初始化,这些字段包括引用
计数和 lock。这是因为上述的字段会被设备模型核心或总线驱动假设在任何
时候都是可用的。


Transition Bus Drivers
转换到总线驱动
~~~~~~~~~~~~~~~~~~~~~~

By defining wrapper functions, the transition to the new model can be
made easier. Drivers can ignore the generic structure altogether and
let the bus wrapper fill in the fields. For the callbacks, the bus can
define generic callbacks that forward the call to the bus-specific
callbacks of the drivers. 
定义一个封装函数,可以更容易的实现到新模型的转换。driver 可以完全忽略
通用结构并让总线封装函数去填充这些字段。对于那些回调函数,总线则可以
定义一组通用回调函数用来指向 driver 的总线定制回调函数。


This solution is intended to be only temporary. In order to get class
information in the driver, the drivers must be modified anyway. Since
converting drivers to the new model should reduce some infrastructural
complexity and code size, it is recommended that they are converted as
class information is added.
该解决方案目的只是暂时的。为了得到 driver 里的 class 信息,这些 driver 必
须能够被修改。因为从 driver 到新模型的转换应当减少基础结构的复杂性和代码
模,所以建议添加它们到 class 信息的转换。


Access
访问
~~~~~~

Once the object has been registered, it may access the common fields of
the object, like the lock and the list of devices. 
一旦该对象已被注册,它就可以访问对象的公共字段,比如 lock 和设备列表。

  1. int driver_for_each_dev(struct device_driver * drv, void * data,
  2.                         int (*callback)(struct device * dev, void * data));

The devices field is a list of all the devices that have been bound to
the driver. The LDM core provides a helper function to operate on all
the devices a driver controls. This helper locks the driver on each
node access, and does proper reference counting on each device as it
accesses it. 
devices 字段就是一组已经绑定到 driver 的设备。LDM 核心提供操作 driver
所控制的所有设备的辅助函数。这个辅助函数将在访问每个节点时锁定 driver,
并且会在访问每个设备时设置正确的引用计数。


sysfs
~~~~~

When a driver is registered, a sysfs directory is created in its
bus's directory. In this directory, the driver can export an interface
to userspace to control operation of the driver on a global basis;
e.g. toggling debugging output in the driver.
当一个 driver 注册之后,就会在 sysfs 中它所属总线目录下创建一个目录。
在这个目录中,driver 可以在全局范围内向用户空间导出驱动控制操作接
口,例如切换驱动程序中的 debug 输出。

A future feature of this directory will be a 'devices' directory. This
directory will contain symlinks to the directories of devices it
supports.
这个目录的一个未来的特性就是它本身将是一个‘devices’目录。该目录将会包
它所支持的那些设备目录的符号链接。



Callbacks
回调
~~~~~~~~~

  1. int (*probe)(struct device * dev);

The probe() entry is called in task context, with the bus's rwsem locked
and the driver partially bound to the device.  Drivers commonly use
container_of() to convert "dev" to a bus-specific type, both in probe()
and other routines.  That type often provides device resource data, such
as pci_dev.resource[] or platform_device.resources, which is used in
addition to dev->platform_data to initialize the driver.
probe() 将在总线的 rwsem 锁定的情况下在任务上下文中调用,然后 driver 将部分
与设备绑定。在 probe() 或其他程序中,driver 通常使用 container_of() 实现‘dev’
到总线定制类型的转换。该类型往往会提供设备的资源数据,就像 pci_dev.resource[]
或 platform_device.resources,这些资源用于除了 dev->platform_data
的 driver 初始化。

This callback holds the driver-specific logic to bind the driver to a
given device.  That includes verifying that the device is present, that
it's a version the driver can handle, that driver data structures can
be allocated and initialized, and that any hardware can be initialized.
Drivers often store a pointer to their state with dev_set_drvdata().
When the driver has successfully bound itself to that device, then probe()
returns zero and the driver model code will finish its part of binding
the driver to that device.
这个回调包含了绑定该 driver 到给定设备的驱动定制逻辑。这包括了验证该设备
是否存在;该版本能否被处理;能否分配该 driver 的数据结构并初始化;以及哪
些硬件能被初始化。driver 通常会使用 dev_set_drvdata() 保存一个指针指向它的
state。当一个 driver 成功将自己绑定到设备时,probe() 会返回 0,然后驱动模型
代码将会完成它这部分的 driver 到设备的绑定。

A driver's probe() may return a negative errno value to indicate that
the driver did not bind to this device, in which case it should have
released all resources it allocated.
driver 的 probe() 函数返回负的 errno 值表示该 driver 没有被绑定到设备,这种
情况下它必须释放所有已经成功分配的资源。 

  1. int (*remove)(struct device * dev);

remove is called to unbind a driver from a device. This may be
called if a device is physically removed from the system, if the
driver module is being unloaded, during a reboot sequence, or
in other cases.
调用 remove 用来从一个设备解绑定一个 driver。如果从系统中物理移除
一个设备;或者驱动模块已经被卸载;或者在一个 reboot 时序中等等,
这个 remove 都会被调用。

It is up to the driver to determine if the device is present or
not. It should free any resources allocated specifically for the
device; i.e. anything in the device's driver_data field. 
这都取决于这个 driver 判定该设备存在于否。它应该释放为这个设备专门分配
的资源,比如 driver_data 字段中的一切。

If the device is still present, it should quiesce the device and place
it into a supported low-power state.
如果该设备任然存在,它应该暂停该设备并将其置于能够支持的低功耗状态。

  1. int (*suspend)(struct device * dev, pm_message_t state);

suspend is called to put the device in a low power state.
suspend 将设备置于在低功耗状态。

  1. int (*resume)(struct device * dev);

Resume is used to bring a device back from a low power state.
resume 则用于把设备从低功耗状态中恢复回来。


Attributes
属性
~~~~~~~~~~

  1. struct driver_attribute {
  2.     struct attribute attr;
  3.     ssize_t (*show)(struct device_driver *driver, char *buf);
  4.     ssize_t (*store)(struct device_driver *, const char * buf, size_t count);
  5. };

Device drivers can export attributes via their sysfs directories. 
Drivers can declare attributes using a DRIVER_ATTR macro that works
identically to the DEVICE_ATTR macro. 
设备驱动程序可以通过它们的 sysfs 目录将属性导出。可以使用宏 DRIVER_ATTR
定义属性,这个宏工作原理和 DEVICE_ATTR 是一样的。

Example:
示例:

  1. DRIVER_ATTR(debug,0644,show_debug,store_debug);

This is equivalent to declaring:
这实际上就是定义一个这样的东西:

  1. struct driver_attribute driver_attr_debug;

This can then be used to add and remove the attribute from the
driver's directory using:
稍后就可以使用以下函数在 driver 的目录中添加或删除属性。

  1. int driver_create_file(struct device_driver *, const struct driver_attribute *);
  2. void driver_remove_file(struct device_driver *, const struct driver_attribute *);
阅读(1275) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~