Index: firmware/export/usb_core.h =================================================================== --- firmware/export/usb_core.h (revision 16668) +++ firmware/export/usb_core.h (working copy) @@ -21,9 +21,9 @@ #ifndef BOOTLOADER -//#define USB_SERIAL +#define USB_SERIAL #define USB_STORAGE -#define USB_CHARGING_ONLY +#define USB_AUDIO #else /* BOOTLOADER */ #define USB_CHARGING_ONLY #endif /* BOOTLOADER */ @@ -47,6 +47,7 @@ bool usb_core_driver_enabled (int driver); void usb_core_handle_transfer_completion( struct usb_transfer_completion_event_data* event); +int usb_core_ack_control(struct usb_ctrlrequest* req); #ifdef HAVE_HOTSWAP void usb_core_hotswap_event(int volume,bool inserted); #endif Index: firmware/export/usb.h =================================================================== --- firmware/export/usb.h (revision 16668) +++ firmware/export/usb.h (working copy) @@ -70,7 +70,7 @@ enum { USB_DRIVER_MASS_STORAGE, USB_DRIVER_SERIAL, - USB_DRIVER_CHARGING_ONLY, + USB_DRIVER_AUDIO, USB_NUM_DRIVERS }; #endif Index: firmware/usbstack/usb_class_driver.h =================================================================== --- firmware/usbstack/usb_class_driver.h (revision 16668) +++ firmware/usbstack/usb_class_driver.h (working copy) @@ -23,41 +23,65 @@ /* Common api, implemented by all class drivers */ struct usb_class_driver { + /* First some runtime data */ bool enabled; + int first_interface; + int last_interface; + + /* Driver api starts here */ + + /* Set this to true if the driver needs exclusive disk access (e.g. usb storage) */ bool needs_exclusive_ata; - int usb_endpoint; - int usb_interface; + /* Tells the driver what its first interface number will be. The driver + returns the number of the first available interface for the next driver + (i.e. a driver with one interface will return interface+1) + A driver must have at least one interface + Mandatory function */ + int (*set_first_interface)(int interface); + + /* Tells the driver what its first endpoint pair number will be. The driver + returns the number of the first available endpoint pair for the next + driver (i.e. a driver with one endpoint pair will return endpoint +1) + Mandatory function */ + int (*set_first_endpoint)(int endpoint); + /* Asks the driver to put the interface descriptor and all other - needed descriptor for this driver at dest, for the given settings. - Returns the number of bytes taken by these descriptors. */ - int (*get_config_descriptor)(unsigned char *dest, - int max_packet_size, int interface_number, int endpoint); + needed descriptor for this driver at dest. + Returns the number of bytes taken by these descriptors. + Mandatory function */ + int (*get_config_descriptor)(unsigned char *dest, int max_packet_size); /* Tells the driver that a usb connection has been set up and is now - ready to use. */ - void (*init_connection)(int interface,int endpoint); + ready to use. + Optional function */ + void (*init_connection)(void); /* Initialises the driver. This can be called multiple times, and should not perform any action that can disturb other threads - (like getting the audio buffer) */ + (like getting the audio buffer) + Optional function */ void (*init)(void); - /* Tells the driver that the usb connection is no longer active */ + /* Tells the driver that the usb connection is no longer active + Optional function */ void (*disconnect)(void); /* Tells the driver that a usb transfer has been completed. Note that "in" - is relative to the host */ - void (*transfer_complete)(bool in, int status, int length); + is relative to the host + Optional function */ + void (*transfer_complete)(int ep,bool in, int status, int length); /* Tells the driver that a control request has come in. If the driver is able to handle it, it should ack the request, and return true. Otherwise - it should return false. */ + it should return false. + Optional function */ bool (*control_request)(struct usb_ctrlrequest* req); #ifdef HAVE_HOTSWAP /* Tells the driver that a hotswappable disk/card was inserted or - extracted */ + extracted + Optional function */ void (*notify_hotswap)(int volume, bool inserted); #endif }; Index: firmware/usbstack/usb_audio.h =================================================================== --- firmware/usbstack/usb_audio.h (revision 0) +++ firmware/usbstack/usb_audio.h (revision 0) @@ -0,0 +1,31 @@ +/*************************************************************************** + * __________ __ ___. + * Open \______ \ ____ ____ | | _\_ |__ _______ ___ + * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / + * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < + * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ + * \/ \/ \/ \/ \/ + * $Id: $ + * + * Copyright (C) 2008 by Frank Gevaerts + * + * 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. + * + ****************************************************************************/ +#ifndef USB_AUDIO_H +#define USB_AUDIO_H + +#include "usb_ch9.h" + +void usb_audio_init(void); +int usb_audio_set_first_endpoint(int endpoint); +int usb_audio_set_first_interface(int interface); +int usb_audio_get_config_descriptor(unsigned char *dest,int max_packet_size); +bool usb_audio_control_request(struct usb_ctrlrequest* req); + +#endif + Index: firmware/usbstack/usb_core.c =================================================================== --- firmware/usbstack/usb_core.c (revision 16668) +++ firmware/usbstack/usb_core.c (working copy) @@ -20,7 +20,7 @@ #include "thread.h" #include "kernel.h" #include "string.h" -//#define LOGF_ENABLE +#define LOGF_ENABLE #include "logf.h" #include "usb.h" @@ -37,6 +37,10 @@ #include "usb_serial.h" #endif +#if defined(USB_AUDIO) +#include "usb_audio.h" +#endif + /* TODO: Move target-specific stuff somewhere else (serial number reading) */ #ifdef HAVE_AS3514 @@ -91,22 +95,6 @@ .bMaxPower = 250, /* 500mA in 2mA units */ }; -#ifdef USB_CHARGING_ONLY -/* dummy interface for charging-only */ -static struct usb_interface_descriptor __attribute__((aligned(2))) - charging_interface_descriptor = -{ - .bLength = sizeof(struct usb_interface_descriptor), - .bDescriptorType = USB_DT_INTERFACE, - .bInterfaceNumber = 0, - .bAlternateSetting = 0, - .bNumEndpoints = 0, - .bInterfaceClass = USB_CLASS_VENDOR_SPEC, - .bInterfaceSubClass = 0, - .bInterfaceProtocol = 0, - .iInterface = 4 -}; -#endif static const struct usb_qualifier_descriptor __attribute__((aligned(2))) qualifier_descriptor = @@ -160,21 +148,12 @@ {0x0409} /* LANGID US English */ }; -static struct usb_string_descriptor __attribute__((aligned(2))) - 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_charging_only + &usb_string_iSerial }; static int usb_address = 0; @@ -183,8 +162,12 @@ static int usb_core_num_interfaces; -static int usb_charging_get_config_descriptor(unsigned char *dest,int max_packet_size, - int interface_number,int endpoint); +static struct +{ + void (*completion_handler)(int ep,bool in, int status, int length); + bool (*control_handler)(struct usb_ctrlrequest* req); + struct usb_transfer_completion_event_data completion_event; +} ep_data[NUM_ENDPOINTS]; static struct usb_class_driver drivers[USB_NUM_DRIVERS] = { @@ -192,8 +175,10 @@ [USB_DRIVER_MASS_STORAGE] = { .enabled = false, .needs_exclusive_ata = true, - .usb_endpoint = 0, - .usb_interface = 0, + .first_interface = 0, + .last_interface = 0, + .set_first_interface = usb_storage_set_first_interface, + .set_first_endpoint = usb_storage_set_first_endpoint, .get_config_descriptor = usb_storage_get_config_descriptor, .init_connection = usb_storage_init_connection, .init = usb_storage_init, @@ -209,8 +194,10 @@ [USB_DRIVER_SERIAL] = { .enabled = false, .needs_exclusive_ata = false, - .usb_endpoint = 0, - .usb_interface = 0, + .first_interface = 0, + .last_interface = 0, + .set_first_interface = usb_serial_set_first_interface, + .set_first_endpoint = usb_serial_set_first_endpoint, .get_config_descriptor = usb_serial_get_config_descriptor, .init_connection = usb_serial_init_connection, .init = usb_serial_init, @@ -222,15 +209,17 @@ #endif }, #endif -#ifdef USB_CHARGING_ONLY - [USB_DRIVER_CHARGING_ONLY] = { +#ifdef USB_AUDIO + [USB_DRIVER_AUDIO] = { .enabled = false, .needs_exclusive_ata = false, - .usb_endpoint = 0, - .usb_interface = 0, - .get_config_descriptor = usb_charging_get_config_descriptor, + .first_interface = 0, + .last_interface = 0, + .set_first_interface = usb_audio_set_first_interface, + .set_first_endpoint = usb_audio_set_first_endpoint, + .get_config_descriptor = usb_audio_get_config_descriptor, .init_connection = NULL, - .init = NULL, + .init = usb_audio_init, .disconnect = NULL, .transfer_complete = NULL, .control_request = NULL, @@ -242,12 +231,10 @@ }; static void usb_core_control_request_handler(struct usb_ctrlrequest* req); -static int ack_control(struct usb_ctrlrequest* req); static unsigned char *response_data; static unsigned char __response_data[CACHEALIGN_UP(256)] CACHEALIGN_ATTR; -static struct usb_transfer_completion_event_data events[NUM_ENDPOINTS]; static short hex[16] = {'0','1','2','3','4','5','6','7', '8','9','A','B','C','D','E','F'}; @@ -334,17 +321,6 @@ logf("usb_core_init() finished"); } -static int usb_charging_get_config_descriptor(unsigned char *dest,int max_packet_size, - int interface_number,int endpoint) -{ - (void) max_packet_size; - (void) endpoint; - charging_interface_descriptor.bInterfaceNumber=interface_number; - memcpy(dest,&charging_interface_descriptor, - sizeof(struct usb_interface_descriptor)); - return sizeof(struct usb_interface_descriptor); -} - void usb_core_exit(void) { int i; @@ -363,24 +339,17 @@ void usb_core_handle_transfer_completion( struct usb_transfer_completion_event_data* event) { - int i; - switch(event->endpoint) { + int ep = event->endpoint; + switch(ep) { case EP_CONTROL: logf("ctrl handled %ld",current_tick); usb_core_control_request_handler( (struct usb_ctrlrequest*)event->data); break; default: - for(i=0;iendpoint && - drivers[i].transfer_complete != NULL) - { - drivers[i].transfer_complete(event->in, + if(ep_data[ep].completion_handler != NULL) + ep_data[ep].completion_handler(ep,event->in, event->status,event->length); - break; - } - } break; } } @@ -422,13 +391,29 @@ static void allocate_interfaces_and_endpoints(void) { - int i; + int i,j; int interface=0; int endpoint=1; + + memset(ep_data,0,sizeof(ep_data)); + for(i=0;iNUM_ENDPOINTS) { + drivers[i].enabled = false; + continue; + } + interface = drivers[i].set_first_interface(interface); + drivers[i].last_interface = interface; + + for(j=oldendpoint;jNUM_ENDPOINTS) { drivers[i].enabled = false; @@ -466,7 +451,7 @@ response_data[0] = 1; if(usb_drv_send(EP_CONTROL, response_data, 1)!= 0) break; - ack_control(req); + usb_core_ack_control(req); break; case USB_REQ_SET_CONFIGURATION: logf("usb_core: SET_CONFIG"); @@ -477,22 +462,20 @@ if(drivers[i].enabled && drivers[i].init_connection!=NULL) { - drivers[i].init_connection( - drivers[i].usb_interface, - drivers[i].usb_endpoint); + drivers[i].init_connection(); } } } else { usb_state = ADDRESS; } - ack_control(req); + usb_core_ack_control(req); break; } case USB_REQ_SET_ADDRESS: { unsigned char address = req->wValue; logf("usb_core: SET_ADR %d", address); - if(ack_control(req)!=0) + if(usb_core_ack_control(req)!=0) break; usb_drv_cancel_all_transfers(); usb_address = address; @@ -540,9 +523,7 @@ { size+=drivers[i].get_config_descriptor( &response_data[size], - max_packet_size, - drivers[i].usb_interface, - drivers[i].usb_endpoint); + max_packet_size); } } config_descriptor.bNumInterfaces = @@ -588,7 +569,7 @@ if(usb_drv_send(EP_CONTROL, uncached, length)!=0) break; } - ack_control(req); + usb_core_ack_control(req); break; } /* USB_REQ_GET_DESCRIPTOR */ case USB_REQ_CLEAR_FEATURE: @@ -596,7 +577,7 @@ case USB_REQ_SET_FEATURE: if(req->wValue == 2) { /* TEST_MODE */ int mode=req->wIndex>>8; - ack_control(req); + usb_core_ack_control(req); usb_drv_set_test_mode(mode); } break; @@ -605,7 +586,7 @@ response_data[1]= 0; if(usb_drv_send(EP_CONTROL, response_data, 2)!=0) break; - ack_control(req); + usb_core_ack_control(req); break; default: break; @@ -615,7 +596,7 @@ switch (req->bRequest) { case USB_REQ_SET_INTERFACE: logf("usb_core: SET_INTERFACE"); - ack_control(req); + usb_core_ack_control(req); break; case USB_REQ_GET_INTERFACE: @@ -623,7 +604,7 @@ response_data[0] = 0; if(usb_drv_send(EP_CONTROL, response_data, 1)!=0) break; - ack_control(req); + usb_core_ack_control(req); break; case USB_REQ_CLEAR_FEATURE: break; @@ -634,14 +615,15 @@ response_data[1]= 0; if(usb_drv_send(EP_CONTROL, response_data, 2)!=0) break; - ack_control(req); + usb_core_ack_control(req); break; default: { bool handled=false; for(i=0;iwIndex)) + drivers[i].first_interface >= (req->wIndex) && + drivers[i].last_interface <= (req->wIndex)) { handled = drivers[i].control_request(req); } @@ -650,7 +632,7 @@ /* nope. flag error */ logf("usb bad req %d", req->bRequest); usb_drv_stall(EP_CONTROL, true,true); - ack_control(req); + usb_core_ack_control(req); } break; } @@ -662,13 +644,13 @@ if (req->wValue == 0 ) /* ENDPOINT_HALT */ usb_drv_stall(req->wIndex & 0xf, false, (req->wIndex & 0x80) !=0); - ack_control(req); + usb_core_ack_control(req); break; case USB_REQ_SET_FEATURE: if (req->wValue == 0 ) /* ENDPOINT_HALT */ usb_drv_stall(req->wIndex & 0xf, true, (req->wIndex & 0x80) !=0); - ack_control(req); + usb_core_ack_control(req); break; case USB_REQ_GET_STATUS: response_data[0]= 0; @@ -679,23 +661,17 @@ (req->wIndex&0x80)!=0); if(usb_drv_send(EP_CONTROL, response_data, 2)!=0) break; - ack_control(req); + usb_core_ack_control(req); break; default: { bool handled=false; - for(i=0;iwIndex & 0xf)) - { - handled = drivers[i].control_request(req); - } - } + if(ep_data[req->wIndex & 0xf].control_handler != NULL) + handled = ep_data[req->wIndex & 0xf].control_handler(req); if(!handled) { /* nope. flag error */ logf("usb bad req %d", req->bRequest); usb_drv_stall(EP_CONTROL, true,true); - ack_control(req); + usb_core_ack_control(req); } break; } @@ -720,13 +696,13 @@ break; default: - events[endpoint].endpoint=endpoint; - events[endpoint].in=in; - events[endpoint].data=0; - events[endpoint].status=status; - events[endpoint].length=length; + ep_data[endpoint].completion_event.endpoint=endpoint; + ep_data[endpoint].completion_event.in=in; + ep_data[endpoint].completion_event.data=0; + ep_data[endpoint].completion_event.status=status; + ep_data[endpoint].completion_event.length=length; /* All other endoints. Let the thread deal with it */ - usb_signal_transfer_completion(&events[endpoint]); + usb_signal_transfer_completion(&ep_data[endpoint].completion_event); break; } } @@ -734,16 +710,16 @@ /* 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; - events[0].status=0; - events[0].length=0; + ep_data[0].completion_event.endpoint=0; + ep_data[0].completion_event.in=0; + ep_data[0].completion_event.data=(void *)req; + ep_data[0].completion_event.status=0; + ep_data[0].completion_event.length=0; logf("ctrl received %ld",current_tick); - usb_signal_transfer_completion(&events[0]); + usb_signal_transfer_completion(&ep_data[0].completion_event); } -static int ack_control(struct usb_ctrlrequest* req) +int usb_core_ack_control(struct usb_ctrlrequest* req) { if (req->bRequestType & 0x80) return usb_drv_recv(EP_CONTROL, NULL, 0); Index: firmware/usbstack/usb_storage.h =================================================================== --- firmware/usbstack/usb_storage.h (revision 16668) +++ firmware/usbstack/usb_storage.h (working copy) @@ -21,11 +21,12 @@ #include "usb_ch9.h" -int usb_storage_get_config_descriptor(unsigned char *dest,int max_packet_size, - int interface_number,int endpoint); -void usb_storage_init_connection(int interface,int endpoint); +int usb_storage_set_first_endpoint(int endpoint); +int usb_storage_set_first_interface(int interface); +int usb_storage_get_config_descriptor(unsigned char *dest,int max_packet_size); +void usb_storage_init_connection(void); void usb_storage_init(void); -void usb_storage_transfer_complete(bool in,int state,int length); +void usb_storage_transfer_complete(int ep,bool in,int state,int length); bool usb_storage_control_request(struct usb_ctrlrequest* req); #ifdef HAVE_HOTSWAP void usb_storage_notify_hotswap(int volume,bool inserted); Index: firmware/usbstack/usb_serial.c =================================================================== --- firmware/usbstack/usb_serial.c (revision 16668) +++ firmware/usbstack/usb_serial.c (working copy) @@ -28,7 +28,7 @@ #ifdef USB_SERIAL /* serial interface */ -struct usb_interface_descriptor __attribute__((aligned(2))) +static struct usb_interface_descriptor __attribute__((aligned(2))) interface_descriptor = { .bLength = sizeof(struct usb_interface_descriptor), @@ -42,7 +42,7 @@ .iInterface = 0 }; -struct usb_endpoint_descriptor __attribute__((aligned(2))) endpoint_descriptor = +static struct usb_endpoint_descriptor __attribute__((aligned(2))) endpoint_descriptor = { .bLength = sizeof(struct usb_endpoint_descriptor), .bDescriptorType = USB_DT_ENDPOINT, @@ -85,31 +85,39 @@ busy_sending=true; } -int usb_serial_get_config_descriptor(unsigned char *dest,int max_packet_size, - int interface_number,int endpoint) +int usb_serial_set_first_endpoint(int endpoint) { + usb_endpoint = endpoint; + return endpoint + 1; +} + +int usb_serial_set_first_interface(int interface) +{ + usb_interface = interface; + return interface + 1; +} + + +int usb_serial_get_config_descriptor(unsigned char *dest,int max_packet_size) +{ endpoint_descriptor.wMaxPacketSize=max_packet_size; - interface_descriptor.bInterfaceNumber=interface_number; + interface_descriptor.bInterfaceNumber=usb_interface; - memcpy(dest,&interface_descriptor,sizeof(struct usb_interface_descriptor)); dest+=sizeof(struct usb_interface_descriptor); - endpoint_descriptor.bEndpointAddress = endpoint | USB_DIR_IN, + endpoint_descriptor.bEndpointAddress = usb_endpoint | USB_DIR_IN, memcpy(dest,&endpoint_descriptor,sizeof(struct usb_endpoint_descriptor)); dest+=sizeof(struct usb_endpoint_descriptor); - endpoint_descriptor.bEndpointAddress = endpoint | USB_DIR_OUT, + endpoint_descriptor.bEndpointAddress = usb_endpoint | USB_DIR_OUT, memcpy(dest,&endpoint_descriptor,sizeof(struct usb_endpoint_descriptor)); return sizeof(struct usb_interface_descriptor) + 2 * sizeof(struct usb_endpoint_descriptor); } -void usb_serial_init_connection(int interface,int endpoint) +void usb_serial_init_connection(void) { - usb_interface = interface; - usb_endpoint = endpoint; - /* prime rx endpoint */ usb_drv_recv(usb_endpoint, receive_buffer, sizeof _receive_buffer); @@ -184,8 +192,9 @@ } /* called by usb_core_transfer_complete() */ -void usb_serial_transfer_complete(bool in, int status, int length) +void usb_serial_transfer_complete(int ep,bool in, int status, int length) { + (void)ep; switch (in) { case false: logf("serial: %s", receive_buffer); Index: firmware/usbstack/usb_audio.c =================================================================== --- firmware/usbstack/usb_audio.c (revision 0) +++ firmware/usbstack/usb_audio.c (revision 0) @@ -0,0 +1,228 @@ +/*************************************************************************** + * __________ __ ___. + * Open \______ \ ____ ____ | | _\_ |__ _______ ___ + * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / + * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < + * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ + * \/ \/ \/ \/ \/ + * $Id: $ + * + * Copyright (C) 2008 by Frank Gevaerts + * + * 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 "string.h" +#include "system.h" +#include "usb_core.h" +#include "usb_drv.h" +#include "kernel.h" +#include "sound.h" +#include "../apps/settings.h" + +#define LOGF_ENABLE +#include "logf.h" + +#ifdef USB_AUDIO + +#define USB_SUBCLASS_AUDIO_CONTROL 1 +#define USB_SUBCLASS_AUDIO_STREAMING 2 + +#define USB_AC_HEADER 1 +#define USB_AC_INPUT_TERMINAL 2 +#define USB_AC_OUTPUT_TERMINAL 3 +#define USB_AC_MIXER_UNIT 4 +#define USB_AC_SELECTOR_UNIT 5 +#define USB_AC_FEATURE_UNIT 6 +#define USB_AC_PROCESSING_UNIT 8 +#define USB_AC_EXTENSION_UNIT 9 + +#define SET_CUR 0x01 +#define SET_MIN 0x02 +#define SET_MAX 0x03 +#define SET_RES 0x04 +#define GET_CUR 0x81 +#define GET_MIN 0x82 +#define GET_MAX 0x83 +#define GET_RES 0x84 + +#define TTYPE_MINIDISK 0x0706 +#define TTYPE_HEADPHONES 0x0302 + +/* usb audio datastructures */ +struct usb_ac_header { + uint8_t bLength; + uint8_t bDescriptorType; + uint8_t bDescriptorSubType; + uint8_t bcdADC[2]; + uint8_t wTotalLength[2]; /* Should be a unit16_t, but it's not aligned, so this is safer */ + uint8_t bInCollection; + uint8_t baInterfaceNr[1]; +} __attribute__ ((packed)); + +struct usb_ac_input_terminal { + uint8_t bLength; + uint8_t bDescriptorType; + uint8_t bDescriptorSubType; + uint8_t bTerminalId; + uint16_t wTerminalType; + uint8_t bAssocTerminal; + uint8_t bNrChannels; + uint16_t wChannelConfig; + uint8_t iChannelNames; + uint8_t iTerminal; +} __attribute__ ((packed)); + +struct usb_ac_output_terminal { + uint8_t bLength; + uint8_t bDescriptorType; + uint8_t bDescriptorSubType; + uint8_t bTerminalId; + uint16_t wTerminalType; + uint8_t bAssocTerminal; + uint8_t bSourceId; + uint8_t iTerminal; +} __attribute__ ((packed)); + +struct usb_ac_feature_unit { + uint8_t bLength; + uint8_t bDescriptorType; + uint8_t bDescriptorSubType; + uint8_t bUnitId; + uint8_t bSourceId; + uint8_t bControlSize; + uint8_t bmaControls[2]; + uint8_t iFeature; +} __attribute__ ((packed)); + +struct usb_as_class { + uint8_t bLength; + uint8_t bDescriptorType; + uint8_t bDescriptorSubType; + uint8_t bTerminalLink; + uint8_t bDelay; + uint8_t wFormatTag[2]; /* Yet another unaligned field */ +} __attribute__ ((packed)); + +static unsigned char _buffer[32] __attribute__((aligned(32))); +static unsigned char* buffer; + +/* audio interface */ +static struct usb_interface_descriptor __attribute__((aligned(2))) + interface_descriptor = +{ + .bLength = sizeof(struct usb_interface_descriptor), + .bDescriptorType = USB_DT_INTERFACE, + .bInterfaceNumber = 0, + .bAlternateSetting = 0, + .bNumEndpoints = 0, + .bInterfaceClass = USB_CLASS_AUDIO, + .bInterfaceSubClass = USB_SUBCLASS_AUDIO_CONTROL, + .bInterfaceProtocol = 0, + .iInterface = 0 +}; + +static struct usb_ac_header __attribute__((aligned(2))) ac_header = +{ + .bLength = sizeof(struct usb_ac_header), + .bDescriptorType = USB_DT_CS_INTERFACE, + .bDescriptorSubType = USB_AC_HEADER, + .bcdADC = {0x00,0x01}, + .wTotalLength = {30,0},// TODO + .bInCollection = 1, + .baInterfaceNr = {0}, +}; + +static struct usb_ac_input_terminal __attribute__((aligned(2))) ac_input = +{ + .bLength = sizeof(struct usb_ac_input_terminal), + .bDescriptorType = USB_DT_CS_INTERFACE, + .bDescriptorSubType = USB_AC_INPUT_TERMINAL, + .bTerminalId = 1, + .wTerminalType = TTYPE_MINIDISK, + .bAssocTerminal = 0, + .bNrChannels = 2, + .wChannelConfig = 3, + .iChannelNames = 0, + .iTerminal = 0, +}; + +static struct usb_ac_output_terminal __attribute__((aligned(2))) ac_output = +{ + .bLength = sizeof(struct usb_ac_output_terminal), + .bDescriptorType = USB_DT_CS_INTERFACE, + .bDescriptorSubType = USB_AC_INPUT_TERMINAL, + .bTerminalId = 2, + .wTerminalType = TTYPE_HEADPHONES, + .bAssocTerminal = 0, + .bSourceId = 1, + .iTerminal = 0, +}; + + + +static int usb_interface; + +void usb_audio_init(void) +{ + buffer = (void*)UNCACHED_ADDR(&_buffer); +} + +int usb_audio_set_first_endpoint(int endpoint) +{ + /* The dummy audio driver doesn't need an endpoint pair */ + return endpoint; +} +int usb_audio_set_first_interface(int interface) +{ + usb_interface = interface; + return interface + 2; +} + +int usb_audio_get_config_descriptor(unsigned char *dest,int max_packet_size) +{ + (void)max_packet_size; + unsigned char *orig_dest = dest; + + interface_descriptor.bInterfaceNumber=usb_interface; + interface_descriptor.bInterfaceSubClass=USB_SUBCLASS_AUDIO_CONTROL; + ac_header.baInterfaceNr[0] = usb_interface + 1; + + memcpy(dest,&interface_descriptor,sizeof(struct usb_interface_descriptor)); + dest+=sizeof(struct usb_interface_descriptor); + + memcpy(dest,&ac_header,sizeof(struct usb_ac_header)); + dest+=sizeof(struct usb_ac_header); + + memcpy(dest,&ac_input,sizeof(struct usb_ac_input_terminal)); + dest+=sizeof(struct usb_ac_input_terminal); + + memcpy(dest,&ac_output,sizeof(struct usb_ac_output_terminal)); + dest+=sizeof(struct usb_ac_output_terminal); + + interface_descriptor.bInterfaceNumber=usb_interface + 1; + interface_descriptor.bInterfaceSubClass=USB_SUBCLASS_AUDIO_STREAMING; + + memcpy(dest,&interface_descriptor,sizeof(struct usb_interface_descriptor)); + dest+=sizeof(struct usb_interface_descriptor); + + return (dest-orig_dest); +} + + +/* called by usb_core_control_request() */ +bool usb_audio_control_request(struct usb_ctrlrequest* req) +{ + bool handled = false; + switch (req->bRequest) { + default: + logf("audio: unhandeld req %d", req->bRequest); + } + return handled; +} + +#endif /*USB_AUDIO*/ Index: firmware/usbstack/usb_serial.h =================================================================== --- firmware/usbstack/usb_serial.h (revision 16668) +++ firmware/usbstack/usb_serial.h (working copy) @@ -21,12 +21,13 @@ #include "usb_ch9.h" -int usb_serial_get_config_descriptor(unsigned char *dest,int max_packet_size, - int interface_number, int endpoint); -void usb_serial_init_connection(int interface,int endpoint); +int usb_serial_set_first_endpoint(int endpoint); +int usb_serial_set_first_interface(int interface); +int usb_serial_get_config_descriptor(unsigned char *dest,int max_packet_size); +void usb_serial_init_connection(void); void usb_serial_init(void); void usb_serial_disconnect(void); -void usb_serial_transfer_complete(bool in, int status, int length); +void usb_serial_transfer_complete(int ep,bool in, int status, int length); bool usb_serial_control_request(struct usb_ctrlrequest* req); void usb_serial_send(unsigned char *data,int length); Index: firmware/usbstack/usb_storage.c =================================================================== --- firmware/usbstack/usb_storage.c (revision 16668) +++ firmware/usbstack/usb_storage.c (working copy) @@ -321,23 +321,32 @@ } -int usb_storage_get_config_descriptor(unsigned char *dest,int max_packet_size, - int interface_number,int endpoint) +int usb_storage_set_first_endpoint(int endpoint) { + usb_endpoint = endpoint; + return endpoint + 1; +} +int usb_storage_set_first_interface(int interface) +{ + usb_interface = interface; + return interface + 1; +} + +int usb_storage_get_config_descriptor(unsigned char *dest,int max_packet_size) +{ endpoint_descriptor.wMaxPacketSize=max_packet_size; - interface_descriptor.bInterfaceNumber=interface_number; + interface_descriptor.bInterfaceNumber=usb_interface; - memcpy(dest,&interface_descriptor, sizeof(struct usb_interface_descriptor)); dest+=sizeof(struct usb_interface_descriptor); - endpoint_descriptor.bEndpointAddress = endpoint | USB_DIR_IN, + endpoint_descriptor.bEndpointAddress = usb_endpoint | USB_DIR_IN, memcpy(dest,&endpoint_descriptor, sizeof(struct usb_endpoint_descriptor)); dest+=sizeof(struct usb_endpoint_descriptor); - endpoint_descriptor.bEndpointAddress = endpoint | USB_DIR_OUT, + endpoint_descriptor.bEndpointAddress = usb_endpoint | USB_DIR_OUT, memcpy(dest,&endpoint_descriptor, sizeof(struct usb_endpoint_descriptor)); @@ -345,14 +354,11 @@ 2*sizeof(struct usb_endpoint_descriptor); } -void usb_storage_init_connection(int interface,int endpoint) +void usb_storage_init_connection(void) { size_t bufsize; unsigned char * audio_buffer; - usb_interface = interface; - usb_endpoint = endpoint; - logf("ums: set config"); /* prime rx endpoint. We only need room for commands */ state = WAITING_FOR_COMMAND; @@ -365,8 +371,9 @@ } /* called by usb_core_transfer_complete() */ -void usb_storage_transfer_complete(bool in,int status,int length) +void usb_storage_transfer_complete(int ep,bool in,int status,int length) { + (void)ep; struct command_block_wrapper* cbw = (void*)tb.transfer_buffer; //logf("transfer result %X %d", status, length); Index: firmware/SOURCES =================================================================== --- firmware/SOURCES (revision 16668) +++ firmware/SOURCES (working copy) @@ -236,6 +236,7 @@ usbstack/usb_core.c usbstack/usb_storage.c usbstack/usb_serial.c +usbstack/usb_audio.c #ifdef CPU_PP502x target/arm/usb-drv-pp502x.c #endif Index: firmware/usb.c =================================================================== --- firmware/usb.c (revision 16668) +++ firmware/usb.c (working copy) @@ -192,7 +192,7 @@ usb_state = USB_POWERED; #ifdef HAVE_USBSTACK usb_core_enable_driver(USB_DRIVER_MASS_STORAGE,false); - usb_core_enable_driver(USB_DRIVER_CHARGING_ONLY,true); + usb_core_enable_driver(USB_DRIVER_AUDIO,true); usb_enable(true); #endif } @@ -201,7 +201,7 @@ { #ifdef HAVE_USBSTACK usb_core_enable_driver(USB_DRIVER_MASS_STORAGE,true); - usb_core_enable_driver(USB_DRIVER_CHARGING_ONLY,false); + usb_core_enable_driver(USB_DRIVER_AUDIO,false); usb_enable(true); #else /* Tell all threads that they have to back off the ATA.