/*************************************************************************** * __________ __ ___. * Open \______ \ ____ ____ | | _\_ |__ _______ ___ * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ * \/ \/ \/ \/ \/ * $Id: $ * * Copyright (C) 2007 by Bj�rn Stenberg * * All files in this archive are subject to the GNU General Public License. * See the file COPYING in the source tree root for full license agreement. * * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY * KIND, either express or implied. * ****************************************************************************/ #include "system.h" #include "thread.h" #include "kernel.h" #include "string.h" //#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" #if defined(USB_STORAGE) #include "usb_storage.h" #define USB_THREAD #elif defined(USB_SERIAL) #define USB_THREAD #include "usb_serial.h" #elif defined(USB_BENCHMARK) #include "usb_benchmark.h" #endif /*-------------------------------------------------------------------------*/ /* USB protocol descriptors: */ #define USB_SC_SCSI 0x06 /* Transparent */ #define USB_PROT_BULK 0x50 /* bulk only */ int usb_max_pkt_size = 512; static const struct usb_device_descriptor device_descriptor = { .bLength = sizeof(struct usb_device_descriptor), .bDescriptorType = USB_DT_DEVICE, .bcdUSB = 0x0200, /* USB version 2.0 */ .bDeviceClass = USB_CLASS_PER_INTERFACE, .bDeviceSubClass = 0, .bDeviceProtocol = 0, .bMaxPacketSize0 = 64, .idVendor = USB_VENDOR_ID, .idProduct = USB_PRODUCT_ID, .bcdDevice = 0x0100, .iManufacturer = 1, .iProduct = 2, .iSerialNumber = 3, .bNumConfigurations = 1 }; static const 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 } #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 } #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 } #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 } #endif }, config_data_hs = { { .bLength = sizeof(struct usb_config_descriptor), .bDescriptorType = USB_DT_CONFIG, .wTotalLength = sizeof config_data_hs, .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 } #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 = 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 } #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 = 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 } #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 = 512, .bInterval = 0 }, { .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 } #endif }; static const struct usb_qualifier_descriptor qualifier_descriptor = { .bLength = sizeof(struct usb_qualifier_descriptor), .bDescriptorType = USB_DT_DEVICE_QUALIFIER, .bcdUSB = 0x0200, .bDeviceClass = 0, .bDeviceSubClass = 0, .bDeviceProtocol = 0, .bMaxPacketSize0 = 64, .bNumConfigurations = 1 }; static struct usb_string_descriptor usb_string_iManufacturer = { 24, USB_DT_STRING, {'R','o','c','k','b','o','x','.','o','r','g'} }; static struct usb_string_descriptor usb_string_iProduct = { 42, USB_DT_STRING, {'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 = { 34, USB_DT_STRING, {'0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0'} }; /* Generic for all targets */ /* this is stringid #0: languages supported */ static struct usb_string_descriptor lang_descriptor = { 4, USB_DT_STRING, {0x0409} /* LANGID US English */ }; static struct usb_string_descriptor usb_string_usb_benchmark = { 40, USB_DT_STRING, {'B','u','l','k',' ','t','e','s','t',' ','i','n','t','e','r','f','a','c','e'} }; static struct usb_string_descriptor usb_string_charging_only = { 28, USB_DT_STRING, {'C','h','a','r','g','i','n','g',' ','o','n','l','y'} }; static struct usb_string_descriptor* usb_strings[] = { &lang_descriptor, &usb_string_iManufacturer, &usb_string_iProduct, &usb_string_iSerial, &usb_string_usb_benchmark, &usb_string_charging_only }; static int usb_address = 0; static bool initialized = false; static bool data_connection = false; static struct event_queue usbcore_queue; static enum { DEFAULT, ADDRESS, CONFIGURED } usb_state; #ifdef USB_THREAD static const char usbcore_thread_name[] = "usb_core"; static struct thread_entry* usbcore_thread; static long usbcore_stack[DEFAULT_STACK_SIZE]; static void usb_core_thread(void); #endif static void ack_control(struct usb_ctrlrequest* req); #ifdef IPOD_ARCH 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'}; #ifdef IPOD_VIDEO uint32_t* serial = (uint32_t*)(0x20004034); #else uint32_t* serial = (uint32_t*)(0x20002034); #endif /* We need to convert from a little-endian 64-bit int into a utf-16 string of hex characters */ short* p = &usb_string_iSerial.wString[15]; uint32_t x; int i,j; for (i = 0; i < 2; i++) { x = serial[i]; for (j=0;j<8;j++) { *p-- = hex[x & 0xf]; x >>= 4; } } } #endif void usb_core_init(void) { if (initialized) return; #ifdef IPOD_ARCH set_serial_descriptor(); #endif queue_init(&usbcore_queue, false); usb_drv_init(); #ifdef USB_STORAGE usb_storage_init(); #endif #ifdef USB_SERIAL usb_serial_init(); #endif #ifdef USB_THREAD usbcore_thread = create_thread(usb_core_thread, usbcore_stack, sizeof(usbcore_stack), 0, usbcore_thread_name IF_PRIO(, PRIORITY_SYSTEM) IF_COP(, CPU)); #endif #ifdef USB_BENCHMARK usb_benchmark_init(); #endif initialized = true; usb_state = DEFAULT; logf("usb_core_init() finished"); } void usb_core_exit(void) { if (initialized) { usb_drv_exit(); queue_delete(&usbcore_queue); #ifdef USB_THREAD remove_thread(usbcore_thread); #endif } data_connection = false; initialized = false; logf("usb_core_exit() finished"); } bool usb_core_data_connection(void) { return data_connection; } #ifdef USB_THREAD void usb_core_thread(void) { while (1) { struct queue_event ev; queue_wait(&usbcore_queue, &ev); #ifdef USB_STORAGE usb_storage_transfer_complete(ev.id); #endif #ifdef USB_SERIAL usb_serial_transfer_complete(ev.id); #endif } } #endif /* called by usb_drv_int() */ void usb_core_control_request(struct usb_ctrlrequest* req) { /* note: interrupt context */ data_connection = true; #ifdef USB_BENCHMARK if ((req->bRequestType & 0x60) == USB_TYPE_VENDOR) { usb_benchmark_control_request(req); return; } #endif switch (req->bRequest) { case USB_REQ_SET_CONFIGURATION: logf("usb_core: SET_CONFIG"); #ifdef USB_STORAGE usb_storage_control_request(req); #endif #ifdef USB_SERIAL usb_serial_control_request(req); #endif ack_control(req); if (req->wValue) usb_state = CONFIGURED; else usb_state = ADDRESS; break; case USB_REQ_GET_CONFIGURATION: { static char confignum; char* tmp = (void*)UNCACHED_ADDR(&confignum); logf("usb_core: GET_CONFIG"); if (usb_state == ADDRESS) *tmp = 0; else *tmp = 1; usb_drv_send(EP_CONTROL, tmp, 1); ack_control(req); break; } case USB_REQ_SET_INTERFACE: logf("usb_core: SET_INTERFACE"); ack_control(req); break; case USB_REQ_CLEAR_FEATURE: logf("usb_core: CLEAR_FEATURE"); if (req->wValue) usb_drv_stall(req->wIndex, true); else usb_drv_stall(req->wIndex, false); ack_control(req); break; case USB_REQ_SET_ADDRESS: usb_address = req->wValue; logf("usb_core: SET_ADR %d", usb_address); ack_control(req); usb_drv_set_address(usb_address); usb_state = ADDRESS; break; case USB_REQ_GET_STATUS: { static char tmp[2] = {0,0}; tmp[0] = 0; tmp[1] = 0; logf("usb_core: GET_STATUS"); usb_drv_send(EP_CONTROL, UNCACHED_ADDR(&tmp), 2); ack_control(req); break; } case USB_REQ_GET_DESCRIPTOR: { int index = req->wValue & 0xff; int length = req->wLength; int size; const void* ptr = NULL; logf("usb_core: GET_DESC %d", req->wValue >> 8); switch (req->wValue >> 8) { /* type */ case USB_DT_DEVICE: ptr = &device_descriptor; size = sizeof device_descriptor; break; case USB_DT_CONFIG: if(usb_drv_port_speed()) { ptr = &config_data_hs; size = sizeof config_data_hs; } else { ptr = &config_data_fs; size = sizeof config_data_fs; } break; case USB_DT_STRING: if ((unsigned)index < (sizeof(usb_strings)/sizeof(struct usb_string_descriptor*))) { ptr = usb_strings[index]; size = usb_strings[index]->bLength; } else { logf("bad string id %d", index); usb_drv_stall(EP_CONTROL, true); } break; case USB_DT_DEVICE_QUALIFIER: ptr = &qualifier_descriptor; size = sizeof qualifier_descriptor; break; default: logf("bad desc %d", req->wValue >> 8); usb_drv_stall(EP_CONTROL, true); break; } if (ptr) { length = MIN(size, length); usb_drv_send(EP_CONTROL, (void*)UNCACHED_ADDR(ptr), length); } ack_control(req); break; } /* USB_REQ_GET_DESCRIPTOR */ default: #ifdef USB_STORAGE /* does usb_storage know this request? */ if (!usb_storage_control_request(req)) #endif #ifdef USB_SERIAL /* does usb_serial know this request? */ if (!usb_serial_control_request(req)) #endif { /* nope. flag error */ logf("usb bad req %d", req->bRequest); usb_drv_stall(EP_CONTROL, true); ack_control(req); } break; } } /* called by usb_drv_int() */ void usb_core_bus_reset(void) { usb_address = 0; data_connection = false; usb_state = DEFAULT; } /* called by usb_drv_transfer_completed() */ void usb_core_transfer_complete(int endpoint, bool in) { #ifdef USB_CHARGING_ONLY (void)in; #endif switch (endpoint) { case EP_CONTROL: /* 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: break; } } static void ack_control(struct usb_ctrlrequest* req) { if (req->bRequestType & 0x80) usb_drv_recv(EP_CONTROL, NULL, 0); else usb_drv_send(EP_CONTROL, NULL, 0); }