aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/usb/storage/option_ms.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/usb/storage/option_ms.c')
-rw-r--r--drivers/usb/storage/option_ms.c124
1 files changed, 71 insertions, 53 deletions
diff --git a/drivers/usb/storage/option_ms.c b/drivers/usb/storage/option_ms.c
index 353f922939a4..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,63 +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 return USB_STOR_TRANSPORT_GOOD;
99 95
100 US_DEBUGP("Option MS: option_ms_init called\n"); 96 US_DEBUGP("Option MS: %s", "device inquiry for vendor name\n");
101 97
102 /* Find the right mass storage interface */ 98 buffer = kzalloc(0x24, GFP_KERNEL);
103 iface_desc = intf->cur_altsetting; 99 if (buffer == NULL)
104 if (iface_desc->desc.bInterfaceClass != 0x8 || 100 return USB_STOR_TRANSPORT_ERROR;
105 iface_desc->desc.bInterfaceSubClass != 0x6 ||
106 iface_desc->desc.bInterfaceProtocol != 0x50) {
107 US_DEBUGP("Option MS: mass storage interface not found, no action "
108 "required\n");
109 return USB_STOR_TRANSPORT_GOOD;
110 }
111 101
112 /* Find the mass storage bulk endpoints */ 102 memcpy(buffer, inquiry_msg, sizeof(inquiry_msg));
113 for (i = 0; i < iface_desc->desc.bNumEndpoints && (!ep_in_size || !ep_out_size); ++i) { 103 result = usb_stor_bulk_transfer_buf(us,
114 endpoint = &iface_desc->endpoint[i].desc; 104 us->send_bulk_pipe,
115 105 buffer, sizeof(inquiry_msg), NULL);
116 if (usb_endpoint_is_bulk_in(endpoint)) { 106 if (result != USB_STOR_XFER_GOOD) {
117 ep_in = usb_endpoint_num(endpoint); 107 result = USB_STOR_XFER_ERROR;
118 ep_in_size = le16_to_cpu(endpoint->wMaxPacketSize); 108 goto out;
119 } else if (usb_endpoint_is_bulk_out(endpoint)) {
120 ep_out = usb_endpoint_num(endpoint);
121 ep_out_size = le16_to_cpu(endpoint->wMaxPacketSize);
122 }
123 } 109 }
124 110
125 /* Can't find the mass storage endpoints */ 111 result = usb_stor_bulk_transfer_buf(us,
126 if (!ep_in_size || !ep_out_size) { 112 us->recv_bulk_pipe,
127 US_DEBUGP("Option MS: mass storage endpoints not found, no action " 113 buffer, 0x24, NULL);
128 "required\n"); 114 if (result != USB_STOR_XFER_GOOD) {
129 return USB_STOR_TRANSPORT_GOOD; 115 result = USB_STOR_XFER_ERROR;
116 goto out;
130 } 117 }
131 118
119 result = memcmp(buffer+8, "Option", 6);
120
121 /* Read the CSW */
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");
145 return 0;
146 } else
147 US_DEBUGP("Option MS: this is a genuine Option device,"
148 " proceeding\n");
149
132 /* Force Modem mode */ 150 /* Force Modem mode */
133 if (option_zero_cd == ZCD_FORCE_MODEM) { 151 if (option_zero_cd == ZCD_FORCE_MODEM) {
134 US_DEBUGP("Option MS: %s", "Forcing Modem Mode\n"); 152 US_DEBUGP("Option MS: %s", "Forcing Modem Mode\n");
135 result = option_rezero(us, ep_in, ep_out); 153 result = option_rezero(us);
136 if (result != USB_STOR_XFER_GOOD) 154 if (result != USB_STOR_XFER_GOOD)
137 US_DEBUGP("Option MS: Failed to switch to modem mode.\n"); 155 US_DEBUGP("Option MS: Failed to switch to modem mode.\n");
138 return -EIO; 156 return -EIO;
@@ -142,6 +160,6 @@ int option_ms_init(struct us_data *us)
142 " requests it\n"); 160 " requests it\n");
143 } 161 }
144 162
145 return USB_STOR_TRANSPORT_GOOD; 163 return 0;
146} 164}
147 165