aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/usb
diff options
context:
space:
mode:
authorJosua Dietze <digidietze@draisberghof.de>2009-05-24 17:21:42 -0400
committerGreg Kroah-Hartman <gregkh@suse.de>2009-06-16 00:44:46 -0400
commit32ebbe7b6ad44ae9c276419710b56de6ba705303 (patch)
tree6ae020237f6c409b41c90962ff57179ebd4fbcf7 /drivers/usb
parent68335e816a92411649955a9903b1f30c388ea322 (diff)
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 <digidietze@draisberghof.de> Acked-by: Alan Stern <stern@rowland.harvard.edu> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
Diffstat (limited to 'drivers/usb')
-rw-r--r--drivers/usb/storage/option_ms.c121
1 files changed, 69 insertions, 52 deletions
diff --git a/drivers/usb/storage/option_ms.c b/drivers/usb/storage/option_ms.c
index 0d8853339bb6..d41cc0a970f7 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),"
37 37
38#define RESPONSE_LEN 1024 38#define RESPONSE_LEN 1024
39 39
40static int option_rezero(struct us_data *us, int ep_in, int ep_out) 40static int option_rezero(struct us_data *us)
41{ 41{
42 const unsigned char rezero_msg[] = { 42 const unsigned char rezero_msg[] = {
43 0x55, 0x53, 0x42, 0x43, 0x78, 0x56, 0x34, 0x12, 43 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)
54 if (buffer == NULL) 54 if (buffer == NULL)
55 return USB_STOR_TRANSPORT_ERROR; 55 return USB_STOR_TRANSPORT_ERROR;
56 56
57 memcpy(buffer, rezero_msg, sizeof (rezero_msg)); 57 memcpy(buffer, rezero_msg, sizeof(rezero_msg));
58 result = usb_stor_bulk_transfer_buf(us, 58 result = usb_stor_bulk_transfer_buf(us,
59 usb_sndbulkpipe(us->pusb_dev, ep_out), 59 us->send_bulk_pipe,
60 buffer, sizeof (rezero_msg), NULL); 60 buffer, sizeof(rezero_msg), NULL);
61 if (result != USB_STOR_XFER_GOOD) { 61 if (result != USB_STOR_XFER_GOOD) {
62 result = USB_STOR_XFER_ERROR; 62 result = USB_STOR_XFER_ERROR;
63 goto out; 63 goto out;
@@ -66,9 +66,15 @@ static int option_rezero(struct us_data *us, int ep_in, int ep_out)
66 /* Some of the devices need to be asked for a response, but we don't 66 /* Some of the devices need to be asked for a response, but we don't
67 * care what that response is. 67 * care what that response is.
68 */ 68 */
69 result = usb_stor_bulk_transfer_buf(us, 69 usb_stor_bulk_transfer_buf(us,
70 usb_sndbulkpipe(us->pusb_dev, ep_out), 70 us->recv_bulk_pipe,
71 buffer, RESPONSE_LEN, NULL); 71 buffer, RESPONSE_LEN, NULL);
72
73 /* Read the CSW */
74 usb_stor_bulk_transfer_buf(us,
75 us->recv_bulk_pipe,
76 buffer, 13, NULL);
77
72 result = USB_STOR_XFER_GOOD; 78 result = USB_STOR_XFER_GOOD;
73 79
74out: 80out:
@@ -76,64 +82,75 @@ out:
76 return result; 82 return result;
77} 83}
78 84
79int option_ms_init(struct us_data *us) 85static int option_inquiry(struct us_data *us)
80{ 86{
81 struct usb_device *udev; 87 const unsigned char inquiry_msg[] = {
82 struct usb_interface *intf; 88 0x55, 0x53, 0x42, 0x43, 0x12, 0x34, 0x56, 0x78,
83 struct usb_host_interface *iface_desc; 89 0x24, 0x00, 0x00, 0x00, 0x80, 0x00, 0x06, 0x12,
84 struct usb_endpoint_descriptor *endpoint = NULL; 90 0x00, 0x00, 0x00, 0x24, 0x00, 0x00, 0x00, 0x00,
85 u8 ep_in = 0, ep_out = 0; 91 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
86 int ep_in_size = 0, ep_out_size = 0; 92 };
87 int i, result; 93 char *buffer;
88 94 int result;
89 udev = us->pusb_dev;
90 intf = us->pusb_intf;
91
92 /* Ensure it's really a ZeroCD device; devices that are already
93 * in modem mode return 0xFF for class, subclass, and protocol.
94 */
95 if (udev->descriptor.bDeviceClass != 0 ||
96 udev->descriptor.bDeviceSubClass != 0 ||
97 udev->descriptor.bDeviceProtocol != 0 ||
98 udev->actconfig->desc.bNumInterfaces == 3)
99 return 0;
100 95
101 US_DEBUGP("Option MS: option_ms_init called\n"); 96 US_DEBUGP("Option MS: %s", "device inquiry for vendor name\n");
102 97
103 /* Find the right mass storage interface */ 98 buffer = kzalloc(0x24, GFP_KERNEL);
104 iface_desc = intf->cur_altsetting; 99 if (buffer == NULL)
105 if (iface_desc->desc.bInterfaceClass != 0x8 || 100 return USB_STOR_TRANSPORT_ERROR;
106 iface_desc->desc.bInterfaceSubClass != 0x6 || 101
107 iface_desc->desc.bInterfaceProtocol != 0x50) { 102 memcpy(buffer, inquiry_msg, sizeof(inquiry_msg));
108 US_DEBUGP("Option MS: mass storage interface not found, no action " 103 result = usb_stor_bulk_transfer_buf(us,
109 "required\n"); 104 us->send_bulk_pipe,
110 return 0; 105 buffer, sizeof(inquiry_msg), NULL);
106 if (result != USB_STOR_XFER_GOOD) {
107 result = USB_STOR_XFER_ERROR;
108 goto out;
111 } 109 }
112 110
113 /* Find the mass storage bulk endpoints */ 111 result = usb_stor_bulk_transfer_buf(us,
114 for (i = 0; i < iface_desc->desc.bNumEndpoints && (!ep_in_size || !ep_out_size); ++i) { 112 us->recv_bulk_pipe,
115 endpoint = &iface_desc->endpoint[i].desc; 113 buffer, 0x24, NULL);
116 114 if (result != USB_STOR_XFER_GOOD) {
117 if (usb_endpoint_is_bulk_in(endpoint)) { 115 result = USB_STOR_XFER_ERROR;
118 ep_in = usb_endpoint_num(endpoint); 116 goto out;
119 ep_in_size = le16_to_cpu(endpoint->wMaxPacketSize);
120 } else if (usb_endpoint_is_bulk_out(endpoint)) {
121 ep_out = usb_endpoint_num(endpoint);
122 ep_out_size = le16_to_cpu(endpoint->wMaxPacketSize);
123 }
124 } 117 }
125 118
126 /* Can't find the mass storage endpoints */ 119 result = memcmp(buffer+8, "Option", 6);
127 if (!ep_in_size || !ep_out_size) { 120
128 US_DEBUGP("Option MS: mass storage endpoints not found, no action " 121 /* Read the CSW */
129 "required\n"); 122 usb_stor_bulk_transfer_buf(us,
123 us->recv_bulk_pipe,
124 buffer, 13, NULL);
125
126out:
127 kfree(buffer);
128 return result;
129}
130
131
132int option_ms_init(struct us_data *us)
133{
134 int result;
135
136 US_DEBUGP("Option MS: option_ms_init called\n");
137
138 /* Additional test for vendor information via INQUIRY,
139 * because some vendor/product IDs are ambiguous
140 */
141 result = option_inquiry(us);
142 if (result != 0) {
143 US_DEBUGP("Option MS: vendor is not Option or not determinable,"
144 " no action taken\n");
130 return 0; 145 return 0;
131 } 146 } else
147 US_DEBUGP("Option MS: this is a genuine Option device,"
148 " proceeding\n");
132 149
133 /* Force Modem mode */ 150 /* Force Modem mode */
134 if (option_zero_cd == ZCD_FORCE_MODEM) { 151 if (option_zero_cd == ZCD_FORCE_MODEM) {
135 US_DEBUGP("Option MS: %s", "Forcing Modem Mode\n"); 152 US_DEBUGP("Option MS: %s", "Forcing Modem Mode\n");
136 result = option_rezero(us, ep_in, ep_out); 153 result = option_rezero(us);
137 if (result != USB_STOR_XFER_GOOD) 154 if (result != USB_STOR_XFER_GOOD)
138 US_DEBUGP("Option MS: Failed to switch to modem mode.\n"); 155 US_DEBUGP("Option MS: Failed to switch to modem mode.\n");
139 return -EIO; 156 return -EIO;