diff options
Diffstat (limited to 'firmware/target/arm/usb-drv-pp502x.c')
-rw-r--r-- | firmware/target/arm/usb-drv-pp502x.c | 346 |
1 files changed, 195 insertions, 151 deletions
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 | } |