diff --git a/Demos/Device/ClassDriver/AudioInput/AudioInput.c b/Demos/Device/ClassDriver/AudioInput/AudioInput.c index b197588a8e..58a3668e84 100644 --- a/Demos/Device/ClassDriver/AudioInput/AudioInput.c +++ b/Demos/Device/ClassDriver/AudioInput/AudioInput.c @@ -51,6 +51,9 @@ USB_ClassInfo_Audio_Device_t Microphone_Audio_Interface = }, }; +/** Current audio sampling frequency of the streaming audio endpoint. */ +uint32_t CurrentAudioSampleFrequency = 48000; + /** Main program entry point. This routine contains the overall program flow, including initial * setup of all components and the main program loop. @@ -133,7 +136,7 @@ void EVENT_USB_Device_Connect(void) /* Sample reload timer initialization */ TIMSK0 = (1 << OCIE0A); - OCR0A = ((F_CPU / 8 / AUDIO_SAMPLE_FREQUENCY) - 1); + OCR0A = ((F_CPU / 8 / CurrentAudioSampleFrequency) - 1); TCCR0A = (1 << WGM01); // CTC mode TCCR0B = (1 << CS01); // Fcpu/8 speed } @@ -163,3 +166,72 @@ void EVENT_USB_Device_ControlRequest(void) Audio_Device_ProcessControlRequest(&Microphone_Audio_Interface); } +/** Audio class driver callback for the setting and retrieval of streaming endpoint properties. This callback must be implemented + * in the user application to handle property manipulations on streaming audio endpoints. + * + * When the DataLength parameter is NULL, this callback should only indicate whether the specified operation is valid for + * the given endpoint index, and should return as fast as possible. When non-NULL, this value may be altered for GET operations + * to indicate the size of the retreived data. + * + * \note The length of the retrieved data stored into the Data buffer on GET operations should not exceed the initial value + * of the \c DataLength parameter. + * + * \param[in,out] AudioInterfaceInfo Pointer to a structure containing an Audio Class configuration and state. + * \param[in] EndpointProperty Property of the endpoint to get or set, a value from Audio_ClassRequests_t. + * \param[in] EndpointIndex Index of the streaming endpoint whose property is being referenced. + * \param[in] EndpointControl Parameter of the endpoint to get or set, a value from Audio_EndpointControls_t. + * \param[in,out] DataLength For SET operations, the length of the parameter data to set. For GET operations, the maximum + * length of the retrieved data. When NULL, the function should return whether the given property + * and parameter is valid for the requested endpoint without reading or modifying the Data buffer. + * \param[in,out] Data Pointer to a location where the parameter data is stored for SET operations, or where + * the retrieved data is to be stored for GET operations. + * + * \return Boolean true if the property get/set was successful, false otherwise + */ +bool CALLBACK_Audio_GetSetEndpointProperty(USB_ClassInfo_Audio_Device_t* const AudioInterfaceInfo, + const uint8_t EndpointProperty, + const uint8_t EndpointIndex, + const uint8_t EndpointControl, + uint16_t* const DataLength, + uint8_t* Data) +{ + /* Check the requested endpoint to see if a supported endpoint is being manipulated */ + if (EndpointIndex == Microphone_Audio_Interface.Config.DataINEndpointNumber) + { + /* Check the requested control to see if a supported control is being manipulated */ + if (EndpointControl == AUDIO_EPCONTROL_SamplingFreq) + { + /* Check the requested property to see if a supported property is being manipulated */ + if (EndpointProperty == AUDIO_REQ_SetCurrent) + { + /* Check if we are just testing for a valid property, or actually adjusting it */ + if (DataLength != NULL) + { + /* Set the new sampling frequency to the value given by the host */ + CurrentAudioSampleFrequency = (((uint32_t)Data[2] << 16) | ((uint32_t)Data[1] << 8) | (uint32_t)Data[0]); + + /* Adjust sample reload timer to the new frequency */ + OCR0A = ((F_CPU / 8 / CurrentAudioSampleFrequency) - 1); + } + + return true; + } + else if (EndpointProperty == AUDIO_REQ_GetCurrent) + { + /* Check if we are just testing for a valid property, or actually reading it */ + if (DataLength != NULL) + { + *DataLength = 3; + + Data[2] = (CurrentAudioSampleFrequency >> 16); + Data[1] = (CurrentAudioSampleFrequency >> 8); + Data[0] = (CurrentAudioSampleFrequency & 0xFF); + } + + return true; + } + } + } + + return false; +} diff --git a/Demos/Device/ClassDriver/AudioInput/Descriptors.c b/Demos/Device/ClassDriver/AudioInput/Descriptors.c index bd31bdb0ef..6fffd05d4d 100644 --- a/Demos/Device/ClassDriver/AudioInput/Descriptors.c +++ b/Demos/Device/ClassDriver/AudioInput/Descriptors.c @@ -54,7 +54,7 @@ const USB_Descriptor_Device_t PROGMEM DeviceDescriptor = .Endpoint0Size = FIXED_CONTROL_ENDPOINT_SIZE, .VendorID = 0x03EB, - .ProductID = 0x2047, + .ProductID = 0x206B, .ReleaseNumber = VERSION_BCD(00.01), .ManufacturerStrIndex = 0x01, @@ -191,7 +191,9 @@ const USB_Descriptor_Configuration_t PROGMEM ConfigurationDescriptor = .Audio_AudioFormat = { - .Header = {.Size = sizeof(USB_Audio_Descriptor_Format_t), .Type = DTYPE_CSInterface}, + .Header = {.Size = sizeof(USB_Audio_Descriptor_Format_t) + + sizeof(ConfigurationDescriptor.Audio_AudioFormatSampleRates), + .Type = DTYPE_CSInterface}, .Subtype = AUDIO_DSUBTYPE_CSInterface_FormatType, .FormatType = 0x01, @@ -199,12 +201,17 @@ const USB_Descriptor_Configuration_t PROGMEM ConfigurationDescriptor = .SubFrameSize = 0x02, .BitResolution = 16, - .TotalDiscreteSampleRates = 1, + + .TotalDiscreteSampleRates = (sizeof(ConfigurationDescriptor.Audio_AudioFormatSampleRates) / sizeof(USB_Audio_SampleFreq_t)) }, .Audio_AudioFormatSampleRates = { - AUDIO_SAMPLE_FREQ(AUDIO_SAMPLE_FREQUENCY) + AUDIO_SAMPLE_FREQ(8000), + AUDIO_SAMPLE_FREQ(11025), + AUDIO_SAMPLE_FREQ(22050), + AUDIO_SAMPLE_FREQ(44100), + AUDIO_SAMPLE_FREQ(48000), }, .Audio_StreamEndpoint = @@ -228,7 +235,7 @@ const USB_Descriptor_Configuration_t PROGMEM ConfigurationDescriptor = .Header = {.Size = sizeof(USB_Audio_Descriptor_StreamEndpoint_Spc_t), .Type = DTYPE_CSEndpoint}, .Subtype = AUDIO_DSUBTYPE_CSEndpoint_General, - .Attributes = AUDIO_EP_ACCEPTS_SMALL_PACKETS, + .Attributes = (AUDIO_EP_ACCEPTS_SMALL_PACKETS | AUDIO_EP_SAMPLE_FREQ_CONTROL), .LockDelayUnits = 0x00, .LockDelay = 0x0000 diff --git a/Demos/Device/ClassDriver/AudioInput/Descriptors.h b/Demos/Device/ClassDriver/AudioInput/Descriptors.h index 82dbd517f0..05d1fee36a 100644 --- a/Demos/Device/ClassDriver/AudioInput/Descriptors.h +++ b/Demos/Device/ClassDriver/AudioInput/Descriptors.h @@ -51,9 +51,6 @@ */ #define AUDIO_STREAM_EPSIZE ENDPOINT_MAX_SIZE(AUDIO_STREAM_EPNUM) - /** Sample frequency of the data being transmitted through the streaming endpoint. */ - #define AUDIO_SAMPLE_FREQUENCY 48000 - /* Type Defines: */ /** Type define for the device configuration descriptor structure. This must be defined in the * application code, as the configuration descriptor contains several sub-descriptors which @@ -70,7 +67,7 @@ USB_Descriptor_Interface_t Audio_StreamInterface_Alt1; USB_Audio_Descriptor_Interface_AS_t Audio_StreamInterface_SPC; USB_Audio_Descriptor_Format_t Audio_AudioFormat; - USB_Audio_SampleFreq_t Audio_AudioFormatSampleRates[1]; + USB_Audio_SampleFreq_t Audio_AudioFormatSampleRates[5]; USB_Audio_Descriptor_StreamEndpoint_Std_t Audio_StreamEndpoint; USB_Audio_Descriptor_StreamEndpoint_Spc_t Audio_StreamEndpoint_SPC; } USB_Descriptor_Configuration_t; diff --git a/Demos/Device/ClassDriver/AudioOutput/AudioOutput.c b/Demos/Device/ClassDriver/AudioOutput/AudioOutput.c index dbfd10b8bb..43267b2a7a 100644 --- a/Demos/Device/ClassDriver/AudioOutput/AudioOutput.c +++ b/Demos/Device/ClassDriver/AudioOutput/AudioOutput.c @@ -51,6 +51,9 @@ USB_ClassInfo_Audio_Device_t Speaker_Audio_Interface = }, }; +/** Current audio sampling frequency of the streaming audio endpoint. */ +uint32_t CurrentAudioSampleFrequency = 48000; + /** Main program entry point. This routine contains the overall program flow, including initial * setup of all components and the main program loop. @@ -135,7 +138,7 @@ void EVENT_USB_Device_Connect(void) /* Sample reload timer initialization */ TIMSK0 = (1 << OCIE0A); - OCR0A = ((F_CPU / 8 / AUDIO_SAMPLE_FREQUENCY) - 1); + OCR0A = ((F_CPU / 8 / CurrentAudioSampleFrequency) - 1); TCCR0A = (1 << WGM01); // CTC mode TCCR0B = (1 << CS01); // Fcpu/8 speed @@ -199,3 +202,72 @@ void EVENT_USB_Device_ControlRequest(void) Audio_Device_ProcessControlRequest(&Speaker_Audio_Interface); } +/** Audio class driver callback for the setting and retrieval of streaming endpoint properties. This callback must be implemented + * in the user application to handle property manipulations on streaming audio endpoints. + * + * When the DataLength parameter is NULL, this callback should only indicate whether the specified operation is valid for + * the given endpoint index, and should return as fast as possible. When non-NULL, this value may be altered for GET operations + * to indicate the size of the retreived data. + * + * \note The length of the retrieved data stored into the Data buffer on GET operations should not exceed the initial value + * of the \c DataLength parameter. + * + * \param[in,out] AudioInterfaceInfo Pointer to a structure containing an Audio Class configuration and state. + * \param[in] EndpointProperty Property of the endpoint to get or set, a value from Audio_ClassRequests_t. + * \param[in] EndpointIndex Index of the streaming endpoint whose property is being referenced. + * \param[in] EndpointControl Parameter of the endpoint to get or set, a value from Audio_EndpointControls_t. + * \param[in,out] DataLength For SET operations, the length of the parameter data to set. For GET operations, the maximum + * length of the retrieved data. When NULL, the function should return whether the given property + * and parameter is valid for the requested endpoint without reading or modifying the Data buffer. + * \param[in,out] Data Pointer to a location where the parameter data is stored for SET operations, or where + * the retrieved data is to be stored for GET operations. + * + * \return Boolean true if the property get/set was successful, false otherwise + */ +bool CALLBACK_Audio_GetSetEndpointProperty(USB_ClassInfo_Audio_Device_t* const AudioInterfaceInfo, + const uint8_t EndpointProperty, + const uint8_t EndpointIndex, + const uint8_t EndpointControl, + uint16_t* const DataLength, + uint8_t* Data) +{ + /* Check the requested endpoint to see if a supported endpoint is being manipulated */ + if (EndpointIndex == Speaker_Audio_Interface.Config.DataOUTEndpointNumber) + { + /* Check the requested control to see if a supported control is being manipulated */ + if (EndpointControl == AUDIO_EPCONTROL_SamplingFreq) + { + /* Check the requested property to see if a supported property is being manipulated */ + if (EndpointProperty == AUDIO_REQ_SetCurrent) + { + /* Check if we are just testing for a valid property, or actually adjusting it */ + if (DataLength != NULL) + { + /* Set the new sampling frequency to the value given by the host */ + CurrentAudioSampleFrequency = (((uint32_t)Data[2] << 16) | ((uint32_t)Data[1] << 8) | (uint32_t)Data[0]); + + /* Adjust sample reload timer to the new frequency */ + OCR0A = ((F_CPU / 8 / CurrentAudioSampleFrequency) - 1); + } + + return true; + } + else if (EndpointProperty == AUDIO_REQ_GetCurrent) + { + /* Check if we are just testing for a valid property, or actually reading it */ + if (DataLength != NULL) + { + *DataLength = 3; + + Data[2] = (CurrentAudioSampleFrequency >> 16); + Data[1] = (CurrentAudioSampleFrequency >> 8); + Data[0] = (CurrentAudioSampleFrequency & 0xFF); + } + + return true; + } + } + } + + return false; +} diff --git a/Demos/Device/ClassDriver/AudioOutput/Descriptors.c b/Demos/Device/ClassDriver/AudioOutput/Descriptors.c index e46c3c023e..5bb0e9f116 100644 --- a/Demos/Device/ClassDriver/AudioOutput/Descriptors.c +++ b/Demos/Device/ClassDriver/AudioOutput/Descriptors.c @@ -54,7 +54,7 @@ const USB_Descriptor_Device_t PROGMEM DeviceDescriptor = .Endpoint0Size = FIXED_CONTROL_ENDPOINT_SIZE, .VendorID = 0x03EB, - .ProductID = 0x2046, + .ProductID = 0x206C, .ReleaseNumber = VERSION_BCD(00.01), .ManufacturerStrIndex = 0x01, @@ -191,7 +191,9 @@ const USB_Descriptor_Configuration_t PROGMEM ConfigurationDescriptor = .Audio_AudioFormat = { - .Header = {.Size = sizeof(USB_Audio_Descriptor_Format_t), .Type = DTYPE_CSInterface}, + .Header = {.Size = sizeof(USB_Audio_Descriptor_Format_t) + + sizeof(ConfigurationDescriptor.Audio_AudioFormatSampleRates), + .Type = DTYPE_CSInterface}, .Subtype = AUDIO_DSUBTYPE_CSInterface_FormatType, .FormatType = 0x01, @@ -200,12 +202,16 @@ const USB_Descriptor_Configuration_t PROGMEM ConfigurationDescriptor = .SubFrameSize = 0x02, .BitResolution = 16, - .TotalDiscreteSampleRates = 1, + .TotalDiscreteSampleRates = (sizeof(ConfigurationDescriptor.Audio_AudioFormatSampleRates) / sizeof(USB_Audio_SampleFreq_t)), }, .Audio_AudioFormatSampleRates = { - AUDIO_SAMPLE_FREQ(AUDIO_SAMPLE_FREQUENCY) + AUDIO_SAMPLE_FREQ(8000), + AUDIO_SAMPLE_FREQ(11025), + AUDIO_SAMPLE_FREQ(22050), + AUDIO_SAMPLE_FREQ(44100), + AUDIO_SAMPLE_FREQ(48000), }, .Audio_StreamEndpoint = @@ -229,7 +235,7 @@ const USB_Descriptor_Configuration_t PROGMEM ConfigurationDescriptor = .Header = {.Size = sizeof(USB_Audio_Descriptor_StreamEndpoint_Spc_t), .Type = DTYPE_CSEndpoint}, .Subtype = AUDIO_DSUBTYPE_CSEndpoint_General, - .Attributes = AUDIO_EP_ACCEPTS_SMALL_PACKETS, + .Attributes = (AUDIO_EP_ACCEPTS_SMALL_PACKETS | AUDIO_EP_SAMPLE_FREQ_CONTROL), .LockDelayUnits = 0x00, .LockDelay = 0x0000 diff --git a/Demos/Device/ClassDriver/AudioOutput/Descriptors.h b/Demos/Device/ClassDriver/AudioOutput/Descriptors.h index b4b8db6a4a..ca5c873866 100644 --- a/Demos/Device/ClassDriver/AudioOutput/Descriptors.h +++ b/Demos/Device/ClassDriver/AudioOutput/Descriptors.h @@ -51,9 +51,6 @@ */ #define AUDIO_STREAM_EPSIZE ENDPOINT_MAX_SIZE(AUDIO_STREAM_EPNUM) - /** Sample frequency of the data being transmitted through the streaming endpoint. */ - #define AUDIO_SAMPLE_FREQUENCY 48000 - /* Type Defines: */ /** Type define for the device configuration descriptor structure. This must be defined in the * application code, as the configuration descriptor contains several sub-descriptors which @@ -70,7 +67,7 @@ USB_Descriptor_Interface_t Audio_StreamInterface_Alt1; USB_Audio_Descriptor_Interface_AS_t Audio_StreamInterface_SPC; USB_Audio_Descriptor_Format_t Audio_AudioFormat; - USB_Audio_SampleFreq_t Audio_AudioFormatSampleRates[1]; + USB_Audio_SampleFreq_t Audio_AudioFormatSampleRates[5]; USB_Audio_Descriptor_StreamEndpoint_Std_t Audio_StreamEndpoint; USB_Audio_Descriptor_StreamEndpoint_Spc_t Audio_StreamEndpoint_SPC; } USB_Descriptor_Configuration_t; diff --git a/Demos/Device/LowLevel/AudioInput/Descriptors.c b/Demos/Device/LowLevel/AudioInput/Descriptors.c index 6c8323c56d..8a63d77361 100644 --- a/Demos/Device/LowLevel/AudioInput/Descriptors.c +++ b/Demos/Device/LowLevel/AudioInput/Descriptors.c @@ -191,7 +191,9 @@ const USB_Descriptor_Configuration_t PROGMEM ConfigurationDescriptor = .Audio_AudioFormat = { - .Header = {.Size = sizeof(USB_Audio_Descriptor_Format_t), .Type = DTYPE_CSInterface}, + .Header = {.Size = sizeof(USB_Audio_Descriptor_Format_t) + + sizeof(ConfigurationDescriptor.Audio_AudioFormatSampleRates), + .Type = DTYPE_CSInterface}, .Subtype = AUDIO_DSUBTYPE_CSInterface_FormatType, .FormatType = 0x01, diff --git a/Demos/Device/LowLevel/AudioOutput/Descriptors.c b/Demos/Device/LowLevel/AudioOutput/Descriptors.c index 9c57a421f1..59e3af1dd6 100644 --- a/Demos/Device/LowLevel/AudioOutput/Descriptors.c +++ b/Demos/Device/LowLevel/AudioOutput/Descriptors.c @@ -191,7 +191,9 @@ const USB_Descriptor_Configuration_t PROGMEM ConfigurationDescriptor = .Audio_AudioFormat = { - .Header = {.Size = sizeof(USB_Audio_Descriptor_Format_t), .Type = DTYPE_CSInterface}, + .Header = {.Size = sizeof(USB_Audio_Descriptor_Format_t) + + sizeof(ConfigurationDescriptor.Audio_AudioFormatSampleRates), + .Type = DTYPE_CSInterface}, .Subtype = AUDIO_DSUBTYPE_CSInterface_FormatType, .FormatType = 0x01, diff --git a/Demos/Host/ClassDriver/KeyboardHost/KeyboardHost.c b/Demos/Host/ClassDriver/KeyboardHost/KeyboardHost.c index 9b6125e6c6..38af3a7c53 100644 --- a/Demos/Host/ClassDriver/KeyboardHost/KeyboardHost.c +++ b/Demos/Host/ClassDriver/KeyboardHost/KeyboardHost.c @@ -137,9 +137,13 @@ int main(void) PressedKey = (KeyCode - HID_KEYBOARD_SC_A) + 'A'; } else if ((KeyCode >= HID_KEYBOARD_SC_1_AND_EXCLAMATION) & - (KeyCode <= HID_KEYBOARD_SC_0_AND_CLOSING_PARENTHESIS)) + (KeyCode < HID_KEYBOARD_SC_0_AND_CLOSING_PARENTHESIS)) { - PressedKey = (KeyCode - HID_KEYBOARD_SC_1_AND_EXCLAMATION) + '0'; + PressedKey = (KeyCode - HID_KEYBOARD_SC_1_AND_EXCLAMATION) + '1'; + } + else if (KeyCode == HID_KEYBOARD_SC_0_AND_CLOSING_PARENTHESIS) + { + PressedKey = '0'; } else if (KeyCode == HID_KEYBOARD_SC_SPACE) { diff --git a/Demos/Host/ClassDriver/KeyboardHostWithParser/KeyboardHostWithParser.c b/Demos/Host/ClassDriver/KeyboardHostWithParser/KeyboardHostWithParser.c index abb391ceef..d7df58f07f 100644 --- a/Demos/Host/ClassDriver/KeyboardHostWithParser/KeyboardHostWithParser.c +++ b/Demos/Host/ClassDriver/KeyboardHostWithParser/KeyboardHostWithParser.c @@ -157,9 +157,13 @@ int main(void) PressedKey = (KeyCode - HID_KEYBOARD_SC_A) + 'A'; } else if ((KeyCode >= HID_KEYBOARD_SC_1_AND_EXCLAMATION) & - (KeyCode <= HID_KEYBOARD_SC_0_AND_CLOSING_PARENTHESIS)) + (KeyCode < HID_KEYBOARD_SC_0_AND_CLOSING_PARENTHESIS)) { - PressedKey = (KeyCode - HID_KEYBOARD_SC_1_AND_EXCLAMATION) + '0'; + PressedKey = (KeyCode - HID_KEYBOARD_SC_1_AND_EXCLAMATION) + '1'; + } + else if (KeyCode == HID_KEYBOARD_SC_0_AND_CLOSING_PARENTHESIS) + { + PressedKey = '0'; } else if (KeyCode == HID_KEYBOARD_SC_SPACE) { diff --git a/Demos/Host/LowLevel/KeyboardHost/KeyboardHost.c b/Demos/Host/LowLevel/KeyboardHost/KeyboardHost.c index 84e6145fb1..6df052d720 100644 --- a/Demos/Host/LowLevel/KeyboardHost/KeyboardHost.c +++ b/Demos/Host/LowLevel/KeyboardHost/KeyboardHost.c @@ -173,9 +173,13 @@ void ReadNextReport(void) PressedKey = (KeyCode - HID_KEYBOARD_SC_A) + 'A'; } else if ((KeyCode >= HID_KEYBOARD_SC_1_AND_EXCLAMATION) & - (KeyCode <= HID_KEYBOARD_SC_0_AND_CLOSING_PARENTHESIS)) + (KeyCode < HID_KEYBOARD_SC_0_AND_CLOSING_PARENTHESIS)) { - PressedKey = (KeyCode - HID_KEYBOARD_SC_1_AND_EXCLAMATION) + '0'; + PressedKey = (KeyCode - HID_KEYBOARD_SC_1_AND_EXCLAMATION) + '1'; + } + else if (KeyCode == HID_KEYBOARD_SC_0_AND_CLOSING_PARENTHESIS) + { + PressedKey = '0'; } else if (KeyCode == HID_KEYBOARD_SC_SPACE) { diff --git a/Demos/Host/LowLevel/KeyboardHostWithParser/KeyboardHostWithParser.c b/Demos/Host/LowLevel/KeyboardHostWithParser/KeyboardHostWithParser.c index 512cc1ae21..6ef7a96776 100644 --- a/Demos/Host/LowLevel/KeyboardHostWithParser/KeyboardHostWithParser.c +++ b/Demos/Host/LowLevel/KeyboardHostWithParser/KeyboardHostWithParser.c @@ -287,9 +287,13 @@ void ProcessKeyboardReport(uint8_t* KeyboardReport) PressedKey = (KeyCode - HID_KEYBOARD_SC_A) + 'A'; } else if ((KeyCode >= HID_KEYBOARD_SC_1_AND_EXCLAMATION) & - (KeyCode <= HID_KEYBOARD_SC_0_AND_CLOSING_PARENTHESIS)) + (KeyCode < HID_KEYBOARD_SC_0_AND_CLOSING_PARENTHESIS)) { - PressedKey = (KeyCode - HID_KEYBOARD_SC_1_AND_EXCLAMATION) + '0'; + PressedKey = (KeyCode - HID_KEYBOARD_SC_1_AND_EXCLAMATION) + '1'; + } + else if (KeyCode == HID_KEYBOARD_SC_0_AND_CLOSING_PARENTHESIS) + { + PressedKey = '0'; } else if (KeyCode == HID_KEYBOARD_SC_SPACE) { diff --git a/LUFA/Drivers/USB/Class/Common/Audio.h b/LUFA/Drivers/USB/Class/Common/Audio.h index cc6e8e52d9..fd9a3a92ba 100644 --- a/LUFA/Drivers/USB/Class/Common/Audio.h +++ b/LUFA/Drivers/USB/Class/Common/Audio.h @@ -197,7 +197,7 @@ * * \param[in] freq Required audio sampling frequency in HZ */ - #define AUDIO_SAMPLE_FREQ(freq) {.Byte1 = ((uint32_t)freq & 0x0000FF), .Byte2 = (((uint32_t)freq >> 8) & 0xFF), .Byte3 = (((uint32_t)freq >> 16) & 0xFF)} + #define AUDIO_SAMPLE_FREQ(freq) {.Byte1 = ((uint32_t)freq & 0xFF), .Byte2 = (((uint32_t)freq >> 8) & 0xFF), .Byte3 = (((uint32_t)freq >> 16) & 0xFF)} /** Mask for the attributes parameter of an Audio class-specific Endpoint descriptor, indicating that the endpoint * accepts only filled endpoint packets of audio samples. @@ -208,6 +208,16 @@ * will accept partially filled endpoint packets of audio samples. */ #define AUDIO_EP_ACCEPTS_SMALL_PACKETS (0 << 7) + + /** Mask for the attributes parameter of an Audio class-specific Endpoint descriptor, indicating that the endpoint + * allows for sampling frequency adjustments to be made via control requests directed at the endpoint. + */ + #define AUDIO_EP_SAMPLE_FREQ_CONTROL (1 << 0) + + /** Mask for the attributes parameter of an Audio class-specific Endpoint descriptor, indicating that the endpoint + * allows for pitch adjustments to be made via control requests directed at the endpoint. + */ + #define AUDIO_EP_PITCH_CONTROL (1 << 1) /* Enums: */ /** Enum for possible Class, Subclass and Protocol values of device and interface descriptors relating to the Audio @@ -277,6 +287,15 @@ AUDIO_REQ_GetMemory = 0x85, /**< Audio class-specific request to get the memory value of a parameter within the device. */ AUDIO_REQ_GetStatus = 0xFF, /**< Audio class-specific request to get the device status. */ }; + + /** Enum for Audio class specific Endpoint control modifiers which can be set and retrieved by a USB host, if the corresponding + * endpoint control is indicated to be supported in the Endpoint's Audio-class specific endpoint descriptor. + */ + enum Audio_EndpointControls_t + { + AUDIO_EPCONTROL_SamplingFreq = 0x01, /**< Sampling frequency adjustment of the endpoint. */ + AUDIO_EPCONTROL_Pitch = 0x02, /**< Pitch adjustment of the endpoint. */ + }; /* Type Defines: */ /** \brief Audio class-specific Input Terminal Descriptor (LUFA naming conventions). @@ -538,18 +557,6 @@ uint16_t wFormatTag; /**< Format of the audio stream, see Audio Device Formats specification. */ } ATTR_PACKED USB_Audio_StdDescriptor_Interface_AS_t; - /** \brief 24-Bit Audio Frequency Structure. - * - * Type define for a 24bit audio sample frequency structure. GCC does not contain a built in 24bit datatype, - * this this structure is used to build up the value instead. Fill this structure with the \ref AUDIO_SAMPLE_FREQ() macro. - */ - typedef struct - { - uint8_t Byte1; /**< Lowest 8 bits of the 24-bit value. */ - uint8_t Byte2; /**< Middle 8 bits of the 24-bit value. */ - uint8_t Byte3; /**< Upper 8 bits of the 24-bit value. */ - } ATTR_PACKED USB_Audio_SampleFreq_t; - /** \brief Audio class-specific Format Descriptor (LUFA naming conventions). * * Type define for an Audio class-specific audio format descriptor. This is used to give the host full details @@ -581,6 +588,18 @@ */ } ATTR_PACKED USB_Audio_Descriptor_Format_t; + /** \brief 24-Bit Audio Frequency Structure. + * + * Type define for a 24bit audio sample frequency structure. As GCC does not contain a built in 24-bit datatype, + * this this structure is used to build up the value instead. Fill this structure with the \ref AUDIO_SAMPLE_FREQ() macro. + */ + typedef struct + { + uint8_t Byte1; /**< Lowest 8 bits of the 24-bit value. */ + uint8_t Byte2; /**< Middle 8 bits of the 24-bit value. */ + uint8_t Byte3; /**< Upper 8 bits of the 24-bit value. */ + } ATTR_PACKED USB_Audio_SampleFreq_t; + /** \brief Audio class-specific Format Descriptor (USB-IF naming conventions). * * Type define for an Audio class-specific audio format descriptor. This is used to give the host full details diff --git a/LUFA/Drivers/USB/Class/Device/Audio.c b/LUFA/Drivers/USB/Class/Device/Audio.c index 8c5c9960d5..f183fdedd2 100644 --- a/LUFA/Drivers/USB/Class/Device/Audio.c +++ b/LUFA/Drivers/USB/Class/Device/Audio.c @@ -45,6 +45,22 @@ void Audio_Device_ProcessControlRequest(USB_ClassInfo_Audio_Device_t* const Audi if (USB_ControlRequest.wIndex != AudioInterfaceInfo->Config.StreamingInterfaceNumber) return; + if ((USB_ControlRequest.bmRequestType & CONTROL_REQTYPE_RECIPIENT) == REQREC_INTERFACE) + { + if (USB_ControlRequest.wIndex != AudioInterfaceInfo->Config.StreamingInterfaceNumber) + return; + } + else if ((USB_ControlRequest.bmRequestType & CONTROL_REQTYPE_RECIPIENT) == REQREC_ENDPOINT) + { + if (!((AudioInterfaceInfo->Config.DataINEndpointNumber && + (USB_ControlRequest.wIndex == AudioInterfaceInfo->Config.DataINEndpointNumber)) || + (AudioInterfaceInfo->Config.DataOUTEndpointNumber && + (USB_ControlRequest.wIndex == AudioInterfaceInfo->Config.DataOUTEndpointNumber)))) + { + return; + } + } + switch (USB_ControlRequest.bRequest) { case REQ_SetInterface: @@ -64,6 +80,53 @@ void Audio_Device_ProcessControlRequest(USB_ClassInfo_Audio_Device_t* const Audi Endpoint_ClearSETUP(); Endpoint_ClearStatusStage(); } + + break; + case AUDIO_REQ_SetCurrent: + case AUDIO_REQ_SetMinimum: + case AUDIO_REQ_SetMaximum: + case AUDIO_REQ_SetResolution: + if (USB_ControlRequest.bmRequestType == (REQDIR_HOSTTODEVICE | REQTYPE_CLASS | REQREC_ENDPOINT)) + { + uint8_t EndpointProperty = USB_ControlRequest.bRequest; + uint8_t EndpointIndex = (uint8_t)USB_ControlRequest.wIndex; + uint8_t EndpointControl = (USB_ControlRequest.wValue >> 8); + + if (CALLBACK_Audio_GetSetEndpointProperty(AudioInterfaceInfo, EndpointProperty, EndpointIndex, EndpointControl, NULL, NULL)) + { + uint16_t ValueLength = USB_ControlRequest.wLength; + uint8_t Value[ValueLength]; + + Endpoint_ClearSETUP(); + Endpoint_Read_Control_Stream_LE(Value, ValueLength); + Endpoint_ClearIN(); + + CALLBACK_Audio_GetSetEndpointProperty(AudioInterfaceInfo, EndpointProperty, EndpointIndex, EndpointControl, &ValueLength, Value); + } + } + + break; + case AUDIO_REQ_GetCurrent: + case AUDIO_REQ_GetMinimum: + case AUDIO_REQ_GetMaximum: + case AUDIO_REQ_GetResolution: + if (USB_ControlRequest.bmRequestType == (REQDIR_DEVICETOHOST | REQTYPE_CLASS | REQREC_ENDPOINT)) + { + uint8_t EndpointProperty = USB_ControlRequest.bRequest; + uint8_t EndpointIndex = (uint8_t)USB_ControlRequest.wIndex; + uint8_t EndpointControl = (USB_ControlRequest.wValue >> 8); + uint16_t ValueLength = USB_ControlRequest.wLength; + uint8_t Value[ValueLength]; + + if (CALLBACK_Audio_GetSetEndpointProperty(AudioInterfaceInfo, EndpointProperty, EndpointIndex, EndpointControl, &ValueLength, Value)) + { + Endpoint_ClearSETUP(); + Endpoint_Write_Control_Stream_LE(Value, ValueLength); + Endpoint_ClearOUT(); + } + } + + break; } } diff --git a/LUFA/Drivers/USB/Class/Device/Audio.h b/LUFA/Drivers/USB/Class/Device/Audio.h index a50bd97cc4..a09076341b 100644 --- a/LUFA/Drivers/USB/Class/Device/Audio.h +++ b/LUFA/Drivers/USB/Class/Device/Audio.h @@ -130,6 +130,35 @@ * \param[in,out] AudioInterfaceInfo Pointer to a structure containing an Audio Class configuration and state. */ void Audio_Device_ProcessControlRequest(USB_ClassInfo_Audio_Device_t* const AudioInterfaceInfo) ATTR_NON_NULL_PTR_ARG(1); + + /** Audio class driver callback for the setting and retrieval of streaming endpoint properties. This callback must be implemented + * in the user application to handle property manipulations on streaming audio endpoints. + * + * When the DataLength parameter is NULL, this callback should only indicate whether the specified operation is valid for + * the given endpoint index, and should return as fast as possible. When non-NULL, this value may be altered for GET operations + * to indicate the size of the retreived data. + * + * \note The length of the retrieved data stored into the Data buffer on GET operations should not exceed the initial value + * of the \c DataLength parameter. + * + * \param[in,out] AudioInterfaceInfo Pointer to a structure containing an Audio Class configuration and state. + * \param[in] EndpointProperty Property of the endpoint to get or set, a value from \ref Audio_ClassRequests_t. + * \param[in] EndpointIndex Index of the streaming endpoint whose property is being referenced. + * \param[in] EndpointControl Parameter of the endpoint to get or set, a value from \ref Audio_EndpointControls_t. + * \param[in,out] DataLength For SET operations, the length of the parameter data to set. For GET operations, the maximum + * length of the retrieved data. When NULL, the function should return whether the given property + * and parameter is valid for the requested endpoint without reading or modifying the Data buffer. + * \param[in,out] Data Pointer to a location where the parameter data is stored for SET operations, or where + * the retrieved data is to be stored for GET operations. + * + * \return Boolean true if the property get/set was successful, false otherwise + */ + bool CALLBACK_Audio_GetSetEndpointProperty(USB_ClassInfo_Audio_Device_t* const AudioInterfaceInfo, + const uint8_t EndpointProperty, + const uint8_t EndpointIndex, + const uint8_t EndpointControl, + uint16_t* const DataLength, + uint8_t* Data); /* Inline Functions: */ /** General management task for a given Audio class interface, required for the correct operation of the interface. This should diff --git a/LUFA/Drivers/USB/Core/StdRequestType.h b/LUFA/Drivers/USB/Core/StdRequestType.h index e3e30f95f5..83f59afc62 100644 --- a/LUFA/Drivers/USB/Core/StdRequestType.h +++ b/LUFA/Drivers/USB/Core/StdRequestType.h @@ -74,8 +74,8 @@ */ #define CONTROL_REQTYPE_TYPE 0x60 - /** Mask for the request type parameter, to indicate the recipient of the request (Standard, Class - * or Vendor Specific). The result of this mask should then be compared to the request recipient + /** Mask for the request type parameter, to indicate the recipient of the request (Device, Interface + * Endpoint or Other). The result of this mask should then be compared to the request recipient * masks. * * \see REQREC_* macros for masks indicating the request recipient. diff --git a/LUFA/ManPages/ChangeLog.txt b/LUFA/ManPages/ChangeLog.txt index 27a25e75f1..f0683039b2 100644 --- a/LUFA/ManPages/ChangeLog.txt +++ b/LUFA/ManPages/ChangeLog.txt @@ -13,6 +13,7 @@ * tokens as an alternative to tokens defined in the project makefile * - Added new USB_Host_SetInterfaceAltSetting() convenience function for the selection of an interface's alternative setting * - Added Audio class control request definitions + * - Added new callback to the Audio Class driver to allow for endpoint control manipulations such as data sample rates * - Library Applications: * - Added RNDIS device mode to the Webserver project * - Added new MediaControl project @@ -27,13 +28,14 @@ * the supported audio sampling rates, to allow for multiple audio interfaces with different numbers of supported rates and/or * continuous sample rates * - Library Applications: - * - None + * - Modified the Class Driver AudioInput and AudioOutput demos to support multiple sample rates * * Fixed: * - Core: * - None * - Library Applications: * - Fixed incorrect signature in the CDC and DFU class bootloaders for the ATMEGA8U2 + * - Fixed KeyboardHost and KeyboardHostWithParser demos displaying incorrect values when numerical keys were pressed * * \section Sec_ChangeLog110528 Version 110528 * New: diff --git a/LUFA/ManPages/FutureChanges.txt b/LUFA/ManPages/FutureChanges.txt index 4016bf52b6..75dd9e7292 100644 --- a/LUFA/ManPages/FutureChanges.txt +++ b/LUFA/ManPages/FutureChanges.txt @@ -28,10 +28,11 @@ * -# Write LUFA tutorials * - Demos/Projects * -# Device/Host USB bridge - * -# Alternative (USB-IF endorsed) USB-CDC Ethernet Class * -# Finish incomplete demos and projects * -# Add class driver support for Audio Host class * -# Add class driver support for Test and Measurement class + * -# Add class driver support for EEM class + * -# Add class driver support for ECM class * -# Fix up Audio class support - add support for mixers, etc., add support for GET/SET commands * - Ports * -# Complete AVR32 port for existing devices, add UC3C support diff --git a/LUFA/ManPages/VIDAndPIDValues.txt b/LUFA/ManPages/VIDAndPIDValues.txt index 17d9e1782d..d05334d9a0 100644 --- a/LUFA/ManPages/VIDAndPIDValues.txt +++ b/LUFA/ManPages/VIDAndPIDValues.txt @@ -361,7 +361,7 @@ * 0x206B * * - * Currently Unallocated + * Class Driver Audio Input Demo (Multiple Sample Rates) * * * @@ -373,7 +373,7 @@ * 0x206C * * - * Currently Unallocated + * Class Driver Audio Output Demo (Multiple Sample Rates) * * * diff --git a/Projects/AVRISP-MKII/Lib/ISP/ISPProtocol.c b/Projects/AVRISP-MKII/Lib/ISP/ISPProtocol.c index 42e436cdf3..e9e92f99a0 100644 --- a/Projects/AVRISP-MKII/Lib/ISP/ISPProtocol.c +++ b/Projects/AVRISP-MKII/Lib/ISP/ISPProtocol.c @@ -236,12 +236,12 @@ void ISPProtocol_ProgramMemory(uint8_t V2Command) /* EEPROM just increments the address each byte, flash needs to increment on each word and * also check to ensure that a LOAD EXTENDED ADDRESS command is issued each time the extended - * address boundary has been crossed */ + * address boundary has been crossed during FLASH memory programming */ if ((CurrentByte & 0x01) || (V2Command == CMD_PROGRAM_EEPROM_ISP)) { CurrentAddress++; - if ((V2Command != CMD_PROGRAM_EEPROM_ISP) && !(CurrentAddress & 0xFFFF)) + if ((V2Command == CMD_PROGRAM_FLASH_ISP) && !(CurrentAddress & 0xFFFF)) MustLoadExtendedAddress = true; } }