Index: firmware/export/usb_drv.h =================================================================== --- firmware/export/usb_drv.h (revision 16316) +++ 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 16316) +++ firmware/export/usb_core.h (working copy) @@ -19,6 +19,22 @@ #ifndef USB_CORE_H #define USB_CORE_H +#ifndef BOOTLOADER +#define USB_THREAD + +#ifdef USE_ROCKBOX_USB +//#define USB_SERIAL +//#define USB_BENCHMARK +#define USB_STORAGE + +#else +#define USB_CHARGING_ONLY + +#endif /* USE_ROCKBOX_USB */ +#else +#define USB_CHARGING_ONLY +#endif /* BOOTLOADER */ + #include "usb_ch9.h" #if defined(CPU_PP) @@ -26,14 +42,31 @@ #define USB_IRAM_SIZE ((size_t)0xc000) #endif + +enum { + USB_CORE_QUIT, + USB_CORE_TRANSFER_COMPLETION +}; + /* endpoints */ enum { - EP_CONTROL = 0, - EP_RX, - EP_TX, - NUM_ENDPOINTS + EP_CONTROL = 0, +#ifdef USB_STORAGE + EP_MASS_STORAGE, +#endif +#ifdef USB_SERIAL + EP_SERIAL, +#endif +#ifdef USB_CHARGING_ONLY + EP_CHARGING_ONLY, +#endif +#ifdef USB_BENCHMARK + EP_BENCHMARK, +#endif + NUM_ENDPOINTS }; + /* queue events */ #define USB_TRANSFER_COMPLETE 1 Index: firmware/usbstack/usb_core.c =================================================================== --- firmware/usbstack/usb_core.c (revision 16316) +++ firmware/usbstack/usb_core.c (working copy) @@ -20,35 +20,35 @@ #include "thread.h" #include "kernel.h" #include "string.h" -//#define LOGF_ENABLE +#define LOGF_ENABLE #include "logf.h" -#ifndef BOOTLOADER -//#define USB_SERIAL -//#define USB_BENCHMARK -#ifdef USE_ROCKBOX_USB -#define USB_STORAGE -#else -#define USB_CHARGING_ONLY -#endif /* USE_ROCKBOX_USB */ -#else -#define USB_CHARGING_ONLY -#endif - #include "usb_ch9.h" #include "usb_drv.h" #include "usb_core.h" +#define USB_THREAD + #if defined(USB_STORAGE) #include "usb_storage.h" -#define USB_THREAD -#elif defined(USB_SERIAL) -#define USB_THREAD +#endif + +#if defined(USB_SERIAL) #include "usb_serial.h" -#elif defined(USB_BENCHMARK) +#endif + +#if defined(USB_BENCHMARK) #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: */ @@ -57,10 +57,10 @@ int usb_max_pkt_size = 512; -static const struct usb_device_descriptor device_descriptor = { +static const struct usb_device_descriptor device_descriptor= { .bLength = sizeof(struct usb_device_descriptor), .bDescriptorType = USB_DT_DEVICE, - .bcdUSB = 0x0200, /* USB version 2.0 */ + .bcdUSB = 0x0110, /* USB version 1.1 as long as high-speed doesn't work */ .bDeviceClass = USB_CLASS_PER_INTERFACE, .bDeviceSubClass = 0, .bDeviceProtocol = 0, @@ -74,158 +74,34 @@ .bNumConfigurations = 1 }; -static const struct { +static struct { struct usb_config_descriptor config_descriptor; - struct usb_interface_descriptor interface_descriptor; - struct usb_endpoint_descriptor ep1_in_descriptor; - struct usb_endpoint_descriptor ep1_out_descriptor; -} config_data_fs = -{ - { - .bLength = sizeof(struct usb_config_descriptor), - .bDescriptorType = USB_DT_CONFIG, - .wTotalLength = sizeof config_data_fs, - .bNumInterfaces = 1, - .bConfigurationValue = 1, - .iConfiguration = 0, - .bmAttributes = USB_CONFIG_ATT_ONE | USB_CONFIG_ATT_SELFPOWER, - .bMaxPower = 250, /* 500mA in 2mA units */ - }, - #ifdef USB_CHARGING_ONLY - /* dummy interface for charging-only */ - { - .bLength = sizeof(struct usb_interface_descriptor), - .bDescriptorType = USB_DT_INTERFACE, - .bInterfaceNumber = 0, - .bAlternateSetting = 0, - .bNumEndpoints = 2, - .bInterfaceClass = USB_CLASS_VENDOR_SPEC, - .bInterfaceSubClass = 0, - .bInterfaceProtocol = 0, - .iInterface = 5 - }, - - { - .bLength = sizeof(struct usb_endpoint_descriptor), - .bDescriptorType = USB_DT_ENDPOINT, - .bEndpointAddress = EP_TX | USB_DIR_IN, - .bmAttributes = USB_ENDPOINT_XFER_BULK, - .wMaxPacketSize = 512, - .bInterval = 0 - }, - { - .bLength = sizeof(struct usb_endpoint_descriptor), - .bDescriptorType = USB_DT_ENDPOINT, - .bEndpointAddress = EP_RX | USB_DIR_OUT, - .bmAttributes = USB_ENDPOINT_XFER_BULK, - .wMaxPacketSize = 512, - .bInterval = 0 - } + struct usb_interface_descriptor charging_interface_descriptor; + struct usb_endpoint_descriptor charging_ep_in_descriptor; + struct usb_endpoint_descriptor charging_ep_out_descriptor; #endif - #ifdef USB_STORAGE - /* storage interface */ - { - .bLength = sizeof(struct usb_interface_descriptor), - .bDescriptorType = USB_DT_INTERFACE, - .bInterfaceNumber = 0, - .bAlternateSetting = 0, - .bNumEndpoints = 2, - .bInterfaceClass = USB_CLASS_MASS_STORAGE, - .bInterfaceSubClass = USB_SC_SCSI, - .bInterfaceProtocol = USB_PROT_BULK, - .iInterface = 0 - }, - - { - .bLength = sizeof(struct usb_endpoint_descriptor), - .bDescriptorType = USB_DT_ENDPOINT, - .bEndpointAddress = EP_TX | USB_DIR_IN, - .bmAttributes = USB_ENDPOINT_XFER_BULK, - .wMaxPacketSize = 16, - .bInterval = 0 - }, - { - .bLength = sizeof(struct usb_endpoint_descriptor), - .bDescriptorType = USB_DT_ENDPOINT, - .bEndpointAddress = EP_RX | USB_DIR_OUT, - .bmAttributes = USB_ENDPOINT_XFER_BULK, - .wMaxPacketSize = 16, - .bInterval = 0 - } + struct usb_interface_descriptor mass_storage_interface_descriptor; + struct usb_endpoint_descriptor mass_storage_ep_in_descriptor; + struct usb_endpoint_descriptor mass_storage_ep_out_descriptor; #endif - #ifdef USB_SERIAL - /* serial interface */ - { - .bLength = sizeof(struct usb_interface_descriptor), - .bDescriptorType = USB_DT_INTERFACE, - .bInterfaceNumber = 0, - .bAlternateSetting = 0, - .bNumEndpoints = 2, - .bInterfaceClass = USB_CLASS_CDC_DATA, - .bInterfaceSubClass = 0, - .bInterfaceProtocol = 0, - .iInterface = 0 - }, - - { - .bLength = sizeof(struct usb_endpoint_descriptor), - .bDescriptorType = USB_DT_ENDPOINT, - .bEndpointAddress = EP_TX | USB_DIR_IN, - .bmAttributes = USB_ENDPOINT_XFER_BULK, - .wMaxPacketSize = 64, - .bInterval = 0 - }, - { - .bLength = sizeof(struct usb_endpoint_descriptor), - .bDescriptorType = USB_DT_ENDPOINT, - .bEndpointAddress = EP_RX | USB_DIR_OUT, - .bmAttributes = USB_ENDPOINT_XFER_BULK, - .wMaxPacketSize = 64, - .bInterval = 0 - } + struct usb_interface_descriptor serial_interface_descriptor; + struct usb_endpoint_descriptor serial_ep_in_descriptor; + struct usb_endpoint_descriptor serial_ep_out_descriptor; #endif - #ifdef USB_BENCHMARK - /* bulk test interface */ - { - .bLength = sizeof(struct usb_interface_descriptor), - .bDescriptorType = USB_DT_INTERFACE, - .bInterfaceNumber = 0, - .bAlternateSetting = 0, - .bNumEndpoints = 2, - .bInterfaceClass = USB_CLASS_VENDOR_SPEC, - .bInterfaceSubClass = 255, - .bInterfaceProtocol = 255, - .iInterface = 4 - }, - - { - .bLength = sizeof(struct usb_endpoint_descriptor), - .bDescriptorType = USB_DT_ENDPOINT, - .bEndpointAddress = EP_RX | USB_DIR_OUT, - .bmAttributes = USB_ENDPOINT_XFER_BULK, - .wMaxPacketSize = 64, - .bInterval = 0 - }, - { - .bLength = sizeof(struct usb_endpoint_descriptor), - .bDescriptorType = USB_DT_ENDPOINT, - .bEndpointAddress = EP_TX | USB_DIR_IN, - .bmAttributes = USB_ENDPOINT_XFER_BULK, - .wMaxPacketSize = 64, - .bInterval = 0 - } + struct usb_interface_descriptor benchmark_interface_descriptor; + struct usb_endpoint_descriptor benchmark_ep_in_descriptor; + struct usb_endpoint_descriptor benchmark_ep_out_descriptor; #endif -}, -config_data_hs = +} __attribute__((packed)) *config_data, _config_data = { { .bLength = sizeof(struct usb_config_descriptor), .bDescriptorType = USB_DT_CONFIG, - .wTotalLength = sizeof config_data_hs, + .wTotalLength = sizeof _config_data, .bNumInterfaces = 1, .bConfigurationValue = 1, .iConfiguration = 0, @@ -246,23 +122,23 @@ .bInterfaceProtocol = 0, .iInterface = 5 }, - +/* TODO: try with zero endpoints */ { .bLength = sizeof(struct usb_endpoint_descriptor), .bDescriptorType = USB_DT_ENDPOINT, - .bEndpointAddress = EP_TX | USB_DIR_IN, + .bEndpointAddress = EP_CHARGING_ONLY | USB_DIR_IN, .bmAttributes = USB_ENDPOINT_XFER_BULK, - .wMaxPacketSize = 512, + .wMaxPacketSize = 16, .bInterval = 0 }, { .bLength = sizeof(struct usb_endpoint_descriptor), .bDescriptorType = USB_DT_ENDPOINT, - .bEndpointAddress = EP_RX | USB_DIR_OUT, + .bEndpointAddress = EP_CHARGING_ONLY | USB_DIR_OUT, .bmAttributes = USB_ENDPOINT_XFER_BULK, - .wMaxPacketSize = 512, + .wMaxPacketSize = 16, .bInterval = 0 - } + }, #endif #ifdef USB_STORAGE @@ -282,19 +158,19 @@ { .bLength = sizeof(struct usb_endpoint_descriptor), .bDescriptorType = USB_DT_ENDPOINT, - .bEndpointAddress = EP_TX | USB_DIR_IN, + .bEndpointAddress = EP_MASS_STORAGE | USB_DIR_IN, .bmAttributes = USB_ENDPOINT_XFER_BULK, - .wMaxPacketSize = 512, + .wMaxPacketSize = 16, .bInterval = 0 }, { .bLength = sizeof(struct usb_endpoint_descriptor), .bDescriptorType = USB_DT_ENDPOINT, - .bEndpointAddress = EP_RX | USB_DIR_OUT, + .bEndpointAddress = EP_MASS_STORAGE | USB_DIR_OUT, .bmAttributes = USB_ENDPOINT_XFER_BULK, - .wMaxPacketSize = 512, + .wMaxPacketSize = 16, .bInterval = 0 - } + }, #endif #ifdef USB_SERIAL @@ -314,19 +190,19 @@ { .bLength = sizeof(struct usb_endpoint_descriptor), .bDescriptorType = USB_DT_ENDPOINT, - .bEndpointAddress = EP_TX | USB_DIR_IN, + .bEndpointAddress = EP_SERIAL | USB_DIR_IN, .bmAttributes = USB_ENDPOINT_XFER_BULK, - .wMaxPacketSize = 512, + .wMaxPacketSize = 16, .bInterval = 0 }, { .bLength = sizeof(struct usb_endpoint_descriptor), .bDescriptorType = USB_DT_ENDPOINT, - .bEndpointAddress = EP_RX | USB_DIR_OUT, + .bEndpointAddress = EP_SERIAL | USB_DIR_OUT, .bmAttributes = USB_ENDPOINT_XFER_BULK, - .wMaxPacketSize = 512, + .wMaxPacketSize = 16, .bInterval = 0 - } + }, #endif #ifdef USB_BENCHMARK @@ -346,19 +222,19 @@ { .bLength = sizeof(struct usb_endpoint_descriptor), .bDescriptorType = USB_DT_ENDPOINT, - .bEndpointAddress = EP_RX | USB_DIR_OUT, + .bEndpointAddress = EP_BENCHMARK | USB_DIR_OUT, .bmAttributes = USB_ENDPOINT_XFER_BULK, - .wMaxPacketSize = 512, + .wMaxPacketSize = 16, .bInterval = 0 }, { .bLength = sizeof(struct usb_endpoint_descriptor), .bDescriptorType = USB_DT_ENDPOINT, - .bEndpointAddress = EP_TX | USB_DIR_IN, + .bEndpointAddress = EP_BENCHMARK | USB_DIR_IN, .bmAttributes = USB_ENDPOINT_XFER_BULK, - .wMaxPacketSize = 512, + .wMaxPacketSize = 16, .bInterval = 0 - } + }, #endif }; @@ -388,14 +264,23 @@ {'R','o','c','k','b','o','x',' ','m','e','d','i','a',' ','p','l','a','y','e','r'} }; -static struct usb_string_descriptor usb_string_iSerial = +#if defined(HAVE_AS3514) +static struct usb_string_descriptor usb_string_iSerial __attribute((aligned (2)))= { - 34, - USB_DT_STRING, - {'0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0'} + 66, + 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'} }; +#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 */ /* this is stringid #0: languages supported */ @@ -443,10 +328,20 @@ 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); +struct usb_core_event +{ + unsigned char endpoint; + bool in; + void* data; +}; + +static struct usb_core_event events[NUM_ENDPOINTS]; + #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'}; @@ -471,7 +366,23 @@ x >>= 4; } } +} +#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'}; + unsigned char serial[16]; + short* p = usb_string_iSerial.wString; + int i; + + i2c_readbytes(AS3514_I2C_ADDR, 0x30, 0x10, serial); + for (i = 0; i < 16; i++) + { + *p++ = hex[(serial[i] >> 4) & 0xF]; + *p++ = hex[(serial[i] >> 0) & 0xF]; + } } #endif @@ -480,9 +391,7 @@ if (initialized) return; -#ifdef IPOD_ARCH - set_serial_descriptor(); -#endif + config_data = (void*)UNCACHED_ADDR(&_config_data); queue_init(&usbcore_queue, false); usb_drv_init(); @@ -514,10 +423,11 @@ { if (initialized) { usb_drv_exit(); - queue_delete(&usbcore_queue); #ifdef USB_THREAD - remove_thread(usbcore_thread); + queue_post(&usbcore_queue, USB_CORE_QUIT, 0); + thread_wait(usbcore_thread); #endif + queue_delete(&usbcore_queue); } data_connection = false; initialized = false; @@ -532,25 +442,50 @@ #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 == USB_CORE_QUIT) + return; + if (ev.id == USB_CORE_TRANSFER_COMPLETION) + { + struct usb_core_event* event = (struct usb_core_event*)ev.data; + switch(event->endpoint) { + case EP_CONTROL: + usb_core_control_request_handler((struct usb_ctrlrequest*)event->data); + break; #ifdef USB_STORAGE - usb_storage_transfer_complete(ev.id); + case EP_MASS_STORAGE: + usb_storage_transfer_complete(event->in); + break; #endif - #ifdef USB_SERIAL - usb_serial_transfer_complete(ev.id); + case EP_SERIAL: + usb_serial_transfer_complete(event->in); + break; #endif - +#ifdef USB_BENCHMARK + case EP_BENCHMARK: + usb_benchmark_transfer_complete(event->in); + break; +#endif +#ifdef USB_CHARGING_ONLY + case EP_CHARGING_ONLY: + break; +#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; @@ -637,18 +572,47 @@ size = sizeof device_descriptor; break; - case USB_DT_CONFIG: + case USB_DT_CONFIG: { + int max_packet_size; + int interface_number=0; if(usb_drv_port_speed()) { - ptr = &config_data_hs; - size = sizeof config_data_hs; + max_packet_size=512; } else { - ptr = &config_data_fs; - size = sizeof config_data_fs; + max_packet_size=16; } + +#ifdef USB_CHARGING_ONLY + memcpy(&config_data->charging_ep_in_descriptor.wMaxPacketSize,&max_packet_size,sizeof(unsigned short)); + memcpy(&config_data->charging_ep_out_descriptor.wMaxPacketSize,&max_packet_size,sizeof(unsigned short)); + config_data->charging_interface_descriptor.bInterfaceNumber=interface_number; + interface_number++; +#endif +#ifdef USB_STORAGE + memcpy(&config_data->mass_storage_ep_in_descriptor.wMaxPacketSize,&max_packet_size,sizeof(unsigned short)); + memcpy(&config_data->mass_storage_ep_out_descriptor.wMaxPacketSize,&max_packet_size,sizeof(unsigned short)); + config_data->mass_storage_interface_descriptor.bInterfaceNumber=interface_number; + interface_number++; +#endif +#ifdef USB_SERIAL + memcpy(&config_data->serial_ep_in_descriptor.wMaxPacketSize,&max_packet_size,sizeof(unsigned short)); + memcpy(&config_data->serial_ep_out_descriptor.wMaxPacketSize,&max_packet_size,sizeof(unsigned short)); + config_data->serial_interface_descriptor.bInterfaceNumber=interface_number; + interface_number++; +#endif +#ifdef USB_BENCHMARK + memcpy(&config_data->benchmark_ep_in_descriptor.wMaxPacketSize,&max_packet_size,sizeof(unsigned short)); + memcpy(&config_data->benchmark_ep_out_descriptor.wMaxPacketSize,&max_packet_size,sizeof(unsigned short)); + config_data.benchmark_interface_descriptor.bInterfaceNumber=interface_number; + interface_number++; +#endif + config_data->config_descriptor.bNumInterfaces=interface_number; + ptr = config_data; + size = sizeof _config_data; break; + } case USB_DT_STRING: if ((unsigned)index < (sizeof(usb_strings)/sizeof(struct usb_string_descriptor*))) { @@ -711,7 +675,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 @@ -720,20 +684,25 @@ /* already handled */ break; - case EP_RX: - case EP_TX: -#if defined(USB_BENCHMARK) - usb_benchmark_transfer_complete(endpoint, in); -#elif defined(USB_STORAGE) || defined(USB_SERIAL) - queue_post(&usbcore_queue, endpoint, 0); -#endif - break; - default: + events[endpoint].endpoint=endpoint; + events[endpoint].in=in; + events[endpoint].data=0; + /* All other endoints. Let the thread deal with it */ + queue_post(&usbcore_queue, USB_CORE_TRANSFER_COMPLETION, (intptr_t)&events[endpoint]); break; } } +/* called by usb_drv_int() */ +void usb_core_control_request(struct usb_ctrlrequest* req) +{ + events[0].endpoint=0; + events[0].in=0; + events[0].data=(void *)req; + queue_post(&usbcore_queue, USB_CORE_TRANSFER_COMPLETION,(intptr_t)&events[0]); +} + static void ack_control(struct usb_ctrlrequest* req) { if (req->bRequestType & 0x80) Index: firmware/usbstack/usb_storage.h =================================================================== --- firmware/usbstack/usb_storage.h (revision 16316) +++ firmware/usbstack/usb_storage.h (working copy) @@ -23,7 +23,7 @@ void usb_storage_init(void); void usb_storage_transfer(void* data); -void usb_storage_transfer_complete(int endpoint); +void usb_storage_transfer_complete(bool in); bool usb_storage_control_request(struct usb_ctrlrequest* req); #endif Index: firmware/usbstack/usb_benchmark.c =================================================================== --- firmware/usbstack/usb_benchmark.c (revision 16316) +++ firmware/usbstack/usb_benchmark.c (working copy) @@ -22,6 +22,8 @@ //#define LOGF_ENABLE #include "logf.h" +#ifdef USB_BENCHMARK + static int current_length; static unsigned char _input_buffer[16384]; @@ -56,8 +58,8 @@ logf("bench: read %d", current_length); todo = MIN(usb_max_pkt_size, current_length); state = SENDING; - usb_drv_reset_endpoint(EP_TX, true); - usb_drv_send(EP_TX, &input_buffer, todo); + usb_drv_reset_endpoint(EP_BENCHMARK, true); + usb_drv_send(EP_BENCHMARK, &input_buffer, todo); current_length -= todo; break; @@ -66,13 +68,13 @@ current_length = req->wValue * req->wIndex; logf("bench: write %d", current_length); state = RECEIVING; - usb_drv_reset_endpoint(EP_RX, false); - usb_drv_recv(EP_RX, &input_buffer, sizeof _input_buffer); + usb_drv_reset_endpoint(EP_BENCHMARK, false); + usb_drv_recv(EP_BENCHMARK, &input_buffer, sizeof _input_buffer); break; } } -void usb_benchmark_transfer_complete(int endpoint, bool in) +void usb_benchmark_transfer_complete(bool in) { (void)in; @@ -87,26 +89,26 @@ { case SENDING: { int todo = MIN(usb_max_pkt_size, current_length); - if (endpoint == EP_RX) { + if (in == false) { logf("unexpected ep_rx"); break; } logf("bench: %d more tx", current_length); - usb_drv_send(EP_TX, &input_buffer, todo); + usb_drv_send(EP_BENCHMARK, &input_buffer, todo); current_length -= todo; input_buffer[0]++; break; } case RECEIVING: - if (endpoint == EP_TX) { + if (in == true) { logf("unexpected ep_tx"); break; } /* re-prime endpoint */ - usb_drv_recv(EP_RX, &input_buffer, sizeof _input_buffer); + usb_drv_recv(EP_BENCHMARK, &input_buffer, sizeof _input_buffer); input_buffer[0]++; break; @@ -123,3 +125,4 @@ else usb_drv_send(EP_CONTROL, NULL, 0); } +#endif /*USB_BENCHMARK*/ Index: firmware/usbstack/usb_benchmark.h =================================================================== --- firmware/usbstack/usb_benchmark.h (revision 16316) +++ firmware/usbstack/usb_benchmark.h (working copy) @@ -21,6 +21,6 @@ void usb_benchmark_init(void); void usb_benchmark_control_request(struct usb_ctrlrequest* req); -void usb_benchmark_transfer_complete(int endpoint, bool in); +void usb_benchmark_transfer_complete(bool in); #endif Index: firmware/usbstack/usb_serial.c =================================================================== --- firmware/usbstack/usb_serial.c (revision 16316) +++ firmware/usbstack/usb_serial.c (working copy) @@ -23,6 +23,8 @@ //#define LOGF_ENABLE #include "logf.h" +#ifdef USB_SERIAL + static unsigned char _transfer_buffer[16]; static unsigned char* transfer_buffer; @@ -34,20 +36,20 @@ } /* called by usb_core_transfer_complete() */ -void usb_serial_transfer_complete(int endpoint) +void usb_serial_transfer_complete(bool in) { - switch (endpoint) { - case EP_RX: + switch (in) { + case false: logf("serial: %s", transfer_buffer); /* re-prime endpoint */ - usb_drv_recv(EP_RX, transfer_buffer, sizeof _transfer_buffer); + usb_drv_recv(EP_SERIAL, transfer_buffer, sizeof _transfer_buffer); /* echo back :) */ - usb_drv_send(EP_TX, transfer_buffer, sizeof transfer_buffer); + usb_drv_send(EP_SERIAL, transfer_buffer, sizeof transfer_buffer); break; - case EP_TX: + case true: break; } } @@ -62,7 +64,7 @@ case USB_REQ_SET_CONFIGURATION: logf("serial: set config"); /* prime rx endpoint */ - usb_drv_recv(EP_RX, transfer_buffer, sizeof _transfer_buffer); + usb_drv_recv(EP_SERIAL, transfer_buffer, sizeof _transfer_buffer); handled = true; break; @@ -72,3 +74,5 @@ return handled; } + +#endif /*USB_SERIAL*/ Index: firmware/usbstack/usb_serial.h =================================================================== --- firmware/usbstack/usb_serial.h (revision 16316) +++ firmware/usbstack/usb_serial.h (working copy) @@ -22,7 +22,7 @@ #include "usb_ch9.h" void usb_serial_init(void); -void usb_serial_transfer_complete(int endpoint); +void usb_serial_transfer_complete(bool in); bool usb_serial_control_request(struct usb_ctrlrequest* req); #endif Index: firmware/usbstack/usb_storage.c =================================================================== --- firmware/usbstack/usb_storage.c (revision 16316) +++ firmware/usbstack/usb_storage.c (working copy) @@ -26,6 +26,8 @@ #include "hotswap.h" #include "disk.h" +#ifdef USB_STORAGE + #define SECTOR_SIZE 512 /* bulk-only class specific requests */ @@ -153,18 +155,19 @@ } /* called by usb_core_transfer_complete() */ -void usb_storage_transfer_complete(int endpoint) +void usb_storage_transfer_complete(bool in) { struct command_block_wrapper* cbw = (void*)transfer_buffer; - switch (endpoint) { - case EP_RX: + switch (in) { + case false: //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_MASS_STORAGE,0); + int status = usb_drv_get_last_transfer_status(EP_MASS_STORAGE,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 +180,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); } } @@ -189,13 +192,13 @@ break; - case EP_TX: + case true: //logf("ums: out complete"); if(state != IDLE) { /* re-prime endpoint. We only need room for commands */ state = IDLE; - usb_drv_recv(EP_RX, transfer_buffer, 1024); + usb_drv_recv(EP_MASS_STORAGE, transfer_buffer, 1024); } break; @@ -221,8 +224,8 @@ case USB_BULK_RESET_REQUEST: logf("ums: bulk reset"); - usb_drv_reset_endpoint(EP_RX, false); - usb_drv_reset_endpoint(EP_TX, true); + usb_drv_reset_endpoint(EP_MASS_STORAGE, false); + usb_drv_reset_endpoint(EP_MASS_STORAGE, true); usb_drv_send(EP_CONTROL, NULL, 0); /* ack */ handled = true; break; @@ -231,7 +234,7 @@ logf("ums: set config"); /* prime rx endpoint. We only need room for commands */ state = IDLE; - usb_drv_recv(EP_RX, transfer_buffer, 1024); + usb_drv_recv(EP_MASS_STORAGE, transfer_buffer, 1024); handled = true; break; } @@ -284,7 +287,7 @@ logf("scsi inquiry %d",lun); identify2inquiry(lun); length = MIN(length, cbw->command_block[4]); - usb_drv_send(EP_TX, inquiry, MIN(sizeof _inquiry, length)); + usb_drv_send(EP_MASS_STORAGE, inquiry, MIN(sizeof _inquiry, length)); send_csw(cbw->tag, SCSI_STATUS_GOOD); break; @@ -300,7 +303,7 @@ sense_data->SKSV=0; sense_data->SenseKeySpecific=0; logf("scsi request_sense %d",lun); - usb_drv_send(EP_TX, sense_data, + usb_drv_send(EP_MASS_STORAGE, sense_data, sizeof(_sense_data)); send_csw(cbw->tag, SCSI_STATUS_GOOD); break; @@ -309,7 +312,7 @@ case SCSI_MODE_SENSE: { static unsigned char sense_data[8] = { 0, 0, 0, 0, 0, 0, 0, 0 }; logf("scsi mode_sense %d",lun); - usb_drv_send(EP_TX, UNCACHED_ADDR(&sense_data), + usb_drv_send(EP_MASS_STORAGE, UNCACHED_ADDR(&sense_data), MIN(sizeof sense_data, length)); send_csw(cbw->tag, SCSI_STATUS_GOOD); break; @@ -348,7 +351,7 @@ #endif format_capacity_data->block_size |= SCSI_FORMAT_CAPACITY_FORMATTED_MEDIA; - usb_drv_send(EP_TX, format_capacity_data, + usb_drv_send(EP_MASS_STORAGE, format_capacity_data, MIN(sizeof _format_capacity_data, length)); send_csw(cbw->tag, SCSI_STATUS_GOOD); break; @@ -374,7 +377,7 @@ capacity_data->block_count = htobe32((identify[61] << 16 | identify[60]) / block_size_mult - 1); capacity_data->block_size = htobe32(block_size * block_size_mult); #endif - usb_drv_send(EP_TX, capacity_data, + usb_drv_send(EP_MASS_STORAGE, capacity_data, MIN(sizeof _capacity_data, length)); send_csw(cbw->tag, SCSI_STATUS_GOOD); break; @@ -407,7 +410,7 @@ else { ata_read_sectors(IF_MV2(lun,) current_cmd.sector, current_cmd.count, transfer_buffer); - usb_drv_send(EP_TX, transfer_buffer, + usb_drv_send(EP_MASS_STORAGE, transfer_buffer, current_cmd.count*block_size); send_csw(current_cmd.tag, SCSI_STATUS_GOOD); } @@ -430,7 +433,7 @@ send_csw(current_cmd.tag, SCSI_STATUS_CHECK_CONDITION); } else { - usb_drv_recv(EP_RX, transfer_buffer, + usb_drv_recv(EP_MASS_STORAGE, transfer_buffer, current_cmd.count*block_size); state = RECEIVING; } @@ -439,7 +442,7 @@ default: logf("scsi unknown cmd %x",cbw->command_block[0x0]); - usb_drv_stall(EP_TX, true); + usb_drv_stall(EP_MASS_STORAGE, true); send_csw(current_cmd.tag, SCSI_STATUS_GOOD); break; } @@ -455,7 +458,7 @@ csw->status = status; //logf("csw %x %x", csw->tag, csw->signature); - usb_drv_send(EP_TX, csw, sizeof _csw); + usb_drv_send(EP_MASS_STORAGE, csw, sizeof _csw); } /* convert ATA IDENTIFY to SCSI INQUIRY */ @@ -510,3 +513,4 @@ } +#endif /* USB_STORAGE */ Index: firmware/target/arm/usb-fw-pp502x.c =================================================================== --- firmware/target/arm/usb-fw-pp502x.c (revision 16316) +++ firmware/target/arm/usb-fw-pp502x.c (working copy) @@ -34,6 +34,7 @@ { /* enable usb module */ outl(inl(0x7000002C) | 0x3000000, 0x7000002C); + DEV_EN |= DEV_USB0; DEV_EN |= DEV_USB1; @@ -46,6 +47,7 @@ #if CONFIG_CPU == PP5020 DEV_INIT2 |= INIT_USB; #endif + while ((inl(0x70000028) & 0x80) == 0); outl(inl(0x70000028) | 0x2, 0x70000028); udelay(0x186A0); @@ -68,9 +70,8 @@ void usb_enable(bool on) { if (on) { -#ifdef USE_ROCKBOX_USB usb_core_init(); -#else +#if !defined(USE_ROCKBOX_USB) /* until we have native mass-storage mode, we want to reboot on usb host connect */ #if defined(IRIVER_H10) || defined (IRIVER_H10_5GB) Index: firmware/target/arm/usb-drv-pp502x.c =================================================================== --- firmware/target/arm/usb-drv-pp502x.c (revision 16316) +++ firmware/target/arm/usb-drv-pp502x.c (working copy) @@ -23,13 +23,17 @@ #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) */ #define REG_ID (*(volatile unsigned int *)(USB_BASE+0x000)) #define REG_HWGENERAL (*(volatile unsigned int *)(USB_BASE+0x004)) +#define REG_HWHOST (*(volatile unsigned int *)(USB_BASE+0x008)) +#define REG_HWDEVICE (*(volatile unsigned int *)(USB_BASE+0x00c)) +#define REG_TXBUF (*(volatile unsigned int *)(USB_BASE+0x010)) +#define REG_RXBUF (*(volatile unsigned int *)(USB_BASE+0x014)) #define REG_CAPLENGTH (*(volatile unsigned char*)(USB_BASE+0x100)) #define REG_DCIVERSION (*(volatile unsigned int *)(USB_BASE+0x120)) #define REG_DCCPARAMS (*(volatile unsigned int *)(USB_BASE+0x124)) @@ -278,6 +282,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 +302,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,28 +313,33 @@ 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; /* for software use, pointer to the first TD */ + unsigned int status; /* for software use, status of chain in progress */ + unsigned int length; /* for software use, transfered bytes of chain in progress */ + unsigned int reserved[1]; } __attribute__((packed)); static struct queue_head _qh_array[NUM_ENDPOINTS*2] __attribute((aligned (2048))); static struct queue_head* qh_array; +static struct event_queue transfer_completion_queue[NUM_ENDPOINTS]; -static const unsigned int pipe2mask[NUM_ENDPOINTS*2] = { +static const unsigned int pipe2mask[] = { 0x01, 0x010000, 0x02, 0x020000, 0x04, 0x040000, + 0x08, 0x080000, + 0x10, 0x100000, }; -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); @@ -344,6 +358,7 @@ REG_USBCMD |= USBCMD_CTRL_RESET; while (REG_USBCMD & USBCMD_CTRL_RESET); + REG_USBMODE = USBMODE_CTRL_MODE_DEVICE; /* Force device to full speed */ @@ -372,6 +387,7 @@ /* go go go */ REG_USBCMD |= USBCMD_RUN; + logf("usb_drv_init() finished"); logf("usb id %x", REG_ID); logf("usb dciversion %x", REG_DCIVERSION); @@ -407,15 +423,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) @@ -496,32 +504,17 @@ 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 length = 0; - - while (!((unsigned int)current_td & DTD_NEXT_TERMINATE)) { - if ((current_td->size_ioc_sts & 0xff) != 0) - return -1; - - length += current_td->reserved - - ((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 pipe = endpoint * 2 + (send ? 1 : 0); + struct queue_head* qh = &qh_array[pipe]; + return qh->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; - - while (!((unsigned int)current_td & DTD_NEXT_TERMINATE)) { - if ((current_td->size_ioc_sts & 0xff) != 0) - return current_td->size_ioc_sts & 0xff; - - current_td = (struct transfer_descriptor*)current_td->next_td_ptr; - } - return 0; + int pipe = endpoint * 2 + (send ? 1 : 0); + struct queue_head* qh = &qh_array[pipe]; + return qh->status; } /*-------------------------------------------------------------------------*/ @@ -531,39 +524,56 @@ { 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) { logf("usb: sent %d bytes", len); } */ + qh->status = 0; + qh->length = 0; 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]; } + logf("starting %X",qh->first_td); - 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,26 +596,8 @@ if (send) { /* wait for transfer to finish */ - struct transfer_descriptor* current_td = first_td; - - while (!((unsigned int)current_td & DTD_NEXT_TERMINATE)) { - while ((current_td->size_ioc_sts & 0xff) == DTD_STATUS_ACTIVE) { - if (REG_ENDPTCOMPLETE & mask) - REG_ENDPTCOMPLETE |= mask; - - /* let the host handle timeouts */ - if (REG_USBSTS & USBSTS_RESET) { - logf("td interrupted by reset"); - return -4; - } - } - if ((current_td->size_ioc_sts & 0xff) != 0) { - logf("td failed with error %X",(current_td->size_ioc_sts & 0xff)); - return -6; - } - //logf("td finished : %X",current_td->size_ioc_sts & 0xff); - current_td=(struct transfer_descriptor*)current_td->next_td_ptr; - } + struct queue_event ev; + queue_wait(&transfer_completion_queue[endpoint], &ev); //logf("all tds done"); } @@ -614,7 +606,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,38 +618,112 @@ 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; - previous_td->size_ioc_sts&=~DTD_IOC;// Only an interrupt on the last one } } +static int find_td() +{ + static unsigned int first=0; + unsigned int i=0; + for(i=0;ifirst_td; + logf("looking at %d %X",pipe,(unsigned int)td); + while(((unsigned int)td & DTD_NEXT_TERMINATE) == 0) + { + logf("TD status %X",td->size_ioc_sts&0xff); + if(td->size_ioc_sts & DTD_STATUS_ACTIVE) + { + /* TODO this shouldn't happen, but...*/ + break; + } + if((td->size_ioc_sts & DTD_PACKET_SIZE) >> DTD_LENGTH_BIT_POS != 0 && dir==0) + { + /* TODO We got less data than we asked for. should we flush everything ? */ + } + qh->length += (td->reserved & DTD_RESERVED_LENGTH_MASK) - + ((td->size_ioc_sts & DTD_PACKET_SIZE) >> DTD_LENGTH_BIT_POS); + if(td->size_ioc_sts & DTD_ERROR_MASK) + { + logf("pipe %d err %x", pipe, td->size_ioc_sts & DTD_ERROR_MASK); + qh->status |= td->size_ioc_sts & DTD_ERROR_MASK; + /* TODO we probably need to handle this somehow. FLush the endpoint ? */ + } + logf("deallocating %d for %d",(int)(td-td_array),pipe); + td->reserved &= ~DTD_RESERVED_IN_USE; + td=(struct transfer_descriptor *)td->next_td_ptr; + } + qh->first_td=(unsigned int)td; + if((unsigned int)td & DTD_NEXT_TERMINATE) + { + if((qh->curr_dtd_ptr & DTD_NEXT_TERMINATE) != 0) { + logf("QH is active for an empty QH"); + } + /* The entire chain has been completed */ + if(dir==1) + { + queue_post(&transfer_completion_queue[ep],0, 0); + } + usb_core_transfer_complete(ep, dir); + } } } } + logf("transfer handled"); } /* manual: 32.14.2.1 Bus Reset */ @@ -691,14 +757,6 @@ if (!(REG_PORTSC1 & PORTSCX_PORT_RESET)) { logf("usb: slow reset!"); } - - logf("PTS : %X",(REG_PORTSC1 & 0xC0000000)>>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 */ @@ -706,6 +764,7 @@ { int tx_packetsize; int rx_packetsize; + int i; if (usb_drv_port_speed()) { rx_packetsize = 512; @@ -720,26 +779,37 @@ /*** 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_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; + for(i=1;i