Index: firmware/export/usb_drv.h =================================================================== --- firmware/export/usb_drv.h (revision 16285) +++ firmware/export/usb_drv.h (working copy) @@ -32,8 +32,8 @@ void usb_drv_reset_endpoint(int endpoint, bool send); void usb_drv_wait(int endpoint, bool send); bool usb_drv_powered(void); -int usb_drv_get_last_transfer_status(void); -int usb_drv_get_last_transfer_length(void); +int usb_drv_get_last_transfer_status(int endpoint, bool send); +int usb_drv_get_last_transfer_length(int endpoint, bool send); int usb_drv_port_speed(void); #endif Index: firmware/export/usb_core.h =================================================================== --- firmware/export/usb_core.h (revision 16285) +++ firmware/export/usb_core.h (working copy) @@ -31,7 +31,8 @@ EP_CONTROL = 0, EP_RX, EP_TX, - NUM_ENDPOINTS + NUM_ENDPOINTS, + EP_QUIT }; /* queue events */ Index: firmware/usbstack/usb_core.c =================================================================== --- firmware/usbstack/usb_core.c (revision 16285) +++ firmware/usbstack/usb_core.c (working copy) @@ -49,6 +49,13 @@ #include "usb_benchmark.h" #endif +/* TODO: Move this target-specific stuff somewhere else (serial number reading) */ + +#ifdef HAVE_AS3514 +#include "i2c-pp.h" +#include "as3514.h" +#endif + /*-------------------------------------------------------------------------*/ /* USB protocol descriptors: */ @@ -388,12 +395,23 @@ {'R','o','c','k','b','o','x',' ','m','e','d','i','a',' ','p','l','a','y','e','r'} }; +#if defined(HAVE_AS3514) static struct usb_string_descriptor usb_string_iSerial = { - 34, - USB_DT_STRING, + 90, + USB_DT_STRING, + {'0','0','0','0','0','0','0','0','-','0','0','0','0','0','0','0','0','-', + '0','0','0','0','0','0','0','0','-','0','0','0','0','0','0','0','0','-', + '0','0','0','0','0','0','0','0'} +}; +#else +static struct usb_string_descriptor usb_string_iSerial = +{ + 34, + USB_DT_STRING, {'0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0'} }; +#endif /* Generic for all targets */ @@ -443,10 +461,11 @@ static void usb_core_thread(void); #endif +static void usb_core_control_request_handler(struct usb_ctrlrequest* req); static void ack_control(struct usb_ctrlrequest* req); #ifdef IPOD_ARCH -void set_serial_descriptor(void) +static void set_serial_descriptor(void) { static short hex[16] = {'0','1','2','3','4','5','6','7', '8','9','A','B','C','D','E','F'}; @@ -465,7 +484,7 @@ for (i = 0; i < 2; i++) { x = serial[i]; - for (j=0;j<8;j++) + for (j = 0; j < 8; j++) { *p-- = hex[x & 0xf]; x >>= 4; @@ -473,6 +492,33 @@ } } +#elif defined(HAVE_AS3514) +static void set_serial_descriptor(void) +{ + static short hex[16] = {'0','1','2','3','4','5','6','7', + '8','9','A','B','C','D','E','F'}; + + uint32_t serial[4]; + short* p = &usb_string_iSerial.wString[7]; + uint32_t x; + int i,j; + + i2c_readbytes(AS3514_I2C_ADDR, 0x30, 0x10, (unsigned char*)serial); + + /* We need to convert from little-endian 32-bit ints + into a utf-16 string of hex characters */ + + for (i = 0; i < 4; i++) + { + x = serial[i]; + for (j = 0; j < 8; j++) + { + *p-- = hex[x & 0xf]; + x >>= 4; + } + p += 17; /* Prepare for next 32 bits (8 hex digits) */ + } +} #endif void usb_core_init(void) @@ -480,10 +526,6 @@ if (initialized) return; -#ifdef IPOD_ARCH - set_serial_descriptor(); -#endif - queue_init(&usbcore_queue, false); usb_drv_init(); #ifdef USB_STORAGE @@ -514,10 +556,11 @@ { if (initialized) { usb_drv_exit(); - queue_delete(&usbcore_queue); #ifdef USB_THREAD - remove_thread(usbcore_thread); + queue_post(&usbcore_queue, EP_QUIT, 0); + thread_wait(usbcore_thread); #endif + queue_delete(&usbcore_queue); } data_connection = false; initialized = false; @@ -532,27 +575,36 @@ #ifdef USB_THREAD void usb_core_thread(void) { +#if defined(IPOD_ARCH) || defined(HAVE_AS3514) + set_serial_descriptor(); +#endif + while (1) { struct queue_event ev; queue_wait(&usbcore_queue, &ev); + if (ev.id == EP_QUIT) + return; + + if (ev.id == EP_CONTROL) { + usb_core_control_request_handler((struct usb_ctrlrequest*)ev.data); + } + else { #ifdef USB_STORAGE - usb_storage_transfer_complete(ev.id); + usb_storage_transfer_complete(ev.id); #endif #ifdef USB_SERIAL - usb_serial_transfer_complete(ev.id); + usb_serial_transfer_complete(ev.id); #endif - + } } } #endif -/* called by usb_drv_int() */ -void usb_core_control_request(struct usb_ctrlrequest* req) +static void usb_core_control_request_handler(struct usb_ctrlrequest* req) { - /* note: interrupt context */ data_connection = true; #ifdef USB_BENCHMARK @@ -711,7 +763,7 @@ /* called by usb_drv_transfer_completed() */ void usb_core_transfer_complete(int endpoint, bool in) { -#ifdef USB_CHARGING_ONLY +#if defined(USB_CHARGING_ONLY) || defined(USB_STORAGE) (void)in; #endif @@ -734,6 +786,11 @@ } } +void usb_core_control_request(struct usb_ctrlrequest* req) +{ + queue_post(&usbcore_queue, EP_CONTROL,(intptr_t)req); +} + static void ack_control(struct usb_ctrlrequest* req) { if (req->bRequestType & 0x80) Index: firmware/usbstack/usb_storage.c =================================================================== --- firmware/usbstack/usb_storage.c (revision 16285) +++ firmware/usbstack/usb_storage.c (working copy) @@ -162,9 +162,10 @@ //logf("ums: %d bytes in", length); if(state == RECEIVING) { - int receive_count=usb_drv_get_last_transfer_length(); + int receive_count=usb_drv_get_last_transfer_length(EP_RX,0); + int status = usb_drv_get_last_transfer_status(EP_RX,0); logf("scsi write %d %d", current_cmd.sector, current_cmd.count); - if(usb_drv_get_last_transfer_status()==0) + if(status==0) { if((unsigned int)receive_count!=(SECTOR_SIZE*current_cmd.count)) { @@ -177,7 +178,7 @@ } else { - logf("Transfer failed %X",usb_drv_get_last_transfer_status()); + logf("Transfer failed %X",status); send_csw(current_cmd.tag, SCSI_STATUS_CHECK_CONDITION); } } Index: firmware/target/arm/usb-drv-pp502x.c =================================================================== --- firmware/target/arm/usb-drv-pp502x.c (revision 16285) +++ firmware/target/arm/usb-drv-pp502x.c (working copy) @@ -23,7 +23,7 @@ #include "string.h" #include "usb_ch9.h" #include "usb_core.h" -//#define LOGF_ENABLE +#define LOGF_ENABLE #include "logf.h" /* USB device mode registers (Little Endian) */ @@ -278,6 +278,10 @@ DTD_STATUS_DATA_BUFF_ERR | \ DTD_STATUS_TRANSACTION_ERR) +#define DTD_RESERVED_LENGTH_MASK 0x0001ffff +#define DTD_RESERVED_IN_USE 0x80000000 +#define DTD_RESERVED_PIPE_MASK 0x0ff00000 +#define DTD_RESERVED_PIPE_OFFSET 20 /*-------------------------------------------------------------------------*/ /* manual: 32.13.2 Endpoint Transfer Descriptor (dTD) */ @@ -294,7 +298,8 @@ unsigned int reserved; } __attribute__ ((packed)); -static struct transfer_descriptor _td_array[32] __attribute((aligned (32))); +#define NUM_TRANSFER_DESCRIPTORS 32 +static struct transfer_descriptor _td_array[NUM_TRANSFER_DESCRIPTORS] __attribute((aligned (32))); static struct transfer_descriptor* td_array; /* manual: 32.13.1 Endpoint Queue Head (dQH) */ @@ -304,7 +309,8 @@ unsigned int curr_dtd_ptr; /* Current dTD Pointer(31-5) */ struct transfer_descriptor dtd; /* dTD overlay */ unsigned int setup_buffer[2]; /* Setup data 8 bytes */ - unsigned int reserved[4]; + unsigned int first_td; /* pointer to the first TD */ + unsigned int reserved[3]; } __attribute__((packed)); static struct queue_head _qh_array[NUM_ENDPOINTS*2] __attribute((aligned (2048))); @@ -317,18 +323,18 @@ 0x04, 0x040000, }; -static struct transfer_descriptor* first_td; -static struct transfer_descriptor* last_td; - /*-------------------------------------------------------------------------*/ static void transfer_completed(void); +static void control_received(void); static int prime_transfer(int endpoint, void* ptr, int len, bool send); +static int find_td(void); static void prepare_td(struct transfer_descriptor* td, struct transfer_descriptor* previous_td, - void *ptr, int len); + void *ptr, int len,int pipe); static void bus_reset(void); static void init_queue_heads(void); static void init_endpoints(void); +static int usb_drv_cleanup_last_transfer(int endpoint, bool send); /*-------------------------------------------------------------------------*/ bool usb_drv_powered(void) @@ -407,15 +413,7 @@ /* a control packet? */ if (REG_ENDPTSETUPSTAT & EPSETUP_STATUS_EP0) { - /* copy setup data from packet */ - unsigned int tmp[2]; - tmp[0] = qh_array[0].setup_buffer[0]; - tmp[1] = qh_array[0].setup_buffer[1]; - - /* acknowledge packet recieved */ - REG_ENDPTSETUPSTAT |= EPSETUP_STATUS_EP0; - - usb_core_control_request((struct usb_ctrlrequest*)tmp); + control_received(); } if (REG_ENDPTCOMPLETE) @@ -457,12 +455,16 @@ int usb_drv_send(int endpoint, void* ptr, int length) { - return prime_transfer(endpoint, ptr, length, true); + int result=0; + usb_drv_cleanup_last_transfer(endpoint,true); + result = prime_transfer(endpoint, ptr, length, true); + return result; } int usb_drv_recv(int endpoint, void* ptr, int length) { //logf("usbrecv(%x, %d)", ptr, length); + usb_drv_cleanup_last_transfer(endpoint,false); return prime_transfer(endpoint, ptr, length, false); } @@ -496,24 +498,30 @@ while (REG_ENDPTFLUSH & mask); } -int usb_drv_get_last_transfer_length(void) +int usb_drv_get_last_transfer_length(int endpoint, bool send) { - struct transfer_descriptor* current_td = first_td; + int pipe = endpoint * 2 + (send ? 1 : 0); int length = 0; + struct queue_head* qh = &qh_array[pipe]; + struct transfer_descriptor* current_td = + (struct transfer_descriptor *)qh->first_td; while (!((unsigned int)current_td & DTD_NEXT_TERMINATE)) { if ((current_td->size_ioc_sts & 0xff) != 0) return -1; - length += current_td->reserved - + length += (current_td->reserved & DTD_RESERVED_LENGTH_MASK) - ((current_td->size_ioc_sts & DTD_PACKET_SIZE) >> DTD_LENGTH_BIT_POS); current_td = (struct transfer_descriptor*)current_td->next_td_ptr; } return length; } -int usb_drv_get_last_transfer_status(void) +int usb_drv_get_last_transfer_status(int endpoint, bool send) { - struct transfer_descriptor* current_td = first_td; + int pipe = endpoint * 2 + (send ? 1 : 0); + struct queue_head* qh = &qh_array[pipe]; + struct transfer_descriptor* current_td = + (struct transfer_descriptor *)qh->first_td; while (!((unsigned int)current_td & DTD_NEXT_TERMINATE)) { if ((current_td->size_ioc_sts & 0xff) != 0) @@ -524,6 +532,37 @@ return 0; } +static int usb_drv_cleanup_last_transfer(int endpoint, bool send) +{ + unsigned int pipe = endpoint * 2 + (send ? 1 : 0); + int i=0; + struct queue_head* qh = &qh_array[pipe]; + logf("enter usb_drv_cleanup_last_transfer"); + + for(i=0;i>DTD_RESERVED_PIPE_OFFSET == pipe + && (td_array[i].reserved & DTD_RESERVED_IN_USE)) { + logf("resetting %d for %d",i,pipe); + if(qh->dtd.size_ioc_sts & QH_STATUS_ACTIVE) { + logf("QH is active. Skipping"); + continue; + } + if((unsigned int)(&td_array[i]) == qh->curr_dtd_ptr) { + logf("TD is active. Skipping"); + continue; + } + if((unsigned int)(&td_array[i]) == qh->dtd.next_td_ptr) { + logf("TD is next active. Skipping"); + continue; + } + td_array[i].reserved &= ~DTD_RESERVED_IN_USE; + } + } + qh->first_td = DTD_NEXT_TERMINATE; + logf("exit usb_drv_cleanup_last_transfer"); + return 0; +} + /*-------------------------------------------------------------------------*/ /* manual: 32.14.5.2 */ @@ -531,9 +570,11 @@ { int pipe = endpoint * 2 + (send ? 1 : 0); unsigned int mask = pipe2mask[pipe]; - last_td = 0; + static struct transfer_descriptor* last_td = 0; struct queue_head* qh = &qh_array[pipe]; static long last_tick; + int td_idx; + struct transfer_descriptor* new_td; /* if (send && endpoint > EP_CONTROL) { @@ -542,28 +583,40 @@ */ if (len==0) { - struct transfer_descriptor* new_td = &td_array[0]; - prepare_td(new_td, 0, ptr, 0); + td_idx=find_td(); + if(td_idx<0) + { + return -7; + } + new_td=&td_array[td_idx]; + prepare_td(new_td, 0, ptr, 0,pipe); + logf("Allocating %d for %d",td_idx,pipe); last_td = new_td; - first_td = new_td; + qh->first_td = (unsigned int)new_td; } else { - int td_idx = 0; + qh->first_td = DTD_NEXT_TERMINATE; while (len > 0) { int current_transfer_length = MIN(16384,len); - struct transfer_descriptor* new_td = &td_array[td_idx]; - prepare_td(new_td, last_td, ptr, current_transfer_length); + td_idx=find_td(); + if(td_idx<0) + { + return -7; + } + new_td=&td_array[td_idx]; + prepare_td(new_td, last_td, ptr, current_transfer_length,pipe); + logf("Allocating %d for %d",td_idx,pipe); + if(qh->first_td == DTD_NEXT_TERMINATE) + qh->first_td = (unsigned int) new_td; last_td = new_td; len -= current_transfer_length; - td_idx++; ptr += current_transfer_length; } - first_td = &td_array[0]; } - qh->dtd.next_td_ptr = (unsigned int)first_td; + qh->dtd.next_td_ptr = qh->first_td; qh->dtd.size_ioc_sts &= ~(QH_STATUS_HALT | QH_STATUS_ACTIVE); REG_ENDPTPRIME |= mask; @@ -586,7 +639,8 @@ if (send) { /* wait for transfer to finish */ - struct transfer_descriptor* current_td = first_td; + struct transfer_descriptor* current_td = + (struct transfer_descriptor *) qh->first_td; while (!((unsigned int)current_td & DTD_NEXT_TERMINATE)) { while ((current_td->size_ioc_sts & 0xff) == DTD_STATUS_ACTIVE) { @@ -614,7 +668,7 @@ static void prepare_td(struct transfer_descriptor* td, struct transfer_descriptor* previous_td, - void *ptr, int len) + void *ptr, int len,int pipe) { //logf("adding a td : %d",len); memset(td, 0, sizeof(struct transfer_descriptor)); @@ -626,7 +680,9 @@ td->buff_ptr2 = ((unsigned int)ptr & 0xfffff000) + 0x2000; td->buff_ptr3 = ((unsigned int)ptr & 0xfffff000) + 0x3000; td->buff_ptr4 = ((unsigned int)ptr & 0xfffff000) + 0x4000; - td->reserved = len; + td->reserved |= DTD_RESERVED_LENGTH_MASK & len; + td->reserved |= DTD_RESERVED_IN_USE; + td->reserved |= (pipe << DTD_RESERVED_PIPE_OFFSET); if (previous_td != 0) { previous_td->next_td_ptr=(unsigned int)td; @@ -634,6 +690,30 @@ } } +static int find_td() +{ + unsigned int i=0; + for(i=0;i>30); - logf("STS : %X",(REG_PORTSC1 & 0x20000000)>>29); - logf("PTW : %X",(REG_PORTSC1 & 0x10000000)>>28); - logf("PSPD : %X",(REG_PORTSC1 & 0x0C000000)>>26); - logf("PFSC : %X",(REG_PORTSC1 & 0x01000000)>>24); - logf("PTC : %X",(REG_PORTSC1 & 0x000F0000)>>16); - logf("PO : %X",(REG_PORTSC1 & 0x00002000)>>13); } /* manual: 32.14.4.1 Queue Head Initialization */ @@ -720,14 +793,18 @@ /*** control ***/ qh_array[EP_CONTROL].max_pkt_length = 64 << QH_MAX_PKT_LEN_POS | QH_IOS; qh_array[EP_CONTROL].dtd.next_td_ptr = QH_NEXT_TERMINATE; + qh_array[EP_CONTROL].first_td = DTD_NEXT_TERMINATE; qh_array[EP_CONTROL+1].max_pkt_length = 64 << QH_MAX_PKT_LEN_POS; qh_array[EP_CONTROL+1].dtd.next_td_ptr = QH_NEXT_TERMINATE; + qh_array[EP_CONTROL+1].first_td = DTD_NEXT_TERMINATE; /*** bulk ***/ qh_array[EP_RX*2].max_pkt_length = rx_packetsize << QH_MAX_PKT_LEN_POS | QH_ZLT_SEL; qh_array[EP_RX*2].dtd.next_td_ptr = QH_NEXT_TERMINATE; + qh_array[EP_RX*2].first_td = DTD_NEXT_TERMINATE; qh_array[EP_TX*2+1].max_pkt_length = tx_packetsize << QH_MAX_PKT_LEN_POS | QH_ZLT_SEL; qh_array[EP_TX*2+1].dtd.next_td_ptr = QH_NEXT_TERMINATE; + qh_array[EP_TX*2+1].first_td = DTD_NEXT_TERMINATE; } static void init_endpoints(void)