13.4.1. 驱动支持哪些设备?
struct usb_device_id 结构提供了这个驱动支持的一个不同类型 USB 设备的列表,定义如下:
struct usb_device_id {
/*which fields to match against? */
__u16 match_flags;
/*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;
};
与PCI设备相似,这个宏可以用下面的宏进行初始化:
USB_DEVICE(vendor,product)
创建一个 structusb_device_id可用来只匹配特定供应商和产品 ID 值.
USB_DEVICE_VER(vendor, product,lo, hi)
创建一个 struct usb_device_id用来在一个版本范围中只匹配特定供应商和产品 ID 值.
USB_DEVICE_INFO(class, subclass, protocol)
创建一个 struct usb_device_id可用来只匹配一个特定类的 USB 设备.
USB_INTERFACE_INFO(class,subclass, protocol)
创建一个 struct usb_device_id可用来只匹配一个特定类的 USB接口.
简单举例:
/* table of devices that work with thisdriver */
static struct usb_device_id skel_table[ ] = {
{USB_DEVICE(USB_SKEL_VENDOR_ID, USB_SKEL_PRODUCT_ID) },
{} /* Terminating entry */
};
MODULE_DEVICE_TABLE (usb, skel_table);
13.4.2. 注册一个USB驱动
所有 USB 驱动必须创建的结构是 struct usb_driver. 这个结构必须被 USB 驱动填充并且包含多个回调函数和变量,具体定义如下:
struct usb_driver {
constchar *name;
int(*probe) (struct usb_interface *intf,
const struct usb_device_id *id);
void(*disconnect) (struct usb_interface *intf);
int(*unlocked_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);
conststruct usb_device_id *id_table;
structusb_dynids dynids;
structusbdrv_wrap drvwrap;
unsignedint no_dynamic_id:1;
unsignedint supports_autosuspend:1;
unsignedint soft_unbind:1;
};
但是创建一个struct usb_driver结构,只需要初始化5个部分,例如:
static struct usb_driver skel_driver = {
.owner = THIS_MODULE,
.name = "skeleton",
.id_table = skel_table,
.probe = skel_probe,
.disconnect = skel_disconnect,
};
struct usb_driver 确实包含更多几个回调, 它们通常不经常用到,对于USB 驱动正确工作也不是必须的:
int (*ioctl) (struct usb_interface *intf, unsignedint code, void *buf);
//指向 USB 驱动的 ioctl 函数的指针
int (*suspend) (struct usb_interface *intf, u32state);
//指向 USB 驱动中的悬挂函数的指针.
int (*resume) (struct usb_interface *intf);
//指向 USB 驱动中的恢复函数的指针.
(下面是一句比较绕口的注册过程)
以struct usb_driver指针为参数的usb_register_driver函数调用把structusb_driver注册到USB核心。传统在 USB 驱动的模块初始化代码做这个:
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;
}
当 USB 驱动被卸载,struct usb_driver 需要从内核注销。使用usb_deregister_driver的调用完成这个工作。当这个调用发生, 任何当前绑定到这个驱动的 USB 接口被断开, 并且断开函数将被调用,如下:
static void _ _exit usb_skel_exit(void)
{
/* deregister this driver with the USB subsystem */
usb_deregister(&skel_driver);
}
13.4.3. 侦测与断开的细节
原书中代码具体位置未找到,所以另外截取了drivers/hid/usbhid/usbmouse.c中部分代码:
侦测鼠标:
staticint usb_mouse_probe(struct usb_interface *intf, const struct usb_device_id *id)
{
struct usb_device *dev =interface_to_usbdev(intf);
struct usb_host_interface *interface;
struct usb_endpoint_descriptor *endpoint;
struct usb_mouse *mouse;
struct input_dev *input_dev;
int pipe, maxp;
int error = -ENOMEM;
interface = intf->cur_altsetting;
//判断端点数是否为1
if (interface->desc.bNumEndpoints != 1)
return -ENODEV;
//判断端点是否属于中断传输
endpoint =&interface->endpoint[0].desc;
if (!usb_endpoint_is_int_in(endpoint))
return -ENODEV;
//制定USB设备的制定端点号为一个IN中断端点
pipe = usb_rcvintpipe(dev,endpoint->bEndpointAddress);
maxp = usb_maxpacket(dev, pipe,usb_pipeout(pipe));
mouse = kzalloc(sizeof(struct usb_mouse),GFP_KERNEL);
input_dev = input_allocate_device();
if (!mouse || !input_dev)
goto fail1;
//调整申请到的内存空间
mouse->data = usb_alloc_coherent(dev, 8,GFP_ATOMIC, &mouse->data_dma);
if (!mouse->data)
goto fail1;
//到这里就可以创建一个URB
mouse->irq = usb_alloc_urb(0,GFP_KERNEL);
if (!mouse->irq)
goto fail2;
mouse->usbdev = dev;
mouse->dev = input_dev;
//记录设备信息
。。。
usb_make_path(dev, mouse->phys,sizeof(mouse->phys));
strlcat(mouse->phys, "/input0",sizeof(mouse->phys));
//初始化input
。。。
//
input_set_drvdata(input_dev, mouse);
input_dev->open = usb_mouse_open;
input_dev->close = usb_mouse_close;
//初始化URB
usb_fill_int_urb(mouse->irq, dev, pipe,mouse->data,
(maxp > 8 ? 8 : maxp),
usb_mouse_irq, mouse, endpoint->bInterval);
mouse->irq->transfer_dma =mouse->data_dma;
mouse->irq->transfer_flags |=URB_NO_TRANSFER_DMA_MAP;
error =input_register_device(mouse->dev);
if (error)
goto fail3;
//数据指针保留到usb_interface结构的设备中
usb_set_intfdata(intf, mouse);
return 0;
。。。
}
断开鼠标
staticvoid usb_mouse_disconnect(struct usb_interface *intf)
{
struct usb_mouse *mouse = usb_get_intfdata(intf);
//清空保留usb_interface结构的设备数据指针
usb_set_intfdata(intf, NULL);
//断开连接释放设备
if (mouse) {
usb_kill_urb(mouse->irq);
input_unregister_device(mouse->dev);
usb_free_urb(mouse->irq);
usb_free_coherent(interface_to_usbdev(intf),8, mouse->data, mouse->data_dma);
kfree(mouse);
}
}
/* host-side wrapper for one interfacesetting's parsed descriptors */
struct usb_host_interface {
structusb_interface_descriptor desc;
/*array of desc.bNumEndpoint endpoints associated with this
* interface setting. these will be in no particular order.
*/
structusb_host_endpoint *endpoint;
char*string; /* iInterface string, ifpresent */
unsignedchar *extra; /* Extra descriptors */
intextralen;
};
/* USB_DT_INTERFACE: Interface descriptor*/
struct usb_interface_descriptor {
__u8 bLength;
__u8 bDescriptorType;
__u8 bInterfaceNumber;
__u8 bAlternateSetting;
__u8 bNumEndpoints;
__u8 bInterfaceClass;
__u8 bInterfaceSubClass;
__u8 bInterfaceProtocol;
__u8 iInterface;
} __attribute__ ((packed));
写到这里先告一段落,总结在后续会补上 。