linux usb-skeleton,Linux USB驱动程序(2)----usb-skeleton.c分析

骑猪看日落 2023-01-22 02:51 154阅读 0赞

前文曾经说过这个程序相当于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 */

__u16idVendor;

__u16idProduct;

__u16bcdDevice_lo;

__u16bcdDevice_hi;

/* Used for device class matches */

__u8bDeviceClass;

__u8bDeviceSubClass;

__u8bDeviceProtocol;

/* Used for interface class matches */

__u8bInterfaceClass;

__u8bInterfaceSubClass;

__u8bInterfaceProtocol;

/* not matched against */

kernel_ulong_tdriver_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

发表评论

表情:
评论列表 (有 0 条评论,154人围观)

还没有评论,来说两句吧...

相关阅读