aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorGernot Hillier <gernot@hillier.de>2010-01-11 03:30:00 -0500
committerGreg Kroah-Hartman <gregkh@suse.de>2010-03-02 17:54:21 -0500
commitcc175ce2c01fc78dbf98a2b00f23d8863de20764 (patch)
treecf1cce6adf7fedec1aa06c919db8f006986cdf09
parent79da01d79e0f2c8d2d6f1b823fce429877c423a7 (diff)
USB: serial: option.c: Add blacklisting infrastructure for special device handling
As suggested by Matthias Urlichs, this patch adds a somehow generic mechanism for special handling of devices which don't support all bits expected by this driver. The blacklisting code is heavily stolen from sierra.c, but extended to support different special cases. For now, one case is implemented (OPTION_BLACKLIST_SENDSETUP), targeted at the 4G W14 device: devices which don't understand the setting of RTS/DTR in option_send_setup() causing a USB timeout of 5 s in any userspace open() which leads to errors in most userspace applications. In addition, I prepared another case for devices with interfaces which shall not be accessed by this driver (targeted at the D-Link DWM 652). However, OPTION_BLACKLIST_RESERVED_IF is not fully implemented yet as I have no device to test this. Anyone volunteering to help here? If not, I'll contact the guys who added D-Link DWM 652 support soon. Signed-off-by: Gernot Hillier <gernot@hillier.de> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
-rw-r--r--drivers/usb/serial/option.c40
1 files changed, 40 insertions, 0 deletions
diff --git a/drivers/usb/serial/option.c b/drivers/usb/serial/option.c
index b4fe9ffd6dd6..85e5fc08bba6 100644
--- a/drivers/usb/serial/option.c
+++ b/drivers/usb/serial/option.c
@@ -346,6 +346,19 @@ static int option_resume(struct usb_serial *serial);
346#define HAIER_VENDOR_ID 0x201e 346#define HAIER_VENDOR_ID 0x201e
347#define HAIER_PRODUCT_CE100 0x2009 347#define HAIER_PRODUCT_CE100 0x2009
348 348
349/* some devices interfaces need special handling due to a number of reasons */
350enum option_blacklist_reason {
351 OPTION_BLACKLIST_NONE = 0,
352 OPTION_BLACKLIST_SENDSETUP = 1,
353 OPTION_BLACKLIST_RESERVED_IF = 2
354};
355
356struct option_blacklist_info {
357 const u32 infolen; /* number of interface numbers on blacklist */
358 const u8 *ifaceinfo; /* pointer to the array holding the numbers */
359 enum option_blacklist_reason reason;
360};
361
349static const struct usb_device_id option_ids[] = { 362static const struct usb_device_id option_ids[] = {
350 { USB_DEVICE(OPTION_VENDOR_ID, OPTION_PRODUCT_COLT) }, 363 { USB_DEVICE(OPTION_VENDOR_ID, OPTION_PRODUCT_COLT) },
351 { USB_DEVICE(OPTION_VENDOR_ID, OPTION_PRODUCT_RICOLA) }, 364 { USB_DEVICE(OPTION_VENDOR_ID, OPTION_PRODUCT_RICOLA) },
@@ -711,6 +724,7 @@ struct option_intf_private {
711 spinlock_t susp_lock; 724 spinlock_t susp_lock;
712 unsigned int suspended:1; 725 unsigned int suspended:1;
713 int in_flight; 726 int in_flight;
727 struct option_blacklist_info *blacklist_info;
714}; 728};
715 729
716struct option_port_private { 730struct option_port_private {
@@ -780,9 +794,27 @@ static int option_probe(struct usb_serial *serial,
780 if (!data) 794 if (!data)
781 return -ENOMEM; 795 return -ENOMEM;
782 spin_lock_init(&data->susp_lock); 796 spin_lock_init(&data->susp_lock);
797 data->blacklist_info = (struct option_blacklist_info*) id->driver_info;
783 return 0; 798 return 0;
784} 799}
785 800
801static enum option_blacklist_reason is_blacklisted(const u8 ifnum,
802 const struct option_blacklist_info *blacklist)
803{
804 const u8 *info;
805 int i;
806
807 if (blacklist) {
808 info = blacklist->ifaceinfo;
809
810 for (i = 0; i < blacklist->infolen; i++) {
811 if (info[i] == ifnum)
812 return blacklist->reason;
813 }
814 }
815 return OPTION_BLACKLIST_NONE;
816}
817
786static void option_set_termios(struct tty_struct *tty, 818static void option_set_termios(struct tty_struct *tty,
787 struct usb_serial_port *port, struct ktermios *old_termios) 819 struct usb_serial_port *port, struct ktermios *old_termios)
788{ 820{
@@ -1213,11 +1245,19 @@ static void option_setup_urbs(struct usb_serial *serial)
1213static int option_send_setup(struct usb_serial_port *port) 1245static int option_send_setup(struct usb_serial_port *port)
1214{ 1246{
1215 struct usb_serial *serial = port->serial; 1247 struct usb_serial *serial = port->serial;
1248 struct option_intf_private *intfdata =
1249 (struct option_intf_private *) serial->private;
1216 struct option_port_private *portdata; 1250 struct option_port_private *portdata;
1217 int ifNum = serial->interface->cur_altsetting->desc.bInterfaceNumber; 1251 int ifNum = serial->interface->cur_altsetting->desc.bInterfaceNumber;
1218 int val = 0; 1252 int val = 0;
1219 dbg("%s", __func__); 1253 dbg("%s", __func__);
1220 1254
1255 if (is_blacklisted(ifNum, intfdata->blacklist_info) ==
1256 OPTION_BLACKLIST_SENDSETUP) {
1257 dbg("No send_setup on blacklisted interface #%d\n", ifNum);
1258 return -EIO;
1259 }
1260
1221 portdata = usb_get_serial_port_data(port); 1261 portdata = usb_get_serial_port_data(port);
1222 1262
1223 if (portdata->dtr_state) 1263 if (portdata->dtr_state)