diff --git a/.gitignore b/.gitignore index d38743a7..5b2ff009 100644 --- a/.gitignore +++ b/.gitignore @@ -27,3 +27,4 @@ _build* build/ .build* *.pyc +xscope.xmt diff --git a/CHANGELOG.rst b/CHANGELOG.rst index be867bab..498faf1e 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -1,6 +1,13 @@ lib_xua Change Log ================== +0.3.0 +----- + + * ADDED: UAC1 HID support with simulated Voice Command detection reported + every 10 seconds + * ADDED: Support for USB HID Set Idle request + 0.2.1 ----- diff --git a/lib_xua/api/xua_buffer.h b/lib_xua/api/xua_buffer.h index eaaef881..d351ddc1 100644 --- a/lib_xua/api/xua_buffer.h +++ b/lib_xua/api/xua_buffer.h @@ -1,4 +1,4 @@ -// Copyright (c) 2011-2018, XMOS Ltd, All rights reserved +// Copyright (c) 2011-2019, XMOS Ltd, All rights reserved #ifndef __XUA_BUFFER_H__ #define __XUA_BUFFER_H__ @@ -58,7 +58,7 @@ void XUA_Buffer( chanend c_sof, chanend c_aud_ctl, in port p_off_mclk -#ifdef HID_CONTROLS +#if( 0 < HID_CONTROLS ) , chanend c_hid #endif , chanend c_aud @@ -97,7 +97,7 @@ void XUA_Buffer_Ep(chanend c_aud_out, chanend c_sof, chanend c_aud_ctl, in port p_off_mclk -#ifdef HID_CONTROLS +#if( 0 < HID_CONTROLS ) , chanend c_hid #endif #ifdef CHAN_BUFF_CTRL diff --git a/lib_xua/api/xua_conf_default.h b/lib_xua/api/xua_conf_default.h index d2908342..b7bd71cf 100644 --- a/lib_xua/api/xua_conf_default.h +++ b/lib_xua/api/xua_conf_default.h @@ -1,4 +1,4 @@ -// Copyright (c) 2011-2018, XMOS Ltd, All rights reserved +// Copyright (c) 2011-2019, XMOS Ltd, All rights reserved /* * @brief Defines relating to device configuration and customisation of lib_xua * @author Ross Owen, XMOS Limited @@ -425,10 +425,6 @@ #define HID_CONTROLS (0) #endif -#if defined(HID_CONTROLS) && (HID_CONTROLS == 0) -#undef HID_CONTROLS -#endif - /* @brief Defines whether XMOS device runs as master (i.e. drives LR and Bit clocks) * * 0: XMOS is I2S master. 1: CODEC is I2s master. @@ -1158,6 +1154,10 @@ #endif +#if (defined(UAC_FORCE_FEEDBACK_EP) && UAC_FORCE_FEEDBACK_EP == 0) +#undef UAC_FORCE_FEEDBACK_EP +#endif + #ifndef __ASSEMBLER__ /* Endpoint addresses enums */ enum USBEndpointNumber_In @@ -1173,7 +1173,7 @@ enum USBEndpointNumber_In #ifdef MIDI ENDPOINT_NUMBER_IN_MIDI, #endif -#ifdef HID_CONTROLS +#if( 0 < HID_CONTROLS ) ENDPOINT_NUMBER_IN_HID, #endif #ifdef IAP diff --git a/lib_xua/module_build_info b/lib_xua/module_build_info index f2b3c05d..b41fc2ff 100644 --- a/lib_xua/module_build_info +++ b/lib_xua/module_build_info @@ -1,4 +1,4 @@ -VERSION = 0.2.1 +VERSION = 0.3.0 DEPENDENT_MODULES = lib_logging(>=3.0.0) \ lib_xassert(>=4.0.0) \ @@ -43,6 +43,7 @@ INCLUDE_DIRS = $(EXPORT_INCLUDE_DIRS) \ src/core/support/powersave \ src/core/user \ src/core/user/audiostream \ + src/core/user/hid \ src/core/user/hostactive \ src/midi @@ -61,6 +62,7 @@ SOURCE_DIRS = src/core \ src/core/user/hostactive \ src/core/xuduser \ src/dfu \ + src/hid \ src/midi EXCLUDE_FILES += descriptors_2.rst diff --git a/lib_xua/src/core/buffer/decouple/decouple.xc b/lib_xua/src/core/buffer/decouple/decouple.xc index e503ab71..297dff8d 100644 --- a/lib_xua/src/core/buffer/decouple/decouple.xc +++ b/lib_xua/src/core/buffer/decouple/decouple.xc @@ -1,4 +1,4 @@ -// Copyright (c) 2011-2018, XMOS Ltd, All rights reserved +// Copyright (c) 2011-2019, XMOS Ltd, All rights reserved #include "xua.h" #if XUA_USB_EN @@ -12,7 +12,7 @@ #include "usbaudio20.h" /* Defines from the USB Audio 2.0 Specifications */ #endif -#ifdef HID_CONTROLS +#if( 0 < HID_CONTROLS ) #include "user_hid.h" #endif #define MAX(x,y) ((x)>(y) ? (x) : (y)) diff --git a/lib_xua/src/core/buffer/ep/ep_buffer.xc b/lib_xua/src/core/buffer/ep/ep_buffer.xc index e510d37a..45e08da3 100644 --- a/lib_xua/src/core/buffer/ep/ep_buffer.xc +++ b/lib_xua/src/core/buffer/ep/ep_buffer.xc @@ -1,4 +1,4 @@ -// Copyright (c) 2011-2018, XMOS Ltd, All rights reserved +// Copyright (c) 2011-2019, XMOS Ltd, All rights reserved #include "xua.h" #if XUA_USB_EN #include @@ -19,7 +19,7 @@ #include "xud.h" #include "testct_byref.h" -#ifdef HID_CONTROLS +#if( 0 < HID_CONTROLS ) #include "user_hid.h" unsigned char g_hidData[1] = {0}; #endif @@ -120,7 +120,7 @@ void XUA_Buffer( chanend c_sof, chanend c_aud_ctl, in port p_off_mclk -#ifdef HID_CONTROLS +#if( 0 < HID_CONTROLS ) , chanend c_hid #endif , chanend c_aud @@ -164,7 +164,7 @@ void XUA_Buffer( c_clk_int, #endif c_sof, c_aud_ctl, p_off_mclk -#ifdef HID_CONTROLS +#if( 0 < HID_CONTROLS ) , c_hid #endif #ifdef CHAN_BUFF_CTRL @@ -223,7 +223,7 @@ void XUA_Buffer_Ep(register chanend c_aud_out, chanend c_sof, chanend c_aud_ctl, in port p_off_mclk -#ifdef HID_CONTROLS +#if( 0 < HID_CONTROLS ) , chanend c_hid #endif #ifdef CHAN_BUFF_CTRL @@ -260,7 +260,7 @@ void XUA_Buffer_Ep(register chanend c_aud_out, XUD_ep ep_int = XUD_InitEp(c_ep_int); #endif -#ifdef HID_CONTROLS +#if( 0 < HID_CONTROLS ) XUD_ep ep_hid = XUD_InitEp(c_hid); #endif unsigned u_tmp; @@ -364,7 +364,7 @@ void XUA_Buffer_Ep(register chanend c_aud_out, #endif #endif -#ifdef HID_CONTROLS +#if( 0 < HID_CONTROLS ) XUD_SetReady_In(ep_hid, g_hidData, 1); #endif @@ -875,12 +875,12 @@ void XUA_Buffer_Ep(register chanend c_aud_out, #endif #endif -#ifdef HID_CONTROLS +#if( 0 < HID_CONTROLS ) /* HID Report Data */ case XUD_SetData_Select(c_hid, ep_hid, result): { g_hidData[0]=0; - UserReadHIDButtons(g_hidData); + UserReadHIDData(g_hidData); XUD_SetReady_In(ep_hid, g_hidData, 1); } break; diff --git a/lib_xua/src/core/endpoint0/descriptor_defs.h b/lib_xua/src/core/endpoint0/descriptor_defs.h index 1985d910..0a5a94fd 100644 --- a/lib_xua/src/core/endpoint0/descriptor_defs.h +++ b/lib_xua/src/core/endpoint0/descriptor_defs.h @@ -1,8 +1,13 @@ -// Copyright (c) 2015-2018, XMOS Ltd, All rights reserved +// Copyright (c) 2015-2019, XMOS Ltd, All rights reserved #ifndef __DESCRIPTOR_DEFS_H__ #define __DESCRIPTOR_DEFS_H__ +/* + Include xua.h to pick up the #defines of NUM_USB_CHAN_IN and NUM_USB_CHAN_OUT. + */ +#include "xua.h" + #if (NUM_USB_CHAN_IN > 0) && (NUM_USB_CHAN_OUT > 0) #define AUDIO_INTERFACE_COUNT 3 #elif (NUM_USB_CHAN_IN > 0) || (NUM_USB_CHAN_OUT > 0) @@ -54,10 +59,14 @@ enum USBInterfaceNumber INTERFACE_NUMBER_IAP_EA_NATIVE_TRANS, #endif #endif -#if defined(HID_CONTROLS) && (HID_CONTROLS != 0) +#if( 0 < HID_CONTROLS ) INTERFACE_NUMBER_HID, #endif INTERFACE_COUNT /* End marker */ }; +#if( 0 < HID_CONTROLS ) +#define ENDPOINT_INT_INTERVAL_IN_HID 0x08 +#endif + #endif diff --git a/lib_xua/src/core/endpoint0/xua_endpoint0.c b/lib_xua/src/core/endpoint0/xua_endpoint0.c index a66088f0..3c92defa 100755 --- a/lib_xua/src/core/endpoint0/xua_endpoint0.c +++ b/lib_xua/src/core/endpoint0/xua_endpoint0.c @@ -21,7 +21,7 @@ #include "vendorrequests.h" #include "xc_ptr.h" #include "xua_ep0_uacreqs.h" -#ifdef HID_CONTROLS +#if( 0 < HID_CONTROLS ) #include "hid.h" #endif #if DSD_CHANS_DAC > 0 @@ -60,6 +60,10 @@ extern void device_reboot(void); #endif +#if( 0 < HID_CONTROLS ) +#include "xua_hid.h" +#endif + unsigned int DFU_mode_active = 0; // 0 - App active, 1 - DFU active /* Global volume and mute tables */ @@ -200,13 +204,14 @@ const unsigned g_chanCount_In_HS[INPUT_FORMAT_COUNT] = {HS_STREAM_FORMAT_I #endif }; -/* Endpoint 0 function. Handles all requests to the device */ -void XUA_Endpoint0(chanend c_ep0_out, chanend c_ep0_in, chanend c_audioControl, +XUD_ep ep0_out; +XUD_ep ep0_in; + +void XUA_Endpoint0_init(chanend c_ep0_out, chanend c_ep0_in, chanend c_audioControl, chanend c_mix_ctl, chanend c_clk_ctl, chanend c_EANativeTransport_ctrl, CLIENT_INTERFACE(i_dfu, dfuInterface) VENDOR_REQUESTS_PARAMS_DEC_) { - USB_SetupPacket_t sp; - XUD_ep ep0_out = XUD_InitEp(c_ep0_out); - XUD_ep ep0_in = XUD_InitEp(c_ep0_in); + ep0_out = XUD_InitEp(c_ep0_out); + ep0_in = XUD_InitEp(c_ep0_in); #if 0 /* Dont need to init globals.. */ @@ -295,540 +300,554 @@ void XUA_Endpoint0(chanend c_ep0_out, chanend c_ep0_in, chanend c_audioControl, } #endif +} + +void XUA_Endpoint0_loop(XUD_Result_t result, USB_SetupPacket_t sp, chanend c_ep0_out, chanend c_ep0_in, chanend c_audioControl, + chanend c_mix_ctl, chanend c_clk_ctl, chanend c_EANativeTransport_ctrl, CLIENT_INTERFACE(i_dfu, dfuInterface) VENDOR_REQUESTS_PARAMS_DEC_) +{ + if (result == XUD_RES_OKAY) + { + result = XUD_RES_ERR; + + /* Inspect Request type and Receipient and direction */ + switch( (sp.bmRequestType.Direction << 7) | (sp.bmRequestType.Recipient ) | (sp.bmRequestType.Type << 5) ) + { + case USB_BMREQ_H2D_STANDARD_INT: + + /* Over-riding USB_StandardRequests implementation */ + if(sp.bRequest == USB_SET_INTERFACE) + { + switch (sp.wIndex) + { + /* Check for audio stream from host start/stop */ +#if (NUM_USB_CHAN_OUT > 0) && (AUDIO_CLASS == 2) + case INTERFACE_NUMBER_AUDIO_OUTPUT: + /* Check the alt is in range */ + if(sp.wValue <= OUTPUT_FORMAT_COUNT) + { + /* Alt 0 is stream stop */ + /* Only send change if we need to */ + if((sp.wValue > 0) && (g_curStreamAlt_Out != sp.wValue)) + { + g_curStreamAlt_Out = sp.wValue; + + /* Send format of data onto buffering */ + outuint(c_audioControl, SET_STREAM_FORMAT_OUT); + outuint(c_audioControl, g_dataFormat_Out[sp.wValue-1]); /* Data format (PCM/DSD) */ + + if(g_curUsbSpeed == XUD_SPEED_HS) + { + outuint(c_audioControl, NUM_USB_CHAN_OUT); /* Channel count */ + outuint(c_audioControl, g_subSlot_Out_HS[sp.wValue-1]); /* Subslot */ + outuint(c_audioControl, g_sampRes_Out_HS[sp.wValue-1]); /* Resolution */ + } + else + { + outuint(c_audioControl, NUM_USB_CHAN_OUT_FS); /* Channel count */ + outuint(c_audioControl, g_subSlot_Out_FS[sp.wValue-1]); /* Subslot */ + outuint(c_audioControl, g_sampRes_Out_FS[sp.wValue-1]); /* Resolution */ + } + + /* Handshake */ + chkct(c_audioControl, XS1_CT_END); + } + } + break; +#endif + +#if (NUM_USB_CHAN_IN > 0) && (AUDIO_CLASS == 2) + case INTERFACE_NUMBER_AUDIO_INPUT: + /* Check the alt is in range */ + if(sp.wValue <= INPUT_FORMAT_COUNT) + { + /* Alt 0 is stream stop */ + /* Only send change if we need to */ + if((sp.wValue > 0) && (g_curStreamAlt_In != sp.wValue)) + { + g_curStreamAlt_In = sp.wValue; + + /* Send format of data onto buffering */ + outuint(c_audioControl, SET_STREAM_FORMAT_IN); + outuint(c_audioControl, g_dataFormat_In[sp.wValue-1]); /* Data format (PCM/DSD) */ + + if(g_curUsbSpeed == XUD_SPEED_HS) + { + outuint(c_audioControl, g_chanCount_In_HS[sp.wValue-1]); /* Channel count */ + outuint(c_audioControl, g_subSlot_In_HS[sp.wValue-1]); /* Subslot */ + outuint(c_audioControl, g_sampRes_In_HS[sp.wValue-1]); /* Resolution */ + } + else + { + outuint(c_audioControl, NUM_USB_CHAN_IN_FS); /* Channel count */ + outuint(c_audioControl, g_subSlot_In_FS[sp.wValue-1]); /* Subslot */ + outuint(c_audioControl, g_sampRes_In_FS[sp.wValue-1]); /* Resolution */ + } + + /* Wait for handshake */ + chkct(c_audioControl, XS1_CT_END); + } + } + break; +#endif + +#ifdef IAP_EA_NATIVE_TRANS + case INTERFACE_NUMBER_IAP_EA_NATIVE_TRANS: + /* Check the alt is in range */ + if (sp.wValue <= IAP_EA_NATIVE_TRANS_ALT_COUNT) + { + /* Reset all state of endpoints associated with this interface + * when changing an alternative setting. See USB 2.0 Spec 9.1.1.5 */ + XUD_ResetEpStateByAddr(ENDPOINT_ADDRESS_IN_IAP_EA_NATIVE_TRANS); + XUD_ResetEpStateByAddr(ENDPOINT_ADDRESS_OUT_IAP_EA_NATIVE_TRANS); + + /* Send selected Alt interface number onto EA Native EP manager */ + outuint(c_EANativeTransport_ctrl, (unsigned)sp.wValue); + + /* Wait for handshake */ + chkct(c_EANativeTransport_ctrl, XS1_CT_END); + } + break; +#endif + default: + /* Unhandled interface */ + break; + } + +#if (NUM_USB_CHAN_OUT > 0) && (NUM_USB_CHAN_IN > 0) + unsigned num_input_interfaces = g_interfaceAlt[INTERFACE_NUMBER_AUDIO_INPUT]; + unsigned num_output_interfaces = g_interfaceAlt[INTERFACE_NUMBER_AUDIO_OUTPUT]; + if (sp.wIndex == INTERFACE_NUMBER_AUDIO_INPUT) + { + // in: 0 -> 1 + if (sp.wValue && !num_input_interfaces) + { + UserAudioInputStreamStart(); + if (!num_output_interfaces) + { + UserAudioStreamStart(); + } + } + // in: 1 -> 0 + else if (!sp.wValue && num_input_interfaces) + { + UserAudioInputStreamStop(); + if (!num_output_interfaces) + { + UserAudioStreamStop(); + } + } + } + else if (sp.wIndex == INTERFACE_NUMBER_AUDIO_OUTPUT) + { + // out: 0 -> 1 + if (sp.wValue && !num_output_interfaces) + { + UserAudioOutputStreamStart(); + if (!num_input_interfaces) + { + UserAudioStreamStart(); + } + } + // out: 1 -> 0 + else if (!sp.wValue && num_output_interfaces) + { + UserAudioOutputStreamStop(); + if (!num_input_interfaces) + { + UserAudioStreamStop(); + } + } + } +#elif (NUM_USB_CHAN_OUT > 0) + if(sp.wIndex == INTERFACE_NUMBER_AUDIO_OUTPUT) + { + if(sp.wValue && (!g_interfaceAlt[INTERFACE_NUMBER_AUDIO_OUTPUT])) + { + /* if start and not currently running */ + UserAudioStreamStart(); + UserAudioOutputStreamStart(); + } + else if (!sp.wValue && g_interfaceAlt[INTERFACE_NUMBER_AUDIO_OUTPUT]) + { + /* if stop and currently running */ + UserAudioStreamStop(); + UserAudioOutputStreamStop(); + } + } +#elif (NUM_USB_CHAN_IN > 0) + if(sp.wIndex == INTERFACE_NUMBER_AUDIO_INPUT) + { + if(sp.wValue && (!g_interfaceAlt[INTERFACE_NUMBER_AUDIO_INPUT])) + { + /* if start and not currently running */ + UserAudioStreamStart(); + UserAudioInputStreamStart(); + } + else if (!sp.wValue && g_interfaceAlt[INTERFACE_NUMBER_AUDIO_INPUT]) + { + /* if stop and currently running */ + UserAudioStreamStop(); + UserAudioInputStreamStop(); + } + } +#endif + } /* if(sp.bRequest == SET_INTERFACE) */ + + break; /* BMREQ_H2D_STANDARD_INT */ + + case USB_BMREQ_D2H_STANDARD_INT: + + switch(sp.bRequest) + { +#if( 0 < HID_CONTROLS ) + case USB_GET_DESCRIPTOR: + + /* Check what inteface request is for */ + if(sp.wIndex == INTERFACE_NUMBER_HID) + { + /* High byte of wValue is descriptor type */ + unsigned descriptorType = sp.wValue & 0xff00; + + switch (descriptorType) + { + case HID_HID: + /* Return HID Descriptor */ + result = XUD_DoGetRequest(ep0_out, ep0_in, hidDescriptor, + sizeof(hidDescriptor), sp.wLength); + break; + case HID_REPORT: + /* Return HID report descriptor */ + result = XUD_DoGetRequest(ep0_out, ep0_in, hidReportDescriptor, + sizeof(hidReportDescriptor), sp.wLength); + break; + } + } + break; +#endif + default: + break; + } + break; + + /* Recipient: Device */ + case USB_BMREQ_H2D_STANDARD_DEV: + + /* Inspect for actual request */ + switch( sp.bRequest ) + { + /* Standard request: SetConfiguration */ + /* Overriding implementation in USB_StandardRequests */ + case USB_SET_CONFIGURATION: + + //if(g_current_config == 1) + { + /* Consider host active with valid driver at this point */ + UserHostActive(1); + } + + /* We want to run USB_StandardsRequests() implementation also. Don't modify result + * and don't call XUD_DoSetRequestStatus() */ + break; + + default: + //Unknown device request" + break; + } + break; + + /* Audio Class 1.0 Sampling Freqency Requests go to Endpoint */ + case USB_BMREQ_H2D_CLASS_EP: + case USB_BMREQ_D2H_CLASS_EP: + { + unsigned epNum = sp.wIndex & 0xff; + + if ((epNum == ENDPOINT_ADDRESS_OUT_AUDIO) || (epNum == ENDPOINT_ADDRESS_IN_AUDIO)) + { +#if (AUDIO_CLASS == 2) && (AUDIO_CLASS_FALLBACK) + if(g_curUsbSpeed == XUD_SPEED_FS) + { + result = AudioEndpointRequests_1(ep0_out, ep0_in, &sp, c_audioControl, c_mix_ctl, c_clk_ctl); + } +#elif (AUDIO_CLASS==1) + result = AudioEndpointRequests_1(ep0_out, ep0_in, &sp, c_audioControl, c_mix_ctl, c_clk_ctl); +#endif + } + + } + break; + + case USB_BMREQ_H2D_CLASS_INT: + case USB_BMREQ_D2H_CLASS_INT: + { + unsigned interfaceNum = sp.wIndex & 0xff; + //unsigned request = (sp.bmRequestType.Recipient ) | (sp.bmRequestType.Type << 5); + + /* TODO Check on return value retval = */ +#if (XUA_DFU_EN == 1) + unsigned DFU_IF = INTERFACE_NUMBER_DFU; + + /* DFU interface number changes based on which mode we are currently running in */ + if (DFU_mode_active) + { + DFU_IF = 0; + } + + if (interfaceNum == DFU_IF) + { + int reset = 0; + + /* If running in application mode stop audio */ + /* Don't interupt audio for save and restore cmds */ + if ((DFU_IF == INTERFACE_NUMBER_DFU) && (sp.bRequest != XMOS_DFU_SAVESTATE) && + (sp.bRequest != XMOS_DFU_RESTORESTATE)) + { + // Stop audio + outuint(c_audioControl, SET_SAMPLE_FREQ); + outuint(c_audioControl, AUDIO_STOP_FOR_DFU); + // Handshake + chkct(c_audioControl, XS1_CT_END); + } + + /* This will return 1 if reset requested */ + result = DFUDeviceRequests(ep0_out, &ep0_in, &sp, null, g_interfaceAlt[sp.wIndex], dfuInterface, &reset); + + if(reset) + { + DFUDelay(50000000); + device_reboot(); + } + } +#endif + /* Check for: - Audio CONTROL interface request - always 0, note we check for DFU first + * - Audio STREAMING interface request (In or Out) + * - Audio endpoint request (Audio 1.0 Sampling freq requests are sent to the endpoint) + */ + if(((interfaceNum == 0) || (interfaceNum == 1) || (interfaceNum == 2)) +#if (XUA_DFU_EN == 1) + && !DFU_mode_active +#endif + ) + { +#if (AUDIO_CLASS == 2) && (AUDIO_CLASS_FALLBACK) + if(g_curUsbSpeed == XUD_SPEED_HS) + { + result = AudioClassRequests_2(ep0_out, ep0_in, &sp, c_audioControl, c_mix_ctl, c_clk_ctl); + } + else + { + result = AudioClassRequests_1(ep0_out, ep0_in, &sp, c_audioControl, c_mix_ctl, c_clk_ctl); + } +#elif (AUDIO_CLASS==2) + result = AudioClassRequests_2(ep0_out, ep0_in, &sp, c_audioControl, c_mix_ctl, c_clk_ctl); +#else + result = AudioClassRequests_1(ep0_out, ep0_in, &sp, c_audioControl, c_mix_ctl, c_clk_ctl); +#endif + +#ifdef VENDOR_AUDIO_REQS + /* If result is ERR at this point, then request to audio interface not handled - handle vendor audio reqs */ + if(result == XUD_RES_ERR) + { + result = VendorAudioRequests(ep0_out, ep0_in, sp.bRequest, + sp.wValue >> 8, sp.wValue & 0xff, + sp.wIndex >> 8, sp.bmRequestType.Direction, + c_audioControl, c_mix_ctl, c_clk_ctl); + } +#endif + } + } + break; + + default: + break; + } + + } /* if(result == XUD_RES_OKAY) */ + + { + if(result == XUD_RES_ERR) + { + /* Run vendor defined parsing/processing */ + /* Note, an interface might seem ideal here but this *must* be executed on the same + * core sure to shared memory depandancy */ + result = VendorRequests(ep0_out, ep0_in, &sp VENDOR_REQUESTS_PARAMS_); + } + } + + if(result == XUD_RES_ERR) + { +#if (XUA_DFU_EN == 1) + if (!DFU_mode_active) + { +#endif +#if (AUDIO_CLASS_FALLBACK) && (AUDIO_CLASS != 1) + /* Return Audio 2.0 Descriptors with Audio 1.0 as fallback */ + result = USB_StandardRequests(ep0_out, ep0_in, + (unsigned char*)&devDesc_Audio2, sizeof(devDesc_Audio2), + (unsigned char*)&cfgDesc_Audio2, sizeof(cfgDesc_Audio2), + (unsigned char*)&devDesc_Audio1, sizeof(devDesc_Audio1), + cfgDesc_Audio1, sizeof(cfgDesc_Audio1), + (char**)&g_strTable, sizeof(g_strTable)/sizeof(char *), + &sp, g_curUsbSpeed); +#elif FULL_SPEED_AUDIO_2 + /* Return Audio 2.0 Descriptors for high_speed and full-speed */ + + /* Unfortunately we need to munge the descriptors a bit between full and high-speed */ + if(g_curUsbSpeed == XUD_SPEED_HS) + { + /* Modify Audio Class 2.0 Config descriptor for High-speed operation */ +#if (NUM_USB_CHAN_OUT > 0) + cfgDesc_Audio2.Audio_CS_Control_Int.Audio_Out_InputTerminal.bNrChannels = NUM_USB_CHAN_OUT; +#if (NUM_USB_CHAN_OUT > 0) + cfgDesc_Audio2.Audio_Out_Format.bSubslotSize = HS_STREAM_FORMAT_OUTPUT_1_SUBSLOT_BYTES; + cfgDesc_Audio2.Audio_Out_Format.bBitResolution = HS_STREAM_FORMAT_OUTPUT_1_RESOLUTION_BITS; + cfgDesc_Audio2.Audio_Out_Endpoint.wMaxPacketSize = HS_STREAM_FORMAT_OUTPUT_1_MAXPACKETSIZE; + cfgDesc_Audio2.Audio_Out_ClassStreamInterface.bNrChannels = NUM_USB_CHAN_OUT; +#endif +#if (OUTPUT_FORMAT_COUNT > 1) + cfgDesc_Audio2.Audio_Out_Format_2.bSubslotSize = HS_STREAM_FORMAT_OUTPUT_2_SUBSLOT_BYTES; + cfgDesc_Audio2.Audio_Out_Format_2.bBitResolution = HS_STREAM_FORMAT_OUTPUT_2_RESOLUTION_BITS; + cfgDesc_Audio2.Audio_Out_Endpoint_2.wMaxPacketSize = HS_STREAM_FORMAT_OUTPUT_2_MAXPACKETSIZE; + cfgDesc_Audio2.Audio_Out_ClassStreamInterface_2.bNrChannels = NUM_USB_CHAN_OUT; +#endif + +#if (OUTPUT_FORMAT_COUNT > 2) + cfgDesc_Audio2.Audio_Out_Format_3.bSubslotSize = HS_STREAM_FORMAT_OUTPUT_3_SUBSLOT_BYTES; + cfgDesc_Audio2.Audio_Out_Format_3.bBitResolution = HS_STREAM_FORMAT_OUTPUT_3_RESOLUTION_BITS; + cfgDesc_Audio2.Audio_Out_Endpoint_3.wMaxPacketSize = HS_STREAM_FORMAT_OUTPUT_3_MAXPACKETSIZE; + cfgDesc_Audio2.Audio_Out_ClassStreamInterface_3.bNrChannels = NUM_USB_CHAN_OUT; +#endif +#endif +#if (NUM_USB_CHAN_IN > 0) + cfgDesc_Audio2.Audio_CS_Control_Int.Audio_In_InputTerminal.bNrChannels = NUM_USB_CHAN_IN; + cfgDesc_Audio2.Audio_In_Format.bSubslotSize = HS_STREAM_FORMAT_INPUT_1_SUBSLOT_BYTES; + cfgDesc_Audio2.Audio_In_Format.bBitResolution = HS_STREAM_FORMAT_INPUT_1_RESOLUTION_BITS; + cfgDesc_Audio2.Audio_In_Endpoint.wMaxPacketSize = HS_STREAM_FORMAT_INPUT_1_MAXPACKETSIZE; + cfgDesc_Audio2.Audio_In_ClassStreamInterface.bNrChannels = NUM_USB_CHAN_IN; +#endif + } + else + { + /* Modify Audio Class 2.0 Config descriptor for Full-speed operation */ +#if (NUM_USB_CHAN_OUT > 0) + cfgDesc_Audio2.Audio_CS_Control_Int.Audio_Out_InputTerminal.bNrChannels = NUM_USB_CHAN_OUT_FS; +#if (NUM_USB_CHAN_OUT > 0) + cfgDesc_Audio2.Audio_Out_Format.bSubslotSize = FS_STREAM_FORMAT_OUTPUT_1_SUBSLOT_BYTES; + cfgDesc_Audio2.Audio_Out_Format.bBitResolution = FS_STREAM_FORMAT_OUTPUT_1_RESOLUTION_BITS; + cfgDesc_Audio2.Audio_Out_Endpoint.wMaxPacketSize = FS_STREAM_FORMAT_OUTPUT_1_MAXPACKETSIZE; + cfgDesc_Audio2.Audio_Out_ClassStreamInterface.bNrChannels = NUM_USB_CHAN_OUT_FS; +#endif +#if (OUTPUT_FORMAT_COUNT > 1) + cfgDesc_Audio2.Audio_Out_Format_2.bSubslotSize = FS_STREAM_FORMAT_OUTPUT_2_SUBSLOT_BYTES; + cfgDesc_Audio2.Audio_Out_Format_2.bBitResolution = FS_STREAM_FORMAT_OUTPUT_2_RESOLUTION_BITS; + cfgDesc_Audio2.Audio_Out_Endpoint_2.wMaxPacketSize = FS_STREAM_FORMAT_OUTPUT_2_MAXPACKETSIZE; + cfgDesc_Audio2.Audio_Out_ClassStreamInterface_2.bNrChannels = NUM_USB_CHAN_OUT_FS; +#endif + +#if (OUTPUT_FORMAT_COUNT > 2) + cfgDesc_Audio2.Audio_Out_Format_3.bSubslotSize = FS_STREAM_FORMAT_OUTPUT_3_SUBSLOT_BYTES; + cfgDesc_Audio2.Audio_Out_Format_3.bBitResolution = FS_STREAM_FORMAT_OUTPUT_3_RESOLUTION_BITS; + cfgDesc_Audio2.Audio_Out_Endpoint_3.wMaxPacketSize = FS_STREAM_FORMAT_OUTPUT_3_MAXPACKETSIZE; + cfgDesc_Audio2.Audio_Out_ClassStreamInterface_3.bNrChannels = NUM_USB_CHAN_OUT_FS; +#endif +#endif +#if (NUM_USB_CHAN_IN > 0) + cfgDesc_Audio2.Audio_CS_Control_Int.Audio_In_InputTerminal.bNrChannels = NUM_USB_CHAN_IN_FS; + cfgDesc_Audio2.Audio_In_Format.bSubslotSize = FS_STREAM_FORMAT_INPUT_1_SUBSLOT_BYTES; + cfgDesc_Audio2.Audio_In_Format.bBitResolution = FS_STREAM_FORMAT_INPUT_1_RESOLUTION_BITS; + cfgDesc_Audio2.Audio_In_Endpoint.wMaxPacketSize = FS_STREAM_FORMAT_INPUT_1_MAXPACKETSIZE; + cfgDesc_Audio2.Audio_In_ClassStreamInterface.bNrChannels = NUM_USB_CHAN_IN_FS; +#endif + } + + result = USB_StandardRequests(ep0_out, ep0_in, + (unsigned char*)&devDesc_Audio2, sizeof(devDesc_Audio2), + (unsigned char*)&cfgDesc_Audio2, sizeof(cfgDesc_Audio2), + null, 0, + null, 0, +#ifdef __XC__ + g_strTable, sizeof(g_strTable), sp, null, g_curUsbSpeed); +#else + (char**)&g_strTable, sizeof(g_strTable)/sizeof(char *), &sp, g_curUsbSpeed); +#endif +#elif (AUDIO_CLASS == 1) + /* Return Audio 1.0 Descriptors in FS, should never be in HS! */ + result = USB_StandardRequests(ep0_out, ep0_in, + null, 0, + null, 0, + (unsigned char*)&devDesc_Audio1, sizeof(devDesc_Audio1), + cfgDesc_Audio1, sizeof(cfgDesc_Audio1), + (char**)&g_strTable, sizeof(g_strTable)/sizeof(char *), &sp, g_curUsbSpeed); +#else + /* Return Audio 2.0 Descriptors with Null device as fallback */ + result = USB_StandardRequests(ep0_out, ep0_in, + (unsigned char*)&devDesc_Audio2, sizeof(devDesc_Audio2), + (unsigned char*)&cfgDesc_Audio2, sizeof(cfgDesc_Audio2), + devDesc_Null, sizeof(devDesc_Null), + cfgDesc_Null, sizeof(cfgDesc_Null), + (char**)&g_strTable, sizeof(g_strTable)/sizeof(char *), &sp, g_curUsbSpeed); +#endif +#if (XUA_DFU_EN == 1) + } + + else + { + /* Running in DFU mode - always return same descs for DFU whether HS or FS */ + result = USB_StandardRequests(ep0_out, ep0_in, + DFUdevDesc, sizeof(DFUdevDesc), + DFUcfgDesc, sizeof(DFUcfgDesc), + null, 0, /* Used same descriptors for full and high-speed */ + null, 0, + (char**)&g_strTable, sizeof(g_strTable)/sizeof(char *), &sp, g_curUsbSpeed); + } +#endif + } + + if (result == XUD_RES_RST) + { +#ifdef __XC__ + g_curUsbSpeed = XUD_ResetEndpoint(ep0_out, ep0_in); +#else + g_curUsbSpeed = XUD_ResetEndpoint(ep0_out, &ep0_in); +#endif + g_currentConfig = 0; + g_curStreamAlt_Out = 0; + g_curStreamAlt_In = 0; + +#if (XUA_DFU_EN == 1) + if (DFUReportResetState(null)) + { + if (!DFU_mode_active) + { + DFU_mode_active = 1; + } + } + else + { + if (DFU_mode_active) + { + DFU_mode_active = 0; + + /* Send reboot command */ + DFUDelay(5000000); + device_reboot(); + } + } +#endif + } +} + +/* Endpoint 0 function. Handles all requests to the device */ +void XUA_Endpoint0(chanend c_ep0_out, chanend c_ep0_in, chanend c_audioControl, + chanend c_mix_ctl, chanend c_clk_ctl, chanend c_EANativeTransport_ctrl, CLIENT_INTERFACE(i_dfu, dfuInterface) VENDOR_REQUESTS_PARAMS_DEC_) +{ + USB_SetupPacket_t sp; + XUA_Endpoint0_init(c_ep0_out, c_ep0_in, c_audioControl, c_mix_ctl, c_clk_ctl, c_EANativeTransport_ctrl, dfuInterface VENDOR_REQUESTS_PARAMS_); + while(1) { /* Returns XUD_RES_OKAY for success, XUD_RES_RST for bus reset */ XUD_Result_t result = USB_GetSetupPacket(ep0_out, ep0_in, &sp); - - if (result == XUD_RES_OKAY) - { - result = XUD_RES_ERR; - - /* Inspect Request type and Receipient and direction */ - switch( (sp.bmRequestType.Direction << 7) | (sp.bmRequestType.Recipient ) | (sp.bmRequestType.Type << 5) ) - { - case USB_BMREQ_H2D_STANDARD_INT: - - /* Over-riding USB_StandardRequests implementation */ - if(sp.bRequest == USB_SET_INTERFACE) - { - switch (sp.wIndex) - { - /* Check for audio stream from host start/stop */ -#if (NUM_USB_CHAN_OUT > 0) && (AUDIO_CLASS == 2) - case INTERFACE_NUMBER_AUDIO_OUTPUT: - /* Check the alt is in range */ - if(sp.wValue <= OUTPUT_FORMAT_COUNT) - { - /* Alt 0 is stream stop */ - /* Only send change if we need to */ - if((sp.wValue > 0) && (g_curStreamAlt_Out != sp.wValue)) - { - g_curStreamAlt_Out = sp.wValue; - - /* Send format of data onto buffering */ - outuint(c_audioControl, SET_STREAM_FORMAT_OUT); - outuint(c_audioControl, g_dataFormat_Out[sp.wValue-1]); /* Data format (PCM/DSD) */ - - if(g_curUsbSpeed == XUD_SPEED_HS) - { - outuint(c_audioControl, NUM_USB_CHAN_OUT); /* Channel count */ - outuint(c_audioControl, g_subSlot_Out_HS[sp.wValue-1]); /* Subslot */ - outuint(c_audioControl, g_sampRes_Out_HS[sp.wValue-1]); /* Resolution */ - } - else - { - outuint(c_audioControl, NUM_USB_CHAN_OUT_FS); /* Channel count */ - outuint(c_audioControl, g_subSlot_Out_FS[sp.wValue-1]); /* Subslot */ - outuint(c_audioControl, g_sampRes_Out_FS[sp.wValue-1]); /* Resolution */ - } - - /* Handshake */ - chkct(c_audioControl, XS1_CT_END); - } - } - break; -#endif - -#if (NUM_USB_CHAN_IN > 0) && (AUDIO_CLASS == 2) - case INTERFACE_NUMBER_AUDIO_INPUT: - /* Check the alt is in range */ - if(sp.wValue <= INPUT_FORMAT_COUNT) - { - /* Alt 0 is stream stop */ - /* Only send change if we need to */ - if((sp.wValue > 0) && (g_curStreamAlt_In != sp.wValue)) - { - g_curStreamAlt_In = sp.wValue; - - /* Send format of data onto buffering */ - outuint(c_audioControl, SET_STREAM_FORMAT_IN); - outuint(c_audioControl, g_dataFormat_In[sp.wValue-1]); /* Data format (PCM/DSD) */ - - if(g_curUsbSpeed == XUD_SPEED_HS) - { - outuint(c_audioControl, g_chanCount_In_HS[sp.wValue-1]); /* Channel count */ - outuint(c_audioControl, g_subSlot_In_HS[sp.wValue-1]); /* Subslot */ - outuint(c_audioControl, g_sampRes_In_HS[sp.wValue-1]); /* Resolution */ - } - else - { - outuint(c_audioControl, NUM_USB_CHAN_IN_FS); /* Channel count */ - outuint(c_audioControl, g_subSlot_In_FS[sp.wValue-1]); /* Subslot */ - outuint(c_audioControl, g_sampRes_In_FS[sp.wValue-1]); /* Resolution */ - } - - /* Wait for handshake */ - chkct(c_audioControl, XS1_CT_END); - } - } - break; -#endif - -#ifdef IAP_EA_NATIVE_TRANS - case INTERFACE_NUMBER_IAP_EA_NATIVE_TRANS: - /* Check the alt is in range */ - if (sp.wValue <= IAP_EA_NATIVE_TRANS_ALT_COUNT) - { - /* Reset all state of endpoints associated with this interface - * when changing an alternative setting. See USB 2.0 Spec 9.1.1.5 */ - XUD_ResetEpStateByAddr(ENDPOINT_ADDRESS_IN_IAP_EA_NATIVE_TRANS); - XUD_ResetEpStateByAddr(ENDPOINT_ADDRESS_OUT_IAP_EA_NATIVE_TRANS); - - /* Send selected Alt interface number onto EA Native EP manager */ - outuint(c_EANativeTransport_ctrl, (unsigned)sp.wValue); - - /* Wait for handshake */ - chkct(c_EANativeTransport_ctrl, XS1_CT_END); - } - break; -#endif - default: - /* Unhandled interface */ - break; - } - -#if (NUM_USB_CHAN_OUT > 0) && (NUM_USB_CHAN_IN > 0) - unsigned num_input_interfaces = g_interfaceAlt[INTERFACE_NUMBER_AUDIO_INPUT]; - unsigned num_output_interfaces = g_interfaceAlt[INTERFACE_NUMBER_AUDIO_OUTPUT]; - if (sp.wIndex == INTERFACE_NUMBER_AUDIO_INPUT) - { - // in: 0 -> 1 - if (sp.wValue && !num_input_interfaces) - { - UserAudioInputStreamStart(); - if (!num_output_interfaces) - { - UserAudioStreamStart(); - } - } - // in: 1 -> 0 - else if (!sp.wValue && num_input_interfaces) - { - UserAudioInputStreamStop(); - if (!num_output_interfaces) - { - UserAudioStreamStop(); - } - } - } - else if (sp.wIndex == INTERFACE_NUMBER_AUDIO_OUTPUT) - { - // out: 0 -> 1 - if (sp.wValue && !num_output_interfaces) - { - UserAudioOutputStreamStart(); - if (!num_input_interfaces) - { - UserAudioStreamStart(); - } - } - // out: 1 -> 0 - else if (!sp.wValue && num_output_interfaces) - { - UserAudioOutputStreamStop(); - if (!num_input_interfaces) - { - UserAudioStreamStop(); - } - } - } -#elif (NUM_USB_CHAN_OUT > 0) - if(sp.wIndex == INTERFACE_NUMBER_AUDIO_OUTPUT) - { - if(sp.wValue && (!g_interfaceAlt[INTERFACE_NUMBER_AUDIO_OUTPUT])) - { - /* if start and not currently running */ - UserAudioStreamStart(); - UserAudioOutputStreamStart(); - } - else if (!sp.wValue && g_interfaceAlt[INTERFACE_NUMBER_AUDIO_OUTPUT]) - { - /* if stop and currently running */ - UserAudioStreamStop(); - UserAudioOutputStreamStop(); - } - } -#elif (NUM_USB_CHAN_IN > 0) - if(sp.wIndex == INTERFACE_NUMBER_AUDIO_INPUT) - { - if(sp.wValue && (!g_interfaceAlt[INTERFACE_NUMBER_AUDIO_INPUT])) - { - /* if start and not currently running */ - UserAudioStreamStart(); - UserAudioInputStreamStart(); - } - else if (!sp.wValue && g_interfaceAlt[INTERFACE_NUMBER_AUDIO_INPUT]) - { - /* if stop and currently running */ - UserAudioStreamStop(); - UserAudioInputStreamStop(); - } - } -#endif - } /* if(sp.bRequest == SET_INTERFACE) */ - - break; /* BMREQ_H2D_STANDARD_INT */ - - case USB_BMREQ_D2H_STANDARD_INT: - - switch(sp.bRequest) - { -#ifdef HID_CONTROLS - case USB_GET_DESCRIPTOR: - - /* Check what inteface request is for */ - if(sp.wIndex == INTERFACE_NUMBER_HID) - { - /* High byte of wValue is descriptor type */ - unsigned descriptorType = sp.wValue & 0xff00; - - switch (descriptorType) - { - case HID_HID: - /* Return HID Descriptor */ - result = XUD_DoGetRequest(ep0_out, ep0_in, hidDescriptor, - sizeof(hidDescriptor), sp.wLength); - break; - case HID_REPORT: - /* Return HID report descriptor */ - result = XUD_DoGetRequest(ep0_out, ep0_in, hidReportDescriptor, - sizeof(hidReportDescriptor), sp.wLength); - break; - } - } - break; -#endif - default: - break; - } - break; - - /* Recipient: Device */ - case USB_BMREQ_H2D_STANDARD_DEV: - - /* Inspect for actual request */ - switch( sp.bRequest ) - { - /* Standard request: SetConfiguration */ - /* Overriding implementation in USB_StandardRequests */ - case USB_SET_CONFIGURATION: - - //if(g_current_config == 1) - { - /* Consider host active with valid driver at this point */ - UserHostActive(1); - } - - /* We want to run USB_StandardsRequests() implementation also. Don't modify result - * and don't call XUD_DoSetRequestStatus() */ - break; - - default: - //Unknown device request" - break; - } - break; - - /* Audio Class 1.0 Sampling Freqency Requests go to Endpoint */ - case USB_BMREQ_H2D_CLASS_EP: - case USB_BMREQ_D2H_CLASS_EP: - { - unsigned epNum = sp.wIndex & 0xff; - - if ((epNum == ENDPOINT_ADDRESS_OUT_AUDIO) || (epNum == ENDPOINT_ADDRESS_IN_AUDIO)) - { -#if (AUDIO_CLASS == 2) && (AUDIO_CLASS_FALLBACK) - if(g_curUsbSpeed == XUD_SPEED_FS) - { - result = AudioEndpointRequests_1(ep0_out, ep0_in, &sp, c_audioControl, c_mix_ctl, c_clk_ctl); - } -#elif (AUDIO_CLASS==1) - result = AudioEndpointRequests_1(ep0_out, ep0_in, &sp, c_audioControl, c_mix_ctl, c_clk_ctl); -#endif - } - - } - break; - - case USB_BMREQ_H2D_CLASS_INT: - case USB_BMREQ_D2H_CLASS_INT: - { - unsigned interfaceNum = sp.wIndex & 0xff; - //unsigned request = (sp.bmRequestType.Recipient ) | (sp.bmRequestType.Type << 5); - - /* TODO Check on return value retval = */ -#if (XUA_DFU_EN == 1) - unsigned DFU_IF = INTERFACE_NUMBER_DFU; - - /* DFU interface number changes based on which mode we are currently running in */ - if (DFU_mode_active) - { - DFU_IF = 0; - } - - if (interfaceNum == DFU_IF) - { - int reset = 0; - - /* If running in application mode stop audio */ - /* Don't interupt audio for save and restore cmds */ - if ((DFU_IF == INTERFACE_NUMBER_DFU) && (sp.bRequest != XMOS_DFU_SAVESTATE) && - (sp.bRequest != XMOS_DFU_RESTORESTATE)) - { - // Stop audio - outuint(c_audioControl, SET_SAMPLE_FREQ); - outuint(c_audioControl, AUDIO_STOP_FOR_DFU); - // Handshake - chkct(c_audioControl, XS1_CT_END); - } - - /* This will return 1 if reset requested */ - result = DFUDeviceRequests(ep0_out, &ep0_in, &sp, null, g_interfaceAlt[sp.wIndex], dfuInterface, &reset); - - if(reset) - { - DFUDelay(50000000); - device_reboot(); - } - } -#endif - /* Check for: - Audio CONTROL interface request - always 0, note we check for DFU first - * - Audio STREAMING interface request (In or Out) - * - Audio endpoint request (Audio 1.0 Sampling freq requests are sent to the endpoint) - */ - if(((interfaceNum == 0) || (interfaceNum == 1) || (interfaceNum == 2)) -#if (XUA_DFU_EN == 1) - && !DFU_mode_active -#endif - ) - { -#if (AUDIO_CLASS == 2) && (AUDIO_CLASS_FALLBACK) - if(g_curUsbSpeed == XUD_SPEED_HS) - { - result = AudioClassRequests_2(ep0_out, ep0_in, &sp, c_audioControl, c_mix_ctl, c_clk_ctl); - } - else - { - result = AudioClassRequests_1(ep0_out, ep0_in, &sp, c_audioControl, c_mix_ctl, c_clk_ctl); - } -#elif (AUDIO_CLASS==2) - result = AudioClassRequests_2(ep0_out, ep0_in, &sp, c_audioControl, c_mix_ctl, c_clk_ctl); -#else - result = AudioClassRequests_1(ep0_out, ep0_in, &sp, c_audioControl, c_mix_ctl, c_clk_ctl); -#endif - -#ifdef VENDOR_AUDIO_REQS - /* If result is ERR at this point, then request to audio interface not handled - handle vendor audio reqs */ - if(result == XUD_RES_ERR) - { - result = VendorAudioRequests(ep0_out, ep0_in, sp.bRequest, - sp.wValue >> 8, sp.wValue & 0xff, - sp.wIndex >> 8, sp.bmRequestType.Direction, - c_audioControl, c_mix_ctl, c_clk_ctl); - } -#endif - } - } - break; - - default: - break; - } - - } /* if(result == XUD_RES_OKAY) */ - - { - if(result == XUD_RES_ERR) - { - /* Run vendor defined parsing/processing */ - /* Note, an interface might seem ideal here but this *must* be executed on the same - * core sure to shared memory depandancy */ - result = VendorRequests(ep0_out, ep0_in, &sp VENDOR_REQUESTS_PARAMS_); - } - } - - if(result == XUD_RES_ERR) - { -#if (XUA_DFU_EN == 1) - if (!DFU_mode_active) - { -#endif -#if (AUDIO_CLASS_FALLBACK) && (AUDIO_CLASS != 1) - /* Return Audio 2.0 Descriptors with Audio 1.0 as fallback */ - result = USB_StandardRequests(ep0_out, ep0_in, - (unsigned char*)&devDesc_Audio2, sizeof(devDesc_Audio2), - (unsigned char*)&cfgDesc_Audio2, sizeof(cfgDesc_Audio2), - (unsigned char*)&devDesc_Audio1, sizeof(devDesc_Audio1), - cfgDesc_Audio1, sizeof(cfgDesc_Audio1), - (char**)&g_strTable, sizeof(g_strTable)/sizeof(char *), - &sp, g_curUsbSpeed); -#elif FULL_SPEED_AUDIO_2 - /* Return Audio 2.0 Descriptors for high_speed and full-speed */ - - /* Unfortunately we need to munge the descriptors a bit between full and high-speed */ - if(g_curUsbSpeed == XUD_SPEED_HS) - { - /* Modify Audio Class 2.0 Config descriptor for High-speed operation */ -#if (NUM_USB_CHAN_OUT > 0) - cfgDesc_Audio2.Audio_CS_Control_Int.Audio_Out_InputTerminal.bNrChannels = NUM_USB_CHAN_OUT; -#if (NUM_USB_CHAN_OUT > 0) - cfgDesc_Audio2.Audio_Out_Format.bSubslotSize = HS_STREAM_FORMAT_OUTPUT_1_SUBSLOT_BYTES; - cfgDesc_Audio2.Audio_Out_Format.bBitResolution = HS_STREAM_FORMAT_OUTPUT_1_RESOLUTION_BITS; - cfgDesc_Audio2.Audio_Out_Endpoint.wMaxPacketSize = HS_STREAM_FORMAT_OUTPUT_1_MAXPACKETSIZE; - cfgDesc_Audio2.Audio_Out_ClassStreamInterface.bNrChannels = NUM_USB_CHAN_OUT; -#endif -#if (OUTPUT_FORMAT_COUNT > 1) - cfgDesc_Audio2.Audio_Out_Format_2.bSubslotSize = HS_STREAM_FORMAT_OUTPUT_2_SUBSLOT_BYTES; - cfgDesc_Audio2.Audio_Out_Format_2.bBitResolution = HS_STREAM_FORMAT_OUTPUT_2_RESOLUTION_BITS; - cfgDesc_Audio2.Audio_Out_Endpoint_2.wMaxPacketSize = HS_STREAM_FORMAT_OUTPUT_2_MAXPACKETSIZE; - cfgDesc_Audio2.Audio_Out_ClassStreamInterface_2.bNrChannels = NUM_USB_CHAN_OUT; -#endif - -#if (OUTPUT_FORMAT_COUNT > 2) - cfgDesc_Audio2.Audio_Out_Format_3.bSubslotSize = HS_STREAM_FORMAT_OUTPUT_3_SUBSLOT_BYTES; - cfgDesc_Audio2.Audio_Out_Format_3.bBitResolution = HS_STREAM_FORMAT_OUTPUT_3_RESOLUTION_BITS; - cfgDesc_Audio2.Audio_Out_Endpoint_3.wMaxPacketSize = HS_STREAM_FORMAT_OUTPUT_3_MAXPACKETSIZE; - cfgDesc_Audio2.Audio_Out_ClassStreamInterface_3.bNrChannels = NUM_USB_CHAN_OUT; -#endif -#endif -#if (NUM_USB_CHAN_IN > 0) - cfgDesc_Audio2.Audio_CS_Control_Int.Audio_In_InputTerminal.bNrChannels = NUM_USB_CHAN_IN; - cfgDesc_Audio2.Audio_In_Format.bSubslotSize = HS_STREAM_FORMAT_INPUT_1_SUBSLOT_BYTES; - cfgDesc_Audio2.Audio_In_Format.bBitResolution = HS_STREAM_FORMAT_INPUT_1_RESOLUTION_BITS; - cfgDesc_Audio2.Audio_In_Endpoint.wMaxPacketSize = HS_STREAM_FORMAT_INPUT_1_MAXPACKETSIZE; - cfgDesc_Audio2.Audio_In_ClassStreamInterface.bNrChannels = NUM_USB_CHAN_IN; -#endif - } - else - { - /* Modify Audio Class 2.0 Config descriptor for Full-speed operation */ -#if (NUM_USB_CHAN_OUT > 0) - cfgDesc_Audio2.Audio_CS_Control_Int.Audio_Out_InputTerminal.bNrChannels = NUM_USB_CHAN_OUT_FS; -#if (NUM_USB_CHAN_OUT > 0) - cfgDesc_Audio2.Audio_Out_Format.bSubslotSize = FS_STREAM_FORMAT_OUTPUT_1_SUBSLOT_BYTES; - cfgDesc_Audio2.Audio_Out_Format.bBitResolution = FS_STREAM_FORMAT_OUTPUT_1_RESOLUTION_BITS; - cfgDesc_Audio2.Audio_Out_Endpoint.wMaxPacketSize = FS_STREAM_FORMAT_OUTPUT_1_MAXPACKETSIZE; - cfgDesc_Audio2.Audio_Out_ClassStreamInterface.bNrChannels = NUM_USB_CHAN_OUT_FS; -#endif -#if (OUTPUT_FORMAT_COUNT > 1) - cfgDesc_Audio2.Audio_Out_Format_2.bSubslotSize = FS_STREAM_FORMAT_OUTPUT_2_SUBSLOT_BYTES; - cfgDesc_Audio2.Audio_Out_Format_2.bBitResolution = FS_STREAM_FORMAT_OUTPUT_2_RESOLUTION_BITS; - cfgDesc_Audio2.Audio_Out_Endpoint_2.wMaxPacketSize = FS_STREAM_FORMAT_OUTPUT_2_MAXPACKETSIZE; - cfgDesc_Audio2.Audio_Out_ClassStreamInterface_2.bNrChannels = NUM_USB_CHAN_OUT_FS; -#endif - -#if (OUTPUT_FORMAT_COUNT > 2) - cfgDesc_Audio2.Audio_Out_Format_3.bSubslotSize = FS_STREAM_FORMAT_OUTPUT_3_SUBSLOT_BYTES; - cfgDesc_Audio2.Audio_Out_Format_3.bBitResolution = FS_STREAM_FORMAT_OUTPUT_3_RESOLUTION_BITS; - cfgDesc_Audio2.Audio_Out_Endpoint_3.wMaxPacketSize = FS_STREAM_FORMAT_OUTPUT_3_MAXPACKETSIZE; - cfgDesc_Audio2.Audio_Out_ClassStreamInterface_3.bNrChannels = NUM_USB_CHAN_OUT_FS; -#endif -#endif -#if (NUM_USB_CHAN_IN > 0) - cfgDesc_Audio2.Audio_CS_Control_Int.Audio_In_InputTerminal.bNrChannels = NUM_USB_CHAN_IN_FS; - cfgDesc_Audio2.Audio_In_Format.bSubslotSize = FS_STREAM_FORMAT_INPUT_1_SUBSLOT_BYTES; - cfgDesc_Audio2.Audio_In_Format.bBitResolution = FS_STREAM_FORMAT_INPUT_1_RESOLUTION_BITS; - cfgDesc_Audio2.Audio_In_Endpoint.wMaxPacketSize = FS_STREAM_FORMAT_INPUT_1_MAXPACKETSIZE; - cfgDesc_Audio2.Audio_In_ClassStreamInterface.bNrChannels = NUM_USB_CHAN_IN_FS; -#endif - } - - result = USB_StandardRequests(ep0_out, ep0_in, - (unsigned char*)&devDesc_Audio2, sizeof(devDesc_Audio2), - (unsigned char*)&cfgDesc_Audio2, sizeof(cfgDesc_Audio2), - null, 0, - null, 0, -#ifdef __XC__ - g_strTable, sizeof(g_strTable), sp, null, g_curUsbSpeed); -#else - (char**)&g_strTable, sizeof(g_strTable)/sizeof(char *), &sp, g_curUsbSpeed); -#endif -#elif (AUDIO_CLASS == 1) - /* Return Audio 1.0 Descriptors in FS, should never be in HS! */ - result = USB_StandardRequests(ep0_out, ep0_in, - null, 0, - null, 0, - (unsigned char*)&devDesc_Audio1, sizeof(devDesc_Audio1), - cfgDesc_Audio1, sizeof(cfgDesc_Audio1), - (char**)&g_strTable, sizeof(g_strTable)/sizeof(char *), &sp, g_curUsbSpeed); -#else - /* Return Audio 2.0 Descriptors with Null device as fallback */ - result = USB_StandardRequests(ep0_out, ep0_in, - (unsigned char*)&devDesc_Audio2, sizeof(devDesc_Audio2), - (unsigned char*)&cfgDesc_Audio2, sizeof(cfgDesc_Audio2), - devDesc_Null, sizeof(devDesc_Null), - cfgDesc_Null, sizeof(cfgDesc_Null), - (char**)&g_strTable, sizeof(g_strTable)/sizeof(char *), &sp, g_curUsbSpeed); -#endif -#if (XUA_DFU_EN == 1) - } - - else - { - /* Running in DFU mode - always return same descs for DFU whether HS or FS */ - result = USB_StandardRequests(ep0_out, ep0_in, - DFUdevDesc, sizeof(DFUdevDesc), - DFUcfgDesc, sizeof(DFUcfgDesc), - null, 0, /* Used same descriptors for full and high-speed */ - null, 0, - (char**)&g_strTable, sizeof(g_strTable)/sizeof(char *), &sp, g_curUsbSpeed); - } -#endif - } - - if (result == XUD_RES_RST) - { -#ifdef __XC__ - g_curUsbSpeed = XUD_ResetEndpoint(ep0_out, ep0_in); -#else - g_curUsbSpeed = XUD_ResetEndpoint(ep0_out, &ep0_in); -#endif - g_currentConfig = 0; - g_curStreamAlt_Out = 0; - g_curStreamAlt_In = 0; - -#if (XUA_DFU_EN == 1) - if (DFUReportResetState(null)) - { - if (!DFU_mode_active) - { - DFU_mode_active = 1; - } - } - else - { - if (DFU_mode_active) - { - DFU_mode_active = 0; - - /* Send reboot command */ - DFUDelay(5000000); - device_reboot(); - } - } -#endif - } + XUA_Endpoint0_loop(result, sp, c_ep0_out, c_ep0_in, c_audioControl, c_mix_ctl, c_clk_ctl, c_EANativeTransport_ctrl, dfuInterface VENDOR_REQUESTS_PARAMS_); } } #endif /* XUA_USB_EN*/ diff --git a/lib_xua/src/core/endpoint0/xua_ep0_descriptors.h b/lib_xua/src/core/endpoint0/xua_ep0_descriptors.h index d9d0c832..208114b5 100644 --- a/lib_xua/src/core/endpoint0/xua_ep0_descriptors.h +++ b/lib_xua/src/core/endpoint0/xua_ep0_descriptors.h @@ -561,27 +561,24 @@ unsigned char devQualDesc_Null[] = #define MIXER_LENGTH (0) #endif - -#ifdef HID_CONTROLS -unsigned char hidReportDescriptor[] = +#if( 0 < HID_CONTROLS ) +unsigned char hidReportDescriptor[] = /* Voice Command usage as per request #HUTRR45 */ { - 0x05, 0x0c, /* Usage Page (Consumer Device) */ - 0x09, 0x01, /* Usage (Consumer Control) */ - 0xa1, 0x01, /* Collection (Application) */ - 0x15, 0x00, /* Logical Minimum (0) */ - 0x25, 0x01, /* Logical Maximum (1) */ - 0x09, 0xb0, /* Usage (Play) */ - 0x09, 0xb5, /* Usage (Scan Next Track) */ - 0x09, 0xb6, /* Usage (Scan Previous Track) */ - 0x09, 0xe9, /* Usage (Volume Up) */ - 0x09, 0xea, /* Usage (Volume Down) */ - 0x09, 0xe2, /* Usage (Mute) */ - 0x75, 0x01, /* Report Size (1) */ - 0x95, 0x06, /* Report Count (6) */ - 0x81, 0x02, /* Input (Data, Var, Abs) */ - 0x95, 0x02, /* Report Count (2) */ - 0x81, 0x01, /* Input (Cnst, Ary, Abs) */ - 0xc0 /* End collection */ + 0x15, 0x01, /* Logical Minimum (1) */ + 0x25, 0x01, /* Logical Maximum (1) */ + 0x75, 0x01, /* Report Size (1) */ + 0x05, 0x0c, /* Usage Page (Consumer Device) */ + 0x09, 0x01, /* Usage (Consumer Control) */ + 0xa1, 0x01, /* Collection (Application) */ + 0x0a, 0x00, 0x02, /* Usage (Generic GUI Application Controls) */ + 0xa1, 0x02, /* Collection (Logical) */ + 0x0a, 0x21, 0x02, /* Usage (AC Search) */ + 0x95, 0x01, /* Report Count (1) */ + 0x81, 0x40, /* Input (Data, Ary, Abs, Nul) */ + 0x95, 0x07, /* Report Count (7) */ + 0x81, 0x01, /* Input (Cnst, Ary, Abs) */ + 0xc0, /* End collection (Logical) */ + 0xc0 /* End collection (Application) */ }; #endif @@ -784,7 +781,7 @@ typedef struct #endif #endif -#ifdef HID_CONTROLS +#if( 0 < HID_CONTROLS ) USB_Descriptor_Interface_t HID_Interface; unsigned char hidDesc[9]; //TODO ideally we would have a struct for this. USB_Descriptor_Endpoint_t HID_In_Endpoint; @@ -1099,7 +1096,7 @@ USB_Config_Descriptor_Audio2_t cfgDesc_Audio2= }, 0, /* 60 iFeature */ }, -#endif +#endif /* (OUTPUT_VOLUME_CONTROL == 1) */ /* Output Terminal Descriptor (Audio) */ .Audio_Out_OutputTerminal = @@ -1119,7 +1116,7 @@ USB_Config_Descriptor_Audio2_t cfgDesc_Audio2= 0x0000, /* 9 bmControls */ 0, /* 11 iTerminal */ }, -#endif +#endif /* (NUM_USB_CHAN_OUT > 0) */ @@ -1274,7 +1271,7 @@ USB_Config_Descriptor_Audio2_t cfgDesc_Audio2= }, 0, /* 60 iFeature */ }, -#endif +#endif /* (INPUT_VOLUME_CONTROL == 1) */ .Audio_In_OutputTerminal = { @@ -1295,7 +1292,7 @@ USB_Config_Descriptor_Audio2_t cfgDesc_Audio2= .bmControls = 0x0000, .iTerminal = offsetof(StringDescTable_t, usbOutputTermStr_Audio2)/sizeof(char *) }, -#endif +#endif /* (NUM_USB_CHAN_IN > 0) */ #if defined(MIXER) && (MAX_MIX_COUNT > 0) /* Extension Unit Descriptor (4.7.2.12) */ @@ -1389,7 +1386,7 @@ USB_Config_Descriptor_Audio2_t cfgDesc_Audio2= 0x00, /* bmControls */ 0 /* Mixer unit string descriptor index */ }, -#endif +#endif /* defined(MIXER) && (MAX_MIX_COUNT > 0) */ #if (SPDIF_RX) || (ADAT_RX) /* Standard AS Interrupt Endpoint Descriptor (4.8.2.1): */ @@ -1586,7 +1583,7 @@ USB_Config_Descriptor_Audio2_t cfgDesc_Audio2= 4, /* 6 bInterval. Only values <= 1 frame (4) supported by MS */ }, #endif -#endif +#endif /* OUTPUT_FORMAT_COUNT > 1 */ #if (OUTPUT_FORMAT_COUNT > 2) /* Standard AS Interface Descriptor (4.9.1) (Alt) */ .Audio_Out_StreamInterface_Alt3 = @@ -1831,7 +1828,7 @@ USB_Config_Descriptor_Audio2_t cfgDesc_Audio2= .bLockDelayUnits = 0x02, .wLockDelay = 0x0008, }, -#endif +#endif /* (INPUT_FORMAT_COUNT > 1) */ #if (INPUT_FORMAT_COUNT > 2) /* Alternative 3 */ /* Standard AS Interface Descriptor (4.9.1) (Alt) */ @@ -1904,7 +1901,7 @@ USB_Config_Descriptor_Audio2_t cfgDesc_Audio2= .bLockDelayUnits = 0x02, .wLockDelay = 0x0008, }, -#endif +#endif /* (INPUT_FORMAT_COUNT > 2) */ #endif /* #if(NUM_USB_CHAN_IN > 0) */ #ifdef MIDI @@ -2060,7 +2057,7 @@ USB_Config_Descriptor_Audio2_t cfgDesc_Audio2= 0x10, /* 7 bcdDFUVersion */ 0x01}, /* 7 bcdDFUVersion */ #endif -#endif +#endif /* (XUA_DFU_EN == 1) */ #ifdef IAP /* Interface descriptor */ @@ -2169,7 +2166,7 @@ USB_Config_Descriptor_Audio2_t cfgDesc_Audio2= #endif #endif /* IAP */ -#ifdef HID_CONTROLS +#if( 0 < HID_CONTROLS ) .HID_Interface = { 9, /* 0 bLength : Size of descriptor in Bytes */ @@ -2203,22 +2200,22 @@ USB_Config_Descriptor_Audio2_t cfgDesc_Audio2= ENDPOINT_ADDRESS_IN_HID, /* 2 bEndpointAddress */ 3, /* 3 bmAttributes (INTERRUPT) */ 64, /* 4 wMaxPacketSize */ - 8, /* 6 bInterval */ + ENDPOINT_INT_INTERVAL_IN_HID, /* 6 bInterval */ } #endif }; -#endif +#endif /* (AUDIO_CLASS == 2) */ -#ifdef HID_CONTROLS +#if( 0 < HID_CONTROLS ) unsigned char hidDescriptor[] = { - 9, /* 0 bLength : Size of descriptor in Bytes */ + 0x09, /* 0 bLength : Size of descriptor in Bytes */ 0x21, /* 1 bDescriptorType (HID) */ 0x10, /* 2 bcdHID */ 0x01, /* 3 bcdHID */ - 0, /* 4 bCountryCode */ - 1, /* 5 bNumDescriptors */ + 0x00, /* 4 bCountryCode */ + 0x01, /* 5 bNumDescriptors */ 0x22, /* 6 bDescriptorType[0] (Report) */ sizeof(hidReportDescriptor) & 0xff, /* 7 wDescriptorLength[0] */ sizeof(hidReportDescriptor) >> 8, /* 8 wDescriptorLength[0] */ @@ -2325,18 +2322,13 @@ const unsigned num_freqs_a1 = MAX(3, (0 #define DFU_INTERFACES_A1 0 #endif -/* Total number of bytes returned for the class-specific AudioControl interface descriptor. - * Includes the combined length of this descriptor header and all Unit and Terminal descriptors - * For us this is IT -> FU -> OT * 2 and a header */ -#define AC_TOTAL_LENGTH (AC_LENGTH + \ - (INPUT_INTERFACES_A1 * (12 + ( (8 + NUM_USB_CHAN_IN_FS) * INPUT_VOLUME_CONTROL) + 9)) +\ - (OUTPUT_INTERFACES_A1 * (12 + ( (8 + NUM_USB_CHAN_OUT_FS) * OUTPUT_VOLUME_CONTROL) + 9))) - -#define STREAMING_INTERFACES (INPUT_INTERFACES_A1 + OUTPUT_INTERFACES_A1) - -//#if (NUM_USB_CHAN_IN == 0) || defined(UAC_FORCE_FEEDBACK_EP) -//#define CFG_TOTAL_LENGTH_A1 (18 + AC_TOTAL_LENGTH + (INPUT_INTERFACES_A1 * (49 + num_freqs_a1 * 3)) + (OUTPUT_INTERFACES_A1 * (58 + num_freqs_a1 * 3)) + CONTROL_INTERFACE_BYTES + DFU_INTERFACE_BYTES) -//#endif +#if( 0 < HID_CONTROLS ) +#define HID_INTERFACE_BYTES ( 9 + 9 + 7 ) +#define HID_INTERFACES_A1 1 +#else +#define HID_INTERFACE_BYTES 0 +#define HID_INTERFACES_A1 0 +#endif /* Total number of bytes returned for the class-specific AudioControl interface descriptor. * Includes the combined length of this descriptor header and all Unit and Terminal descriptors @@ -2349,12 +2341,12 @@ const unsigned num_freqs_a1 = MAX(3, (0 /* Number of interfaces for Audio 1.0 (+1 for control ) */ /* Note, this is different that INTERFACE_COUNT since we dont support items such as MIDI, iAP etc in UAC1 mode */ -#define NUM_INTERFACES_A1 (1+INPUT_INTERFACES_A1 + OUTPUT_INTERFACES_A1+NUM_CONTROL_USB_INTERFACES+DFU_INTERFACES_A1) +#define NUM_INTERFACES_A1 (1 + INPUT_INTERFACES_A1 + OUTPUT_INTERFACES_A1 + NUM_CONTROL_USB_INTERFACES + DFU_INTERFACES_A1 + HID_INTERFACES_A1) #if (NUM_USB_CHAN_IN == 0) || defined(UAC_FORCE_FEEDBACK_EP) -#define CFG_TOTAL_LENGTH_A1 (18 + AC_TOTAL_LENGTH + (INPUT_INTERFACES_A1 * (49 + num_freqs_a1 * 3)) + (OUTPUT_INTERFACES_A1 * (58 + num_freqs_a1 * 3)) + CONTROL_INTERFACE_BYTES + DFU_INTERFACE_BYTES) +#define CFG_TOTAL_LENGTH_A1 (18 + AC_TOTAL_LENGTH + (INPUT_INTERFACES_A1 * (49 + num_freqs_a1 * 3)) + (OUTPUT_INTERFACES_A1 * (58 + num_freqs_a1 * 3)) + CONTROL_INTERFACE_BYTES + DFU_INTERFACE_BYTES + HID_INTERFACE_BYTES) #else -#define CFG_TOTAL_LENGTH_A1 (18 + AC_TOTAL_LENGTH + (INPUT_INTERFACES_A1 * (49 + num_freqs_a1 * 3)) + (OUTPUT_INTERFACES_A1 * (49 + num_freqs_a1 * 3)) + CONTROL_INTERFACE_BYTES + DFU_INTERFACE_BYTES) +#define CFG_TOTAL_LENGTH_A1 (18 + AC_TOTAL_LENGTH + (INPUT_INTERFACES_A1 * (49 + num_freqs_a1 * 3)) + (OUTPUT_INTERFACES_A1 * (49 + num_freqs_a1 * 3)) + CONTROL_INTERFACE_BYTES + DFU_INTERFACE_BYTES + HID_INTERFACE_BYTES) #endif #define CHARIFY_SR(x) (x & 0xff),((x & 0xff00)>> 8),((x & 0xff0000)>> 16) @@ -2856,6 +2848,39 @@ unsigned char cfgDesc_Audio1[] = offsetof(StringDescTable_t, ctrlStr)/sizeof(char *), /* 8 iInterface */ #endif +#if( 0 < HID_CONTROLS ) + /* HID interface descriptor */ + 0x09, /* 0 bLength : Size of descriptor in Bytes */ + 0x04, /* 1 bDescriptorType (Interface: 0x04)*/ + INTERFACE_NUMBER_HID, /* 2 bInterfaceNumber : Number of interface */ + 0x00, /* 3 bAlternateSetting : Value used alternate interfaces using SetInterface Request */ + 0x01, /* 4: bNumEndpoints : Number of endpoitns for this interface (excluding 0) */ + 0x03, /* 5: bInterfaceClass */ + 0x00, /* 6: bInterfaceSubClass - no boot device */ + 0x00, /* 7: bInterfaceProtocol*/ + 0x00, /* 8 iInterface */ + + /* HID descriptor */ + 0x09, /* 0 bLength : Size of descriptor in Bytes */ + 0x21, /* 1 bDescriptorType (HID) */ + 0x10, /* 2 bcdHID */ + 0x01, /* 3 bcdHID */ + 0x00, /* 4 bCountryCode */ + 0x01, /* 5 bNumDescriptors */ + 0x22, /* 6 bDescriptorType[0] (Report) */ + 0x1E, /* 7 wDescriptorLength[0] */ + 0x00, /* 8 wDescriptorLength[0] */ + + /* HID Endpoint descriptor (IN) */ + 0x07, /* 0 bLength */ + 0x05, /* 1 bDescriptorType */ + ENDPOINT_ADDRESS_IN_HID, /* 2 bEndpointAddress */ + 0x03, /* 3 bmAttributes (INTERRUPT) */ + 0x40, /* 4 wMaxPacketSize */ + 0x00, /* 5 wMaxPacketSize */ + ENDPOINT_INT_INTERVAL_IN_HID, /* 6 bInterval */ +#endif + }; #endif #endif diff --git a/lib_xua/src/core/endpoint0/xua_ep0_uacreqs.h b/lib_xua/src/core/endpoint0/xua_ep0_uacreqs.h index 16d21b47..ab4c613d 100644 --- a/lib_xua/src/core/endpoint0/xua_ep0_uacreqs.h +++ b/lib_xua/src/core/endpoint0/xua_ep0_uacreqs.h @@ -5,13 +5,13 @@ #include -int AudioClassRequests_2(XUD_ep ep0_out, XUD_ep ep0_in, REFERENCE_PARAM(USB_SetupPacket_t, sp), chanend c_audioControl, +int AudioClassRequests_2(XUD_ep ep0_out, XUD_ep ep0_in, REFERENCE_PARAM(USB_SetupPacket_t, sp), NULLABLE_RESOURCE(chanend, c_audioControl), NULLABLE_RESOURCE(chanend, c_mix_ctl), NULLABLE_RESOURCE(chanend, c_clk_ctl)); -XUD_Result_t AudioClassRequests_1(XUD_ep ep0_out, XUD_ep ep0_in, REFERENCE_PARAM(USB_SetupPacket_t, sp), chanend c_audioControl, +XUD_Result_t AudioClassRequests_1(XUD_ep ep0_out, XUD_ep ep0_in, REFERENCE_PARAM(USB_SetupPacket_t, sp), NULLABLE_RESOURCE(chanend, c_audioControl), NULLABLE_RESOURCE(chanend, c_mix_ctl), NULLABLE_RESOURCE(chanend, c_clk_ctl)); -int AudioEndpointRequests_1(XUD_ep ep0_out, XUD_ep ep0_in, REFERENCE_PARAM(USB_SetupPacket_t, sp), chanend c_audioControl, +int AudioEndpointRequests_1(XUD_ep ep0_out, XUD_ep ep0_in, REFERENCE_PARAM(USB_SetupPacket_t, sp), NULLABLE_RESOURCE(chanend, c_audioControl), NULLABLE_RESOURCE(chanend, c_mix_ctl), NULLABLE_RESOURCE(chanend, c_clk_ctl)); diff --git a/lib_xua/src/core/endpoint0/xua_ep0_uacreqs.xc b/lib_xua/src/core/endpoint0/xua_ep0_uacreqs.xc index d10dc437..2fdd434c 100644 --- a/lib_xua/src/core/endpoint0/xua_ep0_uacreqs.xc +++ b/lib_xua/src/core/endpoint0/xua_ep0_uacreqs.xc @@ -273,7 +273,7 @@ static void updateVol(int unitID, int channel, chanend ?c_mix_ctl) * XUD_RES_RST for device reset * else XUD_RES_ERR */ -int AudioClassRequests_2(XUD_ep ep0_out, XUD_ep ep0_in, USB_SetupPacket_t &sp, chanend c_audioControl, chanend ?c_mix_ctl, chanend ?c_clk_ctl +int AudioClassRequests_2(XUD_ep ep0_out, XUD_ep ep0_in, USB_SetupPacket_t &sp, chanend ?c_audioControl, chanend ?c_mix_ctl, chanend ?c_clk_ctl ) { unsigned int buffer[32]; @@ -1071,7 +1071,7 @@ int AudioClassRequests_2(XUD_ep ep0_out, XUD_ep ep0_in, USB_SetupPacket_t &sp, c #if (AUDIO_CLASS_FALLBACK != 0) || (AUDIO_CLASS == 1) -int AudioEndpointRequests_1(XUD_ep ep0_out, XUD_ep ep0_in, USB_SetupPacket_t &sp, chanend c_audioControl, chanend ?c_mix_ctl, chanend ?c_clk_ctl) +int AudioEndpointRequests_1(XUD_ep ep0_out, XUD_ep ep0_in, USB_SetupPacket_t &sp, chanend ?c_audioControl, chanend ?c_mix_ctl, chanend ?c_clk_ctl) { /* At this point we know: * bmRequestType.Recipient = Endpoint @@ -1159,7 +1159,7 @@ int AudioEndpointRequests_1(XUD_ep ep0_out, XUD_ep ep0_in, USB_SetupPacket_t &sp /* Handles the Audio Class 1.0 specific requests */ -XUD_Result_t AudioClassRequests_1(XUD_ep ep0_out, XUD_ep ep0_in, USB_SetupPacket_t &sp, chanend c_audioControl, chanend ?c_mix_ctl, chanend ?c_clk_ctl +XUD_Result_t AudioClassRequests_1(XUD_ep ep0_out, XUD_ep ep0_in, USB_SetupPacket_t &sp, chanend ?c_audioControl, chanend ?c_mix_ctl, chanend ?c_clk_ctl ) { #if (OUTPUT_VOLUME_CONTROL == 1) || (INPUT_VOLUME_CONTROL == 1) diff --git a/lib_xua/src/core/main.xc b/lib_xua/src/core/main.xc index cb9d8af7..afc819c4 100755 --- a/lib_xua/src/core/main.xc +++ b/lib_xua/src/core/main.xc @@ -1,4 +1,4 @@ -// Copyright (c) 2012-2018, XMOS Ltd, All rights reserved +// Copyright (c) 2012-2019, XMOS Ltd, All rights reserved #include "xua.h" /* Device specific defines */ #ifndef EXCLUDE_USB_AUDIO_MAIN @@ -259,7 +259,7 @@ XUD_EpType epTypeTableIn[ENDPOINT_COUNT_IN] = { XUD_EPTYPE_CTL | XUD_STATUS_ENAB #ifdef MIDI XUD_EPTYPE_BUL, #endif -#ifdef HID_CONTROLS +#if( 0 < HID_CONTROLS ) XUD_EPTYPE_INT, #endif #ifdef IAP @@ -400,7 +400,7 @@ VENDOR_REQUESTS_PARAMS_DEC_ c_clk_int, #endif c_sof, c_aud_ctl, p_for_mclk_count -#ifdef HID_CONTROLS +#if( 0 < HID_CONTROLS ) , c_xud_in[ENDPOINT_NUMBER_IN_HID] #endif #ifdef CHAN_BUFF_CTRL diff --git a/lib_xua/src/core/user/hid/user_hid.h b/lib_xua/src/core/user/hid/user_hid.h new file mode 100644 index 00000000..88165b2a --- /dev/null +++ b/lib_xua/src/core/user/hid/user_hid.h @@ -0,0 +1,19 @@ +// Copyright (c) 2013-2019, XMOS Ltd, All rights reserved + +/* These defines relate to the HID report desc - do not mod */ +#define HID_CONTROL_PLAYPAUSE_SHIFT 0x00 +#define HID_CONTROL_NEXT_SHIFT 0x01 +#define HID_CONTROL_PREV_SHIFT 0x02 +#define HID_CONTROL_VOLUP_SHIFT 0x03 +#define HID_CONTROL_VOLDN_SHIFT 0x04 +#define HID_CONTROL_MUTE_SHIFT 0x05 + +#define HID_DATA_SIZE 1 + +#if( 0 < HID_CONTROLS ) + +void UserInitHIDData( void ); +void UserReadHIDData( unsigned char hidData[ HID_DATA_SIZE ]); +void UserSetHIDData( const unsigned hidData ); + +#endif /* ( 0 < HID_CONTROLS ) */ diff --git a/lib_xua/src/core/user/user_hid.h b/lib_xua/src/core/user/user_hid.h deleted file mode 100644 index b2530d0f..00000000 --- a/lib_xua/src/core/user/user_hid.h +++ /dev/null @@ -1,13 +0,0 @@ -// Copyright (c) 2013-2018, XMOS Ltd, All rights reserved - - -/* These defines relate to the HID report desc - do not mod */ -#define HID_CONTROL_PLAYPAUSE_SHIFT 0x00 -#define HID_CONTROL_NEXT_SHIFT 0x01 -#define HID_CONTROL_PREV_SHIFT 0x02 -#define HID_CONTROL_VOLUP_SHIFT 0x03 -#define HID_CONTROL_VOLDN_SHIFT 0x04 -#define HID_CONTROL_MUTE_SHIFT 0x05 - -void UserReadHIDButtons(unsigned char hidData[]); - diff --git a/lib_xua/src/hid/hid.xc b/lib_xua/src/hid/hid.xc new file mode 100644 index 00000000..478bfea5 --- /dev/null +++ b/lib_xua/src/hid/hid.xc @@ -0,0 +1,222 @@ +// Copyright (c) 2019, XMOS Ltd, All rights reserved +#include +#include "descriptor_defs.h" +#include "hid.h" +#include "xud.h" +#include "xud_std_requests.h" +#include "xua_hid.h" + +#if( 0 < HID_CONTROLS ) +#define MS_IN_TICKS 100000U + +static unsigned s_hidIdleActive = 0U; +static unsigned s_hidCurrentPeriod = ENDPOINT_INT_INTERVAL_IN_HID * MS_IN_TICKS; +static unsigned s_hidIndefiniteDuration = 0U; +static unsigned s_hidNextReportTime = 0U; +static unsigned s_hidReportTime = 0U; + +static unsigned HidCalcNewReportTime( const unsigned currentPeriod, const unsigned reportTime, const unsigned reportToSetIdleInterval, const unsigned newPeriod ); +static unsigned HidCalcReportToSetIdleInterval( const unsigned reportTime ); +static unsigned HidFindSetIdleActivationPoint( const unsigned currentPeriod, const unsigned timeWithinPeriod ); +static XUD_Result_t HidProcessSetIdleRequest( XUD_ep c_ep0_out, XUD_ep c_ep0_in, USB_SetupPacket_t &sp ); +static unsigned HidTimeDiff( const unsigned earlierTime, const unsigned laterTime ); + +void HidCalcNextReportTime( void ) +{ + s_hidNextReportTime = s_hidReportTime + s_hidCurrentPeriod; +} + +void HidCaptureReportTime( void ) +{ + timer tmr; + tmr :> s_hidReportTime; +} + +XUD_Result_t HidInterfaceClassRequests( + XUD_ep c_ep0_out, + XUD_ep c_ep0_in, + USB_SetupPacket_t &sp ) +{ + XUD_Result_t result = XUD_RES_ERR; + + switch ( sp.bRequest ) { + case HID_SET_IDLE: + result = HidProcessSetIdleRequest( c_ep0_out, c_ep0_in, sp ); + break; + + default: + break; + } + + return result; +} + +unsigned HidIsSetIdleSilenced( void ) +{ + unsigned isSilenced = s_hidIdleActive; + + if( s_hidIdleActive ) { + unsigned currentTime; + asm volatile( "gettime %0" : "=r" ( currentTime )); // Use inline assembly to access the time without creating a side-effect + isSilenced = ( s_hidIndefiniteDuration || ( timeafter( s_hidNextReportTime, currentTime ))); + } + + return isSilenced; +} + +/** + * \brief Calculate the timer value for sending the next HID Report. + * + * With regard to Section 7.2.4 Set_Idle Request of the USB Device Class Definition for Human + * Interface Devices (HID) Version 1.11, I've interpreted 'currently executing period' and + * 'current period' to mean the previously established Set Idle duration if one has been + * established or the polling interval from the HID Report Descriptor if a Set Idle duration + * has not been established. + * + * \param[in] currentPeriod -- The duration of the current period in timer ticks + * \param[in] reportTime -- The time at which the last HID Report was sent + * \param[in] reportToSetIdleInterval -- The time interval between receiving the Set Idle Request + * and sending the most recent HID Report + * \param[in] newPeriod -- The new period value in timer ticks + * + * \return The time at which the next HID Report should be sent + */ +static unsigned HidCalcNewReportTime( const unsigned currentPeriod, const unsigned reportTime, const unsigned reportToSetIdleInterval, const unsigned newPeriod ) +{ + unsigned nextReportTime = 0; + + if( HidFindSetIdleActivationPoint( currentPeriod, reportToSetIdleInterval )) { + /* Activate immediately after sending the next HID Report */ + nextReportTime = reportTime + currentPeriod; + } else { + /* Activate immediately after sending the most recent HID Report */ + nextReportTime = reportTime + newPeriod; + } + + return nextReportTime; +} + +/** + * \brief Calculate the time interval between the most recent HID Report and a subsequent Set Idle Request + * + * \warning For this function to produce an accurate interval measument, it must be called without delay + * upon receiving a Set Idle Request from the USB Host. + * + * \param[in] reportTime -- The time at which the last HID Report was sent + * + * \return The time interval between receiving the Set Idle Request and sending the most recent HID Report + */ +static unsigned HidCalcReportToSetIdleInterval( const unsigned reportTime ) +{ + timer tmr; + unsigned setIdleTime; + + tmr :> setIdleTime; + unsigned result = HidTimeDiff( reportTime, setIdleTime ); + return result; +} + +/** + * \brief Indicate if activation of the Set Idle Request happens at the previous or next HID Report + * + * Section 7.2.4 Set_Idle Request of the USB Device Class Definition for Human Interface + * Devices (HID) Version 1.11 makes two statements about the activation point for starting the + * duration of the request: + * - 'A new request will be executed as if it were issued immediately after the last report, if + * the new request is received at least 4 milliseconds before the end of the currently executing + * period.' + * - 'If the new request is received within 4 milliseconds of the end of the current period, then + * the new request will have no effect until after the report.' + * + * \param[in] currentPeriod -- The duration of the current period + * \param[in] timeWithinPeriod -- The current point in time relative to the current period + * + * \return A Boolean indicating where the activation of the Set Idle Request Duration occurs. + * \retval 1 -- Activate immediately after the next HID Report + * \retval 0 -- Activate immediately after the previous HID Report + */ +static unsigned HidFindSetIdleActivationPoint( const unsigned currentPeriod, const unsigned timeWithinPeriod ) +{ + unsigned result = (( currentPeriod - timeWithinPeriod ) < ( 4U * MS_IN_TICKS )) ? 1 : 0; + + return result; +} + +/** + * \brief Process a Set Idle request + * + * \param[in] c_ep0_out -- the channel that carries data from Endpoint 0 + * \param[in] c_ep0_in -- the channel that carries data for Endpoint 0 + * \param[in] sp -- a structure containing the Set Idle data + * + * \return An XUD status value + */ +static XUD_Result_t HidProcessSetIdleRequest( XUD_ep c_ep0_out, XUD_ep c_ep0_in, USB_SetupPacket_t &sp ) +{ + XUD_Result_t result = XUD_RES_ERR; + + /* + The Set Idle request wValue field contains two sub-fields: + - Duration in the MSB; and + - Report ID in the LSB. + + The Duration field specifies how long the USB Device responds with NAK provided the HID data hasn't changed. + Zero means indefinitely. + The value is in units of 4ms. + + The Report ID identifies the HID report that the USB Host wishes to silence. + + The Set Idle request xIndex field contains the interface number. + */ + uint16_t duration = ( sp.wValue & 0xFF00 ) >> 6; // Transform from units of 4ms into units of 1ms. + uint8_t reportId = sp.wValue & 0x00FF; + uint16_t interfaceNum = sp.wIndex; + + /* + As long as our HID Report Descriptor does not include a Report ID, any Report ID value other than zero + indicates an error by the USB Host (see xua_ep0_descriptors.h for the definition of the HID + Report Descriptor). + + Any Interface value other than INTERFACE_NUMBER_HID indicates an error by the USB Host. + */ + if(( 0U == reportId ) && ( INTERFACE_NUMBER_HID == interfaceNum )) { + s_hidIdleActive = (( 0U == duration ) || ( ENDPOINT_INT_INTERVAL_IN_HID < duration )); + + if( s_hidIdleActive ) { + unsigned reportToSetIdleInterval = HidCalcReportToSetIdleInterval( s_hidReportTime ); + s_hidNextReportTime = HidCalcNewReportTime( s_hidCurrentPeriod, s_hidReportTime, reportToSetIdleInterval, duration * MS_IN_TICKS ); + s_hidCurrentPeriod = duration * MS_IN_TICKS; + s_hidIndefiniteDuration = ( 0U == duration ); + } else { + s_hidCurrentPeriod = ENDPOINT_INT_INTERVAL_IN_HID * MS_IN_TICKS; + s_hidIndefiniteDuration = 0U; + } + + result = XUD_DoSetRequestStatus( c_ep0_in ); + } + + return result; +} + +/** + * \brief Calculate the difference between two points in time + * + * This function calculates the difference between two two points in time. + * It always returns a positive value even if the timer used to obtain the two + * time measurements has wrapped around. + * + * \warning If time values have been obtained from a timer that has wrapped + * more than once in between the two measurements, this function returns an + * incorrect value. + * + * \param[in] earlierTime -- A value from a timer + * \param[in] laterTime -- A value from a timer taken after \a earlierTime + * + * \return The interval between the two points in time + */ +static unsigned HidTimeDiff( const unsigned earlierTime, const unsigned laterTime ) +{ + return ( earlierTime < laterTime ) ? laterTime - earlierTime : UINT_MAX - earlierTime + laterTime; +} + +#endif /* ( 0 < HID_CONTROLS ) */ diff --git a/lib_xua/src/hid/xua_hid.h b/lib_xua/src/hid/xua_hid.h new file mode 100644 index 00000000..23d507e0 --- /dev/null +++ b/lib_xua/src/hid/xua_hid.h @@ -0,0 +1,55 @@ +// Copyright (c) 2019, XMOS Ltd, All rights reserved +#include +#include +#include "xud.h" +#include "xud_std_requests.h" + +/** + * \brief Calculate the next time to respond with a HID Report. + * + * If the USB Host has previously sent a valid HID Set_Idle request with + * a duration of zero or greater than the default reporting interval, + * the device sends HID Reports periodically or when the value of the + * payload has changed. + * + * This function calculates the time for sending the next periodic + * HID Report. + */ +void HidCalcNextReportTime( void ); + +/** + * \brief Capture the time of sending the current HID Report. + * + * If the USB Host has previously sent a valid HID Set_Idle request with + * a duration of zero or greater than the default reporting interval, + * the device sends HID Reports periodically or when the value of the + * payload has changed. + * + * This function captures the time when the HID Report was sent so that + * a subsequent call to HidCalNextReportTime() can calculate the time + * to send the next periodic HID Report. + */ +void HidCaptureReportTime( void ); + +XUD_Result_t HidInterfaceClassRequests( + XUD_ep c_ep0_out, + XUD_ep c_ep0_in, + REFERENCE_PARAM( USB_SetupPacket_t, sp )); + +/** + * \brief Indicate whether to send a HID Report based on elapsed time. + * + * If the USB Host has previously sent a valid HID Set_Idle request with + * a duration of zero or greater than the default reporting interval, + * the device sends HID Reports periodically or when the value of the + * payload has changed. + * + * This function monitors the passage of time and reports to the caller + * whether or not the time to send the next periodic HID Report has + * elapsed. + * + * \return A Boolean value indicating whether or not to send the HID Report. + * \retval 1 -- Do not send the HID Report + * \retval 0 -- Send the HID Report + */ +unsigned HidIsSetIdleSilenced( void );