分类: LINUX
2010-09-02 08:26:17
前文曾经说过这个程序相当于linux调试USB的万能驱动,到底它有什么能耐这么厉害。不会很大吧,统计下:
[zhh@localhost usb]$ wc -l usb-skeleton.c
525 usb-skeleton.c
只有525行,500多行的程序,对学习linux的兄弟来说,毛毛雨而已,呵呵。抱着乐观的心情,开始探索之路吧。
先看看注册和注销函数,如下:
static struct usb_driver skel_driver = {
.name = "skeleton",
.probe = skel_probe,
.disconnect = skel_disconnect,
.suspend = skel_suspend,
.resume = skel_resume,
.pre_reset = skel_pre_reset,
.post_reset = skel_post_reset,
.id_table = skel_table,
.supports_autosuspend = 1,
};
static int __init usb_skel_init(void)
{
int result;
/* register this driver with the USB subsystem */
result = usb_register(&skel_driver);
if (result)
err("usb_register failed. Error number %d", result);
return result;
}
static void __exit usb_skel_exit(void)
{
/* deregister this driver with the USB subsystem */
usb_deregister(&skel_driver);
}
module_init(usb_skel_init);
module_exit(usb_skel_exit);
MODULE_LICENSE("GPL");
简单看下struct usb_driver结构体
/**
* struct usb_driver - identifies USB interface driver to usbcore
* @name: The driver name should be unique among USB drivers,
* and should normally be the same as the module name.
指向驱动程序名字的指针。在内核的所有USB驱动程序中它必须是唯一的,通常被设置为和驱动程序模块名相同的名字
* @probe: Called to see if the driver is willing to manage a particular
* interface on a device. If it is, probe returns zero and uses
* usb_set_intfdata() to associate driver-specific data with the
* interface. It may also use usb_set_interface() to specify the
* appropriate altsetting. If unwilling to manage the interface,
* return -ENODEV, if genuine IO errors occured, an appropriate
* negative errno value.指向USB驱动程序的探测函数的指针。当USB核心认为它有一个struct usb_interface可以由该驱动程序处理时,它将调用该函数。USB核心用来判断的指向struct usb_device_id的指针也被传递给该函数。如果USB驱动程序确认传递给它的struct usb_interface,它应该初始化设备然后返回0.如果驱动程序不确认该设备或者发生了错误,它应该返回一个负的错误值。
* @disconnect: Called when the interface is no longer accessible, usually
* because its device has been (or is being) disconnected or the
* driver module is being unloaded.指向USB驱动程序中的断开函数的指针。当struct usb_interface被从系统中移除或者驱动程序正在从USB核心卸载时,USB核心将调用该函数。
* @ioctl: Used for drivers that want to talk to userspace through
* the "usbfs" filesystem. This lets devices provide ways to
* expose information to user space regardless of where they
* do (or don't) show up otherwise in the filesystem.
* @suspend: Called when the device is going to be suspended by the system.
* @resume: Called when the device is being resumed by the system.
* @reset_resume: Called when the suspended device has been reset instead
* of being resumed.
* @pre_reset: Called by usb_reset_device() when the device
* is about to be reset.
* @post_reset: Called by usb_reset_device() after the device
* has been reset
* @id_table: USB drivers use ID table to support hotplugging.
* Export this with MODULE_DEVICE_TABLE(usb,...). This must be set
* or your driver's probe function will never get called.
* @dynids: used internally to hold the list of dynamically added device
* ids for this driver.
* @drvwrap: Driver-model core structure wrapper.
* @no_dynamic_id: if set to 1, the USB core will not allow dynamic ids to be
* added to this driver by preventing the sysfs file from being created.
* @supports_autosuspend: if set to 0, the USB core will not allow autosuspend
* for interfaces bound to this driver.
* @soft_unbind: if set to 1, the USB core will not kill URBs and disable
* endpoints before calling the driver's disconnect method.
*
* USB interface drivers must provide a name, probe() and disconnect()
* methods, and an id_table. Other driver fields are optional.
*
* The id_table is used in hotplugging. It holds a set of descriptors,
* and specialized data may be associated with each entry. That table
* is used by both user and kernel mode hotplugging support.
*
* The probe() and disconnect() methods are called in a context where
* they can sleep, but they should avoid abusing the privilege. Most
* work to connect to a device should be done when the device is opened,
* and undone at the last close. The disconnect code needs to address
* concurrency issues with respect to open() and close() methods, as
* well as forcing all pending I/O requests to complete (by unlinking
* them as necessary, and blocking until the unlinks complete).
*/
struct usb_driver {
const char *name;
int (*probe) (struct usb_interface *intf,
const struct usb_device_id *id);
void (*disconnect) (struct usb_interface *intf);
int (*ioctl) (struct usb_interface *intf, unsigned int code,
void *buf);
int (*suspend) (struct usb_interface *intf, pm_message_t message);
int (*resume) (struct usb_interface *intf);
int (*reset_resume)(struct usb_interface *intf);
int (*pre_reset)(struct usb_interface *intf);
int (*post_reset)(struct usb_interface *intf);
const struct usb_device_id *id_table;
struct usb_dynids dynids;
struct usbdrv_wrap drvwrap;
unsigned int no_dynamic_id:1;
unsigned int supports_autosuspend:1;
unsigned int soft_unbind:1;
};
创建一个有效的struct usb_driver结构体只需要初始化五个字段:
static struct usb_driver skel_driver = {
.owner = THIS_MODULE,
.name = "skeleton",
.probe = skel_probe,
.disconnect = skel_disconnect,
.id_table = skel_table,
};
usb-skeleton.c中定义的结构体就是多加了几个字段,可能眼尖的兄弟会发现貌似有2个问题:
(1)owner字段呢,怎么没有了?别急,看看usb_skel_init()函数里面的
result = usb_register(&skel_driver);
而usb_register的定义
static inline int usb_register(struct usb_driver *driver)
{
return usb_register_driver(driver, THIS_MODULE, KBUILD_MODNAME);
}
不用进去函数里面,我们都知道owner字段肯定是没问题了。这个函数实现的功能就不多说了。
(2)struct device_driver driver在哪里呢?没有它,怎么可能把驱动关联到总线上去?
struct usb_driver里面有这么一个字段struct usbdrv_wrap drvwrap;
定义如下:
/**
* struct usbdrv_wrap - wrapper for driver-model structure
* @driver: The driver-model core driver structure.
* @for_devices: Non-zero for device drivers, 0 for interface drivers.
*/
struct usbdrv_wrap {
struct device_driver driver;
int for_devices;
};
这个USB比较复杂,因此呢,又多定义了这么一个结构体,0代表USB接口驱动,非0代表USB设备驱动。
fudan_abc大虾们已经把这块说的非常通俗易懂了,就跟着他们的步伐前进吧。前面已经说过一个有效的struct usb_driver结构体只需要5个字段,owner是用来给模块计数的,每个模块都这么用,赋值总是THIS_MODULE,而name就是这个模块的名字,usb core会处理它。因此,我们的重点是probe,disconnect与id_table.
首先亮相的是id_table,它到底有什么作用呢?下面2段直接引用fudan_abc大虾们的原文。
“我们说过,一个device只能绑定一个driver,但driver并非只能支持一种设备,道理很简单,比如我有两块U盘,那么我可以一起都插入,但是我只需要加载一个模块,usb-storage,没听说过插入两块U盘就得加载两次驱动程序的,除非这两块U盘本身就得使用不同的驱动程序.也正是因为一个模块可以被多个设备共用,才会有模块计数这么一个说法.
ok,既然一个driver可以支持多个device,那么当发现一个device的时候,如何知道哪个driver才是她的Mr.Right呢?这就是id_table的用处,让每一个struct usb_driver准备一张表,里边注明该driver支持哪些设备,这总可以了吧.如果你这个设备属于这张表里的,那么ok,绑定吧,如果不属于这张表里的,那么不好意思,您请便.哪凉快上哪去.”
说到这里,我们不得不看看struct usb_device_id的定义了
/*
* Device table entry for "new style" table-driven USB drivers.
* User mode code can read these tables to choose which modules to load.
* Declare the table as a MODULE_DEVICE_TABLE.
*
* A probe() parameter will point to a matching entry from this table.
* Use the driver_info field for each match to hold information tied
* to that match: device quirks, etc.
*
* Terminate the driver's table with an all-zeroes entry.
* Use the flag values to control which fields are compared.
*/
/**
* struct usb_device_id - identifies USB devices for probing and hotplugging
* @match_flags: Bit mask controlling of the other fields are used to match
* against new devices. Any field except for driver_info may be used,
* although some only make sense in conjunction with other fields.
* This is usually set by a USB_DEVICE_*() macro, which sets all
* other fields in this structure except for driver_info.
* @idVendor: USB vendor ID for a device; numbers are assigned
* by the USB forum to its members.
* @idProduct: Vendor-assigned product ID.
* @bcdDevice_lo: Low end of range of vendor-assigned product version numbers.
* This is also used to identify individual product versions, for
* a range consisting of a single device.
* @bcdDevice_hi: High end of version number range. The range of product
* versions is inclusive.
* @bDeviceClass: Class of device; numbers are assigned
* by the USB forum. Products may choose to implement classes,
* or be vendor-specific. Device classes specify behavior of all
* the interfaces on a devices.
* @bDeviceSubClass: Subclass of device; associated with bDeviceClass.
* @bDeviceProtocol: Protocol of device; associated with bDeviceClass.
* @bInterfaceClass: Class of interface; numbers are assigned
* by the USB forum. Products may choose to implement classes,
* or be vendor-specific. Interface classes specify behavior only
* of a given interface; other interfaces may support other classes.
* @bInterfaceSubClass: Subclass of interface; associated with bInterfaceClass.
* @bInterfaceProtocol: Protocol of interface; associated with bInterfaceClass.
* @driver_info: Holds information used by the driver. Usually it holds
* a pointer to a descriptor understood by the driver, or perhaps
* device flags.
*
* In most cases, drivers will create a table of device IDs by using
* USB_DEVICE(), or similar macros designed for that purpose.
* They will then export it to userspace using MODULE_DEVICE_TABLE(),
* and provide it to the USB core through their usb_driver structure.
*
* See the usb_match_id() function for information about how matches are
* performed. Briefly, you will normally use one of several macros to help
* construct these entries. Each entry you provide will either identify
* one or more specific products, or will identify a class of products
* which have agreed to behave the same. You should put the more specific
* matches towards the beginning of your table, so that driver_info can
* record quirks of specific products.
*/
struct usb_device_id {
/* which fields to match against? */
__u16 ;
/* Used for product specific matches; range is inclusive */
__u16 idVendor;
__u16 idProduct;
__u16 bcdDevice_lo;
__u16 bcdDevice_hi;
/* Used for device class matches */
__u8 bDeviceClass;
__u8 bDeviceSubClass;
__u8 bDeviceProtocol;
/* Used for interface class matches */
__u8 bInterfaceClass;
__u8 bInterfaceSubClass;
__u8 bInterfaceProtocol;
/* not matched against */
kernel_ulong_t driver_info;
};
相信对USB协议熟悉的兄弟对大部分字段都不会陌生,这里就简要说明下USB协议里面没有的字段,也是非常重要的字段。
match_flags:控制结构体中其他字段的位掩码,被用来匹配新设备,当然driver_info字段不包括在里面了。如下面要提到的skel_table数组,只要匹配VID和PID就认为找到新设备了,就是在这个字段设置的。
从struct usb_driver skel_driver的定义中知道,它所支持的USB设备的列表数组为skel_table,看看定义
/* table of devices that work with this driver */
static struct usb_device_id skel_table [] = {
{ USB_DEVICE(USB_SKEL_VENDOR_ID, USB_SKEL_PRODUCT_ID) },
{ } /* Terminating entry */
};
这里不啰唆了,只要从设备的VID和PID和这里的一致,usb-skeleton就是它的驱动了,也就是以前说的linux万能调试驱动,O(∩_∩)O
chinaunix网友2011-01-04 20:04:27
很好的, 收藏了 推荐一个博客,提供很多免费软件编程电子书下载: http://free-ebooks.appspot.com
chinaunix网友2011-01-04 20:04:11
很好的, 收藏了 推荐一个博客,提供很多免费软件编程电子书下载: http://free-ebooks.appspot.com