Re: [PATCH] Add support for Mobilcom Debitel USB UMTS Surf-Stick to option driver

Gernot Hillier
2009-12-08T06:20:47Z

Matthias Urlichs wrote:
> On Fri, 2009-11-27 at 13:49 +0100, Gernot Hillier wrote:
>> + /* 4G Systems W14 simply ignores this message on interface 0 & 1
>> + and would cause long timeouts when calling usb_control_msg() */
>> + if (serial->dev->descriptor.idVendor == FOUR_G_SYSTEMS_VENDOR_ID &&
>> + serial->dev->descriptor.idProduct == FOUR_G_SYSTEMS_PRODUCT_W14 &&
>> + (ifNum == 0 || ifNum == 1) )
>> + return -EIO;
>>
> I'd appreciate if you'd implement this generically.
>
> I.e., use the driver_info field of struct usb_device for an appropriate
> blacklist flag. (It's not going to be the only one.)
>

Ok, so here's my first shot at it. Code was mostly stolen from drivers/usb/
serial/sierra.c.

Additionally, I needed to add some pieces because blacklist info is needed
in option_send_setup() where I don't have easy access to struct usb_
device_id. So far, I had no better idea than remembering the info in our
private structure.

I also prepared things to include the D-Link DWM 652 exceptions from
option_probe() (that's the intention of OPTION_BLACKLIST_RESERVED_IF).

Could you please confirm if this is what you wanted - if yes, I can
probably repost the patch in three parts (blacklisting infrastructure, add
4G W14 blacklist info, port D-Link DWM 652 blacklist info) with
appropriate summaries.

--- drivers/usb/serial/option.c.orig 2009-12-08 05:52:13.000000000 +0100
+++ drivers/usb/serial/option.c 2009-12-08 06:53:43.000000000 +0100
@@ -340,6 +340,28 @@ static int option_resume(struct usb_ser
#define FOUR_G_SYSTEMS_VENDOR_ID 0x1c9e
#define FOUR_G_SYSTEMS_PRODUCT_W14 0x9603

+/* some devices interfaces need special handling due to a number of reasons */
+typedef enum {
+ OPTION_BLACKLIST_NONE = 0,
+ OPTION_BLACKLIST_SENDSETUP = 1,
+ OPTION_BLACKLIST_RESERVED_IF = 2
+} option_blacklist_reason_t;
+
+struct option_blacklist_info {
+ const u32 infolen; /* number of interface numbers on blacklist */
+ const u8 *ifaceinfo; /* pointer to the array holding the numbers */
+ option_blacklist_reason_t reason;
+};
+
+static const u8 four_g_w14_no_sendsetup[] = { 0, 1 };
+static const struct option_blacklist_info four_g_w14_blacklist = {
+ .infolen = ARRAY_SIZE(four_g_w14_no_sendsetup),
+ .ifaceinfo = four_g_w14_no_sendsetup,
+ .reason = OPTION_BLACKLIST_SENDSETUP
+};
+
+
+
static struct usb_device_id option_ids[] = {
{ USB_DEVICE(OPTION_VENDOR_ID, OPTION_PRODUCT_COLT) },
{ USB_DEVICE(OPTION_VENDOR_ID, OPTION_PRODUCT_RICOLA) },
@@ -604,7 +626,9 @@ static struct usb_device_id option_ids[]
{ USB_DEVICE(ALCATEL_VENDOR_ID, ALCATEL_PRODUCT_X060S) },
{ USB_DEVICE(AIRPLUS_VENDOR_ID, AIRPLUS_PRODUCT_MCD650) },
{ USB_DEVICE(TLAYTECH_VENDOR_ID, TLAYTECH_PRODUCT_TEU800) },
- { USB_DEVICE(FOUR_G_SYSTEMS_VENDOR_ID, FOUR_G_SYSTEMS_PRODUCT_W14) },
+ { USB_DEVICE(FOUR_G_SYSTEMS_VENDOR_ID, FOUR_G_SYSTEMS_PRODUCT_W14),
+ .driver_info = (kernel_ulong_t)&four_g_w14_blacklist
+ },
{ } /* Terminating entry */
};
MODULE_DEVICE_TABLE(usb, option_ids);
@@ -668,6 +692,7 @@ struct option_intf_private {
spinlock_t susp_lock;
unsigned int suspended:1;
int in_flight;
+ struct option_blacklist_info *blacklist_info;
};

struct option_port_private {
@@ -737,9 +762,27 @@ static int option_probe(struct usb_seria
if (!data)
return -ENOMEM;
spin_lock_init(&data->susp_lock);
+ data->blacklist_info = (struct option_blacklist_info*) id->driver_info;
return 0;
}

+static option_blacklist_reason_t is_blacklisted(const u8 ifnum,
+ const struct option_blacklist_info *blacklist)
+{
+ const u8 *info;
+ int i;
+
+ if (blacklist) {
+ info = blacklist->ifaceinfo;
+
+ for (i = 0; i < blacklist->infolen; i++) {
+ if (info[i] == ifnum)
+ return blacklist->reason;
+ }
+ }
+ return OPTION_BLACKLIST_NONE;
+}
+
static void option_set_termios(struct tty_struct *tty,
struct usb_serial_port *port, struct ktermios *old_termios)
{
@@ -1170,11 +1213,18 @@ static void option_setup_urbs(struct usb
static int option_send_setup(struct usb_serial_port *port)
{
struct usb_serial *serial = port->serial;
+ struct option_intf_private *intfdata = (struct option_intf_private *) serial->private;
struct option_port_private *portdata;
int ifNum = serial->interface->cur_altsetting->desc.bInterfaceNumber;
int val = 0;
dbg("%s", __func__);

+ if (is_blacklisted(ifNum, intfdata->blacklist_info) ==
+ OPTION_BLACKLIST_SENDSETUP) {
+ dbg("No send_setup on blacklisted interface #%d\n", ifNum);
+ return -EIO;
+ }
+
portdata = usb_get_serial_port_data(port);

if (portdata->dtr_state)