Saturday, 1 February 2014

Linux USB driver probe() problem

I'm currently work on kernel-mode USB driver for Seowon SWU-3220A WiMAX USB modem. It is a complex device (after plugging it appear in system as USB CDROM, and driver needs to switch it to modem mode). My problem is that the probe() function from my driver is never called. I think it because OS uses standard usb mass storage driver instead of my own.
I initialize driver as follow:
#define GDM7213_VENDOR_ID 0x1076
#define GDM7213_PRODUCT_ID 0x7f40

static struct usb_device_id gdm7213_table [] = {
{ USB_DEVICE(GDM7213_VENDOR_ID, GDM7213_PRODUCT_ID) },
{ }
};

MODULE_DEVICE_TABLE(usb, gdm7213_table);

static struct usb_driver gdm7213_driver = {
.name = "gdm7213",
.probe = gdm7213_probe,
.disconnect = gdm7213_disconnect,
.suspend = gdm7213_suspend,
.resume = gdm7213_resume,
.pre_reset = gdm7213_pre_reset,
.post_reset = gdm7213_post_reset,
.id_table = gdm7213_table,
};

static int gdm7213_probe(struct usb_interface *interface, const struct usb_device_id *id)
{
printk(KERN_INFO "GDM7213 gdm7213_probe()\n");
return 0;
}

static int __init gdm7213_init_module(void)
{
int result;
printk(KERN_INFO "GDM7213 init_module()\n");

result = usb_register(&gdm7213_driver);
if (result)
err("usb_register failed. Error number %d", result);

return result;
}

static void __exit gdm7213_cleanup_module(void)
{
printk(KERN_INFO "GDM7213 cleanup_module()\n");
usb_deregister(&gdm7213_driver);
}

module_init(gdm7213_init_module);
module_exit(gdm7213_cleanup_module);

Answers:-

If it is the USB mass storage driver stealing it before you get a chance you might want to blacklist the VID/PID for the device with that driver.


Since you mentioned it's a USB WiMAX adapter I'm going to have a wild guess though that it's presenting a USB mass storage device that contains a driver for it on Windows. If that's the case you would be better off working with USB Modeswitch, which already handles this for 3G modems. Typically the devices expect some magic bytes (which often is actually a SCSI eject command) to persuade them to stop being mass storage devices and become the real modem. (That has a different PID normally too).


Even if your device can't be persuaded to show the real device instead of the driver with one of the existing USB Modeswitch rules it would be more appropriate to fix the problem with that than a kernel hack.


Doing it with USB Modeswitch has a number of advantages over what you proposed:


  1. Keeps everything modular:

    1. Your driver only has to care about WiMAX and one VID/PID for the device

    2. The mass storage driver doesn't need to care about crazy devices - it just looks like plugging and unplugging a device. Teaching the mass storage driver about every single one of these sort of devices isn't appropriate, your device doesn't seem to be a special case.

    3. The knowledge about the split personalities of the device is only relevant to USB Modeswitch, which only exists to solve this problem.



  2. It doesn't break the USB mass storage aspects of the device - users might want to view the Windows driver under Linux for some reason, blacklisting this device would make that impossible. This might be important if you end up using some firmware shipped with the Windows driver under Linux too.

  3. It follows the existing setup and keeps your changes local to your module. This might well be important if you want to get your driver in the mainline kernel ever.


0 comments:

Post a Comment

Twitter Delicious Facebook Digg Stumbleupon Favorites More