I was trying to learn device drivers in Linux. I came across the code to detect the usb device. But it only detects those devices which have there entry in usb_device_id_pen_table[]
strucutre. How can I make this more generic so as to detect all the usb devices ?
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/usb.h>
#include <linux/usb/hcd.h>
#include <linux/list.h>
static int pen_probe(struct usb_interface *interface, const struct
usb_device_id *id)
{
printk(KERN_INFO "MY Pen drive (%04X:%04X) plugged\n",id->idVendor, id->idProduct);
return 0;
}
static void pen_disconnect(struct usb_interface *interface)
{
printk(KERN_INFO "MY Pen drive removed\n");
}
static struct usb_device_id pen_table[] =
{
{ USB_DEVICE(0x03F0, 0xBF07) },
{ USB_DEVICE(0x0781, 0x5567) },
{} /* Terminating entry */
};
MODULE_DEVICE_TABLE (usb, pen_table);
static struct usb_driver pen_driver =
{
.name = "pen_driver",
.id_table = pen_table,
.probe = pen_probe,
.disconnect = pen_disconnect,
};
static int __init pen_init(void)
{
return usb_register(&pen_driver);
}
static void __exit pen_exit(void)
{
usb_deregister(&pen_driver);
}
module_init(pen_init);
module_exit(pen_exit);
MODULE_LICENSE("GPL");
MODULE_DESCRIPTION("USB Pen Registration Driver");
First of all you should understand what matching means. When you insert new USB device, kernel obtains information from it (vendor ID, product ID, etc) and tries to find some driver that support this device (i.e. driver that specifies the same vendor ID, product ID, etc). This procedure calls matching.
NOTE: Usually matching devices (in your driver) that have vendorID/productID different from your device is bad idea. So maybe you don't really want to do that (actually I don't understand why you want to do so). Anyway, the answer is below.
USB devices matching is happening in usb_match_device()
function (in drivers/usb/core/driver.c). From there you can see that your entries in .id_table
must use one of available matching strategies (see matching flags below).
The crucial thing to notice in usb_match_device()
function is that it returns 1
if device successfully matched (not 0
which usually stands for "success" in kernel). So this function basically checks all matching flags specified, one by one, and checks if corresponding data in your structure is equal to data from tested USB device. All matching fields, specified in .match_flags
must be the same for your device and for device table entry being checked, to usb_match_device()
function return success result.
You can find matching flags in include/linux/mod_devicetable.h:
/* Some useful macros to use to create struct usb_device_id */
#define USB_DEVICE_ID_MATCH_VENDOR 0x0001
#define USB_DEVICE_ID_MATCH_PRODUCT 0x0002
#define USB_DEVICE_ID_MATCH_DEV_LO 0x0004
#define USB_DEVICE_ID_MATCH_DEV_HI 0x0008
#define USB_DEVICE_ID_MATCH_DEV_CLASS 0x0010
#define USB_DEVICE_ID_MATCH_DEV_SUBCLASS 0x0020
#define USB_DEVICE_ID_MATCH_DEV_PROTOCOL 0x0040
Those flags are intended for filling .match_flags
field in struct usb_device_id
. For your convenience there are macros out there that create the whole struct usb_device_id
using chosen strategy (like USB_DEVICE()
macro that you are using). Those macros are defined in include/linux/usb.h:
USB_DEVICE - macro used to describe a specific usb device
USB_DEVICE_VER - describe a specific usb device with a version range
USB_DEVICE_INTERFACE_CLASS - describe a usb device with a specific interface class
USB_DEVICE_INTERFACE_PROTOCOL - describe a usb device with a specific interface protocol
USB_DEVICE_INTERFACE_NUMBER - describe a usb device with a specific interface number
USB_DEVICE_INFO - macro used to describe a class of usb devices
So it looks like you need to use USB_DEVICE_INFO()
instead of USB_DEVICE()
:
/**
* USB_DEVICE_INFO - macro used to describe a class of usb devices
* @cl: bDeviceClass value
* @sc: bDeviceSubClass value
* @pr: bDeviceProtocol value
*
* This macro is used to create a struct usb_device_id that matches a
* specific class of devices.
*/
#define USB_DEVICE_INFO(cl, sc, pr) \
.match_flags = USB_DEVICE_ID_MATCH_DEV_INFO, \
.bDeviceClass = (cl), \
.bDeviceSubClass = (sc), \
.bDeviceProtocol = (pr)