On Sun, 24 May 2009, Josua Dietze wrote: > 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). > > Patch is against 2.6.30-rc6 > > --------------- > > Signed-off-by: Josua Dietze <digidietze@xxxxxxxxxxxxxxx> Acked-by: Alan Stern <stern@xxxxxxxxxxxxxxxxxxx> > diff -upNr linux-2.6.30-rc6.orig/drivers/usb/storage/option_ms.c linux-2.6.30-rc6.new/drivers/usb/storage/option_ms.c > --- linux-2.6.30-rc6.orig/drivers/usb/storage/option_ms.c 2009-05-16 06:12:57.000000000 +0200 > +++ linux-2.6.30-rc6.new/drivers/usb/storage/option_ms.c 2009-05-24 23:08:36.000000000 +0200 > @@ -37,7 +37,7 @@ MODULE_PARM_DESC(option_zero_cd, "ZeroCD > > #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 > 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 > /* 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,63 +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; > + 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; > > - /* 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) > - return USB_STOR_TRANSPORT_GOOD; > + US_DEBUGP("Option MS: %s", "device inquiry for vendor name\n"); > > - US_DEBUGP("Option MS: option_ms_init called\n"); > + buffer = kzalloc(0x24, GFP_KERNEL); > + if (buffer == NULL) > + return USB_STOR_TRANSPORT_ERROR; > > - /* 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 USB_STOR_TRANSPORT_GOOD; > + 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"); > - return USB_STOR_TRANSPORT_GOOD; > - } > + 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; > @@ -142,6 +160,5 @@ int option_ms_init(struct us_data *us) > " requests it\n"); > } > > - return USB_STOR_TRANSPORT_GOOD; > + return 0; > } > - > > -- To unsubscribe from this list: send the line "unsubscribe linux-usb" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html