diff options
Diffstat (limited to 'drivers/net/usb')
-rw-r--r-- | drivers/net/usb/cdc_ether.c | 11 | ||||
-rw-r--r-- | drivers/net/usb/dm9601.c | 52 | ||||
-rw-r--r-- | drivers/net/usb/pegasus.c | 21 | ||||
-rw-r--r-- | drivers/net/usb/rndis_host.c | 4 |
4 files changed, 77 insertions, 11 deletions
diff --git a/drivers/net/usb/cdc_ether.c b/drivers/net/usb/cdc_ether.c index a934428a589..0e061dfea78 100644 --- a/drivers/net/usb/cdc_ether.c +++ b/drivers/net/usb/cdc_ether.c @@ -50,10 +50,18 @@ static int is_activesync(struct usb_interface_descriptor *desc) && desc->bInterfaceProtocol == 1; } +static int is_wireless_rndis(struct usb_interface_descriptor *desc) +{ + return desc->bInterfaceClass == USB_CLASS_WIRELESS_CONTROLLER + && desc->bInterfaceSubClass == 1 + && desc->bInterfaceProtocol == 3; +} + #else #define is_rndis(desc) 0 #define is_activesync(desc) 0 +#define is_wireless_rndis(desc) 0 #endif @@ -110,7 +118,8 @@ int usbnet_generic_cdc_bind(struct usbnet *dev, struct usb_interface *intf) * of cdc-acm, it'll fail RNDIS requests cleanly. */ rndis = is_rndis(&intf->cur_altsetting->desc) - || is_activesync(&intf->cur_altsetting->desc); + || is_activesync(&intf->cur_altsetting->desc) + || is_wireless_rndis(&intf->cur_altsetting->desc); memset(info, 0, sizeof *info); info->control = intf; diff --git a/drivers/net/usb/dm9601.c b/drivers/net/usb/dm9601.c index f7319d32691..78df2be8a72 100644 --- a/drivers/net/usb/dm9601.c +++ b/drivers/net/usb/dm9601.c @@ -55,12 +55,28 @@ static int dm_read(struct usbnet *dev, u8 reg, u16 length, void *data) { + void *buf; + int err = -ENOMEM; + devdbg(dev, "dm_read() reg=0x%02x length=%d", reg, length); - return usb_control_msg(dev->udev, - usb_rcvctrlpipe(dev->udev, 0), - DM_READ_REGS, - USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE, - 0, reg, data, length, USB_CTRL_SET_TIMEOUT); + + buf = kmalloc(length, GFP_KERNEL); + if (!buf) + goto out; + + err = usb_control_msg(dev->udev, + usb_rcvctrlpipe(dev->udev, 0), + DM_READ_REGS, + USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE, + 0, reg, buf, length, USB_CTRL_SET_TIMEOUT); + if (err == length) + memcpy(data, buf, length); + else if (err >= 0) + err = -EINVAL; + kfree(buf); + + out: + return err; } static int dm_read_reg(struct usbnet *dev, u8 reg, u8 *value) @@ -70,12 +86,28 @@ static int dm_read_reg(struct usbnet *dev, u8 reg, u8 *value) static int dm_write(struct usbnet *dev, u8 reg, u16 length, void *data) { + void *buf = NULL; + int err = -ENOMEM; + devdbg(dev, "dm_write() reg=0x%02x, length=%d", reg, length); - return usb_control_msg(dev->udev, - usb_sndctrlpipe(dev->udev, 0), - DM_WRITE_REGS, - USB_DIR_OUT | USB_TYPE_VENDOR |USB_RECIP_DEVICE, - 0, reg, data, length, USB_CTRL_SET_TIMEOUT); + + if (data) { + buf = kmalloc(length, GFP_KERNEL); + if (!buf) + goto out; + memcpy(buf, data, length); + } + + err = usb_control_msg(dev->udev, + usb_sndctrlpipe(dev->udev, 0), + DM_WRITE_REGS, + USB_DIR_OUT | USB_TYPE_VENDOR |USB_RECIP_DEVICE, + 0, reg, buf, length, USB_CTRL_SET_TIMEOUT); + kfree(buf); + if (err >= 0 && err < length) + err = -EINVAL; + out: + return err; } static int dm_write_reg(struct usbnet *dev, u8 reg, u8 value) diff --git a/drivers/net/usb/pegasus.c b/drivers/net/usb/pegasus.c index b588c890ea7..a84ba487c71 100644 --- a/drivers/net/usb/pegasus.c +++ b/drivers/net/usb/pegasus.c @@ -1285,6 +1285,21 @@ static void check_carrier(struct work_struct *work) } } +static int pegasus_blacklisted(struct usb_device *udev) +{ + struct usb_device_descriptor *udd = &udev->descriptor; + + /* Special quirk to keep the driver from handling the Belkin Bluetooth + * dongle which happens to have the same ID. + */ + if ((udd->idVendor == VENDOR_BELKIN && udd->idProduct == 0x0121) && + (udd->bDeviceClass == USB_CLASS_WIRELESS_CONTROLLER) && + (udd->bDeviceProtocol == 1)) + return 1; + + return 0; +} + static int pegasus_probe(struct usb_interface *intf, const struct usb_device_id *id) { @@ -1296,6 +1311,12 @@ static int pegasus_probe(struct usb_interface *intf, DECLARE_MAC_BUF(mac); usb_get_dev(dev); + + if (pegasus_blacklisted(dev)) { + res = -ENODEV; + goto out; + } + net = alloc_etherdev(sizeof(struct pegasus)); if (!net) { dev_err(&intf->dev, "can't allocate %s\n", "device"); diff --git a/drivers/net/usb/rndis_host.c b/drivers/net/usb/rndis_host.c index 61c98beb4d1..bcd858c567e 100644 --- a/drivers/net/usb/rndis_host.c +++ b/drivers/net/usb/rndis_host.c @@ -576,6 +576,10 @@ static const struct usb_device_id products [] = { /* "ActiveSync" is an undocumented variant of RNDIS, used in WM5 */ USB_INTERFACE_INFO(USB_CLASS_MISC, 1, 1), .driver_info = (unsigned long) &rndis_info, +}, { + /* RNDIS for tethering */ + USB_INTERFACE_INFO(USB_CLASS_WIRELESS_CONTROLLER, 1, 3), + .driver_info = (unsigned long) &rndis_info, }, { }, // END }; |