diff options
Diffstat (limited to 'drivers/usb/storage/option_ms.c')
-rw-r--r-- | drivers/usb/storage/option_ms.c | 124 |
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 | ||
40 | static int option_rezero(struct us_data *us, int ep_in, int ep_out) | 40 | static 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 | ||
74 | out: | 80 | out: |
@@ -76,63 +82,75 @@ out: | |||
76 | return result; | 82 | return result; |
77 | } | 83 | } |
78 | 84 | ||
79 | int option_ms_init(struct us_data *us) | 85 | static 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 | |||
126 | out: | ||
127 | kfree(buffer); | ||
128 | return result; | ||
129 | } | ||
130 | |||
131 | |||
132 | int 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 | ||