diff options
Diffstat (limited to 'firmware/usbstack')
-rw-r--r-- | firmware/usbstack/usb_core.c | 339 | ||||
-rw-r--r-- | firmware/usbstack/usb_storage.c | 316 |
2 files changed, 492 insertions, 163 deletions
diff --git a/firmware/usbstack/usb_core.c b/firmware/usbstack/usb_core.c index 7e86086dd4..13993f9271 100644 --- a/firmware/usbstack/usb_core.c +++ b/firmware/usbstack/usb_core.c | |||
@@ -23,10 +23,17 @@ | |||
23 | //#define LOGF_ENABLE | 23 | //#define LOGF_ENABLE |
24 | #include "logf.h" | 24 | #include "logf.h" |
25 | 25 | ||
26 | //#define USB_STORAGE | 26 | #ifndef BOOTLOADER |
27 | //#define USB_SERIAL | 27 | //#define USB_SERIAL |
28 | //#define USB_BENCHMARK | 28 | //#define USB_BENCHMARK |
29 | #ifdef USE_ROCKBOX_USB | ||
30 | #define USB_STORAGE | ||
31 | #else | ||
29 | #define USB_CHARGING_ONLY | 32 | #define USB_CHARGING_ONLY |
33 | #endif /* USE_ROCKBOX_USB */ | ||
34 | #else | ||
35 | #define USB_CHARGING_ONLY | ||
36 | #endif | ||
30 | 37 | ||
31 | #include "usb_ch9.h" | 38 | #include "usb_ch9.h" |
32 | #include "usb_drv.h" | 39 | #include "usb_drv.h" |
@@ -63,21 +70,21 @@ static const struct usb_device_descriptor device_descriptor = { | |||
63 | .bcdDevice = 0x0100, | 70 | .bcdDevice = 0x0100, |
64 | .iManufacturer = 1, | 71 | .iManufacturer = 1, |
65 | .iProduct = 2, | 72 | .iProduct = 2, |
66 | .iSerialNumber = 0, | 73 | .iSerialNumber = 3, |
67 | .bNumConfigurations = 1 | 74 | .bNumConfigurations = 1 |
68 | }; | 75 | }; |
69 | 76 | ||
70 | static const struct { | 77 | static const struct { |
71 | struct usb_config_descriptor config_descriptor; | 78 | struct usb_config_descriptor config_descriptor; |
72 | struct usb_interface_descriptor interface_descriptor; | 79 | struct usb_interface_descriptor interface_descriptor; |
73 | struct usb_endpoint_descriptor ep1_hs_in_descriptor; | 80 | struct usb_endpoint_descriptor ep1_in_descriptor; |
74 | struct usb_endpoint_descriptor ep1_hs_out_descriptor; | 81 | struct usb_endpoint_descriptor ep1_out_descriptor; |
75 | } config_data = | 82 | } config_data_fs = |
76 | { | 83 | { |
77 | { | 84 | { |
78 | .bLength = sizeof(struct usb_config_descriptor), | 85 | .bLength = sizeof(struct usb_config_descriptor), |
79 | .bDescriptorType = USB_DT_CONFIG, | 86 | .bDescriptorType = USB_DT_CONFIG, |
80 | .wTotalLength = sizeof config_data, | 87 | .wTotalLength = sizeof config_data_fs, |
81 | .bNumInterfaces = 1, | 88 | .bNumInterfaces = 1, |
82 | .bConfigurationValue = 1, | 89 | .bConfigurationValue = 1, |
83 | .iConfiguration = 0, | 90 | .iConfiguration = 0, |
@@ -96,12 +103,153 @@ static const struct { | |||
96 | .bInterfaceClass = USB_CLASS_VENDOR_SPEC, | 103 | .bInterfaceClass = USB_CLASS_VENDOR_SPEC, |
97 | .bInterfaceSubClass = 0, | 104 | .bInterfaceSubClass = 0, |
98 | .bInterfaceProtocol = 0, | 105 | .bInterfaceProtocol = 0, |
106 | .iInterface = 5 | ||
107 | }, | ||
108 | |||
109 | { | ||
110 | .bLength = sizeof(struct usb_endpoint_descriptor), | ||
111 | .bDescriptorType = USB_DT_ENDPOINT, | ||
112 | .bEndpointAddress = EP_TX | USB_DIR_IN, | ||
113 | .bmAttributes = USB_ENDPOINT_XFER_BULK, | ||
114 | .wMaxPacketSize = 512, | ||
115 | .bInterval = 0 | ||
116 | }, | ||
117 | { | ||
118 | .bLength = sizeof(struct usb_endpoint_descriptor), | ||
119 | .bDescriptorType = USB_DT_ENDPOINT, | ||
120 | .bEndpointAddress = EP_RX | USB_DIR_OUT, | ||
121 | .bmAttributes = USB_ENDPOINT_XFER_BULK, | ||
122 | .wMaxPacketSize = 512, | ||
123 | .bInterval = 0 | ||
124 | } | ||
125 | #endif | ||
126 | |||
127 | #ifdef USB_STORAGE | ||
128 | /* storage interface */ | ||
129 | { | ||
130 | .bLength = sizeof(struct usb_interface_descriptor), | ||
131 | .bDescriptorType = USB_DT_INTERFACE, | ||
132 | .bInterfaceNumber = 0, | ||
133 | .bAlternateSetting = 0, | ||
134 | .bNumEndpoints = 2, | ||
135 | .bInterfaceClass = USB_CLASS_MASS_STORAGE, | ||
136 | .bInterfaceSubClass = USB_SC_SCSI, | ||
137 | .bInterfaceProtocol = USB_PROT_BULK, | ||
138 | .iInterface = 0 | ||
139 | }, | ||
140 | |||
141 | { | ||
142 | .bLength = sizeof(struct usb_endpoint_descriptor), | ||
143 | .bDescriptorType = USB_DT_ENDPOINT, | ||
144 | .bEndpointAddress = EP_TX | USB_DIR_IN, | ||
145 | .bmAttributes = USB_ENDPOINT_XFER_BULK, | ||
146 | .wMaxPacketSize = 16, | ||
147 | .bInterval = 0 | ||
148 | }, | ||
149 | { | ||
150 | .bLength = sizeof(struct usb_endpoint_descriptor), | ||
151 | .bDescriptorType = USB_DT_ENDPOINT, | ||
152 | .bEndpointAddress = EP_RX | USB_DIR_OUT, | ||
153 | .bmAttributes = USB_ENDPOINT_XFER_BULK, | ||
154 | .wMaxPacketSize = 16, | ||
155 | .bInterval = 0 | ||
156 | } | ||
157 | #endif | ||
158 | |||
159 | #ifdef USB_SERIAL | ||
160 | /* serial interface */ | ||
161 | { | ||
162 | .bLength = sizeof(struct usb_interface_descriptor), | ||
163 | .bDescriptorType = USB_DT_INTERFACE, | ||
164 | .bInterfaceNumber = 0, | ||
165 | .bAlternateSetting = 0, | ||
166 | .bNumEndpoints = 2, | ||
167 | .bInterfaceClass = USB_CLASS_CDC_DATA, | ||
168 | .bInterfaceSubClass = 0, | ||
169 | .bInterfaceProtocol = 0, | ||
170 | .iInterface = 0 | ||
171 | }, | ||
172 | |||
173 | { | ||
174 | .bLength = sizeof(struct usb_endpoint_descriptor), | ||
175 | .bDescriptorType = USB_DT_ENDPOINT, | ||
176 | .bEndpointAddress = EP_TX | USB_DIR_IN, | ||
177 | .bmAttributes = USB_ENDPOINT_XFER_BULK, | ||
178 | .wMaxPacketSize = 64, | ||
179 | .bInterval = 0 | ||
180 | }, | ||
181 | { | ||
182 | .bLength = sizeof(struct usb_endpoint_descriptor), | ||
183 | .bDescriptorType = USB_DT_ENDPOINT, | ||
184 | .bEndpointAddress = EP_RX | USB_DIR_OUT, | ||
185 | .bmAttributes = USB_ENDPOINT_XFER_BULK, | ||
186 | .wMaxPacketSize = 64, | ||
187 | .bInterval = 0 | ||
188 | } | ||
189 | #endif | ||
190 | |||
191 | #ifdef USB_BENCHMARK | ||
192 | /* bulk test interface */ | ||
193 | { | ||
194 | .bLength = sizeof(struct usb_interface_descriptor), | ||
195 | .bDescriptorType = USB_DT_INTERFACE, | ||
196 | .bInterfaceNumber = 0, | ||
197 | .bAlternateSetting = 0, | ||
198 | .bNumEndpoints = 2, | ||
199 | .bInterfaceClass = USB_CLASS_VENDOR_SPEC, | ||
200 | .bInterfaceSubClass = 255, | ||
201 | .bInterfaceProtocol = 255, | ||
99 | .iInterface = 4 | 202 | .iInterface = 4 |
100 | }, | 203 | }, |
101 | 204 | ||
102 | { | 205 | { |
103 | .bLength = sizeof(struct usb_endpoint_descriptor), | 206 | .bLength = sizeof(struct usb_endpoint_descriptor), |
104 | .bDescriptorType = USB_DT_ENDPOINT, | 207 | .bDescriptorType = USB_DT_ENDPOINT, |
208 | .bEndpointAddress = EP_RX | USB_DIR_OUT, | ||
209 | .bmAttributes = USB_ENDPOINT_XFER_BULK, | ||
210 | .wMaxPacketSize = 64, | ||
211 | .bInterval = 0 | ||
212 | }, | ||
213 | { | ||
214 | .bLength = sizeof(struct usb_endpoint_descriptor), | ||
215 | .bDescriptorType = USB_DT_ENDPOINT, | ||
216 | .bEndpointAddress = EP_TX | USB_DIR_IN, | ||
217 | .bmAttributes = USB_ENDPOINT_XFER_BULK, | ||
218 | .wMaxPacketSize = 64, | ||
219 | .bInterval = 0 | ||
220 | } | ||
221 | #endif | ||
222 | }, | ||
223 | config_data_hs = | ||
224 | { | ||
225 | { | ||
226 | .bLength = sizeof(struct usb_config_descriptor), | ||
227 | .bDescriptorType = USB_DT_CONFIG, | ||
228 | .wTotalLength = sizeof config_data_hs, | ||
229 | .bNumInterfaces = 1, | ||
230 | .bConfigurationValue = 1, | ||
231 | .iConfiguration = 0, | ||
232 | .bmAttributes = USB_CONFIG_ATT_ONE | USB_CONFIG_ATT_SELFPOWER, | ||
233 | .bMaxPower = 250, /* 500mA in 2mA units */ | ||
234 | }, | ||
235 | |||
236 | #ifdef USB_CHARGING_ONLY | ||
237 | /* dummy interface for charging-only */ | ||
238 | { | ||
239 | .bLength = sizeof(struct usb_interface_descriptor), | ||
240 | .bDescriptorType = USB_DT_INTERFACE, | ||
241 | .bInterfaceNumber = 0, | ||
242 | .bAlternateSetting = 0, | ||
243 | .bNumEndpoints = 2, | ||
244 | .bInterfaceClass = USB_CLASS_VENDOR_SPEC, | ||
245 | .bInterfaceSubClass = 0, | ||
246 | .bInterfaceProtocol = 0, | ||
247 | .iInterface = 5 | ||
248 | }, | ||
249 | |||
250 | { | ||
251 | .bLength = sizeof(struct usb_endpoint_descriptor), | ||
252 | .bDescriptorType = USB_DT_ENDPOINT, | ||
105 | .bEndpointAddress = EP_TX | USB_DIR_IN, | 253 | .bEndpointAddress = EP_TX | USB_DIR_IN, |
106 | .bmAttributes = USB_ENDPOINT_XFER_BULK, | 254 | .bmAttributes = USB_ENDPOINT_XFER_BULK, |
107 | .wMaxPacketSize = 512, | 255 | .wMaxPacketSize = 512, |
@@ -168,7 +316,7 @@ static const struct { | |||
168 | .bDescriptorType = USB_DT_ENDPOINT, | 316 | .bDescriptorType = USB_DT_ENDPOINT, |
169 | .bEndpointAddress = EP_TX | USB_DIR_IN, | 317 | .bEndpointAddress = EP_TX | USB_DIR_IN, |
170 | .bmAttributes = USB_ENDPOINT_XFER_BULK, | 318 | .bmAttributes = USB_ENDPOINT_XFER_BULK, |
171 | .wMaxPacketSize = 64, | 319 | .wMaxPacketSize = 512, |
172 | .bInterval = 0 | 320 | .bInterval = 0 |
173 | }, | 321 | }, |
174 | { | 322 | { |
@@ -176,7 +324,7 @@ static const struct { | |||
176 | .bDescriptorType = USB_DT_ENDPOINT, | 324 | .bDescriptorType = USB_DT_ENDPOINT, |
177 | .bEndpointAddress = EP_RX | USB_DIR_OUT, | 325 | .bEndpointAddress = EP_RX | USB_DIR_OUT, |
178 | .bmAttributes = USB_ENDPOINT_XFER_BULK, | 326 | .bmAttributes = USB_ENDPOINT_XFER_BULK, |
179 | .wMaxPacketSize = 64, | 327 | .wMaxPacketSize = 512, |
180 | .bInterval = 0 | 328 | .bInterval = 0 |
181 | } | 329 | } |
182 | #endif | 330 | #endif |
@@ -192,7 +340,7 @@ static const struct { | |||
192 | .bInterfaceClass = USB_CLASS_VENDOR_SPEC, | 340 | .bInterfaceClass = USB_CLASS_VENDOR_SPEC, |
193 | .bInterfaceSubClass = 255, | 341 | .bInterfaceSubClass = 255, |
194 | .bInterfaceProtocol = 255, | 342 | .bInterfaceProtocol = 255, |
195 | .iInterface = 3 | 343 | .iInterface = 4 |
196 | }, | 344 | }, |
197 | 345 | ||
198 | { | 346 | { |
@@ -200,7 +348,6 @@ static const struct { | |||
200 | .bDescriptorType = USB_DT_ENDPOINT, | 348 | .bDescriptorType = USB_DT_ENDPOINT, |
201 | .bEndpointAddress = EP_RX | USB_DIR_OUT, | 349 | .bEndpointAddress = EP_RX | USB_DIR_OUT, |
202 | .bmAttributes = USB_ENDPOINT_XFER_BULK, | 350 | .bmAttributes = USB_ENDPOINT_XFER_BULK, |
203 | // .wMaxPacketSize = 64, | ||
204 | .wMaxPacketSize = 512, | 351 | .wMaxPacketSize = 512, |
205 | .bInterval = 0 | 352 | .bInterval = 0 |
206 | }, | 353 | }, |
@@ -209,7 +356,6 @@ static const struct { | |||
209 | .bDescriptorType = USB_DT_ENDPOINT, | 356 | .bDescriptorType = USB_DT_ENDPOINT, |
210 | .bEndpointAddress = EP_TX | USB_DIR_IN, | 357 | .bEndpointAddress = EP_TX | USB_DIR_IN, |
211 | .bmAttributes = USB_ENDPOINT_XFER_BULK, | 358 | .bmAttributes = USB_ENDPOINT_XFER_BULK, |
212 | // .wMaxPacketSize = 64, | ||
213 | .wMaxPacketSize = 512, | 359 | .wMaxPacketSize = 512, |
214 | .bInterval = 0 | 360 | .bInterval = 0 |
215 | } | 361 | } |
@@ -228,72 +374,61 @@ static const struct usb_qualifier_descriptor qualifier_descriptor = | |||
228 | .bNumConfigurations = 1 | 374 | .bNumConfigurations = 1 |
229 | }; | 375 | }; |
230 | 376 | ||
231 | /* full speed = 12 Mbit */ | 377 | static struct usb_string_descriptor usb_string_iManufacturer = |
232 | static const struct usb_endpoint_descriptor ep1_fs_in_descriptor = | ||
233 | { | 378 | { |
234 | .bLength = sizeof(struct usb_endpoint_descriptor), | 379 | 24, |
235 | .bDescriptorType = USB_DT_ENDPOINT, | 380 | USB_DT_STRING, |
236 | .bEndpointAddress = 1 | USB_DIR_IN, | 381 | {'R','o','c','k','b','o','x','.','o','r','g'} |
237 | .bmAttributes = USB_ENDPOINT_XFER_BULK, | ||
238 | .wMaxPacketSize = 64, | ||
239 | .bInterval = 0 | ||
240 | }; | 382 | }; |
241 | 383 | ||
242 | static const struct usb_endpoint_descriptor ep1_fs_out_descriptor = | 384 | static struct usb_string_descriptor usb_string_iProduct = |
243 | { | 385 | { |
244 | .bLength = sizeof(struct usb_endpoint_descriptor), | 386 | 42, |
245 | .bDescriptorType = USB_DT_ENDPOINT, | 387 | USB_DT_STRING, |
246 | .bEndpointAddress = 1 | USB_DIR_OUT, | 388 | {'R','o','c','k','b','o','x',' ','m','e','d','i','a',' ','p','l','a','y','e','r'} |
247 | .bmAttributes = USB_ENDPOINT_XFER_BULK, | ||
248 | .wMaxPacketSize = 64, | ||
249 | .bInterval = 0 | ||
250 | }; | 389 | }; |
251 | 390 | ||
252 | static const struct usb_endpoint_descriptor* ep_descriptors[4] = | 391 | static struct usb_string_descriptor usb_string_iSerial = |
253 | { | 392 | { |
254 | &config_data.ep1_hs_in_descriptor, | 393 | 34, |
255 | &config_data.ep1_hs_out_descriptor, | 394 | USB_DT_STRING, |
256 | &ep1_fs_in_descriptor, | 395 | {'0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0'} |
257 | &ep1_fs_out_descriptor | ||
258 | }; | 396 | }; |
259 | 397 | ||
398 | |||
399 | /* Generic for all targets */ | ||
400 | |||
260 | /* this is stringid #0: languages supported */ | 401 | /* this is stringid #0: languages supported */ |
261 | static const struct usb_string_descriptor lang_descriptor = | 402 | static struct usb_string_descriptor lang_descriptor = |
262 | { | 403 | { |
263 | sizeof(struct usb_string_descriptor), | 404 | 4, |
264 | USB_DT_STRING, | 405 | USB_DT_STRING, |
265 | {0x0409} /* LANGID US English */ | 406 | {0x0409} /* LANGID US English */ |
266 | }; | 407 | }; |
267 | 408 | ||
268 | /* this is stringid #1 and up: the actual strings */ | 409 | static struct usb_string_descriptor usb_string_usb_benchmark = |
269 | static const struct { | ||
270 | unsigned char size; | ||
271 | unsigned char type; | ||
272 | unsigned short string[32]; | ||
273 | } usb_strings[] = | ||
274 | { | 410 | { |
275 | { | 411 | 40, |
276 | 24, | 412 | USB_DT_STRING, |
277 | USB_DT_STRING, | 413 | {'B','u','l','k',' ','t','e','s','t',' ','i','n','t','e','r','f','a','c','e'} |
278 | {'R','o','c','k','b','o','x','.','o','r','g'} | ||
279 | }, | ||
280 | { | ||
281 | 42, | ||
282 | USB_DT_STRING, | ||
283 | {'R','o','c','k','b','o','x',' ','m','e','d','i','a',' ','p','l','a','y','e','r'} | ||
284 | }, | ||
285 | { | ||
286 | 40, | ||
287 | USB_DT_STRING, | ||
288 | {'B','u','l','k',' ','t','e','s','t',' ','i','n','t','e','r','f','a','c','e'} | ||
289 | }, | ||
290 | { | ||
291 | 28, | ||
292 | USB_DT_STRING, | ||
293 | {'C','h','a','r','g','i','n','g',' ','o','n','l','y'} | ||
294 | } | ||
295 | }; | 414 | }; |
296 | 415 | ||
416 | static struct usb_string_descriptor usb_string_charging_only = | ||
417 | { | ||
418 | 28, | ||
419 | USB_DT_STRING, | ||
420 | {'C','h','a','r','g','i','n','g',' ','o','n','l','y'} | ||
421 | }; | ||
422 | |||
423 | static struct usb_string_descriptor* usb_strings[] = | ||
424 | { | ||
425 | &lang_descriptor, | ||
426 | &usb_string_iManufacturer, | ||
427 | &usb_string_iProduct, | ||
428 | &usb_string_iSerial, | ||
429 | &usb_string_usb_benchmark, | ||
430 | &usb_string_charging_only | ||
431 | }; | ||
297 | 432 | ||
298 | static int usb_address = 0; | 433 | static int usb_address = 0; |
299 | static bool initialized = false; | 434 | static bool initialized = false; |
@@ -310,11 +445,45 @@ static void usb_core_thread(void); | |||
310 | 445 | ||
311 | static void ack_control(struct usb_ctrlrequest* req); | 446 | static void ack_control(struct usb_ctrlrequest* req); |
312 | 447 | ||
448 | #ifdef IPOD_ARCH | ||
449 | void set_serial_descriptor(void) | ||
450 | { | ||
451 | static short hex[16] = {'0','1','2','3','4','5','6','7', | ||
452 | '8','9','A','B','C','D','E','F'}; | ||
453 | #ifdef IPOD_VIDEO | ||
454 | uint32_t* serial = (uint32_t*)(0x20004034); | ||
455 | #else | ||
456 | uint32_t* serial = (uint32_t*)(0x20002034); | ||
457 | #endif | ||
458 | |||
459 | /* We need to convert from a little-endian 64-bit int | ||
460 | into a utf-16 string of hex characters */ | ||
461 | short* p = &usb_string_iSerial.wString[15]; | ||
462 | uint32_t x; | ||
463 | int i,j; | ||
464 | |||
465 | for (i = 0; i < 2; i++) | ||
466 | { | ||
467 | x = serial[i]; | ||
468 | for (j=0;j<8;j++) | ||
469 | { | ||
470 | *p-- = hex[x & 0xf]; | ||
471 | x >>= 4; | ||
472 | } | ||
473 | } | ||
474 | |||
475 | } | ||
476 | #endif | ||
477 | |||
313 | void usb_core_init(void) | 478 | void usb_core_init(void) |
314 | { | 479 | { |
315 | if (initialized) | 480 | if (initialized) |
316 | return; | 481 | return; |
317 | 482 | ||
483 | #ifdef IPOD_ARCH | ||
484 | set_serial_descriptor(); | ||
485 | #endif | ||
486 | |||
318 | queue_init(&usbcore_queue, false); | 487 | queue_init(&usbcore_queue, false); |
319 | usb_drv_init(); | 488 | usb_drv_init(); |
320 | #ifdef USB_STORAGE | 489 | #ifdef USB_STORAGE |
@@ -469,43 +638,25 @@ void usb_core_control_request(struct usb_ctrlrequest* req) | |||
469 | break; | 638 | break; |
470 | 639 | ||
471 | case USB_DT_CONFIG: | 640 | case USB_DT_CONFIG: |
472 | ptr = &config_data; | 641 | if(usb_drv_port_speed()) |
473 | size = sizeof config_data; | 642 | { |
474 | break; | 643 | ptr = &config_data_hs; |
475 | 644 | size = sizeof config_data_hs; | |
476 | case USB_DT_STRING: | 645 | } |
477 | switch (index) { | 646 | else |
478 | case 0: /* lang descriptor */ | 647 | { |
479 | ptr = &lang_descriptor; | 648 | ptr = &config_data_fs; |
480 | size = sizeof lang_descriptor; | 649 | size = sizeof config_data_fs; |
481 | break; | ||
482 | |||
483 | default: | ||
484 | if ((unsigned)index <= (sizeof(usb_strings)/sizeof(usb_strings[0]))) { | ||
485 | index -= 1; | ||
486 | ptr = &usb_strings[index]; | ||
487 | size = usb_strings[index].size; | ||
488 | } | ||
489 | else { | ||
490 | logf("bad string id %d", index); | ||
491 | usb_drv_stall(EP_CONTROL, true); | ||
492 | } | ||
493 | break; | ||
494 | } | 650 | } |
495 | break; | 651 | break; |
496 | 652 | ||
497 | case USB_DT_INTERFACE: | 653 | case USB_DT_STRING: |
498 | ptr = &config_data.interface_descriptor; | 654 | if ((unsigned)index < (sizeof(usb_strings)/sizeof(struct usb_string_descriptor*))) { |
499 | size = sizeof config_data.interface_descriptor; | 655 | ptr = usb_strings[index]; |
500 | break; | 656 | size = usb_strings[index]->bLength; |
501 | |||
502 | case USB_DT_ENDPOINT: | ||
503 | if (index <= NUM_ENDPOINTS) { | ||
504 | ptr = &ep_descriptors[index]; | ||
505 | size = sizeof ep_descriptors[index]; | ||
506 | } | 657 | } |
507 | else { | 658 | else { |
508 | logf("bad endpoint %d", index); | 659 | logf("bad string id %d", index); |
509 | usb_drv_stall(EP_CONTROL, true); | 660 | usb_drv_stall(EP_CONTROL, true); |
510 | } | 661 | } |
511 | break; | 662 | break; |
@@ -515,12 +666,6 @@ void usb_core_control_request(struct usb_ctrlrequest* req) | |||
515 | size = sizeof qualifier_descriptor; | 666 | size = sizeof qualifier_descriptor; |
516 | break; | 667 | break; |
517 | 668 | ||
518 | /* | ||
519 | case USB_DT_OTHER_SPEED_CONFIG: | ||
520 | ptr = &other_speed_descriptor; | ||
521 | size = sizeof other_speed_descriptor; | ||
522 | break; | ||
523 | */ | ||
524 | default: | 669 | default: |
525 | logf("bad desc %d", req->wValue >> 8); | 670 | logf("bad desc %d", req->wValue >> 8); |
526 | usb_drv_stall(EP_CONTROL, true); | 671 | usb_drv_stall(EP_CONTROL, true); |
diff --git a/firmware/usbstack/usb_storage.c b/firmware/usbstack/usb_storage.c index b852475663..1fbfe5296d 100644 --- a/firmware/usbstack/usb_storage.c +++ b/firmware/usbstack/usb_storage.c | |||
@@ -24,6 +24,7 @@ | |||
24 | #include "logf.h" | 24 | #include "logf.h" |
25 | #include "ata.h" | 25 | #include "ata.h" |
26 | #include "hotswap.h" | 26 | #include "hotswap.h" |
27 | #include "disk.h" | ||
27 | 28 | ||
28 | #define SECTOR_SIZE 512 | 29 | #define SECTOR_SIZE 512 |
29 | 30 | ||
@@ -40,14 +41,20 @@ | |||
40 | #define SCSI_TEST_UNIT_READY 0x00 | 41 | #define SCSI_TEST_UNIT_READY 0x00 |
41 | #define SCSI_INQUIRY 0x12 | 42 | #define SCSI_INQUIRY 0x12 |
42 | #define SCSI_MODE_SENSE 0x1a | 43 | #define SCSI_MODE_SENSE 0x1a |
44 | #define SCSI_REQUEST_SENSE 0x03 | ||
43 | #define SCSI_ALLOW_MEDIUM_REMOVAL 0x1e | 45 | #define SCSI_ALLOW_MEDIUM_REMOVAL 0x1e |
44 | #define SCSI_READ_CAPACITY 0x25 | 46 | #define SCSI_READ_CAPACITY 0x25 |
47 | #define SCSI_READ_FORMAT_CAPACITY 0x23 | ||
45 | #define SCSI_READ_10 0x28 | 48 | #define SCSI_READ_10 0x28 |
46 | #define SCSI_WRITE_10 0x2a | 49 | #define SCSI_WRITE_10 0x2a |
50 | #define SCSI_START_STOP_UNIT 0x1b | ||
47 | 51 | ||
48 | #define SCSI_STATUS_GOOD 0x00 | 52 | #define SCSI_STATUS_GOOD 0x00 |
53 | #define SCSI_STATUS_FAIL 0x01 | ||
49 | #define SCSI_STATUS_CHECK_CONDITION 0x02 | 54 | #define SCSI_STATUS_CHECK_CONDITION 0x02 |
50 | 55 | ||
56 | #define SCSI_FORMAT_CAPACITY_FORMATTED_MEDIA 0x02000000 | ||
57 | |||
51 | 58 | ||
52 | struct inquiry_data { | 59 | struct inquiry_data { |
53 | unsigned char DeviceType; | 60 | unsigned char DeviceType; |
@@ -62,6 +69,20 @@ struct inquiry_data { | |||
62 | unsigned char ProductRevisionLevel[4]; | 69 | unsigned char ProductRevisionLevel[4]; |
63 | } __attribute__ ((packed)); | 70 | } __attribute__ ((packed)); |
64 | 71 | ||
72 | struct sense_data { | ||
73 | unsigned char ResponseCode; | ||
74 | unsigned char Obsolete; | ||
75 | unsigned char filemark_eom_ili_sensekey; | ||
76 | unsigned int Information; | ||
77 | unsigned char AdditionalSenseLength; | ||
78 | unsigned int CommandSpecificInformation; | ||
79 | unsigned char AdditionalSenseCode; | ||
80 | unsigned char AdditionalSenseCodeQualifier; | ||
81 | unsigned char FieldReplaceableUnitCode; | ||
82 | unsigned char SKSV; | ||
83 | unsigned short SenseKeySpecific; | ||
84 | } __attribute__ ((packed)); | ||
85 | |||
65 | struct command_block_wrapper { | 86 | struct command_block_wrapper { |
66 | unsigned int signature; | 87 | unsigned int signature; |
67 | unsigned int tag; | 88 | unsigned int tag; |
@@ -84,26 +105,34 @@ struct capacity { | |||
84 | unsigned int block_size; | 105 | unsigned int block_size; |
85 | } __attribute__ ((packed)); | 106 | } __attribute__ ((packed)); |
86 | 107 | ||
108 | struct format_capacity { | ||
109 | unsigned int following_length; | ||
110 | unsigned int block_count; | ||
111 | unsigned int block_size; | ||
112 | } __attribute__ ((packed)); | ||
113 | |||
87 | /* the ARC USB controller can at most buffer 16KB unaligned data */ | 114 | /* the ARC USB controller can at most buffer 16KB unaligned data */ |
88 | static unsigned char _transfer_buffer[16384]; | 115 | static unsigned char _transfer_buffer[16384*8] __attribute((aligned (4096))); |
89 | static unsigned char* transfer_buffer; | 116 | static unsigned char* transfer_buffer; |
90 | static struct inquiry_data _inquiry; | 117 | static struct inquiry_data _inquiry CACHEALIGN_ATTR; |
91 | static struct inquiry_data* inquiry; | 118 | static struct inquiry_data* inquiry; |
92 | static struct capacity _capacity_data; | 119 | static struct capacity _capacity_data CACHEALIGN_ATTR; |
93 | static struct capacity* capacity_data; | 120 | static struct capacity* capacity_data; |
94 | 121 | static struct format_capacity _format_capacity_data CACHEALIGN_ATTR; | |
95 | //static unsigned char partial_sector[SECTOR_SIZE]; | 122 | static struct format_capacity* format_capacity_data; |
123 | static struct sense_data _sense_data CACHEALIGN_ATTR; | ||
124 | static struct sense_data *sense_data; | ||
96 | 125 | ||
97 | static struct { | 126 | static struct { |
98 | unsigned int sector; | 127 | unsigned int sector; |
99 | unsigned int offset; /* if partial sector */ | ||
100 | unsigned int count; | 128 | unsigned int count; |
101 | unsigned int tag; | 129 | unsigned int tag; |
130 | unsigned int lun; | ||
102 | } current_cmd; | 131 | } current_cmd; |
103 | 132 | ||
104 | void handle_scsi(struct command_block_wrapper* cbw); | 133 | static void handle_scsi(struct command_block_wrapper* cbw); |
105 | void send_csw(unsigned int tag, int status); | 134 | static void send_csw(unsigned int tag, int status); |
106 | static void identify2inquiry(void); | 135 | static void identify2inquiry(int lun); |
107 | 136 | ||
108 | static enum { | 137 | static enum { |
109 | IDLE, | 138 | IDLE, |
@@ -117,7 +146,10 @@ void usb_storage_init(void) | |||
117 | inquiry = (void*)UNCACHED_ADDR(&_inquiry); | 146 | inquiry = (void*)UNCACHED_ADDR(&_inquiry); |
118 | transfer_buffer = (void*)UNCACHED_ADDR(&_transfer_buffer); | 147 | transfer_buffer = (void*)UNCACHED_ADDR(&_transfer_buffer); |
119 | capacity_data = (void*)UNCACHED_ADDR(&_capacity_data); | 148 | capacity_data = (void*)UNCACHED_ADDR(&_capacity_data); |
120 | identify2inquiry(); | 149 | format_capacity_data = (void*)UNCACHED_ADDR(&_format_capacity_data); |
150 | sense_data = (void*)UNCACHED_ADDR(&_sense_data); | ||
151 | state = IDLE; | ||
152 | logf("usb_storage_init done"); | ||
121 | } | 153 | } |
122 | 154 | ||
123 | /* called by usb_core_transfer_complete() */ | 155 | /* called by usb_core_transfer_complete() */ |
@@ -128,21 +160,44 @@ void usb_storage_transfer_complete(int endpoint) | |||
128 | switch (endpoint) { | 160 | switch (endpoint) { |
129 | case EP_RX: | 161 | case EP_RX: |
130 | //logf("ums: %d bytes in", length); | 162 | //logf("ums: %d bytes in", length); |
131 | switch (state) { | 163 | if(state == RECEIVING) |
132 | case IDLE: | 164 | { |
133 | handle_scsi(cbw); | 165 | int receive_count=usb_drv_get_last_transfer_length(); |
134 | break; | 166 | logf("scsi write %d %d", current_cmd.sector, current_cmd.count); |
135 | 167 | if(usb_drv_get_last_transfer_status()==0) | |
136 | default: | 168 | { |
137 | break; | 169 | if((unsigned int)receive_count!=(SECTOR_SIZE*current_cmd.count)) |
170 | { | ||
171 | logf("%d >= %d",SECTOR_SIZE*current_cmd.count,receive_count); | ||
172 | } | ||
173 | ata_write_sectors(IF_MV2(current_cmd.lun,) | ||
174 | current_cmd.sector, current_cmd.count, | ||
175 | transfer_buffer); | ||
176 | send_csw(current_cmd.tag, SCSI_STATUS_GOOD); | ||
177 | } | ||
178 | else | ||
179 | { | ||
180 | logf("Transfer failed %X",usb_drv_get_last_transfer_status()); | ||
181 | send_csw(current_cmd.tag, SCSI_STATUS_CHECK_CONDITION); | ||
182 | } | ||
138 | } | 183 | } |
139 | 184 | else | |
140 | /* re-prime endpoint */ | 185 | { |
141 | usb_drv_recv(EP_RX, transfer_buffer, sizeof _transfer_buffer); | 186 | state = SENDING; |
187 | handle_scsi(cbw); | ||
188 | } | ||
189 | |||
142 | break; | 190 | break; |
143 | 191 | ||
144 | case EP_TX: | 192 | case EP_TX: |
145 | //logf("ums: %d bytes out", length); | 193 | //logf("ums: out complete"); |
194 | if(state != IDLE) | ||
195 | { | ||
196 | /* re-prime endpoint. We only need room for commands */ | ||
197 | state = IDLE; | ||
198 | usb_drv_recv(EP_RX, transfer_buffer, 1024); | ||
199 | } | ||
200 | |||
146 | break; | 201 | break; |
147 | } | 202 | } |
148 | } | 203 | } |
@@ -156,7 +211,7 @@ bool usb_storage_control_request(struct usb_ctrlrequest* req) | |||
156 | 211 | ||
157 | switch (req->bRequest) { | 212 | switch (req->bRequest) { |
158 | case USB_BULK_GET_MAX_LUN: { | 213 | case USB_BULK_GET_MAX_LUN: { |
159 | static char maxlun = 0; | 214 | static char maxlun = NUM_VOLUMES - 1; |
160 | logf("ums: getmaxlun"); | 215 | logf("ums: getmaxlun"); |
161 | usb_drv_send(EP_CONTROL, UNCACHED_ADDR(&maxlun), 1); | 216 | usb_drv_send(EP_CONTROL, UNCACHED_ADDR(&maxlun), 1); |
162 | usb_drv_recv(EP_CONTROL, NULL, 0); /* ack */ | 217 | usb_drv_recv(EP_CONTROL, NULL, 0); /* ack */ |
@@ -174,8 +229,9 @@ bool usb_storage_control_request(struct usb_ctrlrequest* req) | |||
174 | 229 | ||
175 | case USB_REQ_SET_CONFIGURATION: | 230 | case USB_REQ_SET_CONFIGURATION: |
176 | logf("ums: set config"); | 231 | logf("ums: set config"); |
177 | /* prime rx endpoint */ | 232 | /* prime rx endpoint. We only need room for commands */ |
178 | usb_drv_recv(EP_RX, transfer_buffer, sizeof _transfer_buffer); | 233 | state = IDLE; |
234 | usb_drv_recv(EP_RX, transfer_buffer, 1024); | ||
179 | handled = true; | 235 | handled = true; |
180 | break; | 236 | break; |
181 | } | 237 | } |
@@ -185,50 +241,138 @@ bool usb_storage_control_request(struct usb_ctrlrequest* req) | |||
185 | 241 | ||
186 | /****************************************************************************/ | 242 | /****************************************************************************/ |
187 | 243 | ||
188 | void handle_scsi(struct command_block_wrapper* cbw) | 244 | static void handle_scsi(struct command_block_wrapper* cbw) |
189 | { | 245 | { |
190 | /* USB Mass Storage assumes LBA capability. | 246 | /* USB Mass Storage assumes LBA capability. |
191 | TODO: support 48-bit LBA */ | 247 | TODO: support 48-bit LBA */ |
192 | 248 | ||
249 | unsigned int sectors_per_transfer=0; | ||
193 | unsigned int length = cbw->data_transfer_length; | 250 | unsigned int length = cbw->data_transfer_length; |
251 | unsigned int block_size; | ||
252 | unsigned char lun = cbw->lun; | ||
253 | unsigned int block_size_mult = 1; | ||
254 | #ifdef HAVE_HOTSWAP | ||
255 | tCardInfo* cinfo = card_get_info(lun); | ||
256 | block_size = cinfo->blocksize; | ||
257 | if(cinfo->initialized==1) | ||
258 | { | ||
259 | sectors_per_transfer=(sizeof _transfer_buffer/ block_size); | ||
260 | } | ||
261 | #else | ||
262 | block_size = SECTOR_SIZE; | ||
263 | sectors_per_transfer=(sizeof _transfer_buffer/ block_size); | ||
264 | #endif | ||
265 | |||
266 | #ifdef MAX_LOG_SECTOR_SIZE | ||
267 | block_size_mult = disk_sector_multiplier; | ||
268 | #endif | ||
194 | 269 | ||
195 | switch (cbw->command_block[0]) { | 270 | switch (cbw->command_block[0]) { |
196 | case SCSI_TEST_UNIT_READY: | 271 | case SCSI_TEST_UNIT_READY: |
197 | logf("scsi test_unit_ready"); | 272 | logf("scsi test_unit_ready %d",lun); |
273 | #ifdef HAVE_HOTSWAP | ||
274 | if(cinfo->initialized==1) | ||
275 | send_csw(cbw->tag, SCSI_STATUS_GOOD); | ||
276 | else | ||
277 | send_csw(cbw->tag, SCSI_STATUS_FAIL); | ||
278 | #else | ||
198 | send_csw(cbw->tag, SCSI_STATUS_GOOD); | 279 | send_csw(cbw->tag, SCSI_STATUS_GOOD); |
280 | #endif | ||
199 | break; | 281 | break; |
200 | 282 | ||
201 | case SCSI_INQUIRY: | 283 | case SCSI_INQUIRY: |
202 | logf("scsi inquiry"); | 284 | logf("scsi inquiry %d",lun); |
285 | identify2inquiry(lun); | ||
203 | length = MIN(length, cbw->command_block[4]); | 286 | length = MIN(length, cbw->command_block[4]); |
204 | usb_drv_send(EP_TX, inquiry, MIN(sizeof _inquiry, length)); | 287 | usb_drv_send(EP_TX, inquiry, MIN(sizeof _inquiry, length)); |
205 | send_csw(cbw->tag, SCSI_STATUS_GOOD); | 288 | send_csw(cbw->tag, SCSI_STATUS_GOOD); |
206 | break; | 289 | break; |
207 | 290 | ||
291 | case SCSI_REQUEST_SENSE: { | ||
292 | sense_data->ResponseCode=0x70; | ||
293 | sense_data->filemark_eom_ili_sensekey=2; | ||
294 | sense_data->Information=2; | ||
295 | sense_data->AdditionalSenseLength=10; | ||
296 | sense_data->CommandSpecificInformation=0; | ||
297 | sense_data->AdditionalSenseCode=0x3a; | ||
298 | sense_data->AdditionalSenseCodeQualifier=0; | ||
299 | sense_data->FieldReplaceableUnitCode=0; | ||
300 | sense_data->SKSV=0; | ||
301 | sense_data->SenseKeySpecific=0; | ||
302 | logf("scsi request_sense %d",lun); | ||
303 | usb_drv_send(EP_TX, sense_data, | ||
304 | sizeof(_sense_data)); | ||
305 | send_csw(cbw->tag, SCSI_STATUS_GOOD); | ||
306 | break; | ||
307 | } | ||
308 | |||
208 | case SCSI_MODE_SENSE: { | 309 | case SCSI_MODE_SENSE: { |
209 | static unsigned char sense_data[8] = { 0, 0, 0, 0, 0, 0, 0, 0 }; | 310 | static unsigned char sense_data[8] = { 0, 0, 0, 0, 0, 0, 0, 0 }; |
210 | logf("scsi mode_sense"); | 311 | logf("scsi mode_sense %d",lun); |
211 | usb_drv_send(EP_TX, UNCACHED_ADDR(&sense_data), | 312 | usb_drv_send(EP_TX, UNCACHED_ADDR(&sense_data), |
212 | MIN(sizeof sense_data, length)); | 313 | MIN(sizeof sense_data, length)); |
213 | send_csw(cbw->tag, SCSI_STATUS_GOOD); | 314 | send_csw(cbw->tag, SCSI_STATUS_GOOD); |
214 | break; | 315 | break; |
215 | } | 316 | } |
216 | 317 | ||
318 | case SCSI_START_STOP_UNIT: | ||
319 | logf("scsi start_stop unit %d",lun); | ||
320 | send_csw(cbw->tag, SCSI_STATUS_GOOD); | ||
321 | break; | ||
322 | |||
217 | case SCSI_ALLOW_MEDIUM_REMOVAL: | 323 | case SCSI_ALLOW_MEDIUM_REMOVAL: |
218 | logf("scsi allow_medium_removal"); | 324 | logf("scsi allow_medium_removal %d",lun); |
325 | send_csw(cbw->tag, SCSI_STATUS_GOOD); | ||
326 | break; | ||
327 | |||
328 | case SCSI_READ_FORMAT_CAPACITY: { | ||
329 | logf("scsi read_format_capacity %d",lun); | ||
330 | format_capacity_data->following_length=htobe32(8); | ||
331 | #ifdef HAVE_HOTSWAP | ||
332 | /* Careful: "block count" actually means "number of last block" */ | ||
333 | if(cinfo->initialized==1) | ||
334 | { | ||
335 | format_capacity_data->block_count = htobe32(cinfo->numblocks - 1); | ||
336 | format_capacity_data->block_size = htobe32(cinfo->blocksize); | ||
337 | } | ||
338 | else | ||
339 | { | ||
340 | format_capacity_data->block_count = htobe32(0); | ||
341 | format_capacity_data->block_size = htobe32(0); | ||
342 | } | ||
343 | #else | ||
344 | unsigned short* identify = ata_get_identify(); | ||
345 | /* Careful: "block count" actually means "number of last block" */ | ||
346 | format_capacity_data->block_count = htobe32((identify[61] << 16 | identify[60]) / block_size_mult - 1); | ||
347 | format_capacity_data->block_size = htobe32(block_size * block_size_mult); | ||
348 | #endif | ||
349 | format_capacity_data->block_size |= SCSI_FORMAT_CAPACITY_FORMATTED_MEDIA; | ||
350 | |||
351 | usb_drv_send(EP_TX, format_capacity_data, | ||
352 | MIN(sizeof _format_capacity_data, length)); | ||
219 | send_csw(cbw->tag, SCSI_STATUS_GOOD); | 353 | send_csw(cbw->tag, SCSI_STATUS_GOOD); |
220 | break; | 354 | break; |
355 | } | ||
221 | 356 | ||
222 | case SCSI_READ_CAPACITY: { | 357 | case SCSI_READ_CAPACITY: { |
223 | logf("scsi read_capacity"); | 358 | logf("scsi read_capacity %d",lun); |
224 | #ifdef HAVE_FLASH_STORAGE | 359 | #ifdef HAVE_HOTSWAP |
225 | tCardInfo* cinfo = card_get_info(0); | 360 | /* Careful: "block count" actually means "number of last block" */ |
226 | capacity_data->block_count = htobe32(cinfo->numblocks); | 361 | if(cinfo->initialized==1) |
227 | capacity_data->block_size = htobe32(cinfo->blocksize); | 362 | { |
363 | capacity_data->block_count = htobe32(cinfo->numblocks - 1); | ||
364 | capacity_data->block_size = htobe32(cinfo->blocksize); | ||
365 | } | ||
366 | else | ||
367 | { | ||
368 | capacity_data->block_count = htobe32(0); | ||
369 | capacity_data->block_size = htobe32(0); | ||
370 | } | ||
228 | #else | 371 | #else |
229 | unsigned short* identify = ata_get_identify(); | 372 | unsigned short* identify = ata_get_identify(); |
230 | capacity_data->block_count = htobe32(identify[60] << 16 | identify[61]); | 373 | /* Careful : "block count" actually means the number of the last block */ |
231 | capacity_data->block_size = htobe32(SECTOR_SIZE); | 374 | capacity_data->block_count = htobe32((identify[61] << 16 | identify[60]) / block_size_mult - 1); |
375 | capacity_data->block_size = htobe32(block_size * block_size_mult); | ||
232 | #endif | 376 | #endif |
233 | usb_drv_send(EP_TX, capacity_data, | 377 | usb_drv_send(EP_TX, capacity_data, |
234 | MIN(sizeof _capacity_data, length)); | 378 | MIN(sizeof _capacity_data, length)); |
@@ -237,43 +381,71 @@ void handle_scsi(struct command_block_wrapper* cbw) | |||
237 | } | 381 | } |
238 | 382 | ||
239 | case SCSI_READ_10: | 383 | case SCSI_READ_10: |
240 | current_cmd.sector = | 384 | current_cmd.sector = block_size_mult * |
241 | cbw->command_block[2] << 24 | | 385 | (cbw->command_block[2] << 24 | |
242 | cbw->command_block[3] << 16 | | 386 | cbw->command_block[3] << 16 | |
243 | cbw->command_block[4] << 8 | | 387 | cbw->command_block[4] << 8 | |
244 | cbw->command_block[5] ; | 388 | cbw->command_block[5] ); |
245 | current_cmd.count = | 389 | current_cmd.count = block_size_mult * |
246 | cbw->command_block[7] << 16 | | 390 | (cbw->command_block[7] << 16 | |
247 | cbw->command_block[8]; | 391 | cbw->command_block[8]); |
248 | current_cmd.offset = 0; | ||
249 | current_cmd.tag = cbw->tag; | 392 | current_cmd.tag = cbw->tag; |
393 | current_cmd.lun = cbw->lun; | ||
250 | 394 | ||
251 | logf("scsi read %d %d", current_cmd.sector, current_cmd.count); | 395 | //logf("scsi read %d %d", current_cmd.sector, current_cmd.count); |
252 | 396 | ||
253 | /* too much? */ | 397 | //logf("Asked for %d sectors",current_cmd.count); |
254 | if (current_cmd.count > (sizeof _transfer_buffer / SECTOR_SIZE)) { | 398 | if(current_cmd.count > sectors_per_transfer) |
255 | send_csw(current_cmd.tag, SCSI_STATUS_CHECK_CONDITION); | 399 | { |
256 | break; | 400 | current_cmd.count = sectors_per_transfer; |
257 | } | 401 | } |
402 | //logf("Sending %d sectors",current_cmd.count); | ||
258 | 403 | ||
259 | ata_read_sectors(IF_MV2(0,) current_cmd.sector, current_cmd.count, | 404 | if(current_cmd.count*block_size > sizeof(_transfer_buffer)) { |
260 | transfer_buffer); | 405 | send_csw(current_cmd.tag, SCSI_STATUS_CHECK_CONDITION); |
261 | state = SENDING; | 406 | } |
262 | usb_drv_send(EP_TX, transfer_buffer, | 407 | else { |
263 | MIN(current_cmd.count * SECTOR_SIZE, length)); | 408 | ata_read_sectors(IF_MV2(lun,) current_cmd.sector, |
409 | current_cmd.count, transfer_buffer); | ||
410 | usb_drv_send(EP_TX, transfer_buffer, | ||
411 | current_cmd.count*block_size); | ||
412 | send_csw(current_cmd.tag, SCSI_STATUS_GOOD); | ||
413 | } | ||
264 | break; | 414 | break; |
265 | 415 | ||
266 | case SCSI_WRITE_10: | 416 | case SCSI_WRITE_10: |
267 | logf("scsi write10"); | 417 | //logf("scsi write10"); |
418 | current_cmd.sector = block_size_mult * | ||
419 | (cbw->command_block[2] << 24 | | ||
420 | cbw->command_block[3] << 16 | | ||
421 | cbw->command_block[4] << 8 | | ||
422 | cbw->command_block[5] ); | ||
423 | current_cmd.count = block_size_mult * | ||
424 | (cbw->command_block[7] << 16 | | ||
425 | cbw->command_block[8]); | ||
426 | current_cmd.tag = cbw->tag; | ||
427 | current_cmd.lun = cbw->lun; | ||
428 | /* expect data */ | ||
429 | if(current_cmd.count*block_size > sizeof(_transfer_buffer)) { | ||
430 | send_csw(current_cmd.tag, SCSI_STATUS_CHECK_CONDITION); | ||
431 | } | ||
432 | else { | ||
433 | usb_drv_recv(EP_RX, transfer_buffer, | ||
434 | current_cmd.count*block_size); | ||
435 | state = RECEIVING; | ||
436 | } | ||
437 | |||
268 | break; | 438 | break; |
269 | 439 | ||
270 | default: | 440 | default: |
271 | logf("scsi unknown cmd %x", cbw->command_block[0]); | 441 | logf("scsi unknown cmd %x",cbw->command_block[0x0]); |
442 | usb_drv_stall(EP_TX, true); | ||
443 | send_csw(current_cmd.tag, SCSI_STATUS_GOOD); | ||
272 | break; | 444 | break; |
273 | } | 445 | } |
274 | } | 446 | } |
275 | 447 | ||
276 | void send_csw(unsigned int tag, int status) | 448 | static void send_csw(unsigned int tag, int status) |
277 | { | 449 | { |
278 | static struct command_status_wrapper _csw; | 450 | static struct command_status_wrapper _csw; |
279 | struct command_status_wrapper* csw = UNCACHED_ADDR(&_csw); | 451 | struct command_status_wrapper* csw = UNCACHED_ADDR(&_csw); |
@@ -287,16 +459,23 @@ void send_csw(unsigned int tag, int status) | |||
287 | } | 459 | } |
288 | 460 | ||
289 | /* convert ATA IDENTIFY to SCSI INQUIRY */ | 461 | /* convert ATA IDENTIFY to SCSI INQUIRY */ |
290 | static void identify2inquiry(void) | 462 | static void identify2inquiry(int lun) |
291 | { | 463 | { |
292 | unsigned int i; | ||
293 | #ifdef HAVE_FLASH_STORAGE | 464 | #ifdef HAVE_FLASH_STORAGE |
294 | for (i=0; i<8; i++) | 465 | if(lun==0) |
295 | inquiry->VendorId[i] = i + 'A'; | 466 | { |
296 | 467 | memcpy(&inquiry->VendorId,"Rockbox ",8); | |
297 | for (i=0; i<8; i++) | 468 | memcpy(&inquiry->ProductId,"Internal Storage",16); |
298 | inquiry->ProductId[i] = i + 'm'; | 469 | memcpy(&inquiry->ProductRevisionLevel,"0.00",4); |
470 | } | ||
471 | else | ||
472 | { | ||
473 | memcpy(&inquiry->VendorId,"Rockbox ",8); | ||
474 | memcpy(&inquiry->ProductId,"SD Card Slot ",16); | ||
475 | memcpy(&inquiry->ProductRevisionLevel,"0.00",4); | ||
476 | } | ||
299 | #else | 477 | #else |
478 | unsigned int i; | ||
300 | unsigned short* dest; | 479 | unsigned short* dest; |
301 | unsigned short* src; | 480 | unsigned short* src; |
302 | unsigned short* identify = ata_get_identify(); | 481 | unsigned short* identify = ata_get_identify(); |
@@ -310,22 +489,27 @@ static void identify2inquiry(void) | |||
310 | src = (unsigned short*)&identify[27]; | 489 | src = (unsigned short*)&identify[27]; |
311 | dest = (unsigned short*)&inquiry->VendorId; | 490 | dest = (unsigned short*)&inquiry->VendorId; |
312 | for (i=0;i<4;i++) | 491 | for (i=0;i<4;i++) |
313 | dest[i] = src[i]; | 492 | dest[i] = htobe16(src[i]); |
314 | 493 | ||
315 | src = (unsigned short*)&identify[27+8]; | 494 | src = (unsigned short*)&identify[27+8]; |
316 | dest = (unsigned short*)&inquiry->ProductId; | 495 | dest = (unsigned short*)&inquiry->ProductId; |
317 | for (i=0;i<8;i++) | 496 | for (i=0;i<8;i++) |
318 | dest[i] = src[i]; | 497 | dest[i] = htobe16(src[i]); |
319 | 498 | ||
320 | src = (unsigned short*)&identify[23]; | 499 | src = (unsigned short*)&identify[23]; |
321 | dest = (unsigned short*)&inquiry->ProductRevisionLevel; | 500 | dest = (unsigned short*)&inquiry->ProductRevisionLevel; |
322 | for (i=0;i<2;i++) | 501 | for (i=0;i<2;i++) |
323 | dest[i] = src[i]; | 502 | dest[i] = htobe16(src[i]); |
324 | #endif | 503 | #endif |
325 | 504 | ||
326 | inquiry->DeviceType = DIRECT_ACCESS_DEVICE; | 505 | inquiry->DeviceType = DIRECT_ACCESS_DEVICE; |
327 | inquiry->AdditionalLength = 0x1f; | 506 | inquiry->AdditionalLength = 0x1f; |
328 | inquiry->Versions = 3; /* ANSI SCSI level 2 */ | 507 | inquiry->Versions = 3; /* ANSI SCSI level 2 */ |
329 | inquiry->Format = 3; /* ANSI SCSI level 2 INQUIRY format */ | 508 | inquiry->Format = 3; /* ANSI SCSI level 2 INQUIRY format */ |
509 | |||
510 | #ifdef HAVE_HOTSWAP | ||
511 | inquiry->DeviceTypeModifier = DEVICE_REMOVABLE; | ||
512 | #endif | ||
513 | |||
330 | } | 514 | } |
331 | 515 | ||