From c5be1b52d9ea6ede4931691bf9f0bd454515aa52 Mon Sep 17 00:00:00 2001 From: Pascal Terjan Date: Thu, 16 Apr 2009 19:00:45 +0200 Subject: USB: Ignore storage device in modem mode on DWN-652 D-Link DWN-652 in Modem mode exposes 3 interfaces - First one is the USB storage one - Second one is for both control and connection - Third one is unknown This patch avoids usb-storage trying to switch again when already in modem mode, and exposes only 2 ttyUSB instead of 3 by not attaching to the storage interface Signed-off-by: Pascal Terjan Signed-off-by: Greg Kroah-Hartman --- drivers/usb/storage/option_ms.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'drivers/usb/storage/option_ms.c') diff --git a/drivers/usb/storage/option_ms.c b/drivers/usb/storage/option_ms.c index 353f922939a..126ea3424c0 100644 --- a/drivers/usb/storage/option_ms.c +++ b/drivers/usb/storage/option_ms.c @@ -94,7 +94,8 @@ int option_ms_init(struct us_data *us) */ if (udev->descriptor.bDeviceClass != 0 || udev->descriptor.bDeviceSubClass != 0 || - udev->descriptor.bDeviceProtocol != 0) + udev->descriptor.bDeviceProtocol != 0 || + udev->actconfig->desc.bNumInterfaces == 3) return USB_STOR_TRANSPORT_GOOD; US_DEBUGP("Option MS: option_ms_init called\n"); -- cgit v1.2.3-70-g09d2 From be475d9027a07069407a19980d1a4fcb7b18b23c Mon Sep 17 00:00:00 2001 From: Alan Stern Date: Thu, 21 May 2009 17:37:58 -0400 Subject: USB: usb-storage: fix return values from init functions This patch (as1242) fixes the return values from the special init functions in usb-storage. They are supposed to return 0 for success, not USB_STOR_TRANSPORT_GOOD. Signed-off-by: Alan Stern Signed-off-by: Greg Kroah-Hartman --- drivers/usb/storage/option_ms.c | 8 ++++---- drivers/usb/storage/sierra_ms.c | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) (limited to 'drivers/usb/storage/option_ms.c') diff --git a/drivers/usb/storage/option_ms.c b/drivers/usb/storage/option_ms.c index 126ea3424c0..0d8853339bb 100644 --- a/drivers/usb/storage/option_ms.c +++ b/drivers/usb/storage/option_ms.c @@ -96,7 +96,7 @@ int option_ms_init(struct us_data *us) udev->descriptor.bDeviceSubClass != 0 || udev->descriptor.bDeviceProtocol != 0 || udev->actconfig->desc.bNumInterfaces == 3) - return USB_STOR_TRANSPORT_GOOD; + return 0; US_DEBUGP("Option MS: option_ms_init called\n"); @@ -107,7 +107,7 @@ int option_ms_init(struct us_data *us) iface_desc->desc.bInterfaceProtocol != 0x50) { US_DEBUGP("Option MS: mass storage interface not found, no action " "required\n"); - return USB_STOR_TRANSPORT_GOOD; + return 0; } /* Find the mass storage bulk endpoints */ @@ -127,7 +127,7 @@ int option_ms_init(struct us_data *us) if (!ep_in_size || !ep_out_size) { US_DEBUGP("Option MS: mass storage endpoints not found, no action " "required\n"); - return USB_STOR_TRANSPORT_GOOD; + return 0; } /* Force Modem mode */ @@ -143,6 +143,6 @@ int option_ms_init(struct us_data *us) " requests it\n"); } - return USB_STOR_TRANSPORT_GOOD; + return 0; } diff --git a/drivers/usb/storage/sierra_ms.c b/drivers/usb/storage/sierra_ms.c index 4359a2cb42d..4395c4100ec 100644 --- a/drivers/usb/storage/sierra_ms.c +++ b/drivers/usb/storage/sierra_ms.c @@ -202,6 +202,6 @@ int sierra_ms_init(struct us_data *us) complete: result = device_create_file(&us->pusb_intf->dev, &dev_attr_truinst); - return USB_STOR_TRANSPORT_GOOD; + return 0; } -- cgit v1.2.3-70-g09d2 From 32ebbe7b6ad44ae9c276419710b56de6ba705303 Mon Sep 17 00:00:00 2001 From: Josua Dietze Date: Sun, 24 May 2009 23:21:42 +0200 Subject: USB: usb-storage: add filter to "option_ms" to leave unrecognized devices alone Some unusual usb devices from the maker "Option" are switched from storage to serial/modem mode by sending a SCSI REZERO command. In one case a fairly common vendor/device ID is affected which led to problems for users of other modems or phones which are not supposed to be switched. The patch adds a filter by reading the vendor name with the SCSI INQUIRY command, and skips the switching code for all unrecognized entries. Further changes are cleanups and corrections pointed out by Alan Stern. Tested with two devices with the IDs 05c6:1000, one from "Option" and switchable, and one from Samsung (cell phone). Signed-off-by: Josua Dietze Acked-by: Alan Stern Signed-off-by: Greg Kroah-Hartman --- drivers/usb/storage/option_ms.c | 121 +++++++++++++++++++++++----------------- 1 file changed, 69 insertions(+), 52 deletions(-) (limited to 'drivers/usb/storage/option_ms.c') diff --git a/drivers/usb/storage/option_ms.c b/drivers/usb/storage/option_ms.c index 0d8853339bb..d41cc0a970f 100644 --- a/drivers/usb/storage/option_ms.c +++ b/drivers/usb/storage/option_ms.c @@ -37,7 +37,7 @@ MODULE_PARM_DESC(option_zero_cd, "ZeroCD mode (1=Force Modem (default)," #define RESPONSE_LEN 1024 -static int option_rezero(struct us_data *us, int ep_in, int ep_out) +static int option_rezero(struct us_data *us) { const unsigned char rezero_msg[] = { 0x55, 0x53, 0x42, 0x43, 0x78, 0x56, 0x34, 0x12, @@ -54,10 +54,10 @@ static int option_rezero(struct us_data *us, int ep_in, int ep_out) if (buffer == NULL) return USB_STOR_TRANSPORT_ERROR; - memcpy(buffer, rezero_msg, sizeof (rezero_msg)); + memcpy(buffer, rezero_msg, sizeof(rezero_msg)); result = usb_stor_bulk_transfer_buf(us, - usb_sndbulkpipe(us->pusb_dev, ep_out), - buffer, sizeof (rezero_msg), NULL); + us->send_bulk_pipe, + buffer, sizeof(rezero_msg), NULL); if (result != USB_STOR_XFER_GOOD) { result = USB_STOR_XFER_ERROR; goto out; @@ -66,9 +66,15 @@ static int option_rezero(struct us_data *us, int ep_in, int ep_out) /* Some of the devices need to be asked for a response, but we don't * care what that response is. */ - result = usb_stor_bulk_transfer_buf(us, - usb_sndbulkpipe(us->pusb_dev, ep_out), + usb_stor_bulk_transfer_buf(us, + us->recv_bulk_pipe, buffer, RESPONSE_LEN, NULL); + + /* Read the CSW */ + usb_stor_bulk_transfer_buf(us, + us->recv_bulk_pipe, + buffer, 13, NULL); + result = USB_STOR_XFER_GOOD; out: @@ -76,64 +82,75 @@ out: return result; } -int option_ms_init(struct us_data *us) +static int option_inquiry(struct us_data *us) { - struct usb_device *udev; - struct usb_interface *intf; - struct usb_host_interface *iface_desc; - struct usb_endpoint_descriptor *endpoint = NULL; - u8 ep_in = 0, ep_out = 0; - int ep_in_size = 0, ep_out_size = 0; - int i, result; - - udev = us->pusb_dev; - intf = us->pusb_intf; - - /* Ensure it's really a ZeroCD device; devices that are already - * in modem mode return 0xFF for class, subclass, and protocol. - */ - if (udev->descriptor.bDeviceClass != 0 || - udev->descriptor.bDeviceSubClass != 0 || - udev->descriptor.bDeviceProtocol != 0 || - udev->actconfig->desc.bNumInterfaces == 3) - return 0; + const unsigned char inquiry_msg[] = { + 0x55, 0x53, 0x42, 0x43, 0x12, 0x34, 0x56, 0x78, + 0x24, 0x00, 0x00, 0x00, 0x80, 0x00, 0x06, 0x12, + 0x00, 0x00, 0x00, 0x24, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 + }; + char *buffer; + int result; - US_DEBUGP("Option MS: option_ms_init called\n"); + US_DEBUGP("Option MS: %s", "device inquiry for vendor name\n"); - /* Find the right mass storage interface */ - iface_desc = intf->cur_altsetting; - if (iface_desc->desc.bInterfaceClass != 0x8 || - iface_desc->desc.bInterfaceSubClass != 0x6 || - iface_desc->desc.bInterfaceProtocol != 0x50) { - US_DEBUGP("Option MS: mass storage interface not found, no action " - "required\n"); - return 0; + buffer = kzalloc(0x24, GFP_KERNEL); + if (buffer == NULL) + return USB_STOR_TRANSPORT_ERROR; + + memcpy(buffer, inquiry_msg, sizeof(inquiry_msg)); + result = usb_stor_bulk_transfer_buf(us, + us->send_bulk_pipe, + buffer, sizeof(inquiry_msg), NULL); + if (result != USB_STOR_XFER_GOOD) { + result = USB_STOR_XFER_ERROR; + goto out; } - /* Find the mass storage bulk endpoints */ - for (i = 0; i < iface_desc->desc.bNumEndpoints && (!ep_in_size || !ep_out_size); ++i) { - endpoint = &iface_desc->endpoint[i].desc; - - if (usb_endpoint_is_bulk_in(endpoint)) { - ep_in = usb_endpoint_num(endpoint); - ep_in_size = le16_to_cpu(endpoint->wMaxPacketSize); - } else if (usb_endpoint_is_bulk_out(endpoint)) { - ep_out = usb_endpoint_num(endpoint); - ep_out_size = le16_to_cpu(endpoint->wMaxPacketSize); - } + result = usb_stor_bulk_transfer_buf(us, + us->recv_bulk_pipe, + buffer, 0x24, NULL); + if (result != USB_STOR_XFER_GOOD) { + result = USB_STOR_XFER_ERROR; + goto out; } - /* Can't find the mass storage endpoints */ - if (!ep_in_size || !ep_out_size) { - US_DEBUGP("Option MS: mass storage endpoints not found, no action " - "required\n"); + result = memcmp(buffer+8, "Option", 6); + + /* Read the CSW */ + usb_stor_bulk_transfer_buf(us, + us->recv_bulk_pipe, + buffer, 13, NULL); + +out: + kfree(buffer); + return result; +} + + +int option_ms_init(struct us_data *us) +{ + int result; + + US_DEBUGP("Option MS: option_ms_init called\n"); + + /* Additional test for vendor information via INQUIRY, + * because some vendor/product IDs are ambiguous + */ + result = option_inquiry(us); + if (result != 0) { + US_DEBUGP("Option MS: vendor is not Option or not determinable," + " no action taken\n"); return 0; - } + } else + US_DEBUGP("Option MS: this is a genuine Option device," + " proceeding\n"); /* Force Modem mode */ if (option_zero_cd == ZCD_FORCE_MODEM) { US_DEBUGP("Option MS: %s", "Forcing Modem Mode\n"); - result = option_rezero(us, ep_in, ep_out); + result = option_rezero(us); if (result != USB_STOR_XFER_GOOD) US_DEBUGP("Option MS: Failed to switch to modem mode.\n"); return -EIO; -- cgit v1.2.3-70-g09d2