diff options
author | Björn Stenberg <bjorn@haxx.se> | 2008-02-11 14:26:25 +0000 |
---|---|---|
committer | Björn Stenberg <bjorn@haxx.se> | 2008-02-11 14:26:25 +0000 |
commit | 2f7cffa204eaa2675b0c6782462b19f4f09bff12 (patch) | |
tree | 54ffb4cada2c8db9d0feb4c31efc02cb3ab18a1d | |
parent | 9811fc9abf6c3b2bb9500a99c14a64ee29641b09 (diff) | |
download | rockbox-2f7cffa204eaa2675b0c6782462b19f4f09bff12.tar.gz rockbox-2f7cffa204eaa2675b0c6782462b19f4f09bff12.zip |
Major USB fixes by Frank Gevaerts. Still disabled in builds, #define USE_ROCKBOX_USB to test.
git-svn-id: svn://svn.rockbox.org/rockbox/trunk@16279 a1c6a512-1295-4272-9138-f99709370657
-rw-r--r-- | bootloader/main-pp.c | 2 | ||||
-rw-r--r-- | docs/CREDITS | 1 | ||||
-rw-r--r-- | firmware/common/disk.c | 5 | ||||
-rw-r--r-- | firmware/export/disk.h | 5 | ||||
-rw-r--r-- | firmware/export/usb_ch9.h | 2 | ||||
-rw-r--r-- | firmware/export/usb_drv.h | 3 | ||||
-rw-r--r-- | firmware/target/arm/usb-drv-pp502x.c | 184 | ||||
-rw-r--r-- | firmware/target/arm/usb-fw-pp502x.c | 8 | ||||
-rw-r--r-- | firmware/usbstack/usb_core.c | 339 | ||||
-rw-r--r-- | firmware/usbstack/usb_storage.c | 316 |
10 files changed, 662 insertions, 203 deletions
diff --git a/bootloader/main-pp.c b/bootloader/main-pp.c index 74c66233c0..5af6e57fff 100644 --- a/bootloader/main-pp.c +++ b/bootloader/main-pp.c | |||
@@ -465,6 +465,7 @@ void* main(void) | |||
465 | 465 | ||
466 | btn = button_read_device(); | 466 | btn = button_read_device(); |
467 | #if defined(SANSA_E200) || defined(SANSA_C200) | 467 | #if defined(SANSA_E200) || defined(SANSA_C200) |
468 | #if !defined(USE_ROCKBOX_USB) | ||
468 | usb_init(); | 469 | usb_init(); |
469 | while (usb_drv_powered() && usb_retry < 5 && !usb) | 470 | while (usb_drv_powered() && usb_retry < 5 && !usb) |
470 | { | 471 | { |
@@ -474,6 +475,7 @@ void* main(void) | |||
474 | } | 475 | } |
475 | if (usb) | 476 | if (usb) |
476 | btn |= BOOTLOADER_BOOT_OF; | 477 | btn |= BOOTLOADER_BOOT_OF; |
478 | #endif /* USE_ROCKBOX_USB */ | ||
477 | #endif | 479 | #endif |
478 | /* Enable bootloader messages if any button is pressed */ | 480 | /* Enable bootloader messages if any button is pressed */ |
479 | if (btn) | 481 | if (btn) |
diff --git a/docs/CREDITS b/docs/CREDITS index 7c95ab8804..955b81109e 100644 --- a/docs/CREDITS +++ b/docs/CREDITS | |||
@@ -368,6 +368,7 @@ George Tamplaru | |||
368 | Apoorva Mahajan | 368 | Apoorva Mahajan |
369 | Vuong Minh Hiep | 369 | Vuong Minh Hiep |
370 | Mateusz Kubica | 370 | Mateusz Kubica |
371 | Frank Gevaerts | ||
371 | 372 | ||
372 | The libmad team | 373 | The libmad team |
373 | The wavpack team | 374 | The wavpack team |
diff --git a/firmware/common/disk.c b/firmware/common/disk.c index 9fb73f0070..c26fdb37a4 100644 --- a/firmware/common/disk.c +++ b/firmware/common/disk.c | |||
@@ -48,6 +48,9 @@ | |||
48 | static struct partinfo part[8]; /* space for 4 partitions on 2 drives */ | 48 | static struct partinfo part[8]; /* space for 4 partitions on 2 drives */ |
49 | static int vol_drive[NUM_VOLUMES]; /* mounted to which drive (-1 if none) */ | 49 | static int vol_drive[NUM_VOLUMES]; /* mounted to which drive (-1 if none) */ |
50 | 50 | ||
51 | #ifdef MAX_LOG_SECTOR_SIZE | ||
52 | int disk_sector_multiplier = 1; | ||
53 | #endif | ||
51 | struct partinfo* disk_init(IF_MV_NONVOID(int drive)) | 54 | struct partinfo* disk_init(IF_MV_NONVOID(int drive)) |
52 | { | 55 | { |
53 | int i; | 56 | int i; |
@@ -168,6 +171,8 @@ int disk_mount(int drive) | |||
168 | mounted++; | 171 | mounted++; |
169 | vol_drive[volume] = drive; /* remember the drive for this volume */ | 172 | vol_drive[volume] = drive; /* remember the drive for this volume */ |
170 | volume = get_free_volume(); /* prepare next entry */ | 173 | volume = get_free_volume(); /* prepare next entry */ |
174 | if (drive == 0) | ||
175 | disk_sector_multiplier = j; | ||
171 | break; | 176 | break; |
172 | } | 177 | } |
173 | } | 178 | } |
diff --git a/firmware/export/disk.h b/firmware/export/disk.h index 9672a6d318..d6d6796e9e 100644 --- a/firmware/export/disk.h +++ b/firmware/export/disk.h | |||
@@ -39,4 +39,9 @@ int disk_mount_all(void); /* returns the # of successful mounts */ | |||
39 | int disk_mount(int drive); | 39 | int disk_mount(int drive); |
40 | int disk_unmount(int drive); | 40 | int disk_unmount(int drive); |
41 | 41 | ||
42 | /* The number of 512-byte sectors in a "logical" sector. Needed for ipod 5.5G */ | ||
43 | #ifdef MAX_LOG_SECTOR_SIZE | ||
44 | extern int disk_sector_multiplier; | ||
45 | #endif | ||
46 | |||
42 | #endif | 47 | #endif |
diff --git a/firmware/export/usb_ch9.h b/firmware/export/usb_ch9.h index b8fe181158..1bfc152a8a 100644 --- a/firmware/export/usb_ch9.h +++ b/firmware/export/usb_ch9.h | |||
@@ -244,7 +244,7 @@ struct usb_string_descriptor { | |||
244 | uint8_t bLength; | 244 | uint8_t bLength; |
245 | uint8_t bDescriptorType; | 245 | uint8_t bDescriptorType; |
246 | 246 | ||
247 | uint16_t wData[1]; /* UTF-16LE encoded */ | 247 | uint16_t wString[]; /* UTF-16LE encoded */ |
248 | } __attribute__ ((packed)); | 248 | } __attribute__ ((packed)); |
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 |
diff --git a/firmware/export/usb_drv.h b/firmware/export/usb_drv.h index c503a846ed..6a37144c1a 100644 --- a/firmware/export/usb_drv.h +++ b/firmware/export/usb_drv.h | |||
@@ -32,5 +32,8 @@ void usb_drv_set_address(int address); | |||
32 | void usb_drv_reset_endpoint(int endpoint, bool send); | 32 | void usb_drv_reset_endpoint(int endpoint, bool send); |
33 | void usb_drv_wait(int endpoint, bool send); | 33 | void usb_drv_wait(int endpoint, bool send); |
34 | bool usb_drv_powered(void); | 34 | 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); | ||
35 | 38 | ||
36 | #endif | 39 | #endif |
diff --git a/firmware/target/arm/usb-drv-pp502x.c b/firmware/target/arm/usb-drv-pp502x.c index 1db3ebd42f..413d905293 100644 --- a/firmware/target/arm/usb-drv-pp502x.c +++ b/firmware/target/arm/usb-drv-pp502x.c | |||
@@ -294,7 +294,7 @@ struct transfer_descriptor { | |||
294 | unsigned int reserved; | 294 | unsigned int reserved; |
295 | } __attribute__ ((packed)); | 295 | } __attribute__ ((packed)); |
296 | 296 | ||
297 | static struct transfer_descriptor _td_array[NUM_ENDPOINTS*2] __attribute((aligned (32))); | 297 | static struct transfer_descriptor _td_array[32] __attribute((aligned (32))); |
298 | static struct transfer_descriptor* td_array; | 298 | static struct transfer_descriptor* td_array; |
299 | 299 | ||
300 | /* manual: 32.13.1 Endpoint Queue Head (dQH) */ | 300 | /* manual: 32.13.1 Endpoint Queue Head (dQH) */ |
@@ -317,9 +317,15 @@ static const unsigned int pipe2mask[NUM_ENDPOINTS*2] = { | |||
317 | 0x04, 0x040000, | 317 | 0x04, 0x040000, |
318 | }; | 318 | }; |
319 | 319 | ||
320 | static struct transfer_descriptor* first_td; | ||
321 | static struct transfer_descriptor* last_td; | ||
322 | |||
320 | /*-------------------------------------------------------------------------*/ | 323 | /*-------------------------------------------------------------------------*/ |
321 | static void transfer_completed(void); | 324 | static void transfer_completed(void); |
322 | static int prime_transfer(int endpoint, void* ptr, int len, bool send); | 325 | static int prime_transfer(int endpoint, void* ptr, int len, bool send); |
326 | static void prepare_td(struct transfer_descriptor* td, | ||
327 | struct transfer_descriptor* previous_td, | ||
328 | void *ptr, int len); | ||
323 | static void bus_reset(void); | 329 | static void bus_reset(void); |
324 | static void init_queue_heads(void); | 330 | static void init_queue_heads(void); |
325 | static void init_endpoints(void); | 331 | static void init_endpoints(void); |
@@ -340,6 +346,10 @@ void usb_drv_init(void) | |||
340 | 346 | ||
341 | REG_USBMODE = USBMODE_CTRL_MODE_DEVICE; | 347 | REG_USBMODE = USBMODE_CTRL_MODE_DEVICE; |
342 | 348 | ||
349 | /* Force device to full speed */ | ||
350 | /* See 32.9.5.9.2 */ | ||
351 | REG_PORTSC1 |= PORTSCX_PORT_FORCE_FULL_SPEED; | ||
352 | |||
343 | td_array = (struct transfer_descriptor*)UNCACHED_ADDR(&_td_array); | 353 | td_array = (struct transfer_descriptor*)UNCACHED_ADDR(&_td_array); |
344 | qh_array = (struct queue_head*)UNCACHED_ADDR(&_qh_array); | 354 | qh_array = (struct queue_head*)UNCACHED_ADDR(&_qh_array); |
345 | init_queue_heads(); | 355 | init_queue_heads(); |
@@ -467,6 +477,10 @@ void usb_drv_wait(int endpoint, bool send) | |||
467 | } | 477 | } |
468 | } | 478 | } |
469 | 479 | ||
480 | int usb_drv_port_speed(void) | ||
481 | { | ||
482 | return (REG_PORTSC1 & 0x08000000) ? 1 : 0; | ||
483 | } | ||
470 | 484 | ||
471 | void usb_drv_set_address(int address) | 485 | void usb_drv_set_address(int address) |
472 | { | 486 | { |
@@ -482,44 +496,87 @@ void usb_drv_reset_endpoint(int endpoint, bool send) | |||
482 | while (REG_ENDPTFLUSH & mask); | 496 | while (REG_ENDPTFLUSH & mask); |
483 | } | 497 | } |
484 | 498 | ||
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 | |||
485 | /*-------------------------------------------------------------------------*/ | 527 | /*-------------------------------------------------------------------------*/ |
486 | 528 | ||
487 | /* manual: 32.14.5.2 */ | 529 | /* manual: 32.14.5.2 */ |
488 | static int prime_transfer(int endpoint, void* ptr, int len, bool send) | 530 | static int prime_transfer(int endpoint, void* ptr, int len, bool send) |
489 | { | 531 | { |
490 | int timeout; | ||
491 | int pipe = endpoint * 2 + (send ? 1 : 0); | 532 | int pipe = endpoint * 2 + (send ? 1 : 0); |
492 | unsigned int mask = pipe2mask[pipe]; | 533 | unsigned int mask = pipe2mask[pipe]; |
493 | struct transfer_descriptor* td = &td_array[pipe]; | 534 | last_td = 0; |
494 | struct queue_head* qh = &qh_array[pipe]; | 535 | struct queue_head* qh = &qh_array[pipe]; |
536 | static long last_tick; | ||
495 | 537 | ||
538 | /* | ||
496 | if (send && endpoint > EP_CONTROL) { | 539 | if (send && endpoint > EP_CONTROL) { |
497 | logf("usb: sent %d bytes", len); | 540 | logf("usb: sent %d bytes", len); |
498 | } | 541 | } |
542 | */ | ||
499 | 543 | ||
500 | memset(td, 0, sizeof(struct transfer_descriptor)); | 544 | if (len==0) { |
501 | td->next_td_ptr = DTD_NEXT_TERMINATE; | 545 | struct transfer_descriptor* new_td = &td_array[0]; |
502 | td->size_ioc_sts = (len << DTD_LENGTH_BIT_POS) | | 546 | prepare_td(new_td, 0, ptr, 0); |
503 | DTD_STATUS_ACTIVE | DTD_IOC; | 547 | |
504 | td->buff_ptr0 = (unsigned int)ptr; | 548 | last_td = new_td; |
505 | td->buff_ptr1 = (unsigned int)ptr + 0x1000; | 549 | first_td = new_td; |
506 | td->buff_ptr2 = (unsigned int)ptr + 0x2000; | 550 | } |
507 | td->buff_ptr3 = (unsigned int)ptr + 0x3000; | 551 | else { |
508 | td->buff_ptr4 = (unsigned int)ptr + 0x4000; | 552 | int td_idx = 0; |
509 | td->reserved = len; | 553 | while (len > 0) { |
510 | qh->dtd.next_td_ptr = (unsigned int)td; | 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 | |||
566 | qh->dtd.next_td_ptr = (unsigned int)first_td; | ||
511 | qh->dtd.size_ioc_sts &= ~(QH_STATUS_HALT | QH_STATUS_ACTIVE); | 567 | qh->dtd.size_ioc_sts &= ~(QH_STATUS_HALT | QH_STATUS_ACTIVE); |
512 | 568 | ||
513 | REG_ENDPTPRIME |= mask; | 569 | REG_ENDPTPRIME |= mask; |
514 | 570 | ||
515 | timeout = 10000; | 571 | last_tick = current_tick; |
516 | while ((REG_ENDPTPRIME & mask) && --timeout) { | 572 | while ((REG_ENDPTPRIME & mask)) { |
517 | if (REG_USBSTS & USBSTS_RESET) | 573 | if (REG_USBSTS & USBSTS_RESET) |
518 | return -1; | 574 | return -1; |
519 | } | 575 | |
520 | if (!timeout) { | 576 | if (TIME_AFTER(current_tick, last_tick + HZ/4)) { |
521 | logf("prime timeout"); | 577 | logf("prime timeout"); |
522 | return -2; | 578 | return -2; |
579 | } | ||
523 | } | 580 | } |
524 | 581 | ||
525 | if (!(REG_ENDPTSTATUS & mask)) { | 582 | if (!(REG_ENDPTSTATUS & mask)) { |
@@ -529,23 +586,54 @@ static int prime_transfer(int endpoint, void* ptr, int len, bool send) | |||
529 | 586 | ||
530 | if (send) { | 587 | if (send) { |
531 | /* wait for transfer to finish */ | 588 | /* wait for transfer to finish */ |
532 | timeout = 100000; | 589 | struct transfer_descriptor* current_td = first_td; |
533 | while ((td->size_ioc_sts & DTD_STATUS_ACTIVE) && --timeout) { | 590 | |
534 | if (REG_ENDPTCOMPLETE & mask) | 591 | while (!((unsigned int)current_td & DTD_NEXT_TERMINATE)) { |
535 | REG_ENDPTCOMPLETE |= mask; | 592 | while ((current_td->size_ioc_sts & 0xff) == DTD_STATUS_ACTIVE) { |
536 | 593 | if (REG_ENDPTCOMPLETE & mask) | |
537 | if (REG_USBSTS & USBSTS_RESET) | 594 | REG_ENDPTCOMPLETE |= mask; |
538 | return -4; | 595 | |
539 | } | 596 | /* let the host handle timeouts */ |
540 | if (!timeout) { | 597 | if (REG_USBSTS & USBSTS_RESET) { |
541 | logf("td never finished"); | 598 | logf("td interrupted by reset"); |
542 | return -5; | 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; | ||
543 | } | 608 | } |
609 | //logf("all tds done"); | ||
544 | } | 610 | } |
545 | 611 | ||
546 | return 0; | 612 | return 0; |
547 | } | 613 | } |
548 | 614 | ||
615 | static void prepare_td(struct transfer_descriptor* td, | ||
616 | struct transfer_descriptor* previous_td, | ||
617 | void *ptr, int len) | ||
618 | { | ||
619 | //logf("adding a td : %d",len); | ||
620 | memset(td, 0, sizeof(struct transfer_descriptor)); | ||
621 | td->next_td_ptr = DTD_NEXT_TERMINATE; | ||
622 | td->size_ioc_sts = (len<< DTD_LENGTH_BIT_POS) | | ||
623 | DTD_STATUS_ACTIVE | DTD_IOC; | ||
624 | td->buff_ptr0 = (unsigned int)ptr; | ||
625 | td->buff_ptr1 = ((unsigned int)ptr & 0xfffff000) + 0x1000; | ||
626 | td->buff_ptr2 = ((unsigned int)ptr & 0xfffff000) + 0x2000; | ||
627 | td->buff_ptr3 = ((unsigned int)ptr & 0xfffff000) + 0x3000; | ||
628 | td->buff_ptr4 = ((unsigned int)ptr & 0xfffff000) + 0x4000; | ||
629 | td->reserved = len; | ||
630 | |||
631 | if (previous_td != 0) { | ||
632 | previous_td->next_td_ptr=(unsigned int)td; | ||
633 | previous_td->size_ioc_sts&=~DTD_IOC;// Only an interrupt on the last one | ||
634 | } | ||
635 | } | ||
636 | |||
549 | static void transfer_completed(void) | 637 | static void transfer_completed(void) |
550 | { | 638 | { |
551 | int i; | 639 | int i; |
@@ -557,13 +645,16 @@ static void transfer_completed(void) | |||
557 | for (i=0; i<NUM_ENDPOINTS; i++) { | 645 | for (i=0; i<NUM_ENDPOINTS; i++) { |
558 | int x; | 646 | int x; |
559 | for (x=0; x<2; x++) { | 647 | for (x=0; x<2; x++) { |
648 | unsigned int status; | ||
560 | int pipe = i * 2 + x; | 649 | int pipe = i * 2 + x; |
650 | |||
561 | if (mask & pipe2mask[pipe]) | 651 | if (mask & pipe2mask[pipe]) |
562 | usb_core_transfer_complete(i, x ? true : false); | 652 | usb_core_transfer_complete(i, x ? true : false); |
563 | 653 | ||
654 | status = usb_drv_get_last_transfer_status(); | ||
564 | if ((mask & pipe2mask[pipe]) && | 655 | if ((mask & pipe2mask[pipe]) && |
565 | (td_array[pipe].size_ioc_sts & DTD_ERROR_MASK)) { | 656 | status & DTD_ERROR_MASK) { |
566 | logf("pipe %d err %x", pipe, td_array[pipe].size_ioc_sts & DTD_ERROR_MASK); | 657 | logf("pipe %d err %x", pipe, status & DTD_ERROR_MASK); |
567 | } | 658 | } |
568 | } | 659 | } |
569 | } | 660 | } |
@@ -600,23 +691,42 @@ static void bus_reset(void) | |||
600 | if (!(REG_PORTSC1 & PORTSCX_PORT_RESET)) { | 691 | if (!(REG_PORTSC1 & PORTSCX_PORT_RESET)) { |
601 | logf("usb: slow reset!"); | 692 | logf("usb: slow reset!"); |
602 | } | 693 | } |
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); | ||
603 | } | 702 | } |
604 | 703 | ||
605 | /* manual: 32.14.4.1 Queue Head Initialization */ | 704 | /* manual: 32.14.4.1 Queue Head Initialization */ |
606 | static void init_queue_heads(void) | 705 | static void init_queue_heads(void) |
607 | { | 706 | { |
707 | int tx_packetsize; | ||
708 | int rx_packetsize; | ||
709 | |||
710 | if (usb_drv_port_speed()) { | ||
711 | rx_packetsize = 512; | ||
712 | tx_packetsize = 512; | ||
713 | } | ||
714 | else { | ||
715 | rx_packetsize = 16; | ||
716 | tx_packetsize = 16; | ||
717 | } | ||
608 | memset(qh_array, 0, sizeof _qh_array); | 718 | memset(qh_array, 0, sizeof _qh_array); |
609 | 719 | ||
610 | /*** control ***/ | 720 | /*** control ***/ |
611 | qh_array[EP_CONTROL].max_pkt_length = 512 << QH_MAX_PKT_LEN_POS | QH_IOS; | 721 | qh_array[EP_CONTROL].max_pkt_length = 64 << QH_MAX_PKT_LEN_POS | QH_IOS; |
612 | qh_array[EP_CONTROL].dtd.next_td_ptr = QH_NEXT_TERMINATE; | 722 | qh_array[EP_CONTROL].dtd.next_td_ptr = QH_NEXT_TERMINATE; |
613 | qh_array[EP_CONTROL+1].max_pkt_length = 512 << QH_MAX_PKT_LEN_POS; | 723 | qh_array[EP_CONTROL+1].max_pkt_length = 64 << QH_MAX_PKT_LEN_POS; |
614 | qh_array[EP_CONTROL+1].dtd.next_td_ptr = QH_NEXT_TERMINATE; | 724 | qh_array[EP_CONTROL+1].dtd.next_td_ptr = QH_NEXT_TERMINATE; |
615 | 725 | ||
616 | /*** bulk ***/ | 726 | /*** bulk ***/ |
617 | qh_array[EP_RX*2].max_pkt_length = 512 << QH_MAX_PKT_LEN_POS; | 727 | qh_array[EP_RX*2].max_pkt_length = rx_packetsize << QH_MAX_PKT_LEN_POS | QH_ZLT_SEL; |
618 | qh_array[EP_RX*2].dtd.next_td_ptr = QH_NEXT_TERMINATE; | 728 | qh_array[EP_RX*2].dtd.next_td_ptr = QH_NEXT_TERMINATE; |
619 | qh_array[EP_TX*2+1].max_pkt_length = 512 << QH_MAX_PKT_LEN_POS; | 729 | qh_array[EP_TX*2+1].max_pkt_length = tx_packetsize << QH_MAX_PKT_LEN_POS | QH_ZLT_SEL; |
620 | qh_array[EP_TX*2+1].dtd.next_td_ptr = QH_NEXT_TERMINATE; | 730 | qh_array[EP_TX*2+1].dtd.next_td_ptr = QH_NEXT_TERMINATE; |
621 | } | 731 | } |
622 | 732 | ||
diff --git a/firmware/target/arm/usb-fw-pp502x.c b/firmware/target/arm/usb-fw-pp502x.c index 0813ae1c59..5b71fbd847 100644 --- a/firmware/target/arm/usb-fw-pp502x.c +++ b/firmware/target/arm/usb-fw-pp502x.c | |||
@@ -68,6 +68,9 @@ void usb_init_device(void) | |||
68 | void usb_enable(bool on) | 68 | void usb_enable(bool on) |
69 | { | 69 | { |
70 | if (on) { | 70 | if (on) { |
71 | #ifdef USE_ROCKBOX_USB | ||
72 | usb_core_init(); | ||
73 | #else | ||
71 | /* until we have native mass-storage mode, we want to reboot on | 74 | /* until we have native mass-storage mode, we want to reboot on |
72 | usb host connect */ | 75 | usb host connect */ |
73 | #if defined(IRIVER_H10) || defined (IRIVER_H10_5GB) | 76 | #if defined(IRIVER_H10) || defined (IRIVER_H10_5GB) |
@@ -89,6 +92,7 @@ void usb_enable(bool on) | |||
89 | 92 | ||
90 | system_reboot(); /* Reboot */ | 93 | system_reboot(); /* Reboot */ |
91 | } | 94 | } |
95 | #endif /* USE_ROCKBOX_USB */ | ||
92 | } | 96 | } |
93 | else | 97 | else |
94 | usb_core_exit(); | 98 | usb_core_exit(); |
@@ -195,9 +199,9 @@ int usb_detect(void) | |||
195 | return status; | 199 | return status; |
196 | } | 200 | } |
197 | 201 | ||
198 | /* Wait up to 50 ticks (500ms) before deciding there is no computer | 202 | /* Wait up to 100 ticks (1s) before deciding there is no computer |
199 | attached. */ | 203 | attached. */ |
200 | countdown = 50; | 204 | countdown = 100; |
201 | 205 | ||
202 | return status; | 206 | return status; |
203 | } | 207 | } |
diff --git a/firmware/usbstack/usb_core.c b/firmware/usbstack/usb_core.c index 7e86086dd4..13993f9271 100644 --- a/firmware/usbstack/usb_core.c +++ b/firmware/usbstack/usb_core.c | |||
@@ -23,10 +23,17 @@ | |||
23 | //#define LOGF_ENABLE | 23 | //#define LOGF_ENABLE |
24 | #include "logf.h" | 24 | #include "logf.h" |
25 | 25 | ||
26 | //#define USB_STORAGE | 26 | #ifndef BOOTLOADER |
27 | //#define USB_SERIAL | 27 | //#define USB_SERIAL |
28 | //#define USB_BENCHMARK | 28 | //#define USB_BENCHMARK |
29 | #ifdef USE_ROCKBOX_USB | ||
30 | #define USB_STORAGE | ||
31 | #else | ||
29 | #define USB_CHARGING_ONLY | 32 | #define USB_CHARGING_ONLY |
33 | #endif /* USE_ROCKBOX_USB */ | ||
34 | #else | ||
35 | #define USB_CHARGING_ONLY | ||
36 | #endif | ||
30 | 37 | ||
31 | #include "usb_ch9.h" | 38 | #include "usb_ch9.h" |
32 | #include "usb_drv.h" | 39 | #include "usb_drv.h" |
@@ -63,21 +70,21 @@ static const struct usb_device_descriptor device_descriptor = { | |||
63 | .bcdDevice = 0x0100, | 70 | .bcdDevice = 0x0100, |
64 | .iManufacturer = 1, | 71 | .iManufacturer = 1, |
65 | .iProduct = 2, | 72 | .iProduct = 2, |
66 | .iSerialNumber = 0, | 73 | .iSerialNumber = 3, |
67 | .bNumConfigurations = 1 | 74 | .bNumConfigurations = 1 |
68 | }; | 75 | }; |
69 | 76 | ||
70 | static const struct { | 77 | static const struct { |
71 | struct usb_config_descriptor config_descriptor; | 78 | struct usb_config_descriptor config_descriptor; |
72 | struct usb_interface_descriptor interface_descriptor; | 79 | struct usb_interface_descriptor interface_descriptor; |
73 | struct usb_endpoint_descriptor ep1_hs_in_descriptor; | 80 | struct usb_endpoint_descriptor ep1_in_descriptor; |
74 | struct usb_endpoint_descriptor ep1_hs_out_descriptor; | 81 | struct usb_endpoint_descriptor ep1_out_descriptor; |
75 | } config_data = | 82 | } config_data_fs = |
76 | { | 83 | { |
77 | { | 84 | { |
78 | .bLength = sizeof(struct usb_config_descriptor), | 85 | .bLength = sizeof(struct usb_config_descriptor), |
79 | .bDescriptorType = USB_DT_CONFIG, | 86 | .bDescriptorType = USB_DT_CONFIG, |
80 | .wTotalLength = sizeof config_data, | 87 | .wTotalLength = sizeof config_data_fs, |
81 | .bNumInterfaces = 1, | 88 | .bNumInterfaces = 1, |
82 | .bConfigurationValue = 1, | 89 | .bConfigurationValue = 1, |
83 | .iConfiguration = 0, | 90 | .iConfiguration = 0, |
@@ -96,12 +103,153 @@ static const struct { | |||
96 | .bInterfaceClass = USB_CLASS_VENDOR_SPEC, | 103 | .bInterfaceClass = USB_CLASS_VENDOR_SPEC, |
97 | .bInterfaceSubClass = 0, | 104 | .bInterfaceSubClass = 0, |
98 | .bInterfaceProtocol = 0, | 105 | .bInterfaceProtocol = 0, |
106 | .iInterface = 5 | ||
107 | }, | ||
108 | |||
109 | { | ||
110 | .bLength = sizeof(struct usb_endpoint_descriptor), | ||
111 | .bDescriptorType = USB_DT_ENDPOINT, | ||
112 | .bEndpointAddress = EP_TX | USB_DIR_IN, | ||
113 | .bmAttributes = USB_ENDPOINT_XFER_BULK, | ||
114 | .wMaxPacketSize = 512, | ||
115 | .bInterval = 0 | ||
116 | }, | ||
117 | { | ||
118 | .bLength = sizeof(struct usb_endpoint_descriptor), | ||
119 | .bDescriptorType = USB_DT_ENDPOINT, | ||
120 | .bEndpointAddress = EP_RX | USB_DIR_OUT, | ||
121 | .bmAttributes = USB_ENDPOINT_XFER_BULK, | ||
122 | .wMaxPacketSize = 512, | ||
123 | .bInterval = 0 | ||
124 | } | ||
125 | #endif | ||
126 | |||
127 | #ifdef USB_STORAGE | ||
128 | /* storage interface */ | ||
129 | { | ||
130 | .bLength = sizeof(struct usb_interface_descriptor), | ||
131 | .bDescriptorType = USB_DT_INTERFACE, | ||
132 | .bInterfaceNumber = 0, | ||
133 | .bAlternateSetting = 0, | ||
134 | .bNumEndpoints = 2, | ||
135 | .bInterfaceClass = USB_CLASS_MASS_STORAGE, | ||
136 | .bInterfaceSubClass = USB_SC_SCSI, | ||
137 | .bInterfaceProtocol = USB_PROT_BULK, | ||
138 | .iInterface = 0 | ||
139 | }, | ||
140 | |||
141 | { | ||
142 | .bLength = sizeof(struct usb_endpoint_descriptor), | ||
143 | .bDescriptorType = USB_DT_ENDPOINT, | ||
144 | .bEndpointAddress = EP_TX | USB_DIR_IN, | ||
145 | .bmAttributes = USB_ENDPOINT_XFER_BULK, | ||
146 | .wMaxPacketSize = 16, | ||
147 | .bInterval = 0 | ||
148 | }, | ||
149 | { | ||
150 | .bLength = sizeof(struct usb_endpoint_descriptor), | ||
151 | .bDescriptorType = USB_DT_ENDPOINT, | ||
152 | .bEndpointAddress = EP_RX | USB_DIR_OUT, | ||
153 | .bmAttributes = USB_ENDPOINT_XFER_BULK, | ||
154 | .wMaxPacketSize = 16, | ||
155 | .bInterval = 0 | ||
156 | } | ||
157 | #endif | ||
158 | |||
159 | #ifdef USB_SERIAL | ||
160 | /* serial interface */ | ||
161 | { | ||
162 | .bLength = sizeof(struct usb_interface_descriptor), | ||
163 | .bDescriptorType = USB_DT_INTERFACE, | ||
164 | .bInterfaceNumber = 0, | ||
165 | .bAlternateSetting = 0, | ||
166 | .bNumEndpoints = 2, | ||
167 | .bInterfaceClass = USB_CLASS_CDC_DATA, | ||
168 | .bInterfaceSubClass = 0, | ||
169 | .bInterfaceProtocol = 0, | ||
170 | .iInterface = 0 | ||
171 | }, | ||
172 | |||
173 | { | ||
174 | .bLength = sizeof(struct usb_endpoint_descriptor), | ||
175 | .bDescriptorType = USB_DT_ENDPOINT, | ||
176 | .bEndpointAddress = EP_TX | USB_DIR_IN, | ||
177 | .bmAttributes = USB_ENDPOINT_XFER_BULK, | ||
178 | .wMaxPacketSize = 64, | ||
179 | .bInterval = 0 | ||
180 | }, | ||
181 | { | ||
182 | .bLength = sizeof(struct usb_endpoint_descriptor), | ||
183 | .bDescriptorType = USB_DT_ENDPOINT, | ||
184 | .bEndpointAddress = EP_RX | USB_DIR_OUT, | ||
185 | .bmAttributes = USB_ENDPOINT_XFER_BULK, | ||
186 | .wMaxPacketSize = 64, | ||
187 | .bInterval = 0 | ||
188 | } | ||
189 | #endif | ||
190 | |||
191 | #ifdef USB_BENCHMARK | ||
192 | /* bulk test interface */ | ||
193 | { | ||
194 | .bLength = sizeof(struct usb_interface_descriptor), | ||
195 | .bDescriptorType = USB_DT_INTERFACE, | ||
196 | .bInterfaceNumber = 0, | ||
197 | .bAlternateSetting = 0, | ||
198 | .bNumEndpoints = 2, | ||
199 | .bInterfaceClass = USB_CLASS_VENDOR_SPEC, | ||
200 | .bInterfaceSubClass = 255, | ||
201 | .bInterfaceProtocol = 255, | ||
99 | .iInterface = 4 | 202 | .iInterface = 4 |
100 | }, | 203 | }, |
101 | 204 | ||
102 | { | 205 | { |
103 | .bLength = sizeof(struct usb_endpoint_descriptor), | 206 | .bLength = sizeof(struct usb_endpoint_descriptor), |
104 | .bDescriptorType = USB_DT_ENDPOINT, | 207 | .bDescriptorType = USB_DT_ENDPOINT, |
208 | .bEndpointAddress = EP_RX | USB_DIR_OUT, | ||
209 | .bmAttributes = USB_ENDPOINT_XFER_BULK, | ||
210 | .wMaxPacketSize = 64, | ||
211 | .bInterval = 0 | ||
212 | }, | ||
213 | { | ||
214 | .bLength = sizeof(struct usb_endpoint_descriptor), | ||
215 | .bDescriptorType = USB_DT_ENDPOINT, | ||
216 | .bEndpointAddress = EP_TX | USB_DIR_IN, | ||
217 | .bmAttributes = USB_ENDPOINT_XFER_BULK, | ||
218 | .wMaxPacketSize = 64, | ||
219 | .bInterval = 0 | ||
220 | } | ||
221 | #endif | ||
222 | }, | ||
223 | config_data_hs = | ||
224 | { | ||
225 | { | ||
226 | .bLength = sizeof(struct usb_config_descriptor), | ||
227 | .bDescriptorType = USB_DT_CONFIG, | ||
228 | .wTotalLength = sizeof config_data_hs, | ||
229 | .bNumInterfaces = 1, | ||
230 | .bConfigurationValue = 1, | ||
231 | .iConfiguration = 0, | ||
232 | .bmAttributes = USB_CONFIG_ATT_ONE | USB_CONFIG_ATT_SELFPOWER, | ||
233 | .bMaxPower = 250, /* 500mA in 2mA units */ | ||
234 | }, | ||
235 | |||
236 | #ifdef USB_CHARGING_ONLY | ||
237 | /* dummy interface for charging-only */ | ||
238 | { | ||
239 | .bLength = sizeof(struct usb_interface_descriptor), | ||
240 | .bDescriptorType = USB_DT_INTERFACE, | ||
241 | .bInterfaceNumber = 0, | ||
242 | .bAlternateSetting = 0, | ||
243 | .bNumEndpoints = 2, | ||
244 | .bInterfaceClass = USB_CLASS_VENDOR_SPEC, | ||
245 | .bInterfaceSubClass = 0, | ||
246 | .bInterfaceProtocol = 0, | ||
247 | .iInterface = 5 | ||
248 | }, | ||
249 | |||
250 | { | ||
251 | .bLength = sizeof(struct usb_endpoint_descriptor), | ||
252 | .bDescriptorType = USB_DT_ENDPOINT, | ||
105 | .bEndpointAddress = EP_TX | USB_DIR_IN, | 253 | .bEndpointAddress = EP_TX | USB_DIR_IN, |
106 | .bmAttributes = USB_ENDPOINT_XFER_BULK, | 254 | .bmAttributes = USB_ENDPOINT_XFER_BULK, |
107 | .wMaxPacketSize = 512, | 255 | .wMaxPacketSize = 512, |
@@ -168,7 +316,7 @@ static const struct { | |||
168 | .bDescriptorType = USB_DT_ENDPOINT, | 316 | .bDescriptorType = USB_DT_ENDPOINT, |
169 | .bEndpointAddress = EP_TX | USB_DIR_IN, | 317 | .bEndpointAddress = EP_TX | USB_DIR_IN, |
170 | .bmAttributes = USB_ENDPOINT_XFER_BULK, | 318 | .bmAttributes = USB_ENDPOINT_XFER_BULK, |
171 | .wMaxPacketSize = 64, | 319 | .wMaxPacketSize = 512, |
172 | .bInterval = 0 | 320 | .bInterval = 0 |
173 | }, | 321 | }, |
174 | { | 322 | { |
@@ -176,7 +324,7 @@ static const struct { | |||
176 | .bDescriptorType = USB_DT_ENDPOINT, | 324 | .bDescriptorType = USB_DT_ENDPOINT, |
177 | .bEndpointAddress = EP_RX | USB_DIR_OUT, | 325 | .bEndpointAddress = EP_RX | USB_DIR_OUT, |
178 | .bmAttributes = USB_ENDPOINT_XFER_BULK, | 326 | .bmAttributes = USB_ENDPOINT_XFER_BULK, |
179 | .wMaxPacketSize = 64, | 327 | .wMaxPacketSize = 512, |
180 | .bInterval = 0 | 328 | .bInterval = 0 |
181 | } | 329 | } |
182 | #endif | 330 | #endif |
@@ -192,7 +340,7 @@ static const struct { | |||
192 | .bInterfaceClass = USB_CLASS_VENDOR_SPEC, | 340 | .bInterfaceClass = USB_CLASS_VENDOR_SPEC, |
193 | .bInterfaceSubClass = 255, | 341 | .bInterfaceSubClass = 255, |
194 | .bInterfaceProtocol = 255, | 342 | .bInterfaceProtocol = 255, |
195 | .iInterface = 3 | 343 | .iInterface = 4 |
196 | }, | 344 | }, |
197 | 345 | ||
198 | { | 346 | { |
@@ -200,7 +348,6 @@ static const struct { | |||
200 | .bDescriptorType = USB_DT_ENDPOINT, | 348 | .bDescriptorType = USB_DT_ENDPOINT, |
201 | .bEndpointAddress = EP_RX | USB_DIR_OUT, | 349 | .bEndpointAddress = EP_RX | USB_DIR_OUT, |
202 | .bmAttributes = USB_ENDPOINT_XFER_BULK, | 350 | .bmAttributes = USB_ENDPOINT_XFER_BULK, |
203 | // .wMaxPacketSize = 64, | ||
204 | .wMaxPacketSize = 512, | 351 | .wMaxPacketSize = 512, |
205 | .bInterval = 0 | 352 | .bInterval = 0 |
206 | }, | 353 | }, |
@@ -209,7 +356,6 @@ static const struct { | |||
209 | .bDescriptorType = USB_DT_ENDPOINT, | 356 | .bDescriptorType = USB_DT_ENDPOINT, |
210 | .bEndpointAddress = EP_TX | USB_DIR_IN, | 357 | .bEndpointAddress = EP_TX | USB_DIR_IN, |
211 | .bmAttributes = USB_ENDPOINT_XFER_BULK, | 358 | .bmAttributes = USB_ENDPOINT_XFER_BULK, |
212 | // .wMaxPacketSize = 64, | ||
213 | .wMaxPacketSize = 512, | 359 | .wMaxPacketSize = 512, |
214 | .bInterval = 0 | 360 | .bInterval = 0 |
215 | } | 361 | } |
@@ -228,72 +374,61 @@ static const struct usb_qualifier_descriptor qualifier_descriptor = | |||
228 | .bNumConfigurations = 1 | 374 | .bNumConfigurations = 1 |
229 | }; | 375 | }; |
230 | 376 | ||
231 | /* full speed = 12 Mbit */ | 377 | static struct usb_string_descriptor usb_string_iManufacturer = |
232 | static const struct usb_endpoint_descriptor ep1_fs_in_descriptor = | ||
233 | { | 378 | { |
234 | .bLength = sizeof(struct usb_endpoint_descriptor), | 379 | 24, |
235 | .bDescriptorType = USB_DT_ENDPOINT, | 380 | USB_DT_STRING, |
236 | .bEndpointAddress = 1 | USB_DIR_IN, | 381 | {'R','o','c','k','b','o','x','.','o','r','g'} |
237 | .bmAttributes = USB_ENDPOINT_XFER_BULK, | ||
238 | .wMaxPacketSize = 64, | ||
239 | .bInterval = 0 | ||
240 | }; | 382 | }; |
241 | 383 | ||
242 | static const struct usb_endpoint_descriptor ep1_fs_out_descriptor = | 384 | static struct usb_string_descriptor usb_string_iProduct = |
243 | { | 385 | { |
244 | .bLength = sizeof(struct usb_endpoint_descriptor), | 386 | 42, |
245 | .bDescriptorType = USB_DT_ENDPOINT, | 387 | USB_DT_STRING, |
246 | .bEndpointAddress = 1 | USB_DIR_OUT, | 388 | {'R','o','c','k','b','o','x',' ','m','e','d','i','a',' ','p','l','a','y','e','r'} |
247 | .bmAttributes = USB_ENDPOINT_XFER_BULK, | ||
248 | .wMaxPacketSize = 64, | ||
249 | .bInterval = 0 | ||
250 | }; | 389 | }; |
251 | 390 | ||
252 | static const struct usb_endpoint_descriptor* ep_descriptors[4] = | 391 | static struct usb_string_descriptor usb_string_iSerial = |
253 | { | 392 | { |
254 | &config_data.ep1_hs_in_descriptor, | 393 | 34, |
255 | &config_data.ep1_hs_out_descriptor, | 394 | USB_DT_STRING, |
256 | &ep1_fs_in_descriptor, | 395 | {'0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0'} |
257 | &ep1_fs_out_descriptor | ||
258 | }; | 396 | }; |
259 | 397 | ||
398 | |||
399 | /* Generic for all targets */ | ||
400 | |||
260 | /* this is stringid #0: languages supported */ | 401 | /* this is stringid #0: languages supported */ |
261 | static const struct usb_string_descriptor lang_descriptor = | 402 | static struct usb_string_descriptor lang_descriptor = |
262 | { | 403 | { |
263 | sizeof(struct usb_string_descriptor), | 404 | 4, |
264 | USB_DT_STRING, | 405 | USB_DT_STRING, |
265 | {0x0409} /* LANGID US English */ | 406 | {0x0409} /* LANGID US English */ |
266 | }; | 407 | }; |
267 | 408 | ||
268 | /* this is stringid #1 and up: the actual strings */ | 409 | static struct usb_string_descriptor usb_string_usb_benchmark = |
269 | static const struct { | ||
270 | unsigned char size; | ||
271 | unsigned char type; | ||
272 | unsigned short string[32]; | ||
273 | } usb_strings[] = | ||
274 | { | 410 | { |
275 | { | 411 | 40, |
276 | 24, | 412 | USB_DT_STRING, |
277 | USB_DT_STRING, | 413 | {'B','u','l','k',' ','t','e','s','t',' ','i','n','t','e','r','f','a','c','e'} |
278 | {'R','o','c','k','b','o','x','.','o','r','g'} | ||
279 | }, | ||
280 | { | ||
281 | 42, | ||
282 | USB_DT_STRING, | ||
283 | {'R','o','c','k','b','o','x',' ','m','e','d','i','a',' ','p','l','a','y','e','r'} | ||
284 | }, | ||
285 | { | ||
286 | 40, | ||
287 | USB_DT_STRING, | ||
288 | {'B','u','l','k',' ','t','e','s','t',' ','i','n','t','e','r','f','a','c','e'} | ||
289 | }, | ||
290 | { | ||
291 | 28, | ||
292 | USB_DT_STRING, | ||
293 | {'C','h','a','r','g','i','n','g',' ','o','n','l','y'} | ||
294 | } | ||
295 | }; | 414 | }; |
296 | 415 | ||
416 | static struct usb_string_descriptor usb_string_charging_only = | ||
417 | { | ||
418 | 28, | ||
419 | USB_DT_STRING, | ||
420 | {'C','h','a','r','g','i','n','g',' ','o','n','l','y'} | ||
421 | }; | ||
422 | |||
423 | static struct usb_string_descriptor* usb_strings[] = | ||
424 | { | ||
425 | &lang_descriptor, | ||
426 | &usb_string_iManufacturer, | ||
427 | &usb_string_iProduct, | ||
428 | &usb_string_iSerial, | ||
429 | &usb_string_usb_benchmark, | ||
430 | &usb_string_charging_only | ||
431 | }; | ||
297 | 432 | ||
298 | static int usb_address = 0; | 433 | static int usb_address = 0; |
299 | static bool initialized = false; | 434 | static bool initialized = false; |
@@ -310,11 +445,45 @@ static void usb_core_thread(void); | |||
310 | 445 | ||
311 | static void ack_control(struct usb_ctrlrequest* req); | 446 | static void ack_control(struct usb_ctrlrequest* req); |
312 | 447 | ||
448 | #ifdef IPOD_ARCH | ||
449 | void set_serial_descriptor(void) | ||
450 | { | ||
451 | static short hex[16] = {'0','1','2','3','4','5','6','7', | ||
452 | '8','9','A','B','C','D','E','F'}; | ||
453 | #ifdef IPOD_VIDEO | ||
454 | uint32_t* serial = (uint32_t*)(0x20004034); | ||
455 | #else | ||
456 | uint32_t* serial = (uint32_t*)(0x20002034); | ||
457 | #endif | ||
458 | |||
459 | /* We need to convert from a little-endian 64-bit int | ||
460 | into a utf-16 string of hex characters */ | ||
461 | short* p = &usb_string_iSerial.wString[15]; | ||
462 | uint32_t x; | ||
463 | int i,j; | ||
464 | |||
465 | for (i = 0; i < 2; i++) | ||
466 | { | ||
467 | x = serial[i]; | ||
468 | for (j=0;j<8;j++) | ||
469 | { | ||
470 | *p-- = hex[x & 0xf]; | ||
471 | x >>= 4; | ||
472 | } | ||
473 | } | ||
474 | |||
475 | } | ||
476 | #endif | ||
477 | |||
313 | void usb_core_init(void) | 478 | void usb_core_init(void) |
314 | { | 479 | { |
315 | if (initialized) | 480 | if (initialized) |
316 | return; | 481 | return; |
317 | 482 | ||
483 | #ifdef IPOD_ARCH | ||
484 | set_serial_descriptor(); | ||
485 | #endif | ||
486 | |||
318 | queue_init(&usbcore_queue, false); | 487 | queue_init(&usbcore_queue, false); |
319 | usb_drv_init(); | 488 | usb_drv_init(); |
320 | #ifdef USB_STORAGE | 489 | #ifdef USB_STORAGE |
@@ -469,43 +638,25 @@ void usb_core_control_request(struct usb_ctrlrequest* req) | |||
469 | break; | 638 | break; |
470 | 639 | ||
471 | case USB_DT_CONFIG: | 640 | case USB_DT_CONFIG: |
472 | ptr = &config_data; | 641 | if(usb_drv_port_speed()) |
473 | size = sizeof config_data; | 642 | { |
474 | break; | 643 | ptr = &config_data_hs; |
475 | 644 | size = sizeof config_data_hs; | |
476 | case USB_DT_STRING: | 645 | } |
477 | switch (index) { | 646 | else |
478 | case 0: /* lang descriptor */ | 647 | { |
479 | ptr = &lang_descriptor; | 648 | ptr = &config_data_fs; |
480 | size = sizeof lang_descriptor; | 649 | size = sizeof config_data_fs; |
481 | break; | ||
482 | |||
483 | default: | ||
484 | if ((unsigned)index <= (sizeof(usb_strings)/sizeof(usb_strings[0]))) { | ||
485 | index -= 1; | ||
486 | ptr = &usb_strings[index]; | ||
487 | size = usb_strings[index].size; | ||
488 | } | ||
489 | else { | ||
490 | logf("bad string id %d", index); | ||
491 | usb_drv_stall(EP_CONTROL, true); | ||
492 | } | ||
493 | break; | ||
494 | } | 650 | } |
495 | break; | 651 | break; |
496 | 652 | ||
497 | case USB_DT_INTERFACE: | 653 | case USB_DT_STRING: |
498 | ptr = &config_data.interface_descriptor; | 654 | if ((unsigned)index < (sizeof(usb_strings)/sizeof(struct usb_string_descriptor*))) { |
499 | size = sizeof config_data.interface_descriptor; | 655 | ptr = usb_strings[index]; |
500 | break; | 656 | size = usb_strings[index]->bLength; |
501 | |||
502 | case USB_DT_ENDPOINT: | ||
503 | if (index <= NUM_ENDPOINTS) { | ||
504 | ptr = &ep_descriptors[index]; | ||
505 | size = sizeof ep_descriptors[index]; | ||
506 | } | 657 | } |
507 | else { | 658 | else { |
508 | logf("bad endpoint %d", index); | 659 | logf("bad string id %d", index); |
509 | usb_drv_stall(EP_CONTROL, true); | 660 | usb_drv_stall(EP_CONTROL, true); |
510 | } | 661 | } |
511 | break; | 662 | break; |
@@ -515,12 +666,6 @@ void usb_core_control_request(struct usb_ctrlrequest* req) | |||
515 | size = sizeof qualifier_descriptor; | 666 | size = sizeof qualifier_descriptor; |
516 | break; | 667 | break; |
517 | 668 | ||
518 | /* | ||
519 | case USB_DT_OTHER_SPEED_CONFIG: | ||
520 | ptr = &other_speed_descriptor; | ||
521 | size = sizeof other_speed_descriptor; | ||
522 | break; | ||
523 | */ | ||
524 | default: | 669 | default: |
525 | logf("bad desc %d", req->wValue >> 8); | 670 | logf("bad desc %d", req->wValue >> 8); |
526 | usb_drv_stall(EP_CONTROL, true); | 671 | usb_drv_stall(EP_CONTROL, true); |
diff --git a/firmware/usbstack/usb_storage.c b/firmware/usbstack/usb_storage.c index b852475663..1fbfe5296d 100644 --- a/firmware/usbstack/usb_storage.c +++ b/firmware/usbstack/usb_storage.c | |||
@@ -24,6 +24,7 @@ | |||
24 | #include "logf.h" | 24 | #include "logf.h" |
25 | #include "ata.h" | 25 | #include "ata.h" |
26 | #include "hotswap.h" | 26 | #include "hotswap.h" |
27 | #include "disk.h" | ||
27 | 28 | ||
28 | #define SECTOR_SIZE 512 | 29 | #define SECTOR_SIZE 512 |
29 | 30 | ||
@@ -40,14 +41,20 @@ | |||
40 | #define SCSI_TEST_UNIT_READY 0x00 | 41 | #define SCSI_TEST_UNIT_READY 0x00 |
41 | #define SCSI_INQUIRY 0x12 | 42 | #define SCSI_INQUIRY 0x12 |
42 | #define SCSI_MODE_SENSE 0x1a | 43 | #define SCSI_MODE_SENSE 0x1a |
44 | #define SCSI_REQUEST_SENSE 0x03 | ||
43 | #define SCSI_ALLOW_MEDIUM_REMOVAL 0x1e | 45 | #define SCSI_ALLOW_MEDIUM_REMOVAL 0x1e |
44 | #define SCSI_READ_CAPACITY 0x25 | 46 | #define SCSI_READ_CAPACITY 0x25 |
47 | #define SCSI_READ_FORMAT_CAPACITY 0x23 | ||
45 | #define SCSI_READ_10 0x28 | 48 | #define SCSI_READ_10 0x28 |
46 | #define SCSI_WRITE_10 0x2a | 49 | #define SCSI_WRITE_10 0x2a |
50 | #define SCSI_START_STOP_UNIT 0x1b | ||
47 | 51 | ||
48 | #define SCSI_STATUS_GOOD 0x00 | 52 | #define SCSI_STATUS_GOOD 0x00 |
53 | #define SCSI_STATUS_FAIL 0x01 | ||
49 | #define SCSI_STATUS_CHECK_CONDITION 0x02 | 54 | #define SCSI_STATUS_CHECK_CONDITION 0x02 |
50 | 55 | ||
56 | #define SCSI_FORMAT_CAPACITY_FORMATTED_MEDIA 0x02000000 | ||
57 | |||
51 | 58 | ||
52 | struct inquiry_data { | 59 | struct inquiry_data { |
53 | unsigned char DeviceType; | 60 | unsigned char DeviceType; |
@@ -62,6 +69,20 @@ struct inquiry_data { | |||
62 | unsigned char ProductRevisionLevel[4]; | 69 | unsigned char ProductRevisionLevel[4]; |
63 | } __attribute__ ((packed)); | 70 | } __attribute__ ((packed)); |
64 | 71 | ||
72 | struct sense_data { | ||
73 | unsigned char ResponseCode; | ||
74 | unsigned char Obsolete; | ||
75 | unsigned char filemark_eom_ili_sensekey; | ||
76 | unsigned int Information; | ||
77 | unsigned char AdditionalSenseLength; | ||
78 | unsigned int CommandSpecificInformation; | ||
79 | unsigned char AdditionalSenseCode; | ||
80 | unsigned char AdditionalSenseCodeQualifier; | ||
81 | unsigned char FieldReplaceableUnitCode; | ||
82 | unsigned char SKSV; | ||
83 | unsigned short SenseKeySpecific; | ||
84 | } __attribute__ ((packed)); | ||
85 | |||
65 | struct command_block_wrapper { | 86 | struct command_block_wrapper { |
66 | unsigned int signature; | 87 | unsigned int signature; |
67 | unsigned int tag; | 88 | unsigned int tag; |
@@ -84,26 +105,34 @@ struct capacity { | |||
84 | unsigned int block_size; | 105 | unsigned int block_size; |
85 | } __attribute__ ((packed)); | 106 | } __attribute__ ((packed)); |
86 | 107 | ||
108 | struct format_capacity { | ||
109 | unsigned int following_length; | ||
110 | unsigned int block_count; | ||
111 | unsigned int block_size; | ||
112 | } __attribute__ ((packed)); | ||
113 | |||
87 | /* the ARC USB controller can at most buffer 16KB unaligned data */ | 114 | /* the ARC USB controller can at most buffer 16KB unaligned data */ |
88 | static unsigned char _transfer_buffer[16384]; | 115 | static unsigned char _transfer_buffer[16384*8] __attribute((aligned (4096))); |
89 | static unsigned char* transfer_buffer; | 116 | static unsigned char* transfer_buffer; |
90 | static struct inquiry_data _inquiry; | 117 | static struct inquiry_data _inquiry CACHEALIGN_ATTR; |
91 | static struct inquiry_data* inquiry; | 118 | static struct inquiry_data* inquiry; |
92 | static struct capacity _capacity_data; | 119 | static struct capacity _capacity_data CACHEALIGN_ATTR; |
93 | static struct capacity* capacity_data; | 120 | static struct capacity* capacity_data; |
94 | 121 | static struct format_capacity _format_capacity_data CACHEALIGN_ATTR; | |
95 | //static unsigned char partial_sector[SECTOR_SIZE]; | 122 | static struct format_capacity* format_capacity_data; |
123 | static struct sense_data _sense_data CACHEALIGN_ATTR; | ||
124 | static struct sense_data *sense_data; | ||
96 | 125 | ||
97 | static struct { | 126 | static struct { |
98 | unsigned int sector; | 127 | unsigned int sector; |
99 | unsigned int offset; /* if partial sector */ | ||
100 | unsigned int count; | 128 | unsigned int count; |
101 | unsigned int tag; | 129 | unsigned int tag; |
130 | unsigned int lun; | ||
102 | } current_cmd; | 131 | } current_cmd; |
103 | 132 | ||
104 | void handle_scsi(struct command_block_wrapper* cbw); | 133 | static void handle_scsi(struct command_block_wrapper* cbw); |
105 | void send_csw(unsigned int tag, int status); | 134 | static void send_csw(unsigned int tag, int status); |
106 | static void identify2inquiry(void); | 135 | static void identify2inquiry(int lun); |
107 | 136 | ||
108 | static enum { | 137 | static enum { |
109 | IDLE, | 138 | IDLE, |
@@ -117,7 +146,10 @@ void usb_storage_init(void) | |||
117 | inquiry = (void*)UNCACHED_ADDR(&_inquiry); | 146 | inquiry = (void*)UNCACHED_ADDR(&_inquiry); |
118 | transfer_buffer = (void*)UNCACHED_ADDR(&_transfer_buffer); | 147 | transfer_buffer = (void*)UNCACHED_ADDR(&_transfer_buffer); |
119 | capacity_data = (void*)UNCACHED_ADDR(&_capacity_data); | 148 | capacity_data = (void*)UNCACHED_ADDR(&_capacity_data); |
120 | identify2inquiry(); | 149 | format_capacity_data = (void*)UNCACHED_ADDR(&_format_capacity_data); |
150 | sense_data = (void*)UNCACHED_ADDR(&_sense_data); | ||
151 | state = IDLE; | ||
152 | logf("usb_storage_init done"); | ||
121 | } | 153 | } |
122 | 154 | ||
123 | /* called by usb_core_transfer_complete() */ | 155 | /* called by usb_core_transfer_complete() */ |
@@ -128,21 +160,44 @@ void usb_storage_transfer_complete(int endpoint) | |||
128 | switch (endpoint) { | 160 | switch (endpoint) { |
129 | case EP_RX: | 161 | case EP_RX: |
130 | //logf("ums: %d bytes in", length); | 162 | //logf("ums: %d bytes in", length); |
131 | switch (state) { | 163 | if(state == RECEIVING) |
132 | case IDLE: | 164 | { |
133 | handle_scsi(cbw); | 165 | int receive_count=usb_drv_get_last_transfer_length(); |
134 | break; | 166 | logf("scsi write %d %d", current_cmd.sector, current_cmd.count); |
135 | 167 | if(usb_drv_get_last_transfer_status()==0) | |
136 | default: | 168 | { |
137 | break; | 169 | if((unsigned int)receive_count!=(SECTOR_SIZE*current_cmd.count)) |
170 | { | ||
171 | logf("%d >= %d",SECTOR_SIZE*current_cmd.count,receive_count); | ||
172 | } | ||
173 | ata_write_sectors(IF_MV2(current_cmd.lun,) | ||
174 | current_cmd.sector, current_cmd.count, | ||
175 | transfer_buffer); | ||
176 | send_csw(current_cmd.tag, SCSI_STATUS_GOOD); | ||
177 | } | ||
178 | else | ||
179 | { | ||
180 | logf("Transfer failed %X",usb_drv_get_last_transfer_status()); | ||
181 | send_csw(current_cmd.tag, SCSI_STATUS_CHECK_CONDITION); | ||
182 | } | ||
138 | } | 183 | } |
139 | 184 | else | |
140 | /* re-prime endpoint */ | 185 | { |
141 | usb_drv_recv(EP_RX, transfer_buffer, sizeof _transfer_buffer); | 186 | state = SENDING; |
187 | handle_scsi(cbw); | ||
188 | } | ||
189 | |||
142 | break; | 190 | break; |
143 | 191 | ||
144 | case EP_TX: | 192 | case EP_TX: |
145 | //logf("ums: %d bytes out", length); | 193 | //logf("ums: out complete"); |
194 | if(state != IDLE) | ||
195 | { | ||
196 | /* re-prime endpoint. We only need room for commands */ | ||
197 | state = IDLE; | ||
198 | usb_drv_recv(EP_RX, transfer_buffer, 1024); | ||
199 | } | ||
200 | |||
146 | break; | 201 | break; |
147 | } | 202 | } |
148 | } | 203 | } |
@@ -156,7 +211,7 @@ bool usb_storage_control_request(struct usb_ctrlrequest* req) | |||
156 | 211 | ||
157 | switch (req->bRequest) { | 212 | switch (req->bRequest) { |
158 | case USB_BULK_GET_MAX_LUN: { | 213 | case USB_BULK_GET_MAX_LUN: { |
159 | static char maxlun = 0; | 214 | static char maxlun = NUM_VOLUMES - 1; |
160 | logf("ums: getmaxlun"); | 215 | logf("ums: getmaxlun"); |
161 | usb_drv_send(EP_CONTROL, UNCACHED_ADDR(&maxlun), 1); | 216 | usb_drv_send(EP_CONTROL, UNCACHED_ADDR(&maxlun), 1); |
162 | usb_drv_recv(EP_CONTROL, NULL, 0); /* ack */ | 217 | usb_drv_recv(EP_CONTROL, NULL, 0); /* ack */ |
@@ -174,8 +229,9 @@ bool usb_storage_control_request(struct usb_ctrlrequest* req) | |||
174 | 229 | ||
175 | case USB_REQ_SET_CONFIGURATION: | 230 | case USB_REQ_SET_CONFIGURATION: |
176 | logf("ums: set config"); | 231 | logf("ums: set config"); |
177 | /* prime rx endpoint */ | 232 | /* prime rx endpoint. We only need room for commands */ |
178 | usb_drv_recv(EP_RX, transfer_buffer, sizeof _transfer_buffer); | 233 | state = IDLE; |
234 | usb_drv_recv(EP_RX, transfer_buffer, 1024); | ||
179 | handled = true; | 235 | handled = true; |
180 | break; | 236 | break; |
181 | } | 237 | } |
@@ -185,50 +241,138 @@ bool usb_storage_control_request(struct usb_ctrlrequest* req) | |||
185 | 241 | ||
186 | /****************************************************************************/ | 242 | /****************************************************************************/ |
187 | 243 | ||
188 | void handle_scsi(struct command_block_wrapper* cbw) | 244 | static void handle_scsi(struct command_block_wrapper* cbw) |
189 | { | 245 | { |
190 | /* USB Mass Storage assumes LBA capability. | 246 | /* USB Mass Storage assumes LBA capability. |
191 | TODO: support 48-bit LBA */ | 247 | TODO: support 48-bit LBA */ |
192 | 248 | ||
249 | unsigned int sectors_per_transfer=0; | ||
193 | unsigned int length = cbw->data_transfer_length; | 250 | unsigned int length = cbw->data_transfer_length; |
251 | unsigned int block_size; | ||
252 | unsigned char lun = cbw->lun; | ||
253 | unsigned int block_size_mult = 1; | ||
254 | #ifdef HAVE_HOTSWAP | ||
255 | tCardInfo* cinfo = card_get_info(lun); | ||
256 | block_size = cinfo->blocksize; | ||
257 | if(cinfo->initialized==1) | ||
258 | { | ||
259 | sectors_per_transfer=(sizeof _transfer_buffer/ block_size); | ||
260 | } | ||
261 | #else | ||
262 | block_size = SECTOR_SIZE; | ||
263 | sectors_per_transfer=(sizeof _transfer_buffer/ block_size); | ||
264 | #endif | ||
265 | |||
266 | #ifdef MAX_LOG_SECTOR_SIZE | ||
267 | block_size_mult = disk_sector_multiplier; | ||
268 | #endif | ||
194 | 269 | ||
195 | switch (cbw->command_block[0]) { | 270 | switch (cbw->command_block[0]) { |
196 | case SCSI_TEST_UNIT_READY: | 271 | case SCSI_TEST_UNIT_READY: |
197 | logf("scsi test_unit_ready"); | 272 | logf("scsi test_unit_ready %d",lun); |
273 | #ifdef HAVE_HOTSWAP | ||
274 | if(cinfo->initialized==1) | ||
275 | send_csw(cbw->tag, SCSI_STATUS_GOOD); | ||
276 | else | ||
277 | send_csw(cbw->tag, SCSI_STATUS_FAIL); | ||
278 | #else | ||
198 | send_csw(cbw->tag, SCSI_STATUS_GOOD); | 279 | send_csw(cbw->tag, SCSI_STATUS_GOOD); |
280 | #endif | ||
199 | break; | 281 | break; |
200 | 282 | ||
201 | case SCSI_INQUIRY: | 283 | case SCSI_INQUIRY: |
202 | logf("scsi inquiry"); | 284 | logf("scsi inquiry %d",lun); |
285 | identify2inquiry(lun); | ||
203 | length = MIN(length, cbw->command_block[4]); | 286 | length = MIN(length, cbw->command_block[4]); |
204 | usb_drv_send(EP_TX, inquiry, MIN(sizeof _inquiry, length)); | 287 | usb_drv_send(EP_TX, inquiry, MIN(sizeof _inquiry, length)); |
205 | send_csw(cbw->tag, SCSI_STATUS_GOOD); | 288 | send_csw(cbw->tag, SCSI_STATUS_GOOD); |
206 | break; | 289 | break; |
207 | 290 | ||
291 | case SCSI_REQUEST_SENSE: { | ||
292 | sense_data->ResponseCode=0x70; | ||
293 | sense_data->filemark_eom_ili_sensekey=2; | ||
294 | sense_data->Information=2; | ||
295 | sense_data->AdditionalSenseLength=10; | ||
296 | sense_data->CommandSpecificInformation=0; | ||
297 | sense_data->AdditionalSenseCode=0x3a; | ||
298 | sense_data->AdditionalSenseCodeQualifier=0; | ||
299 | sense_data->FieldReplaceableUnitCode=0; | ||
300 | sense_data->SKSV=0; | ||
301 | sense_data->SenseKeySpecific=0; | ||
302 | logf("scsi request_sense %d",lun); | ||
303 | usb_drv_send(EP_TX, sense_data, | ||
304 | sizeof(_sense_data)); | ||
305 | send_csw(cbw->tag, SCSI_STATUS_GOOD); | ||
306 | break; | ||
307 | } | ||
308 | |||
208 | case SCSI_MODE_SENSE: { | 309 | case SCSI_MODE_SENSE: { |
209 | static unsigned char sense_data[8] = { 0, 0, 0, 0, 0, 0, 0, 0 }; | 310 | static unsigned char sense_data[8] = { 0, 0, 0, 0, 0, 0, 0, 0 }; |
210 | logf("scsi mode_sense"); | 311 | logf("scsi mode_sense %d",lun); |
211 | usb_drv_send(EP_TX, UNCACHED_ADDR(&sense_data), | 312 | usb_drv_send(EP_TX, UNCACHED_ADDR(&sense_data), |
212 | MIN(sizeof sense_data, length)); | 313 | MIN(sizeof sense_data, length)); |
213 | send_csw(cbw->tag, SCSI_STATUS_GOOD); | 314 | send_csw(cbw->tag, SCSI_STATUS_GOOD); |
214 | break; | 315 | break; |
215 | } | 316 | } |
216 | 317 | ||
318 | case SCSI_START_STOP_UNIT: | ||
319 | logf("scsi start_stop unit %d",lun); | ||
320 | send_csw(cbw->tag, SCSI_STATUS_GOOD); | ||
321 | break; | ||
322 | |||
217 | case SCSI_ALLOW_MEDIUM_REMOVAL: | 323 | case SCSI_ALLOW_MEDIUM_REMOVAL: |
218 | logf("scsi allow_medium_removal"); | 324 | logf("scsi allow_medium_removal %d",lun); |
325 | send_csw(cbw->tag, SCSI_STATUS_GOOD); | ||
326 | break; | ||
327 | |||
328 | case SCSI_READ_FORMAT_CAPACITY: { | ||
329 | logf("scsi read_format_capacity %d",lun); | ||
330 | format_capacity_data->following_length=htobe32(8); | ||
331 | #ifdef HAVE_HOTSWAP | ||
332 | /* Careful: "block count" actually means "number of last block" */ | ||
333 | if(cinfo->initialized==1) | ||
334 | { | ||
335 | format_capacity_data->block_count = htobe32(cinfo->numblocks - 1); | ||
336 | format_capacity_data->block_size = htobe32(cinfo->blocksize); | ||
337 | } | ||
338 | else | ||
339 | { | ||
340 | format_capacity_data->block_count = htobe32(0); | ||
341 | format_capacity_data->block_size = htobe32(0); | ||
342 | } | ||
343 | #else | ||
344 | unsigned short* identify = ata_get_identify(); | ||
345 | /* Careful: "block count" actually means "number of last block" */ | ||
346 | format_capacity_data->block_count = htobe32((identify[61] << 16 | identify[60]) / block_size_mult - 1); | ||
347 | format_capacity_data->block_size = htobe32(block_size * block_size_mult); | ||
348 | #endif | ||
349 | format_capacity_data->block_size |= SCSI_FORMAT_CAPACITY_FORMATTED_MEDIA; | ||
350 | |||
351 | usb_drv_send(EP_TX, format_capacity_data, | ||
352 | MIN(sizeof _format_capacity_data, length)); | ||
219 | send_csw(cbw->tag, SCSI_STATUS_GOOD); | 353 | send_csw(cbw->tag, SCSI_STATUS_GOOD); |
220 | break; | 354 | break; |
355 | } | ||
221 | 356 | ||
222 | case SCSI_READ_CAPACITY: { | 357 | case SCSI_READ_CAPACITY: { |
223 | logf("scsi read_capacity"); | 358 | logf("scsi read_capacity %d",lun); |
224 | #ifdef HAVE_FLASH_STORAGE | 359 | #ifdef HAVE_HOTSWAP |
225 | tCardInfo* cinfo = card_get_info(0); | 360 | /* Careful: "block count" actually means "number of last block" */ |
226 | capacity_data->block_count = htobe32(cinfo->numblocks); | 361 | if(cinfo->initialized==1) |
227 | capacity_data->block_size = htobe32(cinfo->blocksize); | 362 | { |
363 | capacity_data->block_count = htobe32(cinfo->numblocks - 1); | ||
364 | capacity_data->block_size = htobe32(cinfo->blocksize); | ||
365 | } | ||
366 | else | ||
367 | { | ||
368 | capacity_data->block_count = htobe32(0); | ||
369 | capacity_data->block_size = htobe32(0); | ||
370 | } | ||
228 | #else | 371 | #else |
229 | unsigned short* identify = ata_get_identify(); | 372 | unsigned short* identify = ata_get_identify(); |
230 | capacity_data->block_count = htobe32(identify[60] << 16 | identify[61]); | 373 | /* Careful : "block count" actually means the number of the last block */ |
231 | capacity_data->block_size = htobe32(SECTOR_SIZE); | 374 | capacity_data->block_count = htobe32((identify[61] << 16 | identify[60]) / block_size_mult - 1); |
375 | capacity_data->block_size = htobe32(block_size * block_size_mult); | ||
232 | #endif | 376 | #endif |
233 | usb_drv_send(EP_TX, capacity_data, | 377 | usb_drv_send(EP_TX, capacity_data, |
234 | MIN(sizeof _capacity_data, length)); | 378 | MIN(sizeof _capacity_data, length)); |
@@ -237,43 +381,71 @@ void handle_scsi(struct command_block_wrapper* cbw) | |||
237 | } | 381 | } |
238 | 382 | ||
239 | case SCSI_READ_10: | 383 | case SCSI_READ_10: |
240 | current_cmd.sector = | 384 | current_cmd.sector = block_size_mult * |
241 | cbw->command_block[2] << 24 | | 385 | (cbw->command_block[2] << 24 | |
242 | cbw->command_block[3] << 16 | | 386 | cbw->command_block[3] << 16 | |
243 | cbw->command_block[4] << 8 | | 387 | cbw->command_block[4] << 8 | |
244 | cbw->command_block[5] ; | 388 | cbw->command_block[5] ); |
245 | current_cmd.count = | 389 | current_cmd.count = block_size_mult * |
246 | cbw->command_block[7] << 16 | | 390 | (cbw->command_block[7] << 16 | |
247 | cbw->command_block[8]; | 391 | cbw->command_block[8]); |
248 | current_cmd.offset = 0; | ||
249 | current_cmd.tag = cbw->tag; | 392 | current_cmd.tag = cbw->tag; |
393 | current_cmd.lun = cbw->lun; | ||
250 | 394 | ||
251 | logf("scsi read %d %d", current_cmd.sector, current_cmd.count); | 395 | //logf("scsi read %d %d", current_cmd.sector, current_cmd.count); |
252 | 396 | ||
253 | /* too much? */ | 397 | //logf("Asked for %d sectors",current_cmd.count); |
254 | if (current_cmd.count > (sizeof _transfer_buffer / SECTOR_SIZE)) { | 398 | if(current_cmd.count > sectors_per_transfer) |
255 | send_csw(current_cmd.tag, SCSI_STATUS_CHECK_CONDITION); | 399 | { |
256 | break; | 400 | current_cmd.count = sectors_per_transfer; |
257 | } | 401 | } |
402 | //logf("Sending %d sectors",current_cmd.count); | ||
258 | 403 | ||
259 | ata_read_sectors(IF_MV2(0,) current_cmd.sector, current_cmd.count, | 404 | if(current_cmd.count*block_size > sizeof(_transfer_buffer)) { |
260 | transfer_buffer); | 405 | send_csw(current_cmd.tag, SCSI_STATUS_CHECK_CONDITION); |
261 | state = SENDING; | 406 | } |
262 | usb_drv_send(EP_TX, transfer_buffer, | 407 | else { |
263 | MIN(current_cmd.count * SECTOR_SIZE, length)); | 408 | ata_read_sectors(IF_MV2(lun,) current_cmd.sector, |
409 | current_cmd.count, transfer_buffer); | ||
410 | usb_drv_send(EP_TX, transfer_buffer, | ||
411 | current_cmd.count*block_size); | ||
412 | send_csw(current_cmd.tag, SCSI_STATUS_GOOD); | ||
413 | } | ||
264 | break; | 414 | break; |
265 | 415 | ||
266 | case SCSI_WRITE_10: | 416 | case SCSI_WRITE_10: |
267 | logf("scsi write10"); | 417 | //logf("scsi write10"); |
418 | current_cmd.sector = block_size_mult * | ||
419 | (cbw->command_block[2] << 24 | | ||
420 | cbw->command_block[3] << 16 | | ||
421 | cbw->command_block[4] << 8 | | ||
422 | cbw->command_block[5] ); | ||
423 | current_cmd.count = block_size_mult * | ||
424 | (cbw->command_block[7] << 16 | | ||
425 | cbw->command_block[8]); | ||
426 | current_cmd.tag = cbw->tag; | ||
427 | current_cmd.lun = cbw->lun; | ||
428 | /* expect data */ | ||
429 | if(current_cmd.count*block_size > sizeof(_transfer_buffer)) { | ||
430 | send_csw(current_cmd.tag, SCSI_STATUS_CHECK_CONDITION); | ||
431 | } | ||
432 | else { | ||
433 | usb_drv_recv(EP_RX, transfer_buffer, | ||
434 | current_cmd.count*block_size); | ||
435 | state = RECEIVING; | ||
436 | } | ||
437 | |||
268 | break; | 438 | break; |
269 | 439 | ||
270 | default: | 440 | default: |
271 | logf("scsi unknown cmd %x", cbw->command_block[0]); | 441 | logf("scsi unknown cmd %x",cbw->command_block[0x0]); |
442 | usb_drv_stall(EP_TX, true); | ||
443 | send_csw(current_cmd.tag, SCSI_STATUS_GOOD); | ||
272 | break; | 444 | break; |
273 | } | 445 | } |
274 | } | 446 | } |
275 | 447 | ||
276 | void send_csw(unsigned int tag, int status) | 448 | static void send_csw(unsigned int tag, int status) |
277 | { | 449 | { |
278 | static struct command_status_wrapper _csw; | 450 | static struct command_status_wrapper _csw; |
279 | struct command_status_wrapper* csw = UNCACHED_ADDR(&_csw); | 451 | struct command_status_wrapper* csw = UNCACHED_ADDR(&_csw); |
@@ -287,16 +459,23 @@ void send_csw(unsigned int tag, int status) | |||
287 | } | 459 | } |
288 | 460 | ||
289 | /* convert ATA IDENTIFY to SCSI INQUIRY */ | 461 | /* convert ATA IDENTIFY to SCSI INQUIRY */ |
290 | static void identify2inquiry(void) | 462 | static void identify2inquiry(int lun) |
291 | { | 463 | { |
292 | unsigned int i; | ||
293 | #ifdef HAVE_FLASH_STORAGE | 464 | #ifdef HAVE_FLASH_STORAGE |
294 | for (i=0; i<8; i++) | 465 | if(lun==0) |
295 | inquiry->VendorId[i] = i + 'A'; | 466 | { |
296 | 467 | memcpy(&inquiry->VendorId,"Rockbox ",8); | |
297 | for (i=0; i<8; i++) | 468 | memcpy(&inquiry->ProductId,"Internal Storage",16); |
298 | inquiry->ProductId[i] = i + 'm'; | 469 | memcpy(&inquiry->ProductRevisionLevel,"0.00",4); |
470 | } | ||
471 | else | ||
472 | { | ||
473 | memcpy(&inquiry->VendorId,"Rockbox ",8); | ||
474 | memcpy(&inquiry->ProductId,"SD Card Slot ",16); | ||
475 | memcpy(&inquiry->ProductRevisionLevel,"0.00",4); | ||
476 | } | ||
299 | #else | 477 | #else |
478 | unsigned int i; | ||
300 | unsigned short* dest; | 479 | unsigned short* dest; |
301 | unsigned short* src; | 480 | unsigned short* src; |
302 | unsigned short* identify = ata_get_identify(); | 481 | unsigned short* identify = ata_get_identify(); |
@@ -310,22 +489,27 @@ static void identify2inquiry(void) | |||
310 | src = (unsigned short*)&identify[27]; | 489 | src = (unsigned short*)&identify[27]; |
311 | dest = (unsigned short*)&inquiry->VendorId; | 490 | dest = (unsigned short*)&inquiry->VendorId; |
312 | for (i=0;i<4;i++) | 491 | for (i=0;i<4;i++) |
313 | dest[i] = src[i]; | 492 | dest[i] = htobe16(src[i]); |
314 | 493 | ||
315 | src = (unsigned short*)&identify[27+8]; | 494 | src = (unsigned short*)&identify[27+8]; |
316 | dest = (unsigned short*)&inquiry->ProductId; | 495 | dest = (unsigned short*)&inquiry->ProductId; |
317 | for (i=0;i<8;i++) | 496 | for (i=0;i<8;i++) |
318 | dest[i] = src[i]; | 497 | dest[i] = htobe16(src[i]); |
319 | 498 | ||
320 | src = (unsigned short*)&identify[23]; | 499 | src = (unsigned short*)&identify[23]; |
321 | dest = (unsigned short*)&inquiry->ProductRevisionLevel; | 500 | dest = (unsigned short*)&inquiry->ProductRevisionLevel; |
322 | for (i=0;i<2;i++) | 501 | for (i=0;i<2;i++) |
323 | dest[i] = src[i]; | 502 | dest[i] = htobe16(src[i]); |
324 | #endif | 503 | #endif |
325 | 504 | ||
326 | inquiry->DeviceType = DIRECT_ACCESS_DEVICE; | 505 | inquiry->DeviceType = DIRECT_ACCESS_DEVICE; |
327 | inquiry->AdditionalLength = 0x1f; | 506 | inquiry->AdditionalLength = 0x1f; |
328 | inquiry->Versions = 3; /* ANSI SCSI level 2 */ | 507 | inquiry->Versions = 3; /* ANSI SCSI level 2 */ |
329 | inquiry->Format = 3; /* ANSI SCSI level 2 INQUIRY format */ | 508 | inquiry->Format = 3; /* ANSI SCSI level 2 INQUIRY format */ |
509 | |||
510 | #ifdef HAVE_HOTSWAP | ||
511 | inquiry->DeviceTypeModifier = DEVICE_REMOVABLE; | ||
512 | #endif | ||
513 | |||
330 | } | 514 | } |
331 | 515 | ||