diff options
author | Frank Gevaerts <frank@gevaerts.be> | 2008-02-20 22:54:26 +0000 |
---|---|---|
committer | Frank Gevaerts <frank@gevaerts.be> | 2008-02-20 22:54:26 +0000 |
commit | 07427592a928ab3d164fbcca842399af6d5ca7ef (patch) | |
tree | eb7b1b748f8ac9ea28ce357290bc5992f5e2403f | |
parent | 6af732d17aa1eb882e3c52242b2bf7f2fcccc752 (diff) | |
download | rockbox-07427592a928ab3d164fbcca842399af6d5ca7ef.tar.gz rockbox-07427592a928ab3d164fbcca842399af6d5ca7ef.zip |
Major USB stack improvements. It now works at nearly the maximum speed for a full speed connection, and does seem stable.
Still not enabled by default, #define USE_ROCKBOX_USB is still required to enable it.
git-svn-id: svn://svn.rockbox.org/rockbox/trunk@16360 a1c6a512-1295-4272-9138-f99709370657
-rw-r--r-- | firmware/export/usb_ch9.h | 2 | ||||
-rw-r--r-- | firmware/export/usb_core.h | 43 | ||||
-rw-r--r-- | firmware/export/usb_drv.h | 7 | ||||
-rw-r--r-- | firmware/target/arm/usb-drv-pp502x.c | 346 | ||||
-rw-r--r-- | firmware/target/arm/usb-fw-pp502x.c | 5 | ||||
-rw-r--r-- | firmware/usbstack/usb_benchmark.c | 21 | ||||
-rw-r--r-- | firmware/usbstack/usb_benchmark.h | 2 | ||||
-rw-r--r-- | firmware/usbstack/usb_core.c | 508 | ||||
-rw-r--r-- | firmware/usbstack/usb_serial.c | 34 | ||||
-rw-r--r-- | firmware/usbstack/usb_serial.h | 2 | ||||
-rw-r--r-- | firmware/usbstack/usb_storage.c | 604 | ||||
-rw-r--r-- | firmware/usbstack/usb_storage.h | 3 |
12 files changed, 977 insertions, 600 deletions
diff --git a/firmware/export/usb_ch9.h b/firmware/export/usb_ch9.h index 1bfc152a8a..d5885ac9b8 100644 --- a/firmware/export/usb_ch9.h +++ b/firmware/export/usb_ch9.h | |||
@@ -245,7 +245,7 @@ struct usb_string_descriptor { | |||
245 | uint8_t bDescriptorType; | 245 | uint8_t bDescriptorType; |
246 | 246 | ||
247 | uint16_t wString[]; /* UTF-16LE encoded */ | 247 | uint16_t wString[]; /* UTF-16LE encoded */ |
248 | } __attribute__ ((packed)); | 248 | } __attribute__ ((packed,aligned(2))); |
249 | 249 | ||
250 | /* note that "string" zero is special, it holds language codes that | 250 | /* note that "string" zero is special, it holds language codes that |
251 | * the device supports, not Unicode characters. | 251 | * the device supports, not Unicode characters. |
diff --git a/firmware/export/usb_core.h b/firmware/export/usb_core.h index 2027cca5e8..73cf5c0127 100644 --- a/firmware/export/usb_core.h +++ b/firmware/export/usb_core.h | |||
@@ -19,6 +19,22 @@ | |||
19 | #ifndef USB_CORE_H | 19 | #ifndef USB_CORE_H |
20 | #define USB_CORE_H | 20 | #define USB_CORE_H |
21 | 21 | ||
22 | #ifndef BOOTLOADER | ||
23 | #define USB_THREAD | ||
24 | |||
25 | #ifdef USE_ROCKBOX_USB | ||
26 | //#define USB_SERIAL | ||
27 | //#define USB_BENCHMARK | ||
28 | #define USB_STORAGE | ||
29 | |||
30 | #else | ||
31 | #define USB_CHARGING_ONLY | ||
32 | |||
33 | #endif /* USE_ROCKBOX_USB */ | ||
34 | #else | ||
35 | #define USB_CHARGING_ONLY | ||
36 | #endif /* BOOTLOADER */ | ||
37 | |||
22 | #include "usb_ch9.h" | 38 | #include "usb_ch9.h" |
23 | 39 | ||
24 | #if defined(CPU_PP) | 40 | #if defined(CPU_PP) |
@@ -26,14 +42,31 @@ | |||
26 | #define USB_IRAM_SIZE ((size_t)0xc000) | 42 | #define USB_IRAM_SIZE ((size_t)0xc000) |
27 | #endif | 43 | #endif |
28 | 44 | ||
45 | |||
46 | enum { | ||
47 | USB_CORE_QUIT, | ||
48 | USB_CORE_TRANSFER_COMPLETION | ||
49 | }; | ||
50 | |||
29 | /* endpoints */ | 51 | /* endpoints */ |
30 | enum { | 52 | enum { |
31 | EP_CONTROL = 0, | 53 | EP_CONTROL = 0, |
32 | EP_RX, | 54 | #ifdef USB_STORAGE |
33 | EP_TX, | 55 | EP_MASS_STORAGE, |
34 | NUM_ENDPOINTS | 56 | #endif |
57 | #ifdef USB_SERIAL | ||
58 | EP_SERIAL, | ||
59 | #endif | ||
60 | #ifdef USB_CHARGING_ONLY | ||
61 | EP_CHARGING_ONLY, | ||
62 | #endif | ||
63 | #ifdef USB_BENCHMARK | ||
64 | EP_BENCHMARK, | ||
65 | #endif | ||
66 | NUM_ENDPOINTS | ||
35 | }; | 67 | }; |
36 | 68 | ||
69 | |||
37 | /* queue events */ | 70 | /* queue events */ |
38 | #define USB_TRANSFER_COMPLETE 1 | 71 | #define USB_TRANSFER_COMPLETE 1 |
39 | 72 | ||
@@ -48,7 +81,7 @@ extern int usb_max_pkt_size; | |||
48 | void usb_core_init(void); | 81 | void usb_core_init(void); |
49 | void usb_core_exit(void); | 82 | void usb_core_exit(void); |
50 | void usb_core_control_request(struct usb_ctrlrequest* req); | 83 | void usb_core_control_request(struct usb_ctrlrequest* req); |
51 | void usb_core_transfer_complete(int endpoint, bool in); | 84 | void usb_core_transfer_complete(int endpoint, bool in, int status, int length); |
52 | void usb_core_bus_reset(void); | 85 | void usb_core_bus_reset(void); |
53 | bool usb_core_data_connection(void); | 86 | bool usb_core_data_connection(void); |
54 | 87 | ||
diff --git a/firmware/export/usb_drv.h b/firmware/export/usb_drv.h index 6a37144c1a..430f03bdc7 100644 --- a/firmware/export/usb_drv.h +++ b/firmware/export/usb_drv.h | |||
@@ -24,16 +24,17 @@ | |||
24 | void usb_drv_init(void); | 24 | void usb_drv_init(void); |
25 | void usb_drv_exit(void); | 25 | void usb_drv_exit(void); |
26 | void usb_drv_int(void); | 26 | void usb_drv_int(void); |
27 | void usb_drv_stall(int endpoint, bool stall); | 27 | void usb_drv_stall(int endpoint, bool stall,bool in); |
28 | bool usb_drv_stalled(int endpoint,bool in); | ||
28 | int usb_drv_send(int endpoint, void* ptr, int length); | 29 | int usb_drv_send(int endpoint, void* ptr, int length); |
30 | int usb_drv_send_nonblocking(int endpoint, void* ptr, int length); | ||
29 | int usb_drv_recv(int endpoint, void* ptr, int length); | 31 | int usb_drv_recv(int endpoint, void* ptr, int length); |
30 | void usb_drv_ack(struct usb_ctrlrequest* req); | 32 | void usb_drv_ack(struct usb_ctrlrequest* req); |
31 | void usb_drv_set_address(int address); | 33 | void usb_drv_set_address(int address); |
32 | void usb_drv_reset_endpoint(int endpoint, bool send); | 34 | void usb_drv_reset_endpoint(int endpoint, bool send); |
33 | void usb_drv_wait(int endpoint, bool send); | 35 | void usb_drv_wait(int endpoint, bool send); |
34 | bool usb_drv_powered(void); | 36 | bool usb_drv_powered(void); |
35 | int usb_drv_get_last_transfer_status(void); | ||
36 | int usb_drv_get_last_transfer_length(void); | ||
37 | int usb_drv_port_speed(void); | 37 | int usb_drv_port_speed(void); |
38 | void usb_drv_cancel_all_transfers(void); | ||
38 | 39 | ||
39 | #endif | 40 | #endif |
diff --git a/firmware/target/arm/usb-drv-pp502x.c b/firmware/target/arm/usb-drv-pp502x.c index 413d905293..2d51ce55e9 100644 --- a/firmware/target/arm/usb-drv-pp502x.c +++ b/firmware/target/arm/usb-drv-pp502x.c | |||
@@ -30,6 +30,10 @@ | |||
30 | 30 | ||
31 | #define REG_ID (*(volatile unsigned int *)(USB_BASE+0x000)) | 31 | #define REG_ID (*(volatile unsigned int *)(USB_BASE+0x000)) |
32 | #define REG_HWGENERAL (*(volatile unsigned int *)(USB_BASE+0x004)) | 32 | #define REG_HWGENERAL (*(volatile unsigned int *)(USB_BASE+0x004)) |
33 | #define REG_HWHOST (*(volatile unsigned int *)(USB_BASE+0x008)) | ||
34 | #define REG_HWDEVICE (*(volatile unsigned int *)(USB_BASE+0x00c)) | ||
35 | #define REG_TXBUF (*(volatile unsigned int *)(USB_BASE+0x010)) | ||
36 | #define REG_RXBUF (*(volatile unsigned int *)(USB_BASE+0x014)) | ||
33 | #define REG_CAPLENGTH (*(volatile unsigned char*)(USB_BASE+0x100)) | 37 | #define REG_CAPLENGTH (*(volatile unsigned char*)(USB_BASE+0x100)) |
34 | #define REG_DCIVERSION (*(volatile unsigned int *)(USB_BASE+0x120)) | 38 | #define REG_DCIVERSION (*(volatile unsigned int *)(USB_BASE+0x120)) |
35 | #define REG_DCCPARAMS (*(volatile unsigned int *)(USB_BASE+0x124)) | 39 | #define REG_DCCPARAMS (*(volatile unsigned int *)(USB_BASE+0x124)) |
@@ -278,6 +282,10 @@ | |||
278 | DTD_STATUS_DATA_BUFF_ERR | \ | 282 | DTD_STATUS_DATA_BUFF_ERR | \ |
279 | DTD_STATUS_TRANSACTION_ERR) | 283 | DTD_STATUS_TRANSACTION_ERR) |
280 | 284 | ||
285 | #define DTD_RESERVED_LENGTH_MASK 0x0001ffff | ||
286 | #define DTD_RESERVED_IN_USE 0x80000000 | ||
287 | #define DTD_RESERVED_PIPE_MASK 0x0ff00000 | ||
288 | #define DTD_RESERVED_PIPE_OFFSET 20 | ||
281 | /*-------------------------------------------------------------------------*/ | 289 | /*-------------------------------------------------------------------------*/ |
282 | 290 | ||
283 | /* manual: 32.13.2 Endpoint Transfer Descriptor (dTD) */ | 291 | /* manual: 32.13.2 Endpoint Transfer Descriptor (dTD) */ |
@@ -294,7 +302,7 @@ struct transfer_descriptor { | |||
294 | unsigned int reserved; | 302 | unsigned int reserved; |
295 | } __attribute__ ((packed)); | 303 | } __attribute__ ((packed)); |
296 | 304 | ||
297 | static struct transfer_descriptor _td_array[32] __attribute((aligned (32))); | 305 | static struct transfer_descriptor _td_array[NUM_ENDPOINTS*2] __attribute((aligned (32))); |
298 | static struct transfer_descriptor* td_array; | 306 | static struct transfer_descriptor* td_array; |
299 | 307 | ||
300 | /* manual: 32.13.1 Endpoint Queue Head (dQH) */ | 308 | /* manual: 32.13.1 Endpoint Queue Head (dQH) */ |
@@ -304,30 +312,36 @@ struct queue_head { | |||
304 | unsigned int curr_dtd_ptr; /* Current dTD Pointer(31-5) */ | 312 | unsigned int curr_dtd_ptr; /* Current dTD Pointer(31-5) */ |
305 | struct transfer_descriptor dtd; /* dTD overlay */ | 313 | struct transfer_descriptor dtd; /* dTD overlay */ |
306 | unsigned int setup_buffer[2]; /* Setup data 8 bytes */ | 314 | unsigned int setup_buffer[2]; /* Setup data 8 bytes */ |
307 | unsigned int reserved[4]; | 315 | unsigned int reserved; /* for software use, pointer to the first TD */ |
316 | unsigned int status; /* for software use, status of chain in progress */ | ||
317 | unsigned int length; /* for software use, transfered bytes of chain in progress */ | ||
318 | unsigned int wait; /* for softwate use, indicates if the transfer is blocking */ | ||
308 | } __attribute__((packed)); | 319 | } __attribute__((packed)); |
309 | 320 | ||
310 | static struct queue_head _qh_array[NUM_ENDPOINTS*2] __attribute((aligned (2048))); | 321 | static struct queue_head _qh_array[NUM_ENDPOINTS*2] __attribute((aligned (2048))); |
311 | static struct queue_head* qh_array; | 322 | static struct queue_head* qh_array; |
323 | static struct event_queue transfer_completion_queue[NUM_ENDPOINTS*2]; | ||
312 | 324 | ||
313 | 325 | ||
314 | static const unsigned int pipe2mask[NUM_ENDPOINTS*2] = { | 326 | static const unsigned int pipe2mask[] = { |
315 | 0x01, 0x010000, | 327 | 0x01, 0x010000, |
316 | 0x02, 0x020000, | 328 | 0x02, 0x020000, |
317 | 0x04, 0x040000, | 329 | 0x04, 0x040000, |
330 | 0x08, 0x080000, | ||
331 | 0x10, 0x100000, | ||
318 | }; | 332 | }; |
319 | 333 | ||
320 | static struct transfer_descriptor* first_td; | ||
321 | static struct transfer_descriptor* last_td; | ||
322 | |||
323 | /*-------------------------------------------------------------------------*/ | 334 | /*-------------------------------------------------------------------------*/ |
324 | static void transfer_completed(void); | 335 | static void transfer_completed(void); |
325 | static int prime_transfer(int endpoint, void* ptr, int len, bool send); | 336 | static void control_received(void); |
337 | static int prime_transfer(int endpoint, void* ptr, | ||
338 | int len, bool send, bool wait); | ||
326 | static void prepare_td(struct transfer_descriptor* td, | 339 | static void prepare_td(struct transfer_descriptor* td, |
327 | struct transfer_descriptor* previous_td, | 340 | struct transfer_descriptor* previous_td, |
328 | void *ptr, int len); | 341 | void *ptr, int len,int pipe); |
329 | static void bus_reset(void); | 342 | static void bus_reset(void); |
330 | static void init_queue_heads(void); | 343 | static void init_control_queue_heads(void); |
344 | static void init_bulk_queue_heads(void); | ||
331 | static void init_endpoints(void); | 345 | static void init_endpoints(void); |
332 | /*-------------------------------------------------------------------------*/ | 346 | /*-------------------------------------------------------------------------*/ |
333 | 347 | ||
@@ -344,6 +358,7 @@ void usb_drv_init(void) | |||
344 | REG_USBCMD |= USBCMD_CTRL_RESET; | 358 | REG_USBCMD |= USBCMD_CTRL_RESET; |
345 | while (REG_USBCMD & USBCMD_CTRL_RESET); | 359 | while (REG_USBCMD & USBCMD_CTRL_RESET); |
346 | 360 | ||
361 | |||
347 | REG_USBMODE = USBMODE_CTRL_MODE_DEVICE; | 362 | REG_USBMODE = USBMODE_CTRL_MODE_DEVICE; |
348 | 363 | ||
349 | /* Force device to full speed */ | 364 | /* Force device to full speed */ |
@@ -352,7 +367,7 @@ void usb_drv_init(void) | |||
352 | 367 | ||
353 | td_array = (struct transfer_descriptor*)UNCACHED_ADDR(&_td_array); | 368 | td_array = (struct transfer_descriptor*)UNCACHED_ADDR(&_td_array); |
354 | qh_array = (struct queue_head*)UNCACHED_ADDR(&_qh_array); | 369 | qh_array = (struct queue_head*)UNCACHED_ADDR(&_qh_array); |
355 | init_queue_heads(); | 370 | init_control_queue_heads(); |
356 | memset(td_array, 0, sizeof _td_array); | 371 | memset(td_array, 0, sizeof _td_array); |
357 | 372 | ||
358 | REG_ENDPOINTLISTADDR = (unsigned int)qh_array; | 373 | REG_ENDPOINTLISTADDR = (unsigned int)qh_array; |
@@ -372,6 +387,7 @@ void usb_drv_init(void) | |||
372 | /* go go go */ | 387 | /* go go go */ |
373 | REG_USBCMD |= USBCMD_RUN; | 388 | REG_USBCMD |= USBCMD_RUN; |
374 | 389 | ||
390 | |||
375 | logf("usb_drv_init() finished"); | 391 | logf("usb_drv_init() finished"); |
376 | logf("usb id %x", REG_ID); | 392 | logf("usb id %x", REG_ID); |
377 | logf("usb dciversion %x", REG_DCIVERSION); | 393 | logf("usb dciversion %x", REG_DCIVERSION); |
@@ -407,15 +423,7 @@ void usb_drv_int(void) | |||
407 | 423 | ||
408 | /* a control packet? */ | 424 | /* a control packet? */ |
409 | if (REG_ENDPTSETUPSTAT & EPSETUP_STATUS_EP0) { | 425 | if (REG_ENDPTSETUPSTAT & EPSETUP_STATUS_EP0) { |
410 | /* copy setup data from packet */ | 426 | control_received(); |
411 | unsigned int tmp[2]; | ||
412 | tmp[0] = qh_array[0].setup_buffer[0]; | ||
413 | tmp[1] = qh_array[0].setup_buffer[1]; | ||
414 | |||
415 | /* acknowledge packet recieved */ | ||
416 | REG_ENDPTSETUPSTAT |= EPSETUP_STATUS_EP0; | ||
417 | |||
418 | usb_core_control_request((struct usb_ctrlrequest*)tmp); | ||
419 | } | 427 | } |
420 | 428 | ||
421 | if (REG_ENDPTCOMPLETE) | 429 | if (REG_ENDPTCOMPLETE) |
@@ -441,29 +449,52 @@ void usb_drv_int(void) | |||
441 | } | 449 | } |
442 | } | 450 | } |
443 | 451 | ||
444 | void usb_drv_stall(int endpoint, bool stall) | 452 | bool usb_drv_stalled(int endpoint,bool in) |
453 | { | ||
454 | if(in) { | ||
455 | return ((REG_ENDPTCTRL(endpoint) & EPCTRL_TX_EP_STALL)!=0); | ||
456 | } | ||
457 | else { | ||
458 | return ((REG_ENDPTCTRL(endpoint) & EPCTRL_RX_EP_STALL)!=0); | ||
459 | } | ||
460 | |||
461 | } | ||
462 | void usb_drv_stall(int endpoint, bool stall,bool in) | ||
445 | { | 463 | { |
446 | logf("%sstall %d", stall?"":"un", endpoint); | 464 | logf("%sstall %d", stall?"":"un", endpoint); |
447 | 465 | ||
448 | if (stall) { | 466 | if(in) { |
449 | REG_ENDPTCTRL(endpoint) |= EPCTRL_RX_EP_STALL; | 467 | if (stall) { |
450 | REG_ENDPTCTRL(endpoint) |= EPCTRL_TX_EP_STALL; | 468 | REG_ENDPTCTRL(endpoint) |= EPCTRL_TX_EP_STALL; |
469 | } | ||
470 | else { | ||
471 | REG_ENDPTCTRL(endpoint) &= ~EPCTRL_TX_EP_STALL; | ||
472 | } | ||
451 | } | 473 | } |
452 | else { | 474 | else { |
453 | REG_ENDPTCTRL(endpoint) &= ~EPCTRL_RX_EP_STALL; | 475 | if (stall) { |
454 | REG_ENDPTCTRL(endpoint) &= ~EPCTRL_TX_EP_STALL; | 476 | REG_ENDPTCTRL(endpoint) |= EPCTRL_RX_EP_STALL; |
477 | } | ||
478 | else { | ||
479 | REG_ENDPTCTRL(endpoint) &= ~EPCTRL_RX_EP_STALL; | ||
480 | } | ||
455 | } | 481 | } |
456 | } | 482 | } |
457 | 483 | ||
484 | int usb_drv_send_nonblocking(int endpoint, void* ptr, int length) | ||
485 | { | ||
486 | return prime_transfer(endpoint, ptr, length, true, false); | ||
487 | } | ||
488 | |||
458 | int usb_drv_send(int endpoint, void* ptr, int length) | 489 | int usb_drv_send(int endpoint, void* ptr, int length) |
459 | { | 490 | { |
460 | return prime_transfer(endpoint, ptr, length, true); | 491 | return prime_transfer(endpoint, ptr, length, true, true); |
461 | } | 492 | } |
462 | 493 | ||
463 | int usb_drv_recv(int endpoint, void* ptr, int length) | 494 | int usb_drv_recv(int endpoint, void* ptr, int length) |
464 | { | 495 | { |
465 | //logf("usbrecv(%x, %d)", ptr, length); | 496 | //logf("usbrecv(%x, %d)", ptr, length); |
466 | return prime_transfer(endpoint, ptr, length, false); | 497 | return prime_transfer(endpoint, ptr, length, false, false); |
467 | } | 498 | } |
468 | 499 | ||
469 | void usb_drv_wait(int endpoint, bool send) | 500 | void usb_drv_wait(int endpoint, bool send) |
@@ -485,6 +516,7 @@ int usb_drv_port_speed(void) | |||
485 | void usb_drv_set_address(int address) | 516 | void usb_drv_set_address(int address) |
486 | { | 517 | { |
487 | REG_DEVICEADDR = address << USBDEVICEADDRESS_BIT_POS; | 518 | REG_DEVICEADDR = address << USBDEVICEADDRESS_BIT_POS; |
519 | init_bulk_queue_heads(); | ||
488 | init_endpoints(); | 520 | init_endpoints(); |
489 | } | 521 | } |
490 | 522 | ||
@@ -496,78 +528,43 @@ void usb_drv_reset_endpoint(int endpoint, bool send) | |||
496 | while (REG_ENDPTFLUSH & mask); | 528 | while (REG_ENDPTFLUSH & mask); |
497 | } | 529 | } |
498 | 530 | ||
499 | int usb_drv_get_last_transfer_length(void) | ||
500 | { | ||
501 | struct transfer_descriptor* current_td = first_td; | ||
502 | int length = 0; | ||
503 | |||
504 | while (!((unsigned int)current_td & DTD_NEXT_TERMINATE)) { | ||
505 | if ((current_td->size_ioc_sts & 0xff) != 0) | ||
506 | return -1; | ||
507 | |||
508 | length += current_td->reserved - | ||
509 | ((current_td->size_ioc_sts & DTD_PACKET_SIZE) >> DTD_LENGTH_BIT_POS); | ||
510 | current_td = (struct transfer_descriptor*)current_td->next_td_ptr; | ||
511 | } | ||
512 | return length; | ||
513 | } | ||
514 | int usb_drv_get_last_transfer_status(void) | ||
515 | { | ||
516 | struct transfer_descriptor* current_td = first_td; | ||
517 | |||
518 | while (!((unsigned int)current_td & DTD_NEXT_TERMINATE)) { | ||
519 | if ((current_td->size_ioc_sts & 0xff) != 0) | ||
520 | return current_td->size_ioc_sts & 0xff; | ||
521 | |||
522 | current_td = (struct transfer_descriptor*)current_td->next_td_ptr; | ||
523 | } | ||
524 | return 0; | ||
525 | } | ||
526 | 531 | ||
527 | /*-------------------------------------------------------------------------*/ | 532 | /*-------------------------------------------------------------------------*/ |
528 | 533 | ||
529 | /* manual: 32.14.5.2 */ | 534 | /* manual: 32.14.5.2 */ |
530 | static int prime_transfer(int endpoint, void* ptr, int len, bool send) | 535 | static int prime_transfer(int endpoint, void* ptr, int len, bool send, bool wait) |
531 | { | 536 | { |
532 | int pipe = endpoint * 2 + (send ? 1 : 0); | 537 | int pipe = endpoint * 2 + (send ? 1 : 0); |
533 | unsigned int mask = pipe2mask[pipe]; | 538 | unsigned int mask = pipe2mask[pipe]; |
534 | last_td = 0; | ||
535 | struct queue_head* qh = &qh_array[pipe]; | 539 | struct queue_head* qh = &qh_array[pipe]; |
536 | static long last_tick; | 540 | static long last_tick; |
541 | struct transfer_descriptor* new_td; | ||
537 | 542 | ||
538 | /* | 543 | /* |
539 | if (send && endpoint > EP_CONTROL) { | 544 | if (send && endpoint > EP_CONTROL) { |
540 | logf("usb: sent %d bytes", len); | 545 | logf("usb: sent %d bytes", len); |
541 | } | 546 | } |
542 | */ | 547 | */ |
548 | qh->status = 0; | ||
549 | qh->length = 0; | ||
550 | qh->wait = wait; | ||
543 | 551 | ||
544 | if (len==0) { | ||
545 | struct transfer_descriptor* new_td = &td_array[0]; | ||
546 | prepare_td(new_td, 0, ptr, 0); | ||
547 | 552 | ||
548 | last_td = new_td; | 553 | new_td=&td_array[pipe]; |
549 | first_td = new_td; | 554 | prepare_td(new_td, 0, ptr, len,pipe); |
550 | } | 555 | //logf("starting ep %d %s",endpoint,send?"send":"receive"); |
551 | else { | ||
552 | int td_idx = 0; | ||
553 | while (len > 0) { | ||
554 | int current_transfer_length = MIN(16384,len); | ||
555 | struct transfer_descriptor* new_td = &td_array[td_idx]; | ||
556 | prepare_td(new_td, last_td, ptr, current_transfer_length); | ||
557 | |||
558 | last_td = new_td; | ||
559 | len -= current_transfer_length; | ||
560 | td_idx++; | ||
561 | ptr += current_transfer_length; | ||
562 | } | ||
563 | first_td = &td_array[0]; | ||
564 | } | ||
565 | 556 | ||
566 | qh->dtd.next_td_ptr = (unsigned int)first_td; | 557 | qh->dtd.next_td_ptr = (unsigned int)new_td; |
567 | qh->dtd.size_ioc_sts &= ~(QH_STATUS_HALT | QH_STATUS_ACTIVE); | 558 | qh->dtd.size_ioc_sts &= ~(QH_STATUS_HALT | QH_STATUS_ACTIVE); |
568 | 559 | ||
569 | REG_ENDPTPRIME |= mask; | 560 | REG_ENDPTPRIME |= mask; |
570 | 561 | ||
562 | if(endpoint == EP_CONTROL && (REG_ENDPTSETUPSTAT & EPSETUP_STATUS_EP0)) { | ||
563 | /* 32.14.3.2.2 */ | ||
564 | logf("new setup arrived"); | ||
565 | return -4; | ||
566 | } | ||
567 | |||
571 | last_tick = current_tick; | 568 | last_tick = current_tick; |
572 | while ((REG_ENDPTPRIME & mask)) { | 569 | while ((REG_ENDPTPRIME & mask)) { |
573 | if (REG_USBSTS & USBSTS_RESET) | 570 | if (REG_USBSTS & USBSTS_RESET) |
@@ -583,38 +580,43 @@ static int prime_transfer(int endpoint, void* ptr, int len, bool send) | |||
583 | logf("no prime! %d %d %x", endpoint, pipe, qh->dtd.size_ioc_sts & 0xff ); | 580 | logf("no prime! %d %d %x", endpoint, pipe, qh->dtd.size_ioc_sts & 0xff ); |
584 | return -3; | 581 | return -3; |
585 | } | 582 | } |
583 | if(endpoint == EP_CONTROL && (REG_ENDPTSETUPSTAT & EPSETUP_STATUS_EP0)) { | ||
584 | /* 32.14.3.2.2 */ | ||
585 | logf("new setup arrived"); | ||
586 | return -4; | ||
587 | } | ||
586 | 588 | ||
587 | if (send) { | 589 | if (wait) { |
588 | /* wait for transfer to finish */ | 590 | /* wait for transfer to finish */ |
589 | struct transfer_descriptor* current_td = first_td; | 591 | struct queue_event ev; |
590 | 592 | queue_wait(&transfer_completion_queue[pipe], &ev); | |
591 | while (!((unsigned int)current_td & DTD_NEXT_TERMINATE)) { | 593 | if(qh->status!=0) { |
592 | while ((current_td->size_ioc_sts & 0xff) == DTD_STATUS_ACTIVE) { | 594 | return -5; |
593 | if (REG_ENDPTCOMPLETE & mask) | ||
594 | REG_ENDPTCOMPLETE |= mask; | ||
595 | |||
596 | /* let the host handle timeouts */ | ||
597 | if (REG_USBSTS & USBSTS_RESET) { | ||
598 | logf("td interrupted by reset"); | ||
599 | return -4; | ||
600 | } | ||
601 | } | ||
602 | if ((current_td->size_ioc_sts & 0xff) != 0) { | ||
603 | logf("td failed with error %X",(current_td->size_ioc_sts & 0xff)); | ||
604 | return -6; | ||
605 | } | ||
606 | //logf("td finished : %X",current_td->size_ioc_sts & 0xff); | ||
607 | current_td=(struct transfer_descriptor*)current_td->next_td_ptr; | ||
608 | } | 595 | } |
609 | //logf("all tds done"); | 596 | //logf("all tds done"); |
610 | } | 597 | } |
611 | |||
612 | return 0; | 598 | return 0; |
613 | } | 599 | } |
614 | 600 | ||
601 | void usb_drv_cancel_all_transfers(void) | ||
602 | { | ||
603 | int i; | ||
604 | REG_ENDPTFLUSH = ~0; | ||
605 | while (REG_ENDPTFLUSH); | ||
606 | |||
607 | memset(td_array, 0, sizeof _td_array); | ||
608 | for(i=0;i<NUM_ENDPOINTS*2;i++) { | ||
609 | if(qh_array[i].wait) { | ||
610 | qh_array[i].wait=0; | ||
611 | qh_array[i].status=DTD_STATUS_HALTED; | ||
612 | queue_post(&transfer_completion_queue[i],0, 0); | ||
613 | } | ||
614 | } | ||
615 | } | ||
616 | |||
615 | static void prepare_td(struct transfer_descriptor* td, | 617 | static void prepare_td(struct transfer_descriptor* td, |
616 | struct transfer_descriptor* previous_td, | 618 | struct transfer_descriptor* previous_td, |
617 | void *ptr, int len) | 619 | void *ptr, int len,int pipe) |
618 | { | 620 | { |
619 | //logf("adding a td : %d",len); | 621 | //logf("adding a td : %d",len); |
620 | memset(td, 0, sizeof(struct transfer_descriptor)); | 622 | memset(td, 0, sizeof(struct transfer_descriptor)); |
@@ -626,35 +628,72 @@ static void prepare_td(struct transfer_descriptor* td, | |||
626 | td->buff_ptr2 = ((unsigned int)ptr & 0xfffff000) + 0x2000; | 628 | td->buff_ptr2 = ((unsigned int)ptr & 0xfffff000) + 0x2000; |
627 | td->buff_ptr3 = ((unsigned int)ptr & 0xfffff000) + 0x3000; | 629 | td->buff_ptr3 = ((unsigned int)ptr & 0xfffff000) + 0x3000; |
628 | td->buff_ptr4 = ((unsigned int)ptr & 0xfffff000) + 0x4000; | 630 | td->buff_ptr4 = ((unsigned int)ptr & 0xfffff000) + 0x4000; |
629 | td->reserved = len; | 631 | td->reserved |= DTD_RESERVED_LENGTH_MASK & len; |
632 | td->reserved |= DTD_RESERVED_IN_USE; | ||
633 | td->reserved |= (pipe << DTD_RESERVED_PIPE_OFFSET); | ||
630 | 634 | ||
631 | if (previous_td != 0) { | 635 | if (previous_td != 0) { |
632 | previous_td->next_td_ptr=(unsigned int)td; | 636 | previous_td->next_td_ptr=(unsigned int)td; |
633 | previous_td->size_ioc_sts&=~DTD_IOC;// Only an interrupt on the last one | ||
634 | } | 637 | } |
635 | } | 638 | } |
636 | 639 | ||
637 | static void transfer_completed(void) | 640 | static void control_received(void) |
638 | { | 641 | { |
639 | int i; | 642 | int i; |
643 | logf("control stuff"); | ||
644 | /* copy setup data from packet */ | ||
645 | static unsigned int tmp[2]; | ||
646 | tmp[0] = qh_array[0].setup_buffer[0]; | ||
647 | tmp[1] = qh_array[0].setup_buffer[1]; | ||
648 | |||
649 | /* acknowledge packet recieved */ | ||
650 | REG_ENDPTSETUPSTAT |= EPSETUP_STATUS_EP0; | ||
651 | |||
652 | /* Stop pending interrupt transfers */ | ||
653 | for(i=0;i<2;i++) { | ||
654 | if(qh_array[i].wait) { | ||
655 | qh_array[i].wait=0; | ||
656 | qh_array[i].status=DTD_STATUS_HALTED; | ||
657 | queue_post(&transfer_completion_queue[i],0, 0); | ||
658 | } | ||
659 | } | ||
660 | |||
661 | usb_core_control_request((struct usb_ctrlrequest*)tmp); | ||
662 | } | ||
663 | |||
664 | static void transfer_completed(void) | ||
665 | { | ||
666 | int ep; | ||
640 | unsigned int mask = REG_ENDPTCOMPLETE; | 667 | unsigned int mask = REG_ENDPTCOMPLETE; |
641 | REG_ENDPTCOMPLETE |= mask; | 668 | REG_ENDPTCOMPLETE |= mask; |
642 | 669 | ||
643 | //logf("usb comp %x", mask); | 670 | for (ep=0; ep<NUM_ENDPOINTS; ep++) { |
644 | 671 | int dir; | |
645 | for (i=0; i<NUM_ENDPOINTS; i++) { | 672 | for (dir=0; dir<2; dir++) { |
646 | int x; | 673 | int pipe = ep * 2 + dir; |
647 | for (x=0; x<2; x++) { | 674 | if (mask & pipe2mask[pipe]) { |
648 | unsigned int status; | 675 | struct queue_head* qh = &qh_array[pipe]; |
649 | int pipe = i * 2 + x; | 676 | struct transfer_descriptor *td = &td_array[pipe]; |
650 | 677 | ||
651 | if (mask & pipe2mask[pipe]) | 678 | if(td->size_ioc_sts & DTD_STATUS_ACTIVE) { |
652 | usb_core_transfer_complete(i, x ? true : false); | 679 | /* TODO this shouldn't happen, but...*/ |
653 | 680 | break; | |
654 | status = usb_drv_get_last_transfer_status(); | 681 | } |
655 | if ((mask & pipe2mask[pipe]) && | 682 | if((td->size_ioc_sts & DTD_PACKET_SIZE) >> DTD_LENGTH_BIT_POS != 0 && dir==0) { |
656 | status & DTD_ERROR_MASK) { | 683 | /* We got less data than we asked for. */ |
657 | logf("pipe %d err %x", pipe, status & DTD_ERROR_MASK); | 684 | } |
685 | qh->length = (td->reserved & DTD_RESERVED_LENGTH_MASK) - | ||
686 | ((td->size_ioc_sts & DTD_PACKET_SIZE) >> DTD_LENGTH_BIT_POS); | ||
687 | if(td->size_ioc_sts & DTD_ERROR_MASK) { | ||
688 | logf("pipe %d err %x", pipe, td->size_ioc_sts & DTD_ERROR_MASK); | ||
689 | qh->status |= td->size_ioc_sts & DTD_ERROR_MASK; | ||
690 | /* TODO we need to handle this somehow. Flush the endpoint ? */ | ||
691 | } | ||
692 | if(qh->wait) { | ||
693 | qh->wait=0; | ||
694 | queue_post(&transfer_completion_queue[pipe],0, 0); | ||
695 | } | ||
696 | usb_core_transfer_complete(ep, dir, qh->status, qh->length); | ||
658 | } | 697 | } |
659 | } | 698 | } |
660 | } | 699 | } |
@@ -685,61 +724,66 @@ static void bus_reset(void) | |||
685 | logf("usb: short reset timeout"); | 724 | logf("usb: short reset timeout"); |
686 | } | 725 | } |
687 | 726 | ||
688 | REG_ENDPTFLUSH = ~0; | 727 | usb_drv_cancel_all_transfers(); |
689 | //while (REG_ENDPTFLUSH); | ||
690 | 728 | ||
691 | if (!(REG_PORTSC1 & PORTSCX_PORT_RESET)) { | 729 | if (!(REG_PORTSC1 & PORTSCX_PORT_RESET)) { |
692 | logf("usb: slow reset!"); | 730 | logf("usb: slow reset!"); |
693 | } | 731 | } |
694 | |||
695 | logf("PTS : %X",(REG_PORTSC1 & 0xC0000000)>>30); | ||
696 | logf("STS : %X",(REG_PORTSC1 & 0x20000000)>>29); | ||
697 | logf("PTW : %X",(REG_PORTSC1 & 0x10000000)>>28); | ||
698 | logf("PSPD : %X",(REG_PORTSC1 & 0x0C000000)>>26); | ||
699 | logf("PFSC : %X",(REG_PORTSC1 & 0x01000000)>>24); | ||
700 | logf("PTC : %X",(REG_PORTSC1 & 0x000F0000)>>16); | ||
701 | logf("PO : %X",(REG_PORTSC1 & 0x00002000)>>13); | ||
702 | } | 732 | } |
703 | 733 | ||
704 | /* manual: 32.14.4.1 Queue Head Initialization */ | 734 | /* manual: 32.14.4.1 Queue Head Initialization */ |
705 | static void init_queue_heads(void) | 735 | static void init_control_queue_heads(void) |
736 | { | ||
737 | int i; | ||
738 | memset(qh_array, 0, sizeof _qh_array); | ||
739 | |||
740 | /*** control ***/ | ||
741 | qh_array[EP_CONTROL].max_pkt_length = 64 << QH_MAX_PKT_LEN_POS | QH_IOS; | ||
742 | qh_array[EP_CONTROL].dtd.next_td_ptr = QH_NEXT_TERMINATE; | ||
743 | qh_array[EP_CONTROL+1].max_pkt_length = 64 << QH_MAX_PKT_LEN_POS; | ||
744 | qh_array[EP_CONTROL+1].dtd.next_td_ptr = QH_NEXT_TERMINATE; | ||
745 | |||
746 | for(i=0;i<2;i++) { | ||
747 | queue_init(&transfer_completion_queue[i], false); | ||
748 | } | ||
749 | } | ||
750 | /* manual: 32.14.4.1 Queue Head Initialization */ | ||
751 | static void init_bulk_queue_heads(void) | ||
706 | { | 752 | { |
707 | int tx_packetsize; | 753 | int tx_packetsize; |
708 | int rx_packetsize; | 754 | int rx_packetsize; |
755 | int i; | ||
709 | 756 | ||
710 | if (usb_drv_port_speed()) { | 757 | if (usb_drv_port_speed()) { |
711 | rx_packetsize = 512; | 758 | rx_packetsize = 512; |
712 | tx_packetsize = 512; | 759 | tx_packetsize = 512; |
713 | } | 760 | } |
714 | else { | 761 | else { |
715 | rx_packetsize = 16; | 762 | rx_packetsize = 64; |
716 | tx_packetsize = 16; | 763 | tx_packetsize = 64; |
717 | } | 764 | } |
718 | memset(qh_array, 0, sizeof _qh_array); | ||
719 | |||
720 | /*** control ***/ | ||
721 | qh_array[EP_CONTROL].max_pkt_length = 64 << QH_MAX_PKT_LEN_POS | QH_IOS; | ||
722 | qh_array[EP_CONTROL].dtd.next_td_ptr = QH_NEXT_TERMINATE; | ||
723 | qh_array[EP_CONTROL+1].max_pkt_length = 64 << QH_MAX_PKT_LEN_POS; | ||
724 | qh_array[EP_CONTROL+1].dtd.next_td_ptr = QH_NEXT_TERMINATE; | ||
725 | 765 | ||
726 | /*** bulk ***/ | 766 | /*** bulk ***/ |
727 | qh_array[EP_RX*2].max_pkt_length = rx_packetsize << QH_MAX_PKT_LEN_POS | QH_ZLT_SEL; | 767 | for(i=1;i<NUM_ENDPOINTS;i++) { |
728 | qh_array[EP_RX*2].dtd.next_td_ptr = QH_NEXT_TERMINATE; | 768 | qh_array[i*2].max_pkt_length = rx_packetsize << QH_MAX_PKT_LEN_POS | QH_ZLT_SEL; |
729 | qh_array[EP_TX*2+1].max_pkt_length = tx_packetsize << QH_MAX_PKT_LEN_POS | QH_ZLT_SEL; | 769 | qh_array[i*2].dtd.next_td_ptr = QH_NEXT_TERMINATE; |
730 | qh_array[EP_TX*2+1].dtd.next_td_ptr = QH_NEXT_TERMINATE; | 770 | qh_array[i*2+1].max_pkt_length = tx_packetsize << QH_MAX_PKT_LEN_POS | QH_ZLT_SEL; |
771 | qh_array[i*2+1].dtd.next_td_ptr = QH_NEXT_TERMINATE; | ||
772 | } | ||
773 | for(i=2;i<NUM_ENDPOINTS*2;i++) { | ||
774 | queue_init(&transfer_completion_queue[i], false); | ||
775 | } | ||
731 | } | 776 | } |
732 | 777 | ||
733 | static void init_endpoints(void) | 778 | static void init_endpoints(void) |
734 | { | 779 | { |
780 | int i; | ||
735 | /* bulk */ | 781 | /* bulk */ |
736 | REG_ENDPTCTRL(EP_RX) = | 782 | for(i=1;i<NUM_ENDPOINTS;i++) { |
737 | EPCTRL_RX_DATA_TOGGLE_RST | EPCTRL_RX_ENABLE | | 783 | REG_ENDPTCTRL(i) = |
738 | (EPCTRL_EP_TYPE_BULK << EPCTRL_RX_EP_TYPE_SHIFT) | | 784 | EPCTRL_RX_DATA_TOGGLE_RST | EPCTRL_RX_ENABLE | |
739 | (EPCTRL_EP_TYPE_BULK << EPCTRL_TX_EP_TYPE_SHIFT); | 785 | EPCTRL_TX_DATA_TOGGLE_RST | EPCTRL_TX_ENABLE | |
740 | 786 | (EPCTRL_EP_TYPE_BULK << EPCTRL_RX_EP_TYPE_SHIFT) | | |
741 | REG_ENDPTCTRL(EP_TX) = | 787 | (EPCTRL_EP_TYPE_BULK << EPCTRL_TX_EP_TYPE_SHIFT); |
742 | EPCTRL_TX_DATA_TOGGLE_RST | EPCTRL_TX_ENABLE | | 788 | } |
743 | (EPCTRL_EP_TYPE_BULK << EPCTRL_RX_EP_TYPE_SHIFT) | | ||
744 | (EPCTRL_EP_TYPE_BULK << EPCTRL_TX_EP_TYPE_SHIFT); | ||
745 | } | 789 | } |
diff --git a/firmware/target/arm/usb-fw-pp502x.c b/firmware/target/arm/usb-fw-pp502x.c index 46a5b9942f..4ac515ba1c 100644 --- a/firmware/target/arm/usb-fw-pp502x.c +++ b/firmware/target/arm/usb-fw-pp502x.c | |||
@@ -34,6 +34,7 @@ void usb_init_device(void) | |||
34 | { | 34 | { |
35 | /* enable usb module */ | 35 | /* enable usb module */ |
36 | outl(inl(0x7000002C) | 0x3000000, 0x7000002C); | 36 | outl(inl(0x7000002C) | 0x3000000, 0x7000002C); |
37 | |||
37 | DEV_EN |= DEV_USB0; | 38 | DEV_EN |= DEV_USB0; |
38 | DEV_EN |= DEV_USB1; | 39 | DEV_EN |= DEV_USB1; |
39 | 40 | ||
@@ -46,6 +47,7 @@ void usb_init_device(void) | |||
46 | #if CONFIG_CPU == PP5020 | 47 | #if CONFIG_CPU == PP5020 |
47 | DEV_INIT2 |= INIT_USB; | 48 | DEV_INIT2 |= INIT_USB; |
48 | #endif | 49 | #endif |
50 | |||
49 | while ((inl(0x70000028) & 0x80) == 0); | 51 | while ((inl(0x70000028) & 0x80) == 0); |
50 | outl(inl(0x70000028) | 0x2, 0x70000028); | 52 | outl(inl(0x70000028) | 0x2, 0x70000028); |
51 | udelay(0x186A0); | 53 | udelay(0x186A0); |
@@ -68,9 +70,8 @@ void usb_init_device(void) | |||
68 | void usb_enable(bool on) | 70 | void usb_enable(bool on) |
69 | { | 71 | { |
70 | if (on) { | 72 | if (on) { |
71 | #ifdef USE_ROCKBOX_USB | ||
72 | usb_core_init(); | 73 | usb_core_init(); |
73 | #else | 74 | #if !defined(USE_ROCKBOX_USB) |
74 | /* until we have native mass-storage mode, we want to reboot on | 75 | /* until we have native mass-storage mode, we want to reboot on |
75 | usb host connect */ | 76 | usb host connect */ |
76 | #if defined(IRIVER_H10) || defined (IRIVER_H10_5GB) | 77 | #if defined(IRIVER_H10) || defined (IRIVER_H10_5GB) |
diff --git a/firmware/usbstack/usb_benchmark.c b/firmware/usbstack/usb_benchmark.c index a6e0e2d3e7..7cd5a3e987 100644 --- a/firmware/usbstack/usb_benchmark.c +++ b/firmware/usbstack/usb_benchmark.c | |||
@@ -22,6 +22,8 @@ | |||
22 | //#define LOGF_ENABLE | 22 | //#define LOGF_ENABLE |
23 | #include "logf.h" | 23 | #include "logf.h" |
24 | 24 | ||
25 | #ifdef USB_BENCHMARK | ||
26 | |||
25 | static int current_length; | 27 | static int current_length; |
26 | 28 | ||
27 | static unsigned char _input_buffer[16384]; | 29 | static unsigned char _input_buffer[16384]; |
@@ -56,8 +58,8 @@ void usb_benchmark_control_request(struct usb_ctrlrequest* req) | |||
56 | logf("bench: read %d", current_length); | 58 | logf("bench: read %d", current_length); |
57 | todo = MIN(usb_max_pkt_size, current_length); | 59 | todo = MIN(usb_max_pkt_size, current_length); |
58 | state = SENDING; | 60 | state = SENDING; |
59 | usb_drv_reset_endpoint(EP_TX, true); | 61 | usb_drv_reset_endpoint(EP_BENCHMARK, true); |
60 | usb_drv_send(EP_TX, &input_buffer, todo); | 62 | usb_drv_send(EP_BENCHMARK, &input_buffer, todo); |
61 | current_length -= todo; | 63 | current_length -= todo; |
62 | break; | 64 | break; |
63 | 65 | ||
@@ -66,13 +68,13 @@ void usb_benchmark_control_request(struct usb_ctrlrequest* req) | |||
66 | current_length = req->wValue * req->wIndex; | 68 | current_length = req->wValue * req->wIndex; |
67 | logf("bench: write %d", current_length); | 69 | logf("bench: write %d", current_length); |
68 | state = RECEIVING; | 70 | state = RECEIVING; |
69 | usb_drv_reset_endpoint(EP_RX, false); | 71 | usb_drv_reset_endpoint(EP_BENCHMARK, false); |
70 | usb_drv_recv(EP_RX, &input_buffer, sizeof _input_buffer); | 72 | usb_drv_recv(EP_BENCHMARK, &input_buffer, sizeof _input_buffer); |
71 | break; | 73 | break; |
72 | } | 74 | } |
73 | } | 75 | } |
74 | 76 | ||
75 | void usb_benchmark_transfer_complete(int endpoint, bool in) | 77 | void usb_benchmark_transfer_complete(bool in) |
76 | { | 78 | { |
77 | (void)in; | 79 | (void)in; |
78 | 80 | ||
@@ -87,26 +89,26 @@ void usb_benchmark_transfer_complete(int endpoint, bool in) | |||
87 | { | 89 | { |
88 | case SENDING: { | 90 | case SENDING: { |
89 | int todo = MIN(usb_max_pkt_size, current_length); | 91 | int todo = MIN(usb_max_pkt_size, current_length); |
90 | if (endpoint == EP_RX) { | 92 | if (in == false) { |
91 | logf("unexpected ep_rx"); | 93 | logf("unexpected ep_rx"); |
92 | break; | 94 | break; |
93 | } | 95 | } |
94 | 96 | ||
95 | logf("bench: %d more tx", current_length); | 97 | logf("bench: %d more tx", current_length); |
96 | usb_drv_send(EP_TX, &input_buffer, todo); | 98 | usb_drv_send(EP_BENCHMARK, &input_buffer, todo); |
97 | current_length -= todo; | 99 | current_length -= todo; |
98 | input_buffer[0]++; | 100 | input_buffer[0]++; |
99 | break; | 101 | break; |
100 | } | 102 | } |
101 | 103 | ||
102 | case RECEIVING: | 104 | case RECEIVING: |
103 | if (endpoint == EP_TX) { | 105 | if (in == true) { |
104 | logf("unexpected ep_tx"); | 106 | logf("unexpected ep_tx"); |
105 | break; | 107 | break; |
106 | } | 108 | } |
107 | 109 | ||
108 | /* re-prime endpoint */ | 110 | /* re-prime endpoint */ |
109 | usb_drv_recv(EP_RX, &input_buffer, sizeof _input_buffer); | 111 | usb_drv_recv(EP_BENCHMARK, &input_buffer, sizeof _input_buffer); |
110 | input_buffer[0]++; | 112 | input_buffer[0]++; |
111 | break; | 113 | break; |
112 | 114 | ||
@@ -123,3 +125,4 @@ static void ack_control(struct usb_ctrlrequest* req) | |||
123 | else | 125 | else |
124 | usb_drv_send(EP_CONTROL, NULL, 0); | 126 | usb_drv_send(EP_CONTROL, NULL, 0); |
125 | } | 127 | } |
128 | #endif /*USB_BENCHMARK*/ | ||
diff --git a/firmware/usbstack/usb_benchmark.h b/firmware/usbstack/usb_benchmark.h index 84853a1656..12c32a724f 100644 --- a/firmware/usbstack/usb_benchmark.h +++ b/firmware/usbstack/usb_benchmark.h | |||
@@ -21,6 +21,6 @@ | |||
21 | 21 | ||
22 | void usb_benchmark_init(void); | 22 | void usb_benchmark_init(void); |
23 | void usb_benchmark_control_request(struct usb_ctrlrequest* req); | 23 | void usb_benchmark_control_request(struct usb_ctrlrequest* req); |
24 | void usb_benchmark_transfer_complete(int endpoint, bool in); | 24 | void usb_benchmark_transfer_complete(bool in); |
25 | 25 | ||
26 | #endif | 26 | #endif |
diff --git a/firmware/usbstack/usb_core.c b/firmware/usbstack/usb_core.c index 13993f9271..c68093b0d2 100644 --- a/firmware/usbstack/usb_core.c +++ b/firmware/usbstack/usb_core.c | |||
@@ -23,44 +23,42 @@ | |||
23 | //#define LOGF_ENABLE | 23 | //#define LOGF_ENABLE |
24 | #include "logf.h" | 24 | #include "logf.h" |
25 | 25 | ||
26 | #ifndef BOOTLOADER | ||
27 | //#define USB_SERIAL | ||
28 | //#define USB_BENCHMARK | ||
29 | #ifdef USE_ROCKBOX_USB | ||
30 | #define USB_STORAGE | ||
31 | #else | ||
32 | #define USB_CHARGING_ONLY | ||
33 | #endif /* USE_ROCKBOX_USB */ | ||
34 | #else | ||
35 | #define USB_CHARGING_ONLY | ||
36 | #endif | ||
37 | |||
38 | #include "usb_ch9.h" | 26 | #include "usb_ch9.h" |
39 | #include "usb_drv.h" | 27 | #include "usb_drv.h" |
40 | #include "usb_core.h" | 28 | #include "usb_core.h" |
41 | 29 | ||
30 | #define USB_THREAD | ||
31 | |||
42 | #if defined(USB_STORAGE) | 32 | #if defined(USB_STORAGE) |
43 | #include "usb_storage.h" | 33 | #include "usb_storage.h" |
44 | #define USB_THREAD | 34 | #endif |
45 | #elif defined(USB_SERIAL) | 35 | |
46 | #define USB_THREAD | 36 | #if defined(USB_SERIAL) |
47 | #include "usb_serial.h" | 37 | #include "usb_serial.h" |
48 | #elif defined(USB_BENCHMARK) | 38 | #endif |
39 | |||
40 | #if defined(USB_BENCHMARK) | ||
49 | #include "usb_benchmark.h" | 41 | #include "usb_benchmark.h" |
50 | #endif | 42 | #endif |
51 | 43 | ||
44 | /* TODO: Move this target-specific stuff somewhere else (serial number reading) */ | ||
45 | |||
46 | #ifdef HAVE_AS3514 | ||
47 | #include "i2c-pp.h" | ||
48 | #include "as3514.h" | ||
49 | #endif | ||
50 | |||
51 | |||
52 | /*-------------------------------------------------------------------------*/ | 52 | /*-------------------------------------------------------------------------*/ |
53 | /* USB protocol descriptors: */ | 53 | /* USB protocol descriptors: */ |
54 | 54 | ||
55 | #define USB_SC_SCSI 0x06 /* Transparent */ | 55 | #define USB_SC_SCSI 0x06 /* Transparent */ |
56 | #define USB_PROT_BULK 0x50 /* bulk only */ | 56 | #define USB_PROT_BULK 0x50 /* bulk only */ |
57 | 57 | ||
58 | int usb_max_pkt_size = 512; | 58 | static const struct usb_device_descriptor device_descriptor= { |
59 | |||
60 | static const struct usb_device_descriptor device_descriptor = { | ||
61 | .bLength = sizeof(struct usb_device_descriptor), | 59 | .bLength = sizeof(struct usb_device_descriptor), |
62 | .bDescriptorType = USB_DT_DEVICE, | 60 | .bDescriptorType = USB_DT_DEVICE, |
63 | .bcdUSB = 0x0200, /* USB version 2.0 */ | 61 | .bcdUSB = 0x0200, |
64 | .bDeviceClass = USB_CLASS_PER_INTERFACE, | 62 | .bDeviceClass = USB_CLASS_PER_INTERFACE, |
65 | .bDeviceSubClass = 0, | 63 | .bDeviceSubClass = 0, |
66 | .bDeviceProtocol = 0, | 64 | .bDeviceProtocol = 0, |
@@ -74,158 +72,34 @@ static const struct usb_device_descriptor device_descriptor = { | |||
74 | .bNumConfigurations = 1 | 72 | .bNumConfigurations = 1 |
75 | }; | 73 | }; |
76 | 74 | ||
77 | static const struct { | 75 | static struct { |
78 | struct usb_config_descriptor config_descriptor; | 76 | struct usb_config_descriptor config_descriptor; |
79 | struct usb_interface_descriptor interface_descriptor; | ||
80 | struct usb_endpoint_descriptor ep1_in_descriptor; | ||
81 | struct usb_endpoint_descriptor ep1_out_descriptor; | ||
82 | } config_data_fs = | ||
83 | { | ||
84 | { | ||
85 | .bLength = sizeof(struct usb_config_descriptor), | ||
86 | .bDescriptorType = USB_DT_CONFIG, | ||
87 | .wTotalLength = sizeof config_data_fs, | ||
88 | .bNumInterfaces = 1, | ||
89 | .bConfigurationValue = 1, | ||
90 | .iConfiguration = 0, | ||
91 | .bmAttributes = USB_CONFIG_ATT_ONE | USB_CONFIG_ATT_SELFPOWER, | ||
92 | .bMaxPower = 250, /* 500mA in 2mA units */ | ||
93 | }, | ||
94 | |||
95 | #ifdef USB_CHARGING_ONLY | 77 | #ifdef USB_CHARGING_ONLY |
96 | /* dummy interface for charging-only */ | 78 | struct usb_interface_descriptor charging_interface_descriptor; |
97 | { | 79 | struct usb_endpoint_descriptor charging_ep_in_descriptor; |
98 | .bLength = sizeof(struct usb_interface_descriptor), | 80 | struct usb_endpoint_descriptor charging_ep_out_descriptor; |
99 | .bDescriptorType = USB_DT_INTERFACE, | ||
100 | .bInterfaceNumber = 0, | ||
101 | .bAlternateSetting = 0, | ||
102 | .bNumEndpoints = 2, | ||
103 | .bInterfaceClass = USB_CLASS_VENDOR_SPEC, | ||
104 | .bInterfaceSubClass = 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 | 81 | #endif |
126 | |||
127 | #ifdef USB_STORAGE | 82 | #ifdef USB_STORAGE |
128 | /* storage interface */ | 83 | struct usb_interface_descriptor mass_storage_interface_descriptor; |
129 | { | 84 | struct usb_endpoint_descriptor mass_storage_ep_in_descriptor; |
130 | .bLength = sizeof(struct usb_interface_descriptor), | 85 | struct usb_endpoint_descriptor mass_storage_ep_out_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 | 86 | #endif |
158 | |||
159 | #ifdef USB_SERIAL | 87 | #ifdef USB_SERIAL |
160 | /* serial interface */ | 88 | struct usb_interface_descriptor serial_interface_descriptor; |
161 | { | 89 | struct usb_endpoint_descriptor serial_ep_in_descriptor; |
162 | .bLength = sizeof(struct usb_interface_descriptor), | 90 | struct usb_endpoint_descriptor serial_ep_out_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 | 91 | #endif |
190 | |||
191 | #ifdef USB_BENCHMARK | 92 | #ifdef USB_BENCHMARK |
192 | /* bulk test interface */ | 93 | struct usb_interface_descriptor benchmark_interface_descriptor; |
193 | { | 94 | struct usb_endpoint_descriptor benchmark_ep_in_descriptor; |
194 | .bLength = sizeof(struct usb_interface_descriptor), | 95 | struct usb_endpoint_descriptor benchmark_ep_out_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, | ||
202 | .iInterface = 4 | ||
203 | }, | ||
204 | |||
205 | { | ||
206 | .bLength = sizeof(struct usb_endpoint_descriptor), | ||
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 | 96 | #endif |
222 | }, | 97 | } __attribute__((packed)) *config_data, _config_data = |
223 | config_data_hs = | ||
224 | { | 98 | { |
225 | { | 99 | { |
226 | .bLength = sizeof(struct usb_config_descriptor), | 100 | .bLength = sizeof(struct usb_config_descriptor), |
227 | .bDescriptorType = USB_DT_CONFIG, | 101 | .bDescriptorType = USB_DT_CONFIG, |
228 | .wTotalLength = sizeof config_data_hs, | 102 | .wTotalLength = sizeof _config_data, |
229 | .bNumInterfaces = 1, | 103 | .bNumInterfaces = 1, |
230 | .bConfigurationValue = 1, | 104 | .bConfigurationValue = 1, |
231 | .iConfiguration = 0, | 105 | .iConfiguration = 0, |
@@ -246,23 +120,23 @@ config_data_hs = | |||
246 | .bInterfaceProtocol = 0, | 120 | .bInterfaceProtocol = 0, |
247 | .iInterface = 5 | 121 | .iInterface = 5 |
248 | }, | 122 | }, |
249 | 123 | /* TODO: try with zero endpoints */ | |
250 | { | 124 | { |
251 | .bLength = sizeof(struct usb_endpoint_descriptor), | 125 | .bLength = sizeof(struct usb_endpoint_descriptor), |
252 | .bDescriptorType = USB_DT_ENDPOINT, | 126 | .bDescriptorType = USB_DT_ENDPOINT, |
253 | .bEndpointAddress = EP_TX | USB_DIR_IN, | 127 | .bEndpointAddress = EP_CHARGING_ONLY | USB_DIR_IN, |
254 | .bmAttributes = USB_ENDPOINT_XFER_BULK, | 128 | .bmAttributes = USB_ENDPOINT_XFER_BULK, |
255 | .wMaxPacketSize = 512, | 129 | .wMaxPacketSize = 16, |
256 | .bInterval = 0 | 130 | .bInterval = 0 |
257 | }, | 131 | }, |
258 | { | 132 | { |
259 | .bLength = sizeof(struct usb_endpoint_descriptor), | 133 | .bLength = sizeof(struct usb_endpoint_descriptor), |
260 | .bDescriptorType = USB_DT_ENDPOINT, | 134 | .bDescriptorType = USB_DT_ENDPOINT, |
261 | .bEndpointAddress = EP_RX | USB_DIR_OUT, | 135 | .bEndpointAddress = EP_CHARGING_ONLY | USB_DIR_OUT, |
262 | .bmAttributes = USB_ENDPOINT_XFER_BULK, | 136 | .bmAttributes = USB_ENDPOINT_XFER_BULK, |
263 | .wMaxPacketSize = 512, | 137 | .wMaxPacketSize = 16, |
264 | .bInterval = 0 | 138 | .bInterval = 0 |
265 | } | 139 | }, |
266 | #endif | 140 | #endif |
267 | 141 | ||
268 | #ifdef USB_STORAGE | 142 | #ifdef USB_STORAGE |
@@ -282,19 +156,19 @@ config_data_hs = | |||
282 | { | 156 | { |
283 | .bLength = sizeof(struct usb_endpoint_descriptor), | 157 | .bLength = sizeof(struct usb_endpoint_descriptor), |
284 | .bDescriptorType = USB_DT_ENDPOINT, | 158 | .bDescriptorType = USB_DT_ENDPOINT, |
285 | .bEndpointAddress = EP_TX | USB_DIR_IN, | 159 | .bEndpointAddress = EP_MASS_STORAGE | USB_DIR_IN, |
286 | .bmAttributes = USB_ENDPOINT_XFER_BULK, | 160 | .bmAttributes = USB_ENDPOINT_XFER_BULK, |
287 | .wMaxPacketSize = 512, | 161 | .wMaxPacketSize = 16, |
288 | .bInterval = 0 | 162 | .bInterval = 0 |
289 | }, | 163 | }, |
290 | { | 164 | { |
291 | .bLength = sizeof(struct usb_endpoint_descriptor), | 165 | .bLength = sizeof(struct usb_endpoint_descriptor), |
292 | .bDescriptorType = USB_DT_ENDPOINT, | 166 | .bDescriptorType = USB_DT_ENDPOINT, |
293 | .bEndpointAddress = EP_RX | USB_DIR_OUT, | 167 | .bEndpointAddress = EP_MASS_STORAGE | USB_DIR_OUT, |
294 | .bmAttributes = USB_ENDPOINT_XFER_BULK, | 168 | .bmAttributes = USB_ENDPOINT_XFER_BULK, |
295 | .wMaxPacketSize = 512, | 169 | .wMaxPacketSize = 16, |
296 | .bInterval = 0 | 170 | .bInterval = 0 |
297 | } | 171 | }, |
298 | #endif | 172 | #endif |
299 | 173 | ||
300 | #ifdef USB_SERIAL | 174 | #ifdef USB_SERIAL |
@@ -314,19 +188,19 @@ config_data_hs = | |||
314 | { | 188 | { |
315 | .bLength = sizeof(struct usb_endpoint_descriptor), | 189 | .bLength = sizeof(struct usb_endpoint_descriptor), |
316 | .bDescriptorType = USB_DT_ENDPOINT, | 190 | .bDescriptorType = USB_DT_ENDPOINT, |
317 | .bEndpointAddress = EP_TX | USB_DIR_IN, | 191 | .bEndpointAddress = EP_SERIAL | USB_DIR_IN, |
318 | .bmAttributes = USB_ENDPOINT_XFER_BULK, | 192 | .bmAttributes = USB_ENDPOINT_XFER_BULK, |
319 | .wMaxPacketSize = 512, | 193 | .wMaxPacketSize = 16, |
320 | .bInterval = 0 | 194 | .bInterval = 0 |
321 | }, | 195 | }, |
322 | { | 196 | { |
323 | .bLength = sizeof(struct usb_endpoint_descriptor), | 197 | .bLength = sizeof(struct usb_endpoint_descriptor), |
324 | .bDescriptorType = USB_DT_ENDPOINT, | 198 | .bDescriptorType = USB_DT_ENDPOINT, |
325 | .bEndpointAddress = EP_RX | USB_DIR_OUT, | 199 | .bEndpointAddress = EP_SERIAL | USB_DIR_OUT, |
326 | .bmAttributes = USB_ENDPOINT_XFER_BULK, | 200 | .bmAttributes = USB_ENDPOINT_XFER_BULK, |
327 | .wMaxPacketSize = 512, | 201 | .wMaxPacketSize = 16, |
328 | .bInterval = 0 | 202 | .bInterval = 0 |
329 | } | 203 | }, |
330 | #endif | 204 | #endif |
331 | 205 | ||
332 | #ifdef USB_BENCHMARK | 206 | #ifdef USB_BENCHMARK |
@@ -346,19 +220,19 @@ config_data_hs = | |||
346 | { | 220 | { |
347 | .bLength = sizeof(struct usb_endpoint_descriptor), | 221 | .bLength = sizeof(struct usb_endpoint_descriptor), |
348 | .bDescriptorType = USB_DT_ENDPOINT, | 222 | .bDescriptorType = USB_DT_ENDPOINT, |
349 | .bEndpointAddress = EP_RX | USB_DIR_OUT, | 223 | .bEndpointAddress = EP_BENCHMARK | USB_DIR_OUT, |
350 | .bmAttributes = USB_ENDPOINT_XFER_BULK, | 224 | .bmAttributes = USB_ENDPOINT_XFER_BULK, |
351 | .wMaxPacketSize = 512, | 225 | .wMaxPacketSize = 16, |
352 | .bInterval = 0 | 226 | .bInterval = 0 |
353 | }, | 227 | }, |
354 | { | 228 | { |
355 | .bLength = sizeof(struct usb_endpoint_descriptor), | 229 | .bLength = sizeof(struct usb_endpoint_descriptor), |
356 | .bDescriptorType = USB_DT_ENDPOINT, | 230 | .bDescriptorType = USB_DT_ENDPOINT, |
357 | .bEndpointAddress = EP_TX | USB_DIR_IN, | 231 | .bEndpointAddress = EP_BENCHMARK | USB_DIR_IN, |
358 | .bmAttributes = USB_ENDPOINT_XFER_BULK, | 232 | .bmAttributes = USB_ENDPOINT_XFER_BULK, |
359 | .wMaxPacketSize = 512, | 233 | .wMaxPacketSize = 16, |
360 | .bInterval = 0 | 234 | .bInterval = 0 |
361 | } | 235 | }, |
362 | #endif | 236 | #endif |
363 | }; | 237 | }; |
364 | 238 | ||
@@ -388,13 +262,22 @@ static struct usb_string_descriptor usb_string_iProduct = | |||
388 | {'R','o','c','k','b','o','x',' ','m','e','d','i','a',' ','p','l','a','y','e','r'} | 262 | {'R','o','c','k','b','o','x',' ','m','e','d','i','a',' ','p','l','a','y','e','r'} |
389 | }; | 263 | }; |
390 | 264 | ||
265 | #if defined(HAVE_AS3514) | ||
391 | static struct usb_string_descriptor usb_string_iSerial = | 266 | static struct usb_string_descriptor usb_string_iSerial = |
392 | { | 267 | { |
393 | 34, | 268 | 66, |
394 | USB_DT_STRING, | 269 | USB_DT_STRING, |
395 | {'0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0'} | 270 | {'0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0', |
271 | '0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0'} | ||
396 | }; | 272 | }; |
397 | 273 | #else | |
274 | static struct usb_string_descriptor usb_string_iSerial = | ||
275 | { | ||
276 | 34, | ||
277 | USB_DT_STRING, | ||
278 | {'0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0'} | ||
279 | }; | ||
280 | #endif | ||
398 | 281 | ||
399 | /* Generic for all targets */ | 282 | /* Generic for all targets */ |
400 | 283 | ||
@@ -443,10 +326,25 @@ static long usbcore_stack[DEFAULT_STACK_SIZE]; | |||
443 | static void usb_core_thread(void); | 326 | static void usb_core_thread(void); |
444 | #endif | 327 | #endif |
445 | 328 | ||
446 | static void ack_control(struct usb_ctrlrequest* req); | 329 | static void usb_core_control_request_handler(struct usb_ctrlrequest* req); |
330 | static int ack_control(struct usb_ctrlrequest* req); | ||
331 | |||
332 | static unsigned char *response_data; | ||
333 | static unsigned char __response_data[CACHEALIGN_UP(2)] CACHEALIGN_ATTR; | ||
334 | |||
335 | struct usb_core_event | ||
336 | { | ||
337 | unsigned char endpoint; | ||
338 | bool in; | ||
339 | int status; | ||
340 | int length; | ||
341 | void* data; | ||
342 | }; | ||
343 | |||
344 | static struct usb_core_event events[NUM_ENDPOINTS]; | ||
447 | 345 | ||
448 | #ifdef IPOD_ARCH | 346 | #ifdef IPOD_ARCH |
449 | void set_serial_descriptor(void) | 347 | static void set_serial_descriptor(void) |
450 | { | 348 | { |
451 | static short hex[16] = {'0','1','2','3','4','5','6','7', | 349 | static short hex[16] = {'0','1','2','3','4','5','6','7', |
452 | '8','9','A','B','C','D','E','F'}; | 350 | '8','9','A','B','C','D','E','F'}; |
@@ -471,7 +369,23 @@ void set_serial_descriptor(void) | |||
471 | x >>= 4; | 369 | x >>= 4; |
472 | } | 370 | } |
473 | } | 371 | } |
372 | } | ||
373 | #elif defined(HAVE_AS3514) | ||
374 | static void set_serial_descriptor(void) | ||
375 | { | ||
376 | static short hex[16] = {'0','1','2','3','4','5','6','7', | ||
377 | '8','9','A','B','C','D','E','F'}; | ||
474 | 378 | ||
379 | unsigned char serial[16]; | ||
380 | short* p = usb_string_iSerial.wString; | ||
381 | int i; | ||
382 | |||
383 | i2c_readbytes(AS3514_I2C_ADDR, 0x30, 0x10, serial); | ||
384 | for (i = 0; i < 16; i++) | ||
385 | { | ||
386 | *p++ = hex[(serial[i] >> 4) & 0xF]; | ||
387 | *p++ = hex[(serial[i] >> 0) & 0xF]; | ||
388 | } | ||
475 | } | 389 | } |
476 | #endif | 390 | #endif |
477 | 391 | ||
@@ -480,9 +394,8 @@ void usb_core_init(void) | |||
480 | if (initialized) | 394 | if (initialized) |
481 | return; | 395 | return; |
482 | 396 | ||
483 | #ifdef IPOD_ARCH | 397 | config_data = (void*)UNCACHED_ADDR(&_config_data); |
484 | set_serial_descriptor(); | 398 | response_data = (void*)UNCACHED_ADDR(&__response_data); |
485 | #endif | ||
486 | 399 | ||
487 | queue_init(&usbcore_queue, false); | 400 | queue_init(&usbcore_queue, false); |
488 | usb_drv_init(); | 401 | usb_drv_init(); |
@@ -514,10 +427,11 @@ void usb_core_exit(void) | |||
514 | { | 427 | { |
515 | if (initialized) { | 428 | if (initialized) { |
516 | usb_drv_exit(); | 429 | usb_drv_exit(); |
517 | queue_delete(&usbcore_queue); | ||
518 | #ifdef USB_THREAD | 430 | #ifdef USB_THREAD |
519 | remove_thread(usbcore_thread); | 431 | queue_post(&usbcore_queue, USB_CORE_QUIT, 0); |
432 | thread_wait(usbcore_thread); | ||
520 | #endif | 433 | #endif |
434 | queue_delete(&usbcore_queue); | ||
521 | } | 435 | } |
522 | data_connection = false; | 436 | data_connection = false; |
523 | initialized = false; | 437 | initialized = false; |
@@ -532,25 +446,52 @@ bool usb_core_data_connection(void) | |||
532 | #ifdef USB_THREAD | 446 | #ifdef USB_THREAD |
533 | void usb_core_thread(void) | 447 | void usb_core_thread(void) |
534 | { | 448 | { |
449 | #if defined(IPOD_ARCH) || defined(HAVE_AS3514) | ||
450 | set_serial_descriptor(); | ||
451 | #endif | ||
452 | |||
535 | while (1) { | 453 | while (1) { |
536 | struct queue_event ev; | 454 | struct queue_event ev; |
537 | 455 | ||
538 | queue_wait(&usbcore_queue, &ev); | 456 | queue_wait(&usbcore_queue, &ev); |
457 | if (ev.id == USB_CORE_QUIT) { | ||
458 | cancel_cpu_boost(); | ||
459 | return; | ||
460 | } | ||
539 | 461 | ||
462 | if (ev.id == USB_CORE_TRANSFER_COMPLETION) { | ||
463 | struct usb_core_event* event = (struct usb_core_event*)ev.data; | ||
464 | switch(event->endpoint) { | ||
465 | case EP_CONTROL: | ||
466 | logf("ctrl handled %ld",current_tick); | ||
467 | usb_core_control_request_handler((struct usb_ctrlrequest*)event->data); | ||
468 | break; | ||
540 | #ifdef USB_STORAGE | 469 | #ifdef USB_STORAGE |
541 | usb_storage_transfer_complete(ev.id); | 470 | case EP_MASS_STORAGE: |
471 | usb_storage_transfer_complete(event->in,event->status,event->length); | ||
472 | break; | ||
542 | #endif | 473 | #endif |
543 | |||
544 | #ifdef USB_SERIAL | 474 | #ifdef USB_SERIAL |
545 | usb_serial_transfer_complete(ev.id); | 475 | case EP_SERIAL: |
476 | usb_serial_transfer_complete(event->in,event->status,event->length); | ||
477 | break; | ||
546 | #endif | 478 | #endif |
547 | 479 | #ifdef USB_BENCHMARK | |
480 | case EP_BENCHMARK: | ||
481 | usb_benchmark_transfer_complete(event->in); | ||
482 | break; | ||
483 | #endif | ||
484 | #ifdef USB_CHARGING_ONLY | ||
485 | case EP_CHARGING_ONLY: | ||
486 | break; | ||
487 | #endif | ||
488 | } | ||
489 | } | ||
548 | } | 490 | } |
549 | } | 491 | } |
550 | #endif | 492 | #endif |
551 | 493 | ||
552 | /* called by usb_drv_int() */ | 494 | static void usb_core_control_request_handler(struct usb_ctrlrequest* req) |
553 | void usb_core_control_request(struct usb_ctrlrequest* req) | ||
554 | { | 495 | { |
555 | /* note: interrupt context */ | 496 | /* note: interrupt context */ |
556 | data_connection = true; | 497 | data_connection = true; |
@@ -565,29 +506,31 @@ void usb_core_control_request(struct usb_ctrlrequest* req) | |||
565 | switch (req->bRequest) { | 506 | switch (req->bRequest) { |
566 | case USB_REQ_SET_CONFIGURATION: | 507 | case USB_REQ_SET_CONFIGURATION: |
567 | logf("usb_core: SET_CONFIG"); | 508 | logf("usb_core: SET_CONFIG"); |
509 | usb_drv_cancel_all_transfers(); | ||
510 | if (req->wValue){ | ||
511 | usb_state = CONFIGURED; | ||
568 | #ifdef USB_STORAGE | 512 | #ifdef USB_STORAGE |
569 | usb_storage_control_request(req); | 513 | usb_storage_control_request(req); |
570 | #endif | 514 | #endif |
571 | 515 | ||
572 | #ifdef USB_SERIAL | 516 | #ifdef USB_SERIAL |
573 | usb_serial_control_request(req); | 517 | usb_serial_control_request(req); |
574 | #endif | 518 | #endif |
575 | ack_control(req); | 519 | } |
576 | if (req->wValue) | 520 | else { |
577 | usb_state = CONFIGURED; | ||
578 | else | ||
579 | usb_state = ADDRESS; | 521 | usb_state = ADDRESS; |
522 | } | ||
523 | ack_control(req); | ||
580 | break; | 524 | break; |
581 | 525 | ||
582 | case USB_REQ_GET_CONFIGURATION: { | 526 | case USB_REQ_GET_CONFIGURATION: { |
583 | static char confignum; | ||
584 | char* tmp = (void*)UNCACHED_ADDR(&confignum); | ||
585 | logf("usb_core: GET_CONFIG"); | 527 | logf("usb_core: GET_CONFIG"); |
586 | if (usb_state == ADDRESS) | 528 | if (usb_state == ADDRESS) |
587 | *tmp = 0; | 529 | response_data[0] = 0; |
588 | else | 530 | else |
589 | *tmp = 1; | 531 | response_data[0] = 1; |
590 | usb_drv_send(EP_CONTROL, tmp, 1); | 532 | if(usb_drv_send(EP_CONTROL, response_data, 1)!= 0) |
533 | break; | ||
591 | ack_control(req); | 534 | ack_control(req); |
592 | break; | 535 | break; |
593 | } | 536 | } |
@@ -597,29 +540,54 @@ void usb_core_control_request(struct usb_ctrlrequest* req) | |||
597 | ack_control(req); | 540 | ack_control(req); |
598 | break; | 541 | break; |
599 | 542 | ||
543 | case USB_REQ_GET_INTERFACE: | ||
544 | logf("usb_core: GET_INTERFACE"); | ||
545 | response_data[0] = 0; | ||
546 | if(usb_drv_send(EP_CONTROL, response_data, 1)!=0) | ||
547 | break; | ||
548 | ack_control(req); | ||
549 | break; | ||
600 | case USB_REQ_CLEAR_FEATURE: | 550 | case USB_REQ_CLEAR_FEATURE: |
601 | logf("usb_core: CLEAR_FEATURE"); | 551 | logf("usb_core: CLEAR_FEATURE"); |
602 | if (req->wValue) | 552 | if (req->wValue) |
603 | usb_drv_stall(req->wIndex, true); | 553 | usb_drv_stall(req->wIndex & 0xf, false,(req->wIndex & 0x80) !=0); |
604 | else | 554 | else |
605 | usb_drv_stall(req->wIndex, false); | 555 | usb_drv_stall(req->wIndex & 0xf, false,(req->wIndex & 0x80) !=0); |
606 | ack_control(req); | 556 | ack_control(req); |
607 | break; | 557 | break; |
608 | 558 | ||
609 | case USB_REQ_SET_ADDRESS: | 559 | case USB_REQ_SET_FEATURE: |
610 | usb_address = req->wValue; | 560 | logf("usb_core: SET_FEATURE"); |
611 | logf("usb_core: SET_ADR %d", usb_address); | 561 | if (req->wValue) |
562 | usb_drv_stall(req->wIndex & 0xf, true,(req->wIndex & 0x80) !=0); | ||
563 | else | ||
564 | usb_drv_stall(req->wIndex & 0xf, false,(req->wIndex & 0x80) !=0); | ||
612 | ack_control(req); | 565 | ack_control(req); |
566 | break; | ||
567 | |||
568 | case USB_REQ_SET_ADDRESS: { | ||
569 | unsigned char address = req->wValue; | ||
570 | logf("usb_core: SET_ADR %d", address); | ||
571 | if(ack_control(req)!=0) | ||
572 | break; | ||
573 | usb_drv_cancel_all_transfers(); | ||
574 | usb_address = address; | ||
613 | usb_drv_set_address(usb_address); | 575 | usb_drv_set_address(usb_address); |
614 | usb_state = ADDRESS; | 576 | usb_state = ADDRESS; |
615 | break; | 577 | break; |
578 | } | ||
616 | 579 | ||
617 | case USB_REQ_GET_STATUS: { | 580 | case USB_REQ_GET_STATUS: { |
618 | static char tmp[2] = {0,0}; | 581 | response_data[0]= 0; |
619 | tmp[0] = 0; | 582 | response_data[1]= 0; |
620 | tmp[1] = 0; | ||
621 | logf("usb_core: GET_STATUS"); | 583 | logf("usb_core: GET_STATUS"); |
622 | usb_drv_send(EP_CONTROL, UNCACHED_ADDR(&tmp), 2); | 584 | if(req->wIndex>0) { |
585 | if(usb_drv_stalled(req->wIndex&0xf,(req->wIndex&0x80)!=0)) | ||
586 | response_data[0] = 1; | ||
587 | } | ||
588 | logf("usb_core: %X %X",response_data[0],response_data[1]); | ||
589 | if(usb_drv_send(EP_CONTROL, response_data, 2)!=0) | ||
590 | break; | ||
623 | ack_control(req); | 591 | ack_control(req); |
624 | break; | 592 | break; |
625 | } | 593 | } |
@@ -637,18 +605,59 @@ void usb_core_control_request(struct usb_ctrlrequest* req) | |||
637 | size = sizeof device_descriptor; | 605 | size = sizeof device_descriptor; |
638 | break; | 606 | break; |
639 | 607 | ||
640 | case USB_DT_CONFIG: | 608 | case USB_DT_OTHER_SPEED_CONFIG: |
641 | if(usb_drv_port_speed()) | 609 | case USB_DT_CONFIG: { |
642 | { | 610 | int max_packet_size; |
643 | ptr = &config_data_hs; | 611 | int interface_number=0; |
644 | size = sizeof config_data_hs; | 612 | |
613 | if(req->wValue >> 8 == USB_DT_CONFIG) { | ||
614 | if(usb_drv_port_speed()) { | ||
615 | max_packet_size=512; | ||
616 | } | ||
617 | else { | ||
618 | max_packet_size=64; | ||
619 | } | ||
620 | config_data->config_descriptor.bDescriptorType=USB_DT_CONFIG; | ||
645 | } | 621 | } |
646 | else | 622 | else { |
647 | { | 623 | if(usb_drv_port_speed()) { |
648 | ptr = &config_data_fs; | 624 | max_packet_size=64; |
649 | size = sizeof config_data_fs; | 625 | } |
626 | else { | ||
627 | max_packet_size=512; | ||
628 | } | ||
629 | config_data->config_descriptor.bDescriptorType=USB_DT_OTHER_SPEED_CONFIG; | ||
650 | } | 630 | } |
631 | |||
632 | #ifdef USB_CHARGING_ONLY | ||
633 | memcpy(&config_data->charging_ep_in_descriptor.wMaxPacketSize,&max_packet_size,sizeof(unsigned short)); | ||
634 | memcpy(&config_data->charging_ep_out_descriptor.wMaxPacketSize,&max_packet_size,sizeof(unsigned short)); | ||
635 | config_data->charging_interface_descriptor.bInterfaceNumber=interface_number; | ||
636 | interface_number++; | ||
637 | #endif | ||
638 | #ifdef USB_STORAGE | ||
639 | memcpy(&config_data->mass_storage_ep_in_descriptor.wMaxPacketSize,&max_packet_size,sizeof(unsigned short)); | ||
640 | memcpy(&config_data->mass_storage_ep_out_descriptor.wMaxPacketSize,&max_packet_size,sizeof(unsigned short)); | ||
641 | config_data->mass_storage_interface_descriptor.bInterfaceNumber=interface_number; | ||
642 | interface_number++; | ||
643 | #endif | ||
644 | #ifdef USB_SERIAL | ||
645 | memcpy(&config_data->serial_ep_in_descriptor.wMaxPacketSize,&max_packet_size,sizeof(unsigned short)); | ||
646 | memcpy(&config_data->serial_ep_out_descriptor.wMaxPacketSize,&max_packet_size,sizeof(unsigned short)); | ||
647 | config_data->serial_interface_descriptor.bInterfaceNumber=interface_number; | ||
648 | interface_number++; | ||
649 | #endif | ||
650 | #ifdef USB_BENCHMARK | ||
651 | memcpy(&config_data->benchmark_ep_in_descriptor.wMaxPacketSize,&max_packet_size,sizeof(unsigned short)); | ||
652 | memcpy(&config_data->benchmark_ep_out_descriptor.wMaxPacketSize,&max_packet_size,sizeof(unsigned short)); | ||
653 | config_data.benchmark_interface_descriptor.bInterfaceNumber=interface_number; | ||
654 | interface_number++; | ||
655 | #endif | ||
656 | config_data->config_descriptor.bNumInterfaces=interface_number; | ||
657 | ptr = config_data; | ||
658 | size = sizeof _config_data; | ||
651 | break; | 659 | break; |
660 | } | ||
652 | 661 | ||
653 | case USB_DT_STRING: | 662 | case USB_DT_STRING: |
654 | if ((unsigned)index < (sizeof(usb_strings)/sizeof(struct usb_string_descriptor*))) { | 663 | if ((unsigned)index < (sizeof(usb_strings)/sizeof(struct usb_string_descriptor*))) { |
@@ -657,7 +666,7 @@ void usb_core_control_request(struct usb_ctrlrequest* req) | |||
657 | } | 666 | } |
658 | else { | 667 | else { |
659 | logf("bad string id %d", index); | 668 | logf("bad string id %d", index); |
660 | usb_drv_stall(EP_CONTROL, true); | 669 | usb_drv_stall(EP_CONTROL, true,true); |
661 | } | 670 | } |
662 | break; | 671 | break; |
663 | 672 | ||
@@ -668,13 +677,14 @@ void usb_core_control_request(struct usb_ctrlrequest* req) | |||
668 | 677 | ||
669 | default: | 678 | default: |
670 | logf("bad desc %d", req->wValue >> 8); | 679 | logf("bad desc %d", req->wValue >> 8); |
671 | usb_drv_stall(EP_CONTROL, true); | 680 | usb_drv_stall(EP_CONTROL, true,true); |
672 | break; | 681 | break; |
673 | } | 682 | } |
674 | 683 | ||
675 | if (ptr) { | 684 | if (ptr) { |
676 | length = MIN(size, length); | 685 | length = MIN(size, length); |
677 | usb_drv_send(EP_CONTROL, (void*)UNCACHED_ADDR(ptr), length); | 686 | if(usb_drv_send(EP_CONTROL, (void*)UNCACHED_ADDR(ptr), length)!=0) |
687 | break; | ||
678 | } | 688 | } |
679 | ack_control(req); | 689 | ack_control(req); |
680 | break; | 690 | break; |
@@ -693,7 +703,7 @@ void usb_core_control_request(struct usb_ctrlrequest* req) | |||
693 | { | 703 | { |
694 | /* nope. flag error */ | 704 | /* nope. flag error */ |
695 | logf("usb bad req %d", req->bRequest); | 705 | logf("usb bad req %d", req->bRequest); |
696 | usb_drv_stall(EP_CONTROL, true); | 706 | usb_drv_stall(EP_CONTROL, true,true); |
697 | ack_control(req); | 707 | ack_control(req); |
698 | } | 708 | } |
699 | break; | 709 | break; |
@@ -709,9 +719,9 @@ void usb_core_bus_reset(void) | |||
709 | } | 719 | } |
710 | 720 | ||
711 | /* called by usb_drv_transfer_completed() */ | 721 | /* called by usb_drv_transfer_completed() */ |
712 | void usb_core_transfer_complete(int endpoint, bool in) | 722 | void usb_core_transfer_complete(int endpoint, bool in, int status,int length) |
713 | { | 723 | { |
714 | #ifdef USB_CHARGING_ONLY | 724 | #if defined(USB_CHARGING_ONLY) || defined(USB_STORAGE) |
715 | (void)in; | 725 | (void)in; |
716 | #endif | 726 | #endif |
717 | 727 | ||
@@ -720,25 +730,35 @@ void usb_core_transfer_complete(int endpoint, bool in) | |||
720 | /* already handled */ | 730 | /* already handled */ |
721 | break; | 731 | break; |
722 | 732 | ||
723 | case EP_RX: | ||
724 | case EP_TX: | ||
725 | #if defined(USB_BENCHMARK) | ||
726 | usb_benchmark_transfer_complete(endpoint, in); | ||
727 | #elif defined(USB_STORAGE) || defined(USB_SERIAL) | ||
728 | queue_post(&usbcore_queue, endpoint, 0); | ||
729 | #endif | ||
730 | break; | ||
731 | |||
732 | default: | 733 | default: |
734 | events[endpoint].endpoint=endpoint; | ||
735 | events[endpoint].in=in; | ||
736 | events[endpoint].data=0; | ||
737 | events[endpoint].status=status; | ||
738 | events[endpoint].length=length; | ||
739 | /* All other endoints. Let the thread deal with it */ | ||
740 | queue_post(&usbcore_queue, USB_CORE_TRANSFER_COMPLETION, (intptr_t)&events[endpoint]); | ||
733 | break; | 741 | break; |
734 | } | 742 | } |
735 | } | 743 | } |
736 | 744 | ||
737 | static void ack_control(struct usb_ctrlrequest* req) | 745 | /* called by usb_drv_int() */ |
746 | void usb_core_control_request(struct usb_ctrlrequest* req) | ||
747 | { | ||
748 | events[0].endpoint=0; | ||
749 | events[0].in=0; | ||
750 | events[0].data=(void *)req; | ||
751 | events[0].status=0; | ||
752 | events[0].length=0; | ||
753 | logf("ctrl received %ld",current_tick); | ||
754 | queue_post(&usbcore_queue, USB_CORE_TRANSFER_COMPLETION,(intptr_t)&events[0]); | ||
755 | } | ||
756 | |||
757 | static int ack_control(struct usb_ctrlrequest* req) | ||
738 | { | 758 | { |
739 | if (req->bRequestType & 0x80) | 759 | if (req->bRequestType & 0x80) |
740 | usb_drv_recv(EP_CONTROL, NULL, 0); | 760 | return usb_drv_recv(EP_CONTROL, NULL, 0); |
741 | else | 761 | else |
742 | usb_drv_send(EP_CONTROL, NULL, 0); | 762 | return usb_drv_send(EP_CONTROL, NULL, 0); |
743 | } | 763 | } |
744 | 764 | ||
diff --git a/firmware/usbstack/usb_serial.c b/firmware/usbstack/usb_serial.c index 5513c56910..77878092d7 100644 --- a/firmware/usbstack/usb_serial.c +++ b/firmware/usbstack/usb_serial.c | |||
@@ -23,6 +23,8 @@ | |||
23 | //#define LOGF_ENABLE | 23 | //#define LOGF_ENABLE |
24 | #include "logf.h" | 24 | #include "logf.h" |
25 | 25 | ||
26 | #ifdef USB_SERIAL | ||
27 | |||
26 | static unsigned char _transfer_buffer[16]; | 28 | static unsigned char _transfer_buffer[16]; |
27 | static unsigned char* transfer_buffer; | 29 | static unsigned char* transfer_buffer; |
28 | 30 | ||
@@ -34,20 +36,26 @@ void usb_serial_init(void) | |||
34 | } | 36 | } |
35 | 37 | ||
36 | /* called by usb_core_transfer_complete() */ | 38 | /* called by usb_core_transfer_complete() */ |
37 | void usb_serial_transfer_complete(int endpoint) | 39 | void usb_serial_transfer_complete(bool in, int status, int length) |
38 | { | 40 | { |
39 | switch (endpoint) { | 41 | int i; |
40 | case EP_RX: | 42 | switch (in) { |
43 | case false: | ||
41 | logf("serial: %s", transfer_buffer); | 44 | logf("serial: %s", transfer_buffer); |
42 | 45 | /* Data received. Send it back */ | |
43 | /* re-prime endpoint */ | 46 | for(i=0;i<length;i++) { |
44 | usb_drv_recv(EP_RX, transfer_buffer, sizeof _transfer_buffer); | 47 | if(transfer_buffer[i]>0x40 && transfer_buffer[i]<0x5b) |
45 | 48 | transfer_buffer[i]+=0x20; | |
46 | /* echo back :) */ | 49 | else if(transfer_buffer[i]>0x60 && transfer_buffer[i]<0x7b) |
47 | usb_drv_send(EP_TX, transfer_buffer, sizeof transfer_buffer); | 50 | transfer_buffer[i]-=0x20; |
51 | } | ||
52 | usb_drv_send_nonblocking(EP_SERIAL, transfer_buffer, length); | ||
48 | break; | 53 | break; |
49 | 54 | ||
50 | case EP_TX: | 55 | case true: |
56 | /* Data sent out (maybe correctly, but we don't actually care. | ||
57 | * Re-prime read endpoint */ | ||
58 | usb_drv_recv(EP_SERIAL, transfer_buffer, sizeof _transfer_buffer); | ||
51 | break; | 59 | break; |
52 | } | 60 | } |
53 | } | 61 | } |
@@ -55,14 +63,12 @@ void usb_serial_transfer_complete(int endpoint) | |||
55 | /* called by usb_core_control_request() */ | 63 | /* called by usb_core_control_request() */ |
56 | bool usb_serial_control_request(struct usb_ctrlrequest* req) | 64 | bool usb_serial_control_request(struct usb_ctrlrequest* req) |
57 | { | 65 | { |
58 | /* note: interrupt context */ | ||
59 | |||
60 | bool handled = false; | 66 | bool handled = false; |
61 | switch (req->bRequest) { | 67 | switch (req->bRequest) { |
62 | case USB_REQ_SET_CONFIGURATION: | 68 | case USB_REQ_SET_CONFIGURATION: |
63 | logf("serial: set config"); | 69 | logf("serial: set config"); |
64 | /* prime rx endpoint */ | 70 | /* prime rx endpoint */ |
65 | usb_drv_recv(EP_RX, transfer_buffer, sizeof _transfer_buffer); | 71 | usb_drv_recv(EP_SERIAL, transfer_buffer, sizeof _transfer_buffer); |
66 | handled = true; | 72 | handled = true; |
67 | break; | 73 | break; |
68 | 74 | ||
@@ -72,3 +78,5 @@ bool usb_serial_control_request(struct usb_ctrlrequest* req) | |||
72 | 78 | ||
73 | return handled; | 79 | return handled; |
74 | } | 80 | } |
81 | |||
82 | #endif /*USB_SERIAL*/ | ||
diff --git a/firmware/usbstack/usb_serial.h b/firmware/usbstack/usb_serial.h index d6f970bc9f..60cede9bda 100644 --- a/firmware/usbstack/usb_serial.h +++ b/firmware/usbstack/usb_serial.h | |||
@@ -22,7 +22,7 @@ | |||
22 | #include "usb_ch9.h" | 22 | #include "usb_ch9.h" |
23 | 23 | ||
24 | void usb_serial_init(void); | 24 | void usb_serial_init(void); |
25 | void usb_serial_transfer_complete(int endpoint); | 25 | void usb_serial_transfer_complete(bool in, int status, int length); |
26 | bool usb_serial_control_request(struct usb_ctrlrequest* req); | 26 | bool usb_serial_control_request(struct usb_ctrlrequest* req); |
27 | 27 | ||
28 | #endif | 28 | #endif |
diff --git a/firmware/usbstack/usb_storage.c b/firmware/usbstack/usb_storage.c index a1faf3d1c4..0904e17e75 100644 --- a/firmware/usbstack/usb_storage.c +++ b/firmware/usbstack/usb_storage.c | |||
@@ -26,8 +26,22 @@ | |||
26 | #include "hotswap.h" | 26 | #include "hotswap.h" |
27 | #include "disk.h" | 27 | #include "disk.h" |
28 | 28 | ||
29 | #ifdef USB_STORAGE | ||
30 | |||
31 | /* Enable the following define to export only the SD card slot. This | ||
32 | * is useful for USBCV MSC tests, as those are destructive. | ||
33 | * This won't work right if the device doesn't have a card slot. | ||
34 | */ | ||
35 | //#define ONLY_EXPOSE_CARD_SLOT | ||
36 | |||
29 | #define SECTOR_SIZE 512 | 37 | #define SECTOR_SIZE 512 |
30 | 38 | ||
39 | /* We can currently use up to 20k buffer size. More than that requires | ||
40 | * transfer chaining in the driver. Tests on sansa c200 show that the 16k | ||
41 | * limitation causes no more than 2% slowdown. | ||
42 | */ | ||
43 | #define BUFFER_SIZE 16384 | ||
44 | |||
31 | /* bulk-only class specific requests */ | 45 | /* bulk-only class specific requests */ |
32 | #define USB_BULK_RESET_REQUEST 0xff | 46 | #define USB_BULK_RESET_REQUEST 0xff |
33 | #define USB_BULK_GET_MAX_LUN 0xfe | 47 | #define USB_BULK_GET_MAX_LUN 0xfe |
@@ -40,7 +54,8 @@ | |||
40 | 54 | ||
41 | #define SCSI_TEST_UNIT_READY 0x00 | 55 | #define SCSI_TEST_UNIT_READY 0x00 |
42 | #define SCSI_INQUIRY 0x12 | 56 | #define SCSI_INQUIRY 0x12 |
43 | #define SCSI_MODE_SENSE 0x1a | 57 | #define SCSI_MODE_SENSE_6 0x1a |
58 | #define SCSI_MODE_SENSE_10 0x5a | ||
44 | #define SCSI_REQUEST_SENSE 0x03 | 59 | #define SCSI_REQUEST_SENSE 0x03 |
45 | #define SCSI_ALLOW_MEDIUM_REMOVAL 0x1e | 60 | #define SCSI_ALLOW_MEDIUM_REMOVAL 0x1e |
46 | #define SCSI_READ_CAPACITY 0x25 | 61 | #define SCSI_READ_CAPACITY 0x25 |
@@ -48,11 +63,23 @@ | |||
48 | #define SCSI_READ_10 0x28 | 63 | #define SCSI_READ_10 0x28 |
49 | #define SCSI_WRITE_10 0x2a | 64 | #define SCSI_WRITE_10 0x2a |
50 | #define SCSI_START_STOP_UNIT 0x1b | 65 | #define SCSI_START_STOP_UNIT 0x1b |
66 | #define SCSI_REPORT_LUNS 0xa0 | ||
51 | 67 | ||
52 | #define SCSI_STATUS_GOOD 0x00 | 68 | #define SCSI_STATUS_GOOD 0x00 |
53 | #define SCSI_STATUS_FAIL 0x01 | 69 | #define SCSI_STATUS_FAIL 0x01 |
54 | #define SCSI_STATUS_CHECK_CONDITION 0x02 | 70 | #define SCSI_STATUS_CHECK_CONDITION 0x02 |
55 | 71 | ||
72 | #define SENSE_NOT_READY 0x02 | ||
73 | #define SENSE_MEDIUM_ERROR 0x03 | ||
74 | #define SENSE_ILLEGAL_REQUEST 0x05 | ||
75 | #define SENSE_UNIT_ATTENTION 0x06 | ||
76 | |||
77 | #define ASC_MEDIUM_NOT_PRESENT 0x3a | ||
78 | #define ASC_INVALID_FIELD_IN_CBD 0x24 | ||
79 | #define ASC_LBA_OUT_OF_RANGE 0x21 | ||
80 | #define ASC_WRITE_ERROR 0x0C | ||
81 | #define ASC_READ_ERROR 0x11 | ||
82 | |||
56 | #define SCSI_FORMAT_CAPACITY_FORMATTED_MEDIA 0x02000000 | 83 | #define SCSI_FORMAT_CAPACITY_FORMATTED_MEDIA 0x02000000 |
57 | 84 | ||
58 | 85 | ||
@@ -69,6 +96,15 @@ struct inquiry_data { | |||
69 | unsigned char ProductRevisionLevel[4]; | 96 | unsigned char ProductRevisionLevel[4]; |
70 | } __attribute__ ((packed)); | 97 | } __attribute__ ((packed)); |
71 | 98 | ||
99 | struct report_lun_data { | ||
100 | unsigned int lun_list_length; | ||
101 | unsigned int reserved1; | ||
102 | unsigned char lun0[8]; | ||
103 | #ifdef HAVE_HOTSWAP | ||
104 | unsigned char lun1[8]; | ||
105 | #endif | ||
106 | } __attribute__ ((packed)); | ||
107 | |||
72 | struct sense_data { | 108 | struct sense_data { |
73 | unsigned char ResponseCode; | 109 | unsigned char ResponseCode; |
74 | unsigned char Obsolete; | 110 | unsigned char Obsolete; |
@@ -83,6 +119,21 @@ struct sense_data { | |||
83 | unsigned short SenseKeySpecific; | 119 | unsigned short SenseKeySpecific; |
84 | } __attribute__ ((packed)); | 120 | } __attribute__ ((packed)); |
85 | 121 | ||
122 | struct mode_sense_header_10 { | ||
123 | unsigned short mode_data_length; | ||
124 | unsigned char medium_type; | ||
125 | unsigned char device_specific; | ||
126 | unsigned char reserved1[2]; | ||
127 | unsigned short block_descriptor_length; | ||
128 | } __attribute__ ((packed)); | ||
129 | |||
130 | struct mode_sense_header_6 { | ||
131 | unsigned char mode_data_length; | ||
132 | unsigned char medium_type; | ||
133 | unsigned char device_specific; | ||
134 | unsigned char block_descriptor_length; | ||
135 | } __attribute__ ((packed)); | ||
136 | |||
86 | struct command_block_wrapper { | 137 | struct command_block_wrapper { |
87 | unsigned int signature; | 138 | unsigned int signature; |
88 | unsigned int tag; | 139 | unsigned int tag; |
@@ -111,93 +162,195 @@ struct format_capacity { | |||
111 | unsigned int block_size; | 162 | unsigned int block_size; |
112 | } __attribute__ ((packed)); | 163 | } __attribute__ ((packed)); |
113 | 164 | ||
114 | /* the ARC USB controller can at most buffer 16KB unaligned data */ | 165 | static unsigned char _transfer_buffer[2*BUFFER_SIZE] __attribute((aligned (4096))); |
115 | static unsigned char _transfer_buffer[16384*8] __attribute((aligned (4096))); | ||
116 | static unsigned char* transfer_buffer; | 166 | static unsigned char* transfer_buffer; |
117 | static struct inquiry_data _inquiry CACHEALIGN_ATTR; | 167 | |
118 | static struct inquiry_data* inquiry; | 168 | static struct inquiry_data* inquiry; |
119 | static struct capacity _capacity_data CACHEALIGN_ATTR; | 169 | static unsigned char __inquiry[CACHEALIGN_UP(sizeof(struct inquiry_data))] CACHEALIGN_ATTR; |
170 | |||
120 | static struct capacity* capacity_data; | 171 | static struct capacity* capacity_data; |
121 | static struct format_capacity _format_capacity_data CACHEALIGN_ATTR; | 172 | static unsigned char __capacity_data[CACHEALIGN_UP(sizeof(struct capacity))] CACHEALIGN_ATTR; |
173 | |||
122 | static struct format_capacity* format_capacity_data; | 174 | static struct format_capacity* format_capacity_data; |
123 | static struct sense_data _sense_data CACHEALIGN_ATTR; | 175 | static unsigned char __format_capacity_data[CACHEALIGN_UP(sizeof(struct format_capacity))] CACHEALIGN_ATTR; |
176 | |||
124 | static struct sense_data *sense_data; | 177 | static struct sense_data *sense_data; |
178 | static unsigned char __sense_data[CACHEALIGN_UP(sizeof(struct sense_data))] CACHEALIGN_ATTR; | ||
179 | |||
180 | static struct mode_sense_header_6 *mode_sense_data_6; | ||
181 | static unsigned char __mode_sense_data_6[CACHEALIGN_UP(sizeof(struct mode_sense_header_6))] CACHEALIGN_ATTR; | ||
182 | |||
183 | static struct mode_sense_header_10 *mode_sense_data_10; | ||
184 | static unsigned char __mode_sense_data_10[CACHEALIGN_UP(sizeof(struct mode_sense_header_10))] CACHEALIGN_ATTR; | ||
185 | |||
186 | static struct report_lun_data *lun_data; | ||
187 | static unsigned char __lun_data[CACHEALIGN_UP(sizeof(struct report_lun_data))] CACHEALIGN_ATTR; | ||
188 | |||
189 | static struct command_status_wrapper* csw; | ||
190 | static unsigned char __csw[CACHEALIGN_UP(sizeof(struct command_status_wrapper))] CACHEALIGN_ATTR; | ||
191 | |||
192 | static char *max_lun; | ||
193 | static unsigned char __max_lun[CACHEALIGN_UP(1)] CACHEALIGN_ATTR; | ||
125 | 194 | ||
126 | static struct { | 195 | static struct { |
127 | unsigned int sector; | 196 | unsigned int sector; |
128 | unsigned int count; | 197 | unsigned int count; |
129 | unsigned int tag; | 198 | unsigned int tag; |
130 | unsigned int lun; | 199 | unsigned int lun; |
200 | unsigned char *data[2]; | ||
201 | unsigned char data_select; | ||
202 | unsigned int last_result; | ||
131 | } current_cmd; | 203 | } current_cmd; |
132 | 204 | ||
205 | static struct { | ||
206 | unsigned char sense_key; | ||
207 | unsigned char information; | ||
208 | unsigned char asc; | ||
209 | } cur_sense_data; | ||
210 | |||
133 | static void handle_scsi(struct command_block_wrapper* cbw); | 211 | static void handle_scsi(struct command_block_wrapper* cbw); |
134 | static void send_csw(unsigned int tag, int status); | 212 | static void send_csw(int status); |
213 | static void send_command_result(void *data,int size); | ||
214 | static void send_block_data(void *data,int size); | ||
215 | static void receive_block_data(void *data,int size); | ||
135 | static void identify2inquiry(int lun); | 216 | static void identify2inquiry(int lun); |
217 | static void send_and_read_next(void); | ||
136 | 218 | ||
137 | static enum { | 219 | static enum { |
138 | IDLE, | 220 | WAITING_FOR_COMMAND, |
139 | SENDING, | 221 | SENDING_BLOCKS, |
140 | RECEIVING | 222 | SENDING_RESULT, |
141 | } state = IDLE; | 223 | RECEIVING_BLOCKS, |
224 | SENDING_CSW | ||
225 | } state = WAITING_FOR_COMMAND; | ||
142 | 226 | ||
143 | /* called by usb_code_init() */ | 227 | /* called by usb_code_init() */ |
144 | void usb_storage_init(void) | 228 | void usb_storage_init(void) |
145 | { | 229 | { |
146 | inquiry = (void*)UNCACHED_ADDR(&_inquiry); | ||
147 | transfer_buffer = (void*)UNCACHED_ADDR(&_transfer_buffer); | 230 | transfer_buffer = (void*)UNCACHED_ADDR(&_transfer_buffer); |
148 | capacity_data = (void*)UNCACHED_ADDR(&_capacity_data); | 231 | inquiry = (void*)UNCACHED_ADDR(&__inquiry); |
149 | format_capacity_data = (void*)UNCACHED_ADDR(&_format_capacity_data); | 232 | capacity_data = (void*)UNCACHED_ADDR(&__capacity_data); |
150 | sense_data = (void*)UNCACHED_ADDR(&_sense_data); | 233 | format_capacity_data = (void*)UNCACHED_ADDR(&__format_capacity_data); |
151 | state = IDLE; | 234 | sense_data = (void*)UNCACHED_ADDR(&__sense_data); |
235 | mode_sense_data_6 = (void*)UNCACHED_ADDR(&__mode_sense_data_6); | ||
236 | mode_sense_data_10 = (void*)UNCACHED_ADDR(&__mode_sense_data_10); | ||
237 | lun_data = (void*)UNCACHED_ADDR(&__lun_data); | ||
238 | max_lun = (void*)UNCACHED_ADDR(&__max_lun); | ||
239 | csw = (void*)UNCACHED_ADDR(&__csw); | ||
152 | logf("usb_storage_init done"); | 240 | logf("usb_storage_init done"); |
153 | } | 241 | } |
154 | 242 | ||
155 | /* called by usb_core_transfer_complete() */ | 243 | /* called by usb_core_transfer_complete() */ |
156 | void usb_storage_transfer_complete(int endpoint) | 244 | void usb_storage_transfer_complete(bool in,int status,int length) |
157 | { | 245 | { |
158 | struct command_block_wrapper* cbw = (void*)transfer_buffer; | 246 | struct command_block_wrapper* cbw = (void*)transfer_buffer; |
159 | 247 | ||
160 | switch (endpoint) { | 248 | //logf("transfer result %X %d", status, length); |
161 | case EP_RX: | 249 | switch(state) { |
162 | //logf("ums: %d bytes in", length); | 250 | case RECEIVING_BLOCKS: |
163 | if(state == RECEIVING) | 251 | if(in==true) { |
164 | { | 252 | logf("IN received in RECEIVING"); |
165 | int receive_count=usb_drv_get_last_transfer_length(); | 253 | } |
166 | logf("scsi write %d %d", current_cmd.sector, current_cmd.count); | 254 | logf("scsi write %d %d", current_cmd.sector, current_cmd.count); |
167 | if(usb_drv_get_last_transfer_status()==0) | 255 | if(status==0) { |
168 | { | 256 | if((unsigned int)length!=(SECTOR_SIZE*current_cmd.count) |
169 | if((unsigned int)receive_count!=(SECTOR_SIZE*current_cmd.count)) | 257 | && (unsigned int)length!=BUFFER_SIZE) { |
170 | { | 258 | logf("unexpected length :%d",length); |
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 | } | 259 | } |
178 | else | 260 | |
179 | { | 261 | unsigned int next_sector = current_cmd.sector + (BUFFER_SIZE/SECTOR_SIZE); |
180 | logf("Transfer failed %X",usb_drv_get_last_transfer_status()); | 262 | unsigned int next_count = current_cmd.count - MIN(current_cmd.count,BUFFER_SIZE/SECTOR_SIZE); |
181 | send_csw(current_cmd.tag, SCSI_STATUS_CHECK_CONDITION); | 263 | |
264 | if(next_count!=0) { | ||
265 | /* Ask the host to send more, to the other buffer */ | ||
266 | receive_block_data(current_cmd.data[!current_cmd.data_select], | ||
267 | MIN(BUFFER_SIZE,next_count*SECTOR_SIZE)); | ||
182 | } | 268 | } |
269 | |||
270 | /* Now write the data that just came in, while the host is sending the next bit */ | ||
271 | int result = ata_write_sectors(IF_MV2(current_cmd.lun,) | ||
272 | current_cmd.sector, MIN(BUFFER_SIZE/SECTOR_SIZE,current_cmd.count), | ||
273 | current_cmd.data[current_cmd.data_select]); | ||
274 | if(result != 0) { | ||
275 | send_csw(SCSI_STATUS_CHECK_CONDITION); | ||
276 | cur_sense_data.sense_key=SENSE_MEDIUM_ERROR; | ||
277 | cur_sense_data.asc=ASC_WRITE_ERROR; | ||
278 | break; | ||
279 | } | ||
280 | |||
281 | if(next_count==0) { | ||
282 | send_csw(SCSI_STATUS_GOOD); | ||
283 | } | ||
284 | |||
285 | /* Switch buffers for the next one */ | ||
286 | current_cmd.data_select=!current_cmd.data_select; | ||
287 | |||
288 | current_cmd.sector = next_sector; | ||
289 | current_cmd.count = next_count; | ||
290 | |||
183 | } | 291 | } |
184 | else | 292 | else { |
185 | { | 293 | logf("Transfer failed %X",status); |
186 | state = SENDING; | 294 | send_csw(SCSI_STATUS_CHECK_CONDITION); |
187 | handle_scsi(cbw); | 295 | /* TODO fill in cur_sense_data */ |
296 | cur_sense_data.sense_key=0; | ||
297 | cur_sense_data.information=0; | ||
298 | cur_sense_data.asc=0; | ||
188 | } | 299 | } |
189 | |||
190 | break; | 300 | break; |
191 | 301 | case WAITING_FOR_COMMAND: | |
192 | case EP_TX: | 302 | if(in==true) { |
193 | //logf("ums: out complete"); | 303 | logf("IN received in WAITING_FOR_COMMAND"); |
194 | if(state != IDLE) | 304 | } |
195 | { | 305 | //logf("command received"); |
196 | /* re-prime endpoint. We only need room for commands */ | 306 | handle_scsi(cbw); |
197 | state = IDLE; | 307 | break; |
198 | usb_drv_recv(EP_RX, transfer_buffer, 1024); | 308 | case SENDING_CSW: |
309 | if(in==false) { | ||
310 | logf("OUT received in SENDING_CSW"); | ||
311 | } | ||
312 | //logf("csw sent, now go back to idle"); | ||
313 | state = WAITING_FOR_COMMAND; | ||
314 | usb_drv_recv(EP_MASS_STORAGE, transfer_buffer, 1024); | ||
315 | break; | ||
316 | case SENDING_RESULT: | ||
317 | if(in==false) { | ||
318 | logf("OUT received in SENDING"); | ||
319 | } | ||
320 | if(status==0) { | ||
321 | //logf("data sent, now send csw"); | ||
322 | send_csw(SCSI_STATUS_GOOD); | ||
323 | } | ||
324 | else { | ||
325 | logf("Transfer failed %X",status); | ||
326 | send_csw(SCSI_STATUS_CHECK_CONDITION); | ||
327 | /* TODO fill in cur_sense_data */ | ||
328 | cur_sense_data.sense_key=0; | ||
329 | cur_sense_data.information=0; | ||
330 | cur_sense_data.asc=0; | ||
331 | } | ||
332 | break; | ||
333 | case SENDING_BLOCKS: | ||
334 | if(in==false) { | ||
335 | logf("OUT received in SENDING"); | ||
336 | } | ||
337 | if(status==0) { | ||
338 | if(current_cmd.count==0) { | ||
339 | //logf("data sent, now send csw"); | ||
340 | send_csw(SCSI_STATUS_GOOD); | ||
341 | } | ||
342 | else { | ||
343 | send_and_read_next(); | ||
344 | } | ||
345 | } | ||
346 | else { | ||
347 | logf("Transfer failed %X",status); | ||
348 | send_csw(SCSI_STATUS_CHECK_CONDITION); | ||
349 | /* TODO fill in cur_sense_data */ | ||
350 | cur_sense_data.sense_key=0; | ||
351 | cur_sense_data.information=0; | ||
352 | cur_sense_data.asc=0; | ||
199 | } | 353 | } |
200 | |||
201 | break; | 354 | break; |
202 | } | 355 | } |
203 | } | 356 | } |
@@ -205,15 +358,24 @@ void usb_storage_transfer_complete(int endpoint) | |||
205 | /* called by usb_core_control_request() */ | 358 | /* called by usb_core_control_request() */ |
206 | bool usb_storage_control_request(struct usb_ctrlrequest* req) | 359 | bool usb_storage_control_request(struct usb_ctrlrequest* req) |
207 | { | 360 | { |
208 | /* note: interrupt context */ | ||
209 | |||
210 | bool handled = false; | 361 | bool handled = false; |
211 | 362 | ||
212 | switch (req->bRequest) { | 363 | switch (req->bRequest) { |
213 | case USB_BULK_GET_MAX_LUN: { | 364 | case USB_BULK_GET_MAX_LUN: { |
214 | static char maxlun = NUM_VOLUMES - 1; | 365 | #ifdef ONLY_EXPOSE_CARD_SLOT |
366 | *max_lun = 0; | ||
367 | #else | ||
368 | *max_lun = NUM_VOLUMES - 1; | ||
369 | #endif | ||
370 | #ifdef HAVE_HOTSWAP | ||
371 | /* Workaround until we find out how to do removable devices properly */ | ||
372 | tCardInfo* cinfo = card_get_info(1); | ||
373 | if(cinfo->initialized==0) { | ||
374 | *max_lun=0; | ||
375 | } | ||
376 | #endif | ||
215 | logf("ums: getmaxlun"); | 377 | logf("ums: getmaxlun"); |
216 | usb_drv_send(EP_CONTROL, UNCACHED_ADDR(&maxlun), 1); | 378 | usb_drv_send(EP_CONTROL, UNCACHED_ADDR(max_lun), 1); |
217 | usb_drv_recv(EP_CONTROL, NULL, 0); /* ack */ | 379 | usb_drv_recv(EP_CONTROL, NULL, 0); /* ack */ |
218 | handled = true; | 380 | handled = true; |
219 | break; | 381 | break; |
@@ -221,8 +383,8 @@ bool usb_storage_control_request(struct usb_ctrlrequest* req) | |||
221 | 383 | ||
222 | case USB_BULK_RESET_REQUEST: | 384 | case USB_BULK_RESET_REQUEST: |
223 | logf("ums: bulk reset"); | 385 | logf("ums: bulk reset"); |
224 | usb_drv_reset_endpoint(EP_RX, false); | 386 | usb_drv_reset_endpoint(EP_MASS_STORAGE, false); |
225 | usb_drv_reset_endpoint(EP_TX, true); | 387 | usb_drv_reset_endpoint(EP_MASS_STORAGE, true); |
226 | usb_drv_send(EP_CONTROL, NULL, 0); /* ack */ | 388 | usb_drv_send(EP_CONTROL, NULL, 0); /* ack */ |
227 | handled = true; | 389 | handled = true; |
228 | break; | 390 | break; |
@@ -230,8 +392,8 @@ bool usb_storage_control_request(struct usb_ctrlrequest* req) | |||
230 | case USB_REQ_SET_CONFIGURATION: | 392 | case USB_REQ_SET_CONFIGURATION: |
231 | logf("ums: set config"); | 393 | logf("ums: set config"); |
232 | /* prime rx endpoint. We only need room for commands */ | 394 | /* prime rx endpoint. We only need room for commands */ |
233 | state = IDLE; | 395 | state = WAITING_FOR_COMMAND; |
234 | usb_drv_recv(EP_RX, transfer_buffer, 1024); | 396 | usb_drv_recv(EP_MASS_STORAGE, transfer_buffer, 1024); |
235 | handled = true; | 397 | handled = true; |
236 | break; | 398 | break; |
237 | } | 399 | } |
@@ -239,6 +401,32 @@ bool usb_storage_control_request(struct usb_ctrlrequest* req) | |||
239 | return handled; | 401 | return handled; |
240 | } | 402 | } |
241 | 403 | ||
404 | static void send_and_read_next(void) | ||
405 | { | ||
406 | if(current_cmd.last_result!=0) { | ||
407 | /* The last read failed. */ | ||
408 | send_csw(SCSI_STATUS_CHECK_CONDITION); | ||
409 | cur_sense_data.sense_key=SENSE_MEDIUM_ERROR; | ||
410 | cur_sense_data.asc=ASC_READ_ERROR; | ||
411 | return; | ||
412 | } | ||
413 | send_block_data(current_cmd.data[current_cmd.data_select], | ||
414 | MIN(BUFFER_SIZE,current_cmd.count*SECTOR_SIZE)); | ||
415 | |||
416 | /* Switch buffers for the next one */ | ||
417 | current_cmd.data_select=!current_cmd.data_select; | ||
418 | |||
419 | current_cmd.sector+=(BUFFER_SIZE/SECTOR_SIZE); | ||
420 | current_cmd.count-=MIN(current_cmd.count,BUFFER_SIZE/SECTOR_SIZE); | ||
421 | |||
422 | if(current_cmd.count!=0){ | ||
423 | /* already read the next bit, so we can send it out immediately when the | ||
424 | * current transfer completes. */ | ||
425 | current_cmd.last_result = ata_read_sectors(IF_MV2(current_cmd.lun,) current_cmd.sector, | ||
426 | MIN(BUFFER_SIZE/SECTOR_SIZE,current_cmd.count), | ||
427 | current_cmd.data[current_cmd.data_select]); | ||
428 | } | ||
429 | } | ||
242 | /****************************************************************************/ | 430 | /****************************************************************************/ |
243 | 431 | ||
244 | static void handle_scsi(struct command_block_wrapper* cbw) | 432 | static void handle_scsi(struct command_block_wrapper* cbw) |
@@ -246,141 +434,196 @@ static void handle_scsi(struct command_block_wrapper* cbw) | |||
246 | /* USB Mass Storage assumes LBA capability. | 434 | /* USB Mass Storage assumes LBA capability. |
247 | TODO: support 48-bit LBA */ | 435 | TODO: support 48-bit LBA */ |
248 | 436 | ||
249 | unsigned int sectors_per_transfer=0; | ||
250 | unsigned int length = cbw->data_transfer_length; | 437 | unsigned int length = cbw->data_transfer_length; |
251 | unsigned int block_size; | 438 | unsigned int block_size; |
439 | unsigned int block_count; | ||
440 | bool lun_present=true; | ||
441 | #ifdef ONLY_EXPOSE_CARD_SLOT | ||
442 | unsigned char lun = cbw->lun+1; | ||
443 | #else | ||
252 | unsigned char lun = cbw->lun; | 444 | unsigned char lun = cbw->lun; |
445 | #endif | ||
253 | unsigned int block_size_mult = 1; | 446 | unsigned int block_size_mult = 1; |
254 | #ifdef HAVE_HOTSWAP | 447 | #ifdef HAVE_HOTSWAP |
255 | tCardInfo* cinfo = card_get_info(lun); | 448 | tCardInfo* cinfo = card_get_info(lun); |
256 | block_size = cinfo->blocksize; | 449 | if(cinfo->initialized==1) { |
257 | if(cinfo->initialized==1) | 450 | block_size = cinfo->blocksize; |
258 | { | 451 | block_count = cinfo->numblocks; |
259 | sectors_per_transfer=(sizeof _transfer_buffer/ block_size); | 452 | } |
453 | else { | ||
454 | lun_present=false; | ||
455 | block_size = 0; | ||
456 | block_count = 0; | ||
260 | } | 457 | } |
261 | #else | 458 | #else |
459 | unsigned short* identify = ata_get_identify(); | ||
262 | block_size = SECTOR_SIZE; | 460 | block_size = SECTOR_SIZE; |
263 | sectors_per_transfer=(sizeof _transfer_buffer/ block_size); | 461 | block_count = (identify[61] << 16 | identify[60]); |
264 | #endif | 462 | #endif |
265 | 463 | ||
266 | #ifdef MAX_LOG_SECTOR_SIZE | 464 | #ifdef MAX_LOG_SECTOR_SIZE |
267 | block_size_mult = disk_sector_multiplier; | 465 | block_size_mult = disk_sector_multiplier; |
268 | #endif | 466 | #endif |
269 | 467 | ||
468 | current_cmd.tag = cbw->tag; | ||
469 | current_cmd.lun = lun; | ||
470 | |||
270 | switch (cbw->command_block[0]) { | 471 | switch (cbw->command_block[0]) { |
271 | case SCSI_TEST_UNIT_READY: | 472 | case SCSI_TEST_UNIT_READY: |
272 | logf("scsi test_unit_ready %d",lun); | 473 | logf("scsi test_unit_ready %d",lun); |
273 | #ifdef HAVE_HOTSWAP | 474 | #ifdef HAVE_HOTSWAP |
274 | if(cinfo->initialized==1) | 475 | if(cinfo->initialized==1) |
275 | send_csw(cbw->tag, SCSI_STATUS_GOOD); | 476 | send_csw(SCSI_STATUS_GOOD); |
276 | else | 477 | else { |
277 | send_csw(cbw->tag, SCSI_STATUS_FAIL); | 478 | send_csw(SCSI_STATUS_FAIL); |
479 | cur_sense_data.sense_key=SENSE_NOT_READY; | ||
480 | cur_sense_data.asc=ASC_MEDIUM_NOT_PRESENT; | ||
481 | } | ||
278 | #else | 482 | #else |
279 | send_csw(cbw->tag, SCSI_STATUS_GOOD); | 483 | send_csw(SCSI_STATUS_GOOD); |
280 | #endif | 484 | #endif |
281 | break; | 485 | break; |
282 | 486 | ||
487 | case SCSI_REPORT_LUNS: { | ||
488 | logf("scsi inquiry %d",lun); | ||
489 | int allocation_length=0; | ||
490 | allocation_length|=(cbw->command_block[6]<<24); | ||
491 | allocation_length|=(cbw->command_block[7]<<16); | ||
492 | allocation_length|=(cbw->command_block[8]<<8); | ||
493 | allocation_length|=(cbw->command_block[9]); | ||
494 | memset(lun_data,0,sizeof(struct report_lun_data)); | ||
495 | #ifdef HAVE_HOTSWAP | ||
496 | lun_data->lun_list_length=htobe32(16); | ||
497 | lun_data->lun1[1]=1; | ||
498 | #else | ||
499 | lun_data->lun_list_length=htobe32(8); | ||
500 | #endif | ||
501 | lun_data->lun0[1]=0; | ||
502 | |||
503 | send_command_result(lun_data, MIN(sizeof(struct report_lun_data), length)); | ||
504 | break; | ||
505 | } | ||
506 | |||
283 | case SCSI_INQUIRY: | 507 | case SCSI_INQUIRY: |
284 | logf("scsi inquiry %d",lun); | 508 | logf("scsi inquiry %d",lun); |
285 | identify2inquiry(lun); | 509 | identify2inquiry(lun); |
286 | length = MIN(length, cbw->command_block[4]); | 510 | length = MIN(length, cbw->command_block[4]); |
287 | usb_drv_send(EP_TX, inquiry, MIN(sizeof _inquiry, length)); | 511 | send_command_result(inquiry, MIN(sizeof(struct inquiry_data), length)); |
288 | send_csw(cbw->tag, SCSI_STATUS_GOOD); | ||
289 | break; | 512 | break; |
290 | 513 | ||
291 | case SCSI_REQUEST_SENSE: { | 514 | case SCSI_REQUEST_SENSE: { |
292 | sense_data->ResponseCode=0x70; | 515 | sense_data->ResponseCode=0x70;/*current error*/ |
293 | sense_data->filemark_eom_ili_sensekey=2; | 516 | sense_data->filemark_eom_ili_sensekey=cur_sense_data.sense_key&0x0f; |
294 | sense_data->Information=2; | 517 | sense_data->Information=cur_sense_data.information; |
295 | sense_data->AdditionalSenseLength=10; | 518 | sense_data->AdditionalSenseLength=10; |
296 | sense_data->CommandSpecificInformation=0; | 519 | sense_data->CommandSpecificInformation=0; |
297 | sense_data->AdditionalSenseCode=0x3a; | 520 | sense_data->AdditionalSenseCode=cur_sense_data.asc; |
298 | sense_data->AdditionalSenseCodeQualifier=0; | 521 | sense_data->AdditionalSenseCodeQualifier=0; |
299 | sense_data->FieldReplaceableUnitCode=0; | 522 | sense_data->FieldReplaceableUnitCode=0; |
300 | sense_data->SKSV=0; | 523 | sense_data->SKSV=0; |
301 | sense_data->SenseKeySpecific=0; | 524 | sense_data->SenseKeySpecific=0; |
302 | logf("scsi request_sense %d",lun); | 525 | logf("scsi request_sense %d",lun); |
303 | usb_drv_send(EP_TX, sense_data, | 526 | send_command_result(sense_data, sizeof(struct sense_data)); |
304 | sizeof(_sense_data)); | ||
305 | send_csw(cbw->tag, SCSI_STATUS_GOOD); | ||
306 | break; | 527 | break; |
307 | } | 528 | } |
308 | 529 | ||
309 | case SCSI_MODE_SENSE: { | 530 | case SCSI_MODE_SENSE_10: { |
310 | static unsigned char sense_data[8] = { 0, 0, 0, 0, 0, 0, 0, 0 }; | 531 | /*unsigned char pc = (cbw->command_block[2] & 0xc0) >>6;*/ |
311 | logf("scsi mode_sense %d",lun); | 532 | unsigned char page_code = cbw->command_block[2] & 0x3f; |
312 | usb_drv_send(EP_TX, UNCACHED_ADDR(&sense_data), | 533 | logf("scsi mode_sense_10 %d %X",lun,page_code); |
313 | MIN(sizeof sense_data, length)); | 534 | switch(page_code) { |
314 | send_csw(cbw->tag, SCSI_STATUS_GOOD); | 535 | case 0x3f: |
536 | default: | ||
537 | mode_sense_data_10->mode_data_length=0; | ||
538 | mode_sense_data_10->medium_type=0; | ||
539 | mode_sense_data_10->device_specific=0; | ||
540 | mode_sense_data_10->block_descriptor_length=0; | ||
541 | send_command_result(mode_sense_data_10, | ||
542 | MIN(sizeof(struct mode_sense_header_10), length)); | ||
543 | break; | ||
544 | #if 0 | ||
545 | default: | ||
546 | send_csw(SCSI_STATUS_CHECK_CONDITION); | ||
547 | cur_sense_data.sense_key=SENSE_ILLEGAL_REQUEST; | ||
548 | cur_sense_data.asc=ASC_INVALID_FIELD_IN_CBD; | ||
549 | break; | ||
550 | #endif | ||
551 | } | ||
552 | break; | ||
553 | } | ||
554 | case SCSI_MODE_SENSE_6: { | ||
555 | /*unsigned char pc = (cbw->command_block[2] & 0xc0) >>6;*/ | ||
556 | unsigned char page_code = cbw->command_block[2] & 0x3f; | ||
557 | logf("scsi mode_sense_6 %d %X",lun,page_code); | ||
558 | switch(page_code) { | ||
559 | case 0x3f: | ||
560 | default: | ||
561 | /* All supported pages Since we support only one this is easy*/ | ||
562 | mode_sense_data_6->mode_data_length=0; | ||
563 | mode_sense_data_6->medium_type=0; | ||
564 | mode_sense_data_6->device_specific=0; | ||
565 | mode_sense_data_6->block_descriptor_length=0; | ||
566 | send_command_result(mode_sense_data_6, | ||
567 | MIN(sizeof(struct mode_sense_header_6), length)); | ||
568 | break; | ||
569 | #if 0 | ||
570 | default: | ||
571 | send_csw(SCSI_STATUS_CHECK_CONDITION); | ||
572 | cur_sense_data.sense_key=SENSE_ILLEGAL_REQUEST; | ||
573 | cur_sense_data.asc=ASC_INVALID_FIELD_IN_CBD; | ||
574 | break; | ||
575 | #endif | ||
576 | } | ||
315 | break; | 577 | break; |
316 | } | 578 | } |
317 | 579 | ||
318 | case SCSI_START_STOP_UNIT: | 580 | case SCSI_START_STOP_UNIT: |
319 | logf("scsi start_stop unit %d",lun); | 581 | logf("scsi start_stop unit %d",lun); |
320 | send_csw(cbw->tag, SCSI_STATUS_GOOD); | 582 | send_csw(SCSI_STATUS_GOOD); |
321 | break; | 583 | break; |
322 | 584 | ||
323 | case SCSI_ALLOW_MEDIUM_REMOVAL: | 585 | case SCSI_ALLOW_MEDIUM_REMOVAL: |
324 | logf("scsi allow_medium_removal %d",lun); | 586 | logf("scsi allow_medium_removal %d",lun); |
325 | send_csw(cbw->tag, SCSI_STATUS_GOOD); | 587 | /* TODO: use this to show the connect screen ? */ |
588 | send_csw(SCSI_STATUS_GOOD); | ||
326 | break; | 589 | break; |
327 | 590 | ||
328 | case SCSI_READ_FORMAT_CAPACITY: { | 591 | case SCSI_READ_FORMAT_CAPACITY: { |
329 | logf("scsi read_format_capacity %d",lun); | 592 | logf("scsi read_format_capacity %d",lun); |
330 | format_capacity_data->following_length=htobe32(8); | 593 | format_capacity_data->following_length=htobe32(8); |
331 | #ifdef HAVE_HOTSWAP | ||
332 | /* Careful: "block count" actually means "number of last block" */ | 594 | /* Careful: "block count" actually means "number of last block" */ |
333 | if(cinfo->initialized==1) | 595 | format_capacity_data->block_count = htobe32(block_count/block_size_mult - 1); |
334 | { | 596 | format_capacity_data->block_size = htobe32(block_size*block_size_mult); |
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; | 597 | format_capacity_data->block_size |= SCSI_FORMAT_CAPACITY_FORMATTED_MEDIA; |
350 | 598 | ||
351 | usb_drv_send(EP_TX, format_capacity_data, | 599 | send_command_result(format_capacity_data, |
352 | MIN(sizeof _format_capacity_data, length)); | 600 | MIN(sizeof(struct format_capacity), length)); |
353 | send_csw(cbw->tag, SCSI_STATUS_GOOD); | 601 | |
354 | break; | 602 | break; |
355 | } | 603 | } |
356 | 604 | ||
357 | case SCSI_READ_CAPACITY: { | 605 | case SCSI_READ_CAPACITY: { |
358 | logf("scsi read_capacity %d",lun); | 606 | logf("scsi read_capacity %d",lun); |
359 | #ifdef HAVE_HOTSWAP | ||
360 | /* Careful: "block count" actually means "number of last block" */ | 607 | /* Careful: "block count" actually means "number of last block" */ |
361 | if(cinfo->initialized==1) | 608 | capacity_data->block_count = htobe32(block_count/block_size_mult - 1); |
362 | { | 609 | capacity_data->block_size = htobe32(block_size*block_size_mult); |
363 | capacity_data->block_count = htobe32(cinfo->numblocks - 1); | 610 | |
364 | capacity_data->block_size = htobe32(cinfo->blocksize); | 611 | send_command_result(capacity_data, MIN(sizeof(struct capacity), length)); |
365 | } | ||
366 | else | ||
367 | { | ||
368 | capacity_data->block_count = htobe32(0); | ||
369 | capacity_data->block_size = htobe32(0); | ||
370 | } | ||
371 | #else | ||
372 | unsigned short* identify = ata_get_identify(); | ||
373 | /* Careful : "block count" actually means the number of the last block */ | ||
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); | ||
376 | #endif | ||
377 | usb_drv_send(EP_TX, capacity_data, | ||
378 | MIN(sizeof _capacity_data, length)); | ||
379 | send_csw(cbw->tag, SCSI_STATUS_GOOD); | ||
380 | break; | 612 | break; |
381 | } | 613 | } |
382 | 614 | ||
383 | case SCSI_READ_10: | 615 | case SCSI_READ_10: |
616 | logf("scsi read10 %d",lun); | ||
617 | if(! lun_present) { | ||
618 | send_csw(SCSI_STATUS_CHECK_CONDITION); | ||
619 | cur_sense_data.sense_key=SENSE_NOT_READY; | ||
620 | cur_sense_data.asc=ASC_MEDIUM_NOT_PRESENT; | ||
621 | break; | ||
622 | } | ||
623 | trigger_cpu_boost(); | ||
624 | current_cmd.data[0] = transfer_buffer; | ||
625 | current_cmd.data[1] = &transfer_buffer[BUFFER_SIZE]; | ||
626 | current_cmd.data_select=0; | ||
384 | current_cmd.sector = block_size_mult * | 627 | current_cmd.sector = block_size_mult * |
385 | (cbw->command_block[2] << 24 | | 628 | (cbw->command_block[2] << 24 | |
386 | cbw->command_block[3] << 16 | | 629 | cbw->command_block[3] << 16 | |
@@ -389,32 +632,35 @@ static void handle_scsi(struct command_block_wrapper* cbw) | |||
389 | current_cmd.count = block_size_mult * | 632 | current_cmd.count = block_size_mult * |
390 | (cbw->command_block[7] << 16 | | 633 | (cbw->command_block[7] << 16 | |
391 | cbw->command_block[8]); | 634 | cbw->command_block[8]); |
392 | current_cmd.tag = cbw->tag; | ||
393 | current_cmd.lun = cbw->lun; | ||
394 | 635 | ||
395 | //logf("scsi read %d %d", current_cmd.sector, current_cmd.count); | 636 | logf("scsi read %d %d", current_cmd.sector, current_cmd.count); |
396 | 637 | ||
397 | //logf("Asked for %d sectors",current_cmd.count); | 638 | if((current_cmd.sector + current_cmd.count) * block_size_mult > block_count) { |
398 | if(current_cmd.count > sectors_per_transfer) | 639 | send_csw(SCSI_STATUS_CHECK_CONDITION); |
399 | { | 640 | cur_sense_data.sense_key=SENSE_ILLEGAL_REQUEST; |
400 | current_cmd.count = sectors_per_transfer; | 641 | cur_sense_data.asc=ASC_LBA_OUT_OF_RANGE; |
401 | } | ||
402 | //logf("Sending %d sectors",current_cmd.count); | ||
403 | |||
404 | if(current_cmd.count*block_size > sizeof(_transfer_buffer)) { | ||
405 | send_csw(current_cmd.tag, SCSI_STATUS_CHECK_CONDITION); | ||
406 | } | 642 | } |
407 | else { | 643 | else { |
408 | ata_read_sectors(IF_MV2(lun,) current_cmd.sector, | 644 | /* TODO: any way to do this nonblocking ? */ |
409 | current_cmd.count, transfer_buffer); | 645 | current_cmd.last_result = ata_read_sectors(IF_MV2(current_cmd.lun,) current_cmd.sector, |
410 | usb_drv_send(EP_TX, transfer_buffer, | 646 | MIN(BUFFER_SIZE/SECTOR_SIZE,current_cmd.count), |
411 | current_cmd.count*block_size); | 647 | current_cmd.data[current_cmd.data_select]); |
412 | send_csw(current_cmd.tag, SCSI_STATUS_GOOD); | 648 | send_and_read_next(); |
413 | } | 649 | } |
414 | break; | 650 | break; |
415 | 651 | ||
416 | case SCSI_WRITE_10: | 652 | case SCSI_WRITE_10: |
417 | //logf("scsi write10"); | 653 | logf("scsi write10 %d",lun); |
654 | if(! lun_present) { | ||
655 | send_csw(SCSI_STATUS_CHECK_CONDITION); | ||
656 | cur_sense_data.sense_key=SENSE_NOT_READY; | ||
657 | cur_sense_data.asc=ASC_MEDIUM_NOT_PRESENT; | ||
658 | break; | ||
659 | } | ||
660 | trigger_cpu_boost(); | ||
661 | current_cmd.data[0] = transfer_buffer; | ||
662 | current_cmd.data[1] = &transfer_buffer[BUFFER_SIZE]; | ||
663 | current_cmd.data_select=0; | ||
418 | current_cmd.sector = block_size_mult * | 664 | current_cmd.sector = block_size_mult * |
419 | (cbw->command_block[2] << 24 | | 665 | (cbw->command_block[2] << 24 | |
420 | cbw->command_block[3] << 16 | | 666 | cbw->command_block[3] << 16 | |
@@ -423,53 +669,74 @@ static void handle_scsi(struct command_block_wrapper* cbw) | |||
423 | current_cmd.count = block_size_mult * | 669 | current_cmd.count = block_size_mult * |
424 | (cbw->command_block[7] << 16 | | 670 | (cbw->command_block[7] << 16 | |
425 | cbw->command_block[8]); | 671 | cbw->command_block[8]); |
426 | current_cmd.tag = cbw->tag; | ||
427 | current_cmd.lun = cbw->lun; | ||
428 | /* expect data */ | 672 | /* expect data */ |
429 | if(current_cmd.count*block_size > sizeof(_transfer_buffer)) { | 673 | if((current_cmd.sector + current_cmd.count) * block_size_mult > block_count) { |
430 | send_csw(current_cmd.tag, SCSI_STATUS_CHECK_CONDITION); | 674 | send_csw(SCSI_STATUS_CHECK_CONDITION); |
675 | cur_sense_data.sense_key=SENSE_ILLEGAL_REQUEST; | ||
676 | cur_sense_data.asc=ASC_LBA_OUT_OF_RANGE; | ||
431 | } | 677 | } |
432 | else { | 678 | else { |
433 | usb_drv_recv(EP_RX, transfer_buffer, | 679 | receive_block_data(current_cmd.data[0], |
434 | current_cmd.count*block_size); | 680 | MIN(BUFFER_SIZE,current_cmd.count*SECTOR_SIZE)); |
435 | state = RECEIVING; | ||
436 | } | 681 | } |
437 | 682 | ||
438 | break; | 683 | break; |
439 | 684 | ||
440 | default: | 685 | default: |
441 | logf("scsi unknown cmd %x",cbw->command_block[0x0]); | 686 | logf("scsi unknown cmd %x",cbw->command_block[0x0]); |
442 | usb_drv_stall(EP_TX, true); | 687 | usb_drv_stall(EP_MASS_STORAGE, true,true); |
443 | send_csw(current_cmd.tag, SCSI_STATUS_GOOD); | 688 | send_csw(SCSI_STATUS_GOOD); |
444 | break; | 689 | break; |
445 | } | 690 | } |
446 | } | 691 | } |
447 | 692 | ||
448 | static void send_csw(unsigned int tag, int status) | 693 | static void send_block_data(void *data,int size) |
694 | { | ||
695 | usb_drv_send_nonblocking(EP_MASS_STORAGE, data,size); | ||
696 | state = SENDING_BLOCKS; | ||
697 | } | ||
698 | |||
699 | static void send_command_result(void *data,int size) | ||
700 | { | ||
701 | usb_drv_send_nonblocking(EP_MASS_STORAGE, data,size); | ||
702 | state = SENDING_RESULT; | ||
703 | } | ||
704 | |||
705 | static void receive_block_data(void *data,int size) | ||
449 | { | 706 | { |
450 | static struct command_status_wrapper _csw; | 707 | usb_drv_recv(EP_MASS_STORAGE, data, size); |
451 | struct command_status_wrapper* csw = UNCACHED_ADDR(&_csw); | 708 | state = RECEIVING_BLOCKS; |
709 | } | ||
710 | |||
711 | static void send_csw(int status) | ||
712 | { | ||
713 | cancel_cpu_boost(); | ||
452 | csw->signature = CSW_SIGNATURE; | 714 | csw->signature = CSW_SIGNATURE; |
453 | csw->tag = tag; | 715 | csw->tag = current_cmd.tag; |
454 | csw->data_residue = 0; | 716 | csw->data_residue = 0; |
455 | csw->status = status; | 717 | csw->status = status; |
456 | 718 | ||
457 | //logf("csw %x %x", csw->tag, csw->signature); | 719 | usb_drv_send_nonblocking(EP_MASS_STORAGE, csw, sizeof(struct command_status_wrapper)); |
458 | usb_drv_send(EP_TX, csw, sizeof _csw); | 720 | state = SENDING_CSW; |
721 | logf("CSW: %X",status); | ||
722 | |||
723 | if(status == SCSI_STATUS_GOOD) { | ||
724 | cur_sense_data.sense_key=0; | ||
725 | cur_sense_data.information=0; | ||
726 | cur_sense_data.asc=0; | ||
727 | } | ||
459 | } | 728 | } |
460 | 729 | ||
461 | /* convert ATA IDENTIFY to SCSI INQUIRY */ | 730 | /* convert ATA IDENTIFY to SCSI INQUIRY */ |
462 | static void identify2inquiry(int lun) | 731 | static void identify2inquiry(int lun) |
463 | { | 732 | { |
464 | #ifdef HAVE_FLASH_STORAGE | 733 | #ifdef HAVE_FLASH_STORAGE |
465 | if(lun==0) | 734 | if(lun==0) { |
466 | { | ||
467 | memcpy(&inquiry->VendorId,"Rockbox ",8); | 735 | memcpy(&inquiry->VendorId,"Rockbox ",8); |
468 | memcpy(&inquiry->ProductId,"Internal Storage",16); | 736 | memcpy(&inquiry->ProductId,"Internal Storage",16); |
469 | memcpy(&inquiry->ProductRevisionLevel,"0.00",4); | 737 | memcpy(&inquiry->ProductRevisionLevel,"0.00",4); |
470 | } | 738 | } |
471 | else | 739 | else { |
472 | { | ||
473 | memcpy(&inquiry->VendorId,"Rockbox ",8); | 740 | memcpy(&inquiry->VendorId,"Rockbox ",8); |
474 | memcpy(&inquiry->ProductId,"SD Card Slot ",16); | 741 | memcpy(&inquiry->ProductId,"SD Card Slot ",16); |
475 | memcpy(&inquiry->ProductRevisionLevel,"0.00",4); | 742 | memcpy(&inquiry->ProductRevisionLevel,"0.00",4); |
@@ -480,7 +747,7 @@ static void identify2inquiry(int lun) | |||
480 | unsigned short* src; | 747 | unsigned short* src; |
481 | unsigned short* identify = ata_get_identify(); | 748 | unsigned short* identify = ata_get_identify(); |
482 | (void)lun; | 749 | (void)lun; |
483 | memset(inquiry, 0, sizeof _inquiry); | 750 | memset(inquiry, 0, sizeof(struct inquiry_data)); |
484 | 751 | ||
485 | if (identify[82] & 4) | 752 | if (identify[82] & 4) |
486 | inquiry->DeviceTypeModifier = DEVICE_REMOVABLE; | 753 | inquiry->DeviceTypeModifier = DEVICE_REMOVABLE; |
@@ -501,8 +768,8 @@ static void identify2inquiry(int lun) | |||
501 | 768 | ||
502 | inquiry->DeviceType = DIRECT_ACCESS_DEVICE; | 769 | inquiry->DeviceType = DIRECT_ACCESS_DEVICE; |
503 | inquiry->AdditionalLength = 0x1f; | 770 | inquiry->AdditionalLength = 0x1f; |
504 | inquiry->Versions = 3; /* ANSI SCSI level 2 */ | 771 | inquiry->Versions = 4; /* SPC-2 */ |
505 | inquiry->Format = 3; /* ANSI SCSI level 2 INQUIRY format */ | 772 | inquiry->Format = 2; /* SPC-2/3 inquiry format */ |
506 | 773 | ||
507 | #ifdef HAVE_HOTSWAP | 774 | #ifdef HAVE_HOTSWAP |
508 | inquiry->DeviceTypeModifier = DEVICE_REMOVABLE; | 775 | inquiry->DeviceTypeModifier = DEVICE_REMOVABLE; |
@@ -510,3 +777,4 @@ static void identify2inquiry(int lun) | |||
510 | 777 | ||
511 | } | 778 | } |
512 | 779 | ||
780 | #endif /* USB_STORAGE */ | ||
diff --git a/firmware/usbstack/usb_storage.h b/firmware/usbstack/usb_storage.h index 9067c92c61..23903a855a 100644 --- a/firmware/usbstack/usb_storage.h +++ b/firmware/usbstack/usb_storage.h | |||
@@ -22,8 +22,7 @@ | |||
22 | #include "usb_ch9.h" | 22 | #include "usb_ch9.h" |
23 | 23 | ||
24 | void usb_storage_init(void); | 24 | void usb_storage_init(void); |
25 | void usb_storage_transfer(void* data); | 25 | void usb_storage_transfer_complete(bool in,int state,int length); |
26 | void usb_storage_transfer_complete(int endpoint); | ||
27 | bool usb_storage_control_request(struct usb_ctrlrequest* req); | 26 | bool usb_storage_control_request(struct usb_ctrlrequest* req); |
28 | 27 | ||
29 | #endif | 28 | #endif |