diff options
Diffstat (limited to 'lib/lufa/LUFA/Drivers/USB/Class/Device')
14 files changed, 3766 insertions, 0 deletions
diff --git a/lib/lufa/LUFA/Drivers/USB/Class/Device/AudioClassDevice.c b/lib/lufa/LUFA/Drivers/USB/Class/Device/AudioClassDevice.c new file mode 100644 index 0000000000..08cbeb7061 --- /dev/null +++ b/lib/lufa/LUFA/Drivers/USB/Class/Device/AudioClassDevice.c @@ -0,0 +1,197 @@ +/* + LUFA Library + Copyright (C) Dean Camera, 2017. + + dean [at] fourwalledcubicle [dot] com + www.lufa-lib.org +*/ + +/* + Copyright 2017 Dean Camera (dean [at] fourwalledcubicle [dot] com) + + Permission to use, copy, modify, distribute, and sell this + software and its documentation for any purpose is hereby granted + without fee, provided that the above copyright notice appear in + all copies and that both that the copyright notice and this + permission notice and warranty disclaimer appear in supporting + documentation, and that the name of the author not be used in + advertising or publicity pertaining to distribution of the + software without specific, written prior permission. + + The author disclaims all warranties with regard to this + software, including all implied warranties of merchantability + and fitness. In no event shall the author be liable for any + special, indirect or consequential damages or any damages + whatsoever resulting from loss of use, data or profits, whether + in an action of contract, negligence or other tortious action, + arising out of or in connection with the use or performance of + this software. +*/ + +#define __INCLUDE_FROM_USB_DRIVER +#include "../../Core/USBMode.h" + +#if defined(USB_CAN_BE_DEVICE) + +#define __INCLUDE_FROM_AUDIO_DRIVER +#define __INCLUDE_FROM_AUDIO_DEVICE_C +#include "AudioClassDevice.h" + +void Audio_Device_ProcessControlRequest(USB_ClassInfo_Audio_Device_t* const AudioInterfaceInfo) +{ + if (!(Endpoint_IsSETUPReceived())) + return; + + if ((USB_ControlRequest.bmRequestType & CONTROL_REQTYPE_RECIPIENT) == REQREC_INTERFACE) + { + uint8_t InterfaceIndex = (USB_ControlRequest.wIndex & 0xFF); + + if ((InterfaceIndex != AudioInterfaceInfo->Config.ControlInterfaceNumber) && + (InterfaceIndex != AudioInterfaceInfo->Config.StreamingInterfaceNumber)) + { + return; + } + } + else if ((USB_ControlRequest.bmRequestType & CONTROL_REQTYPE_RECIPIENT) == REQREC_ENDPOINT) + { + uint8_t EndpointAddress = (USB_ControlRequest.wIndex & 0xFF); + + if ((EndpointAddress != AudioInterfaceInfo->Config.DataINEndpoint.Address) && + (EndpointAddress != AudioInterfaceInfo->Config.DataOUTEndpoint.Address)) + { + return; + } + } + + switch (USB_ControlRequest.bRequest) + { + case REQ_SetInterface: + if (USB_ControlRequest.bmRequestType == (REQDIR_HOSTTODEVICE | REQTYPE_STANDARD | REQREC_INTERFACE)) + { + Endpoint_ClearSETUP(); + Endpoint_ClearStatusStage(); + + AudioInterfaceInfo->State.InterfaceEnabled = ((USB_ControlRequest.wValue & 0xFF) != 0); + EVENT_Audio_Device_StreamStartStop(AudioInterfaceInfo); + } + + break; + case AUDIO_REQ_GetStatus: + if ((USB_ControlRequest.bmRequestType == (REQDIR_HOSTTODEVICE | REQTYPE_CLASS | REQREC_INTERFACE)) || + (USB_ControlRequest.bmRequestType == (REQDIR_HOSTTODEVICE | REQTYPE_CLASS | REQREC_ENDPOINT))) + { + 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 & CONTROL_REQTYPE_RECIPIENT) == REQREC_ENDPOINT) + { + uint8_t EndpointProperty = USB_ControlRequest.bRequest; + uint8_t EndpointAddress = (uint8_t)USB_ControlRequest.wIndex; + uint8_t EndpointControl = (USB_ControlRequest.wValue >> 8); + + if (CALLBACK_Audio_Device_GetSetEndpointProperty(AudioInterfaceInfo, EndpointProperty, EndpointAddress, + 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_Device_GetSetEndpointProperty(AudioInterfaceInfo, EndpointProperty, EndpointAddress, + EndpointControl, &ValueLength, Value); + } + } + else if ((USB_ControlRequest.bmRequestType & CONTROL_REQTYPE_RECIPIENT) == REQREC_INTERFACE) + { + uint8_t Property = USB_ControlRequest.bRequest; + uint8_t Entity = (USB_ControlRequest.wIndex >> 8); + uint16_t Parameter = USB_ControlRequest.wValue; + + if (CALLBACK_Audio_Device_GetSetInterfaceProperty(AudioInterfaceInfo, Property, Entity, + Parameter, 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_Device_GetSetInterfaceProperty(AudioInterfaceInfo, Property, Entity, + Parameter, &ValueLength, Value); + } + } + + break; + case AUDIO_REQ_GetCurrent: + case AUDIO_REQ_GetMinimum: + case AUDIO_REQ_GetMaximum: + case AUDIO_REQ_GetResolution: + if ((USB_ControlRequest.bmRequestType & CONTROL_REQTYPE_RECIPIENT) == REQREC_ENDPOINT) + { + uint8_t EndpointProperty = USB_ControlRequest.bRequest; + uint8_t EndpointAddress = (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_Device_GetSetEndpointProperty(AudioInterfaceInfo, EndpointProperty, EndpointAddress, + EndpointControl, &ValueLength, Value)) + { + Endpoint_ClearSETUP(); + Endpoint_Write_Control_Stream_LE(Value, ValueLength); + Endpoint_ClearOUT(); + } + } + else if ((USB_ControlRequest.bmRequestType & CONTROL_REQTYPE_RECIPIENT) == REQREC_INTERFACE) + { + uint8_t Property = USB_ControlRequest.bRequest; + uint8_t Entity = (USB_ControlRequest.wIndex >> 8); + uint16_t Parameter = USB_ControlRequest.wValue; + uint16_t ValueLength = USB_ControlRequest.wLength; + uint8_t Value[ValueLength]; + + if (CALLBACK_Audio_Device_GetSetInterfaceProperty(AudioInterfaceInfo, Property, Entity, + Parameter, &ValueLength, Value)) + { + Endpoint_ClearSETUP(); + Endpoint_Write_Control_Stream_LE(Value, ValueLength); + Endpoint_ClearOUT(); + } + } + + break; + } +} + +bool Audio_Device_ConfigureEndpoints(USB_ClassInfo_Audio_Device_t* const AudioInterfaceInfo) +{ + memset(&AudioInterfaceInfo->State, 0x00, sizeof(AudioInterfaceInfo->State)); + + AudioInterfaceInfo->Config.DataINEndpoint.Type = EP_TYPE_ISOCHRONOUS; + AudioInterfaceInfo->Config.DataOUTEndpoint.Type = EP_TYPE_ISOCHRONOUS; + + if (!(Endpoint_ConfigureEndpointTable(&AudioInterfaceInfo->Config.DataINEndpoint, 1))) + return false; + + if (!(Endpoint_ConfigureEndpointTable(&AudioInterfaceInfo->Config.DataOUTEndpoint, 1))) + return false; + + return true; +} + +void Audio_Device_Event_Stub(void) +{ + +} + +#endif + diff --git a/lib/lufa/LUFA/Drivers/USB/Class/Device/AudioClassDevice.h b/lib/lufa/LUFA/Drivers/USB/Class/Device/AudioClassDevice.h new file mode 100644 index 0000000000..ca63511b20 --- /dev/null +++ b/lib/lufa/LUFA/Drivers/USB/Class/Device/AudioClassDevice.h @@ -0,0 +1,396 @@ +/* + LUFA Library + Copyright (C) Dean Camera, 2017. + + dean [at] fourwalledcubicle [dot] com + www.lufa-lib.org +*/ + +/* + Copyright 2017 Dean Camera (dean [at] fourwalledcubicle [dot] com) + + Permission to use, copy, modify, distribute, and sell this + software and its documentation for any purpose is hereby granted + without fee, provided that the above copyright notice appear in + all copies and that both that the copyright notice and this + permission notice and warranty disclaimer appear in supporting + documentation, and that the name of the author not be used in + advertising or publicity pertaining to distribution of the + software without specific, written prior permission. + + The author disclaims all warranties with regard to this + software, including all implied warranties of merchantability + and fitness. In no event shall the author be liable for any + special, indirect or consequential damages or any damages + whatsoever resulting from loss of use, data or profits, whether + in an action of contract, negligence or other tortious action, + arising out of or in connection with the use or performance of + this software. +*/ + +/** \file + * \brief Device mode driver for the library USB Audio 1.0 Class driver. + * + * Device mode driver for the library USB Audio 1.0 Class driver. + * + * \note This file should not be included directly. It is automatically included as needed by the USB module driver + * dispatch header located in LUFA/Drivers/USB.h. + */ + +/** \ingroup Group_USBClassAudio + * \defgroup Group_USBClassAudioDevice Audio 1.0 Class Device Mode Driver + * + * \section Sec_USBClassAudioDevice_Dependencies Module Source Dependencies + * The following files must be built with any user project that uses this module: + * - LUFA/Drivers/USB/Class/Device/AudioClassDevice.c <i>(Makefile source module name: LUFA_SRC_USBCLASS)</i> + * + * \section Sec_USBClassAudioDevice_ModDescription Module Description + * Device Mode USB Class driver framework interface, for the Audio 1.0 USB Class driver. + * + * @{ + */ + +#ifndef _AUDIO_CLASS_DEVICE_H_ +#define _AUDIO_CLASS_DEVICE_H_ + + /* Includes: */ + #include "../../USB.h" + #include "../Common/AudioClassCommon.h" + + /* Enable C linkage for C++ Compilers: */ + #if defined(__cplusplus) + extern "C" { + #endif + + /* Preprocessor Checks: */ + #if !defined(__INCLUDE_FROM_AUDIO_DRIVER) + #error Do not include this file directly. Include LUFA/Drivers/USB.h instead. + #endif + + /* Public Interface - May be used in end-application: */ + /* Type Defines: */ + /** \brief Audio Class Device Mode Configuration and State Structure. + * + * Class state structure. An instance of this structure should be made for each Audio interface + * within the user application, and passed to each of the Audio class driver functions as the + * \c AudioInterfaceInfo parameter. This stores each Audio interface's configuration and state information. + */ + typedef struct + { + struct + { + uint8_t ControlInterfaceNumber; /**< Index of the Audio Control interface within the device this + * structure controls. + */ + uint8_t StreamingInterfaceNumber; /**< Index of the Audio Streaming interface within the device this + * structure controls. + */ + + USB_Endpoint_Table_t DataINEndpoint; /**< Data IN endpoint configuration table. */ + USB_Endpoint_Table_t DataOUTEndpoint; /**< Data OUT endpoint configuration table. */ + } Config; /**< Config data for the USB class interface within the device. All elements in this section + * <b>must</b> be set or the interface will fail to enumerate and operate correctly. + */ + struct + { + bool InterfaceEnabled; /**< Set and cleared by the class driver to indicate if the host has enabled the streaming endpoints + * of the Audio Streaming interface. + */ + } State; /**< State data for the USB class interface within the device. All elements in this section + * are reset to their defaults when the interface is enumerated. + */ + } USB_ClassInfo_Audio_Device_t; + + /* Function Prototypes: */ + /** Configures the endpoints of a given Audio interface, ready for use. This should be linked to the library + * \ref EVENT_USB_Device_ConfigurationChanged() event so that the endpoints are configured when the configuration containing the + * given Audio interface is selected. + * + * \param[in,out] AudioInterfaceInfo Pointer to a structure containing an Audio Class configuration and state. + * + * \return Boolean \c true if the endpoints were successfully configured, \c false otherwise. + */ + bool Audio_Device_ConfigureEndpoints(USB_ClassInfo_Audio_Device_t* const AudioInterfaceInfo) ATTR_NON_NULL_PTR_ARG(1); + + /** Processes incoming control requests from the host, that are directed to the given Audio class interface. This should be + * linked to the library \ref EVENT_USB_Device_ControlRequest() event. + * + * \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 retrieved 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] EndpointAddress Address 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 \c true if the property GET/SET was successful, \c false otherwise + */ + bool CALLBACK_Audio_Device_GetSetEndpointProperty(USB_ClassInfo_Audio_Device_t* const AudioInterfaceInfo, + const uint8_t EndpointProperty, + const uint8_t EndpointAddress, + const uint8_t EndpointControl, + uint16_t* const DataLength, + uint8_t* Data) ATTR_NON_NULL_PTR_ARG(1); + + /** Audio class driver callback for the setting and retrieval of streaming interface properties. This callback must be implemented + * in the user application to handle property manipulations on streaming audio interfaces. + * + * When the DataLength parameter is NULL, this callback should only indicate whether the specified operation is valid for + * the given entity and should return as fast as possible. When non-NULL, this value may be altered for GET operations + * to indicate the size of the retrieved 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] Property Property of the interface to get or set, a value from \ref Audio_ClassRequests_t. + * \param[in] EntityAddress Address of the audio entity whose property is being referenced. + * \param[in] Parameter Parameter of the entity to get or set, specific to each type of entity (see USB Audio specification). + * \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 \c true if the property GET/SET was successful, \c false otherwise + */ + bool CALLBACK_Audio_Device_GetSetInterfaceProperty(USB_ClassInfo_Audio_Device_t* const AudioInterfaceInfo, + const uint8_t Property, + const uint8_t EntityAddress, + const uint16_t Parameter, + uint16_t* const DataLength, + uint8_t* Data) ATTR_NON_NULL_PTR_ARG(1); + + /** Audio class driver event for an Audio Stream start/stop change. This event fires each time the device receives a stream enable or + * disable control request from the host, to start and stop the audio stream. The current state of the stream can be determined by the + * State.InterfaceEnabled value inside the Audio interface structure passed as a parameter. + * + * \param[in,out] AudioInterfaceInfo Pointer to a structure containing an Audio Class configuration and state. + */ + void EVENT_Audio_Device_StreamStartStop(USB_ClassInfo_Audio_Device_t* const AudioInterfaceInfo); + + /* Inline Functions: */ + /** General management task for a given Audio class interface, required for the correct operation of the interface. This should + * be called frequently in the main program loop, before the master USB management task \ref USB_USBTask(). + * + * \param[in,out] AudioInterfaceInfo Pointer to a structure containing an Audio Class configuration and state. + */ + static inline void Audio_Device_USBTask(USB_ClassInfo_Audio_Device_t* const AudioInterfaceInfo) + ATTR_NON_NULL_PTR_ARG(1) ATTR_ALWAYS_INLINE; + static inline void Audio_Device_USBTask(USB_ClassInfo_Audio_Device_t* const AudioInterfaceInfo) + { + (void)AudioInterfaceInfo; + } + + /** Determines if the given audio interface is ready for a sample to be read from it, and selects the streaming + * OUT endpoint ready for reading. + * + * \pre This function must only be called when the Device state machine is in the \ref DEVICE_STATE_Configured state or + * the call will fail. + * + * \param[in,out] AudioInterfaceInfo Pointer to a structure containing an Audio Class configuration and state. + * + * \return Boolean \c true if the given Audio interface has a sample to be read, \c false otherwise. + */ + static inline bool Audio_Device_IsSampleReceived(USB_ClassInfo_Audio_Device_t* const AudioInterfaceInfo) + ATTR_NON_NULL_PTR_ARG(1) ATTR_ALWAYS_INLINE; + static inline bool Audio_Device_IsSampleReceived(USB_ClassInfo_Audio_Device_t* const AudioInterfaceInfo) + { + if ((USB_DeviceState != DEVICE_STATE_Configured) || !(AudioInterfaceInfo->State.InterfaceEnabled)) + return false; + + Endpoint_SelectEndpoint(AudioInterfaceInfo->Config.DataOUTEndpoint.Address); + return Endpoint_IsOUTReceived(); + } + + /** Determines if the given audio interface is ready to accept the next sample to be written to it, and selects + * the streaming IN endpoint ready for writing. + * + * \pre This function must only be called when the Device state machine is in the \ref DEVICE_STATE_Configured state or + * the call will fail. + * + * \param[in,out] AudioInterfaceInfo Pointer to a structure containing an Audio Class configuration and state. + * + * \return Boolean \c true if the given Audio interface is ready to accept the next sample, \c false otherwise. + */ + static inline bool Audio_Device_IsReadyForNextSample(USB_ClassInfo_Audio_Device_t* const AudioInterfaceInfo) + ATTR_NON_NULL_PTR_ARG(1) ATTR_ALWAYS_INLINE; + static inline bool Audio_Device_IsReadyForNextSample(USB_ClassInfo_Audio_Device_t* const AudioInterfaceInfo) + { + if ((USB_DeviceState != DEVICE_STATE_Configured) || !(AudioInterfaceInfo->State.InterfaceEnabled)) + return false; + + Endpoint_SelectEndpoint(AudioInterfaceInfo->Config.DataINEndpoint.Address); + return Endpoint_IsINReady(); + } + + /** Reads the next 8-bit audio sample from the current audio interface. + * + * \pre This should be preceded immediately by a call to the \ref Audio_Device_IsSampleReceived() function to ensure + * that the correct endpoint is selected and ready for data. + * + * \param[in,out] AudioInterfaceInfo Pointer to a structure containing an Audio Class configuration and state. + * + * \return Signed 8-bit audio sample from the audio interface. + */ + static inline int8_t Audio_Device_ReadSample8(USB_ClassInfo_Audio_Device_t* const AudioInterfaceInfo) + ATTR_NON_NULL_PTR_ARG(1) ATTR_ALWAYS_INLINE; + static inline int8_t Audio_Device_ReadSample8(USB_ClassInfo_Audio_Device_t* const AudioInterfaceInfo) + { + int8_t Sample; + + (void)AudioInterfaceInfo; + + Sample = Endpoint_Read_8(); + + if (!(Endpoint_BytesInEndpoint())) + Endpoint_ClearOUT(); + + return Sample; + } + + /** Reads the next 16-bit audio sample from the current audio interface. + * + * \pre This should be preceded immediately by a call to the \ref Audio_Device_IsSampleReceived() function to ensure + * that the correct endpoint is selected and ready for data. + * + * \param[in,out] AudioInterfaceInfo Pointer to a structure containing an Audio Class configuration and state. + * + * \return Signed 16-bit audio sample from the audio interface. + */ + static inline int16_t Audio_Device_ReadSample16(USB_ClassInfo_Audio_Device_t* const AudioInterfaceInfo) + ATTR_NON_NULL_PTR_ARG(1) ATTR_ALWAYS_INLINE; + static inline int16_t Audio_Device_ReadSample16(USB_ClassInfo_Audio_Device_t* const AudioInterfaceInfo) + { + int16_t Sample; + + (void)AudioInterfaceInfo; + + Sample = (int16_t)Endpoint_Read_16_LE(); + + if (!(Endpoint_BytesInEndpoint())) + Endpoint_ClearOUT(); + + return Sample; + } + + /** Reads the next 24-bit audio sample from the current audio interface. + * + * \pre This should be preceded immediately by a call to the \ref Audio_Device_IsSampleReceived() function to ensure + * that the correct endpoint is selected and ready for data. + * + * \param[in,out] AudioInterfaceInfo Pointer to a structure containing an Audio Class configuration and state. + * + * \return Signed 24-bit audio sample from the audio interface. + */ + static inline int32_t Audio_Device_ReadSample24(USB_ClassInfo_Audio_Device_t* const AudioInterfaceInfo) + ATTR_NON_NULL_PTR_ARG(1) ATTR_ALWAYS_INLINE; + static inline int32_t Audio_Device_ReadSample24(USB_ClassInfo_Audio_Device_t* const AudioInterfaceInfo) + { + int32_t Sample; + + (void)AudioInterfaceInfo; + + Sample = (((uint32_t)Endpoint_Read_8() << 16) | Endpoint_Read_16_LE()); + + if (!(Endpoint_BytesInEndpoint())) + Endpoint_ClearOUT(); + + return Sample; + } + + /** Writes the next 8-bit audio sample to the current audio interface. + * + * \pre This should be preceded immediately by a call to the \ref Audio_Device_IsReadyForNextSample() function to + * ensure that the correct endpoint is selected and ready for data. + * + * \param[in,out] AudioInterfaceInfo Pointer to a structure containing an Audio Class configuration and state. + * \param[in] Sample Signed 8-bit audio sample. + */ + static inline void Audio_Device_WriteSample8(USB_ClassInfo_Audio_Device_t* const AudioInterfaceInfo, + const int8_t Sample) ATTR_NON_NULL_PTR_ARG(1) ATTR_ALWAYS_INLINE; + static inline void Audio_Device_WriteSample8(USB_ClassInfo_Audio_Device_t* const AudioInterfaceInfo, + const int8_t Sample) + { + Endpoint_Write_8(Sample); + + if (Endpoint_BytesInEndpoint() == AudioInterfaceInfo->Config.DataINEndpoint.Size) + Endpoint_ClearIN(); + } + + /** Writes the next 16-bit audio sample to the current audio interface. + * + * \pre This should be preceded immediately by a call to the \ref Audio_Device_IsReadyForNextSample() function to + * ensure that the correct endpoint is selected and ready for data. + * + * \param[in,out] AudioInterfaceInfo Pointer to a structure containing an Audio Class configuration and state. + * \param[in] Sample Signed 16-bit audio sample. + */ + static inline void Audio_Device_WriteSample16(USB_ClassInfo_Audio_Device_t* const AudioInterfaceInfo, + const int16_t Sample) ATTR_NON_NULL_PTR_ARG(1) ATTR_ALWAYS_INLINE; + static inline void Audio_Device_WriteSample16(USB_ClassInfo_Audio_Device_t* const AudioInterfaceInfo, + const int16_t Sample) + { + Endpoint_Write_16_LE(Sample); + + if (Endpoint_BytesInEndpoint() == AudioInterfaceInfo->Config.DataINEndpoint.Size) + Endpoint_ClearIN(); + } + + /** Writes the next 24-bit audio sample to the current audio interface. + * + * \pre This should be preceded immediately by a call to the \ref Audio_Device_IsReadyForNextSample() function to + * ensure that the correct endpoint is selected and ready for data. + * + * \param[in,out] AudioInterfaceInfo Pointer to a structure containing an Audio Class configuration and state. + * \param[in] Sample Signed 24-bit audio sample. + */ + static inline void Audio_Device_WriteSample24(USB_ClassInfo_Audio_Device_t* const AudioInterfaceInfo, + const int32_t Sample) ATTR_NON_NULL_PTR_ARG(1) ATTR_ALWAYS_INLINE; + static inline void Audio_Device_WriteSample24(USB_ClassInfo_Audio_Device_t* const AudioInterfaceInfo, + const int32_t Sample) + { + Endpoint_Write_16_LE(Sample); + Endpoint_Write_8(Sample >> 16); + + if (Endpoint_BytesInEndpoint() == AudioInterfaceInfo->Config.DataINEndpoint.Size) + Endpoint_ClearIN(); + } + + /* Private Interface - For use in library only: */ + #if !defined(__DOXYGEN__) + /* Function Prototypes: */ + #if defined(__INCLUDE_FROM_AUDIO_DEVICE_C) + void Audio_Device_Event_Stub(void) ATTR_CONST; + + void EVENT_Audio_Device_StreamStartStop(USB_ClassInfo_Audio_Device_t* const AudioInterfaceInfo) + ATTR_WEAK ATTR_NON_NULL_PTR_ARG(1) ATTR_ALIAS(Audio_Device_Event_Stub); + #endif + + #endif + + /* Disable C linkage for C++ Compilers: */ + #if defined(__cplusplus) + } + #endif + +#endif + +/** @} */ + diff --git a/lib/lufa/LUFA/Drivers/USB/Class/Device/CDCClassDevice.c b/lib/lufa/LUFA/Drivers/USB/Class/Device/CDCClassDevice.c new file mode 100644 index 0000000000..867548c00b --- /dev/null +++ b/lib/lufa/LUFA/Drivers/USB/Class/Device/CDCClassDevice.c @@ -0,0 +1,362 @@ +/* + LUFA Library + Copyright (C) Dean Camera, 2017. + + dean [at] fourwalledcubicle [dot] com + www.lufa-lib.org +*/ + +/* + Copyright 2017 Dean Camera (dean [at] fourwalledcubicle [dot] com) + + Permission to use, copy, modify, distribute, and sell this + software and its documentation for any purpose is hereby granted + without fee, provided that the above copyright notice appear in + all copies and that both that the copyright notice and this + permission notice and warranty disclaimer appear in supporting + documentation, and that the name of the author not be used in + advertising or publicity pertaining to distribution of the + software without specific, written prior permission. + + The author disclaims all warranties with regard to this + software, including all implied warranties of merchantability + and fitness. In no event shall the author be liable for any + special, indirect or consequential damages or any damages + whatsoever resulting from loss of use, data or profits, whether + in an action of contract, negligence or other tortious action, + arising out of or in connection with the use or performance of + this software. +*/ + +#define __INCLUDE_FROM_USB_DRIVER +#include "../../Core/USBMode.h" + +#if defined(USB_CAN_BE_DEVICE) + +#define __INCLUDE_FROM_CDC_DRIVER +#define __INCLUDE_FROM_CDC_DEVICE_C +#include "CDCClassDevice.h" + +void CDC_Device_ProcessControlRequest(USB_ClassInfo_CDC_Device_t* const CDCInterfaceInfo) +{ + if (!(Endpoint_IsSETUPReceived())) + return; + + if (USB_ControlRequest.wIndex != CDCInterfaceInfo->Config.ControlInterfaceNumber) + return; + + switch (USB_ControlRequest.bRequest) + { + case CDC_REQ_GetLineEncoding: + if (USB_ControlRequest.bmRequestType == (REQDIR_DEVICETOHOST | REQTYPE_CLASS | REQREC_INTERFACE)) + { + Endpoint_ClearSETUP(); + + while (!(Endpoint_IsINReady())); + + Endpoint_Write_32_LE(CDCInterfaceInfo->State.LineEncoding.BaudRateBPS); + Endpoint_Write_8(CDCInterfaceInfo->State.LineEncoding.CharFormat); + Endpoint_Write_8(CDCInterfaceInfo->State.LineEncoding.ParityType); + Endpoint_Write_8(CDCInterfaceInfo->State.LineEncoding.DataBits); + + Endpoint_ClearIN(); + Endpoint_ClearStatusStage(); + } + + break; + case CDC_REQ_SetLineEncoding: + if (USB_ControlRequest.bmRequestType == (REQDIR_HOSTTODEVICE | REQTYPE_CLASS | REQREC_INTERFACE)) + { + Endpoint_ClearSETUP(); + + while (!(Endpoint_IsOUTReceived())) + { + if (USB_DeviceState == DEVICE_STATE_Unattached) + return; + } + + CDCInterfaceInfo->State.LineEncoding.BaudRateBPS = Endpoint_Read_32_LE(); + CDCInterfaceInfo->State.LineEncoding.CharFormat = Endpoint_Read_8(); + CDCInterfaceInfo->State.LineEncoding.ParityType = Endpoint_Read_8(); + CDCInterfaceInfo->State.LineEncoding.DataBits = Endpoint_Read_8(); + + Endpoint_ClearOUT(); + Endpoint_ClearStatusStage(); + + EVENT_CDC_Device_LineEncodingChanged(CDCInterfaceInfo); + } + + break; + case CDC_REQ_SetControlLineState: + if (USB_ControlRequest.bmRequestType == (REQDIR_HOSTTODEVICE | REQTYPE_CLASS | REQREC_INTERFACE)) + { + Endpoint_ClearSETUP(); + Endpoint_ClearStatusStage(); + + CDCInterfaceInfo->State.ControlLineStates.HostToDevice = USB_ControlRequest.wValue; + + EVENT_CDC_Device_ControLineStateChanged(CDCInterfaceInfo); + } + + break; + case CDC_REQ_SendBreak: + if (USB_ControlRequest.bmRequestType == (REQDIR_HOSTTODEVICE | REQTYPE_CLASS | REQREC_INTERFACE)) + { + Endpoint_ClearSETUP(); + Endpoint_ClearStatusStage(); + + EVENT_CDC_Device_BreakSent(CDCInterfaceInfo, (uint8_t)USB_ControlRequest.wValue); + } + + break; + } +} + +bool CDC_Device_ConfigureEndpoints(USB_ClassInfo_CDC_Device_t* const CDCInterfaceInfo) +{ + memset(&CDCInterfaceInfo->State, 0x00, sizeof(CDCInterfaceInfo->State)); + + CDCInterfaceInfo->Config.DataINEndpoint.Type = EP_TYPE_BULK; + CDCInterfaceInfo->Config.DataOUTEndpoint.Type = EP_TYPE_BULK; + CDCInterfaceInfo->Config.NotificationEndpoint.Type = EP_TYPE_INTERRUPT; + + if (!(Endpoint_ConfigureEndpointTable(&CDCInterfaceInfo->Config.DataINEndpoint, 1))) + return false; + + if (!(Endpoint_ConfigureEndpointTable(&CDCInterfaceInfo->Config.DataOUTEndpoint, 1))) + return false; + + if (!(Endpoint_ConfigureEndpointTable(&CDCInterfaceInfo->Config.NotificationEndpoint, 1))) + return false; + + return true; +} + +void CDC_Device_USBTask(USB_ClassInfo_CDC_Device_t* const CDCInterfaceInfo) +{ + if ((USB_DeviceState != DEVICE_STATE_Configured) || !(CDCInterfaceInfo->State.LineEncoding.BaudRateBPS)) + return; + + #if !defined(NO_CLASS_DRIVER_AUTOFLUSH) + Endpoint_SelectEndpoint(CDCInterfaceInfo->Config.DataINEndpoint.Address); + + if (Endpoint_IsINReady()) + CDC_Device_Flush(CDCInterfaceInfo); + #endif +} + +uint8_t CDC_Device_SendString(USB_ClassInfo_CDC_Device_t* const CDCInterfaceInfo, + const char* const String) +{ + if ((USB_DeviceState != DEVICE_STATE_Configured) || !(CDCInterfaceInfo->State.LineEncoding.BaudRateBPS)) + return ENDPOINT_RWSTREAM_DeviceDisconnected; + + Endpoint_SelectEndpoint(CDCInterfaceInfo->Config.DataINEndpoint.Address); + return Endpoint_Write_Stream_LE(String, strlen(String), NULL); +} + +uint8_t CDC_Device_SendString_P(USB_ClassInfo_CDC_Device_t* const CDCInterfaceInfo, + const char* const String) +{ + if ((USB_DeviceState != DEVICE_STATE_Configured) || !(CDCInterfaceInfo->State.LineEncoding.BaudRateBPS)) + return ENDPOINT_RWSTREAM_DeviceDisconnected; + + Endpoint_SelectEndpoint(CDCInterfaceInfo->Config.DataINEndpoint.Address); + return Endpoint_Write_PStream_LE(String, strlen_P(String), NULL); |