Chinaunix首页 | 论坛 | 博客
  • 博客访问: 559275
  • 博文数量: 105
  • 博客积分: 3274
  • 博客等级: 中校
  • 技术积分: 1161
  • 用 户 组: 普通用户
  • 注册时间: 2010-02-21 12:14
文章分类

全部博文(105)

文章存档

2011年(1)

2010年(104)

分类: 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个问题:

1owner字段呢,怎么没有了?别急,看看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字段肯定是没问题了。这个函数实现的功能就不多说了。

2struct 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,disconnectid_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数组,只要匹配VIDPID就认为找到新设备了,就是在这个字段设置的。

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 */

};

这里不啰唆了,只要从设备的VIDPID和这里的一致,usb-skeleton就是它的驱动了,也就是以前说的linux万能调试驱动,O(_)O

 

阅读(3709) | 评论(2) | 转发(0) |
给主人留下些什么吧!~~

chinaunix网友2011-01-04 20:04:27

很好的, 收藏了 推荐一个博客,提供很多免费软件编程电子书下载: http://free-ebooks.appspot.com

chinaunix网友2011-01-04 20:04:11

很好的, 收藏了 推荐一个博客,提供很多免费软件编程电子书下载: http://free-ebooks.appspot.com