From 044ad7c3987460ede48ff27afd6bdb0ca05a0432 Mon Sep 17 00:00:00 2001 From: Harald Welte Date: Mon, 4 Jul 2011 20:52:54 +0200 Subject: import at91lib from at91lib_20100901_softpack_1_9_v_1_0_svn_v15011 it's sad to see that atmel doesn't publish their svn repo or has a centralized location or even puts proper version/release info into the library itself --- usb/device/audio-speaker/AUDDSpeakerDriver.c | 378 +++++++++++++++++++++++++++ 1 file changed, 378 insertions(+) create mode 100644 usb/device/audio-speaker/AUDDSpeakerDriver.c (limited to 'usb/device/audio-speaker/AUDDSpeakerDriver.c') diff --git a/usb/device/audio-speaker/AUDDSpeakerDriver.c b/usb/device/audio-speaker/AUDDSpeakerDriver.c new file mode 100644 index 0000000..7ca58bd --- /dev/null +++ b/usb/device/audio-speaker/AUDDSpeakerDriver.c @@ -0,0 +1,378 @@ +/* ---------------------------------------------------------------------------- + * ATMEL Microcontroller Software Support + * ---------------------------------------------------------------------------- + * Copyright (c) 2008, Atmel Corporation + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * - Redistributions of source code must retain the above copyright notice, + * this list of conditions and the disclaimer below. + * + * Atmel's name may not be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * DISCLAIMER: THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE + * DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * ---------------------------------------------------------------------------- + */ + +//------------------------------------------------------------------------------ +// Headers +//------------------------------------------------------------------------------ + +#include "AUDDSpeakerDriver.h" +#include "AUDDSpeakerDriverDescriptors.h" +#include "AUDDSpeakerChannel.h" +#include +#include +#include +#include +#include + +//------------------------------------------------------------------------------ +// Internal types +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +/// Audio speaker driver internal state. +//------------------------------------------------------------------------------ +typedef struct { + + /// USB device driver instance. + USBDDriver usbdDriver; + /// List of AUDDSpeakerChannel instances for playback. + AUDDSpeakerChannel channels[AUDDSpeakerDriver_NUMCHANNELS+1]; + +} AUDDSpeakerDriver; + +//------------------------------------------------------------------------------ +// Internal variables +//------------------------------------------------------------------------------ + +/// Global USB audio speaker driver instance. +static AUDDSpeakerDriver auddSpeakerDriver; +/// Array for storing the current setting of each interface. +static unsigned char auddSpeakerDriverInterfaces[2]; +/// Intermediate storage variable for the mute status of a channel. +static unsigned char muted; + +//------------------------------------------------------------------------------ +// Internal functions +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +/// Callback triggered after the new mute status of a channel has been read +/// by AUDDSpeakerDriver_SetFeatureCurrentValue. Changes the mute status +/// of the given channel accordingly. +/// \param channel Number of the channel whose mute status has changed. +//------------------------------------------------------------------------------ +static void AUDDSpeakerDriver_MuteReceived(unsigned int channel) +{ + if (muted) { + + AUDDSpeakerChannel_Mute(&(auddSpeakerDriver.channels[channel])); + } + else { + + AUDDSpeakerChannel_Unmute(&(auddSpeakerDriver.channels[channel])); + } + + USBD_Write(0, 0, 0, 0, 0); +} + +//------------------------------------------------------------------------------ +/// Sets the current value of a particular Feature control of a channel. +/// \param entity Entity number. +/// \param channel Channel number. +/// \param control Control selector value (see TODO). +/// \param length Length of the data containing the new value. +//------------------------------------------------------------------------------ +static void AUDDSpeakerDriver_SetFeatureCurrentValue(unsigned char entity, + unsigned char channel, + unsigned char control, + unsigned short length) +{ + TRACE_INFO_WP("sFeature "); + TRACE_DEBUG("\b(E%d, CS%d, CN%d, L%d) ", + entity, control, channel, length); + + // Check the the requested control is supported + // Control/channel combination not supported + if ((control == AUDFeatureUnitRequest_MUTE) + && (channel < (AUDDSpeakerDriver_NUMCHANNELS+1)) + && (length == 1)) { + + unsigned int argument = channel; // Avoids compiler warning + USBD_Read(0, // Endpoint #0 + &muted, + sizeof(muted), + (TransferCallback) AUDDSpeakerDriver_MuteReceived, + (void *) argument); + } + // Control/channel combination not supported + else { + + USBD_Stall(0); + } +} + +//------------------------------------------------------------------------------ +/// Sends the current value of a particular channel Feature to the USB host. +/// \param entity Entity number. +/// \param channel Channel number. +/// \param control Control selector value (see TODO). +/// \param length Length of the data to return. +//------------------------------------------------------------------------------ +static void AUDDSpeakerDriver_GetFeatureCurrentValue(unsigned char entity, + unsigned char channel, + unsigned char control, + unsigned char length) +{ + TRACE_INFO_WP("gFeature "); + TRACE_DEBUG("\b(CS%d, CN%d, L%d) ", control, channel, length); + + // Check that the requested control is supported + // Master channel mute control + if ((control == AUDFeatureUnitRequest_MUTE) + && (channel < (AUDDSpeakerDriver_NUMCHANNELS+1)) + && (length == 1)) { + + muted = AUDDSpeakerChannel_IsMuted(&(auddSpeakerDriver.channels[channel])); + USBD_Write(0, &muted, sizeof(muted), 0, 0); + } + else { + + USBD_Stall(0); + } +} + +///* +// Function: AUDDSpeakerDriver_SetInterface +// Changes the current active alternate setting of the given interface. +// +// Parameters: +// +//*/ +//TRACE_DEBUG_M("SetInterface(%d,%d) ", setup->wIndex, setup->wValue); +// +// /* Check that interface is AudioStreaming OUT */ +// if (setup->wIndex == INTERFACE_ID_AUDIOSTREAMING_OUT) { +// +// /* Check desired alternate setting */ +// switch (setup->wValue) { +// case 0: +// case 1: +// if (speakerDriver->isOutStreamEnabled != setup->wValue) { +// +// speakerDriver->isOutStreamEnabled = setup->wValue; +// SPK_OutStreamStatusChanged(speakerDriver); +// LED_SetGlowing(LED_OTHER, setup->wValue); +// } +// USB_SendZLP0(usbDriver, 0, 0); +// break; +// +// default: +// USB_Stall(usbDriver, 0); +// } +// } +// else { +// +// USB_Stall(usbDriver, 0); +// } +// + +//------------------------------------------------------------------------------ +// Callback re-implementation +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +/// Triggered when the USB host emits a new SETUP request. The request is +/// forward to . +/// \param request Pointer to a USBGenericRequest instance. +//------------------------------------------------------------------------------ +#if !defined(NOAUTOCALLBACK) +void USBDCallbacks_RequestReceived(const USBGenericRequest *request) +{ + AUDDSpeakerDriver_RequestHandler(request); +} +#endif + +//------------------------------------------------------------------------------ +/// Invoked whenever the active setting of an interface is changed by the +/// host. Changes the status of the third LED accordingly. +/// \param interface Interface number. +/// \param setting Newly active setting. +//------------------------------------------------------------------------------ +void USBDDriverCallbacks_InterfaceSettingChanged(unsigned char interface, + unsigned char setting) +{ + if ((interface == AUDDSpeakerDriverDescriptors_STREAMING) + && (setting == 0)) { + + LED_Clear(USBD_LEDOTHER); + } + else { + + LED_Set(USBD_LEDOTHER); + } +} + +//------------------------------------------------------------------------------ +// Exported functions +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +/// Initializes an USB audio speaker device driver, as well as the underlying +/// USB controller. +//------------------------------------------------------------------------------ +void AUDDSpeakerDriver_Initialize() +{ + // Initialize speaker channels + AUDDSpeakerChannel_Initialize(&(auddSpeakerDriver.channels[0]), + AUDDSpeakerDriver_MASTERCHANNEL, + 0); + AUDDSpeakerChannel_Initialize(&(auddSpeakerDriver.channels[1]), + AUDDSpeakerDriver_LEFTCHANNEL, + 0); + AUDDSpeakerChannel_Initialize(&(auddSpeakerDriver.channels[2]), + AUDDSpeakerDriver_RIGHTCHANNEL, + 0); + + // Initialize the USB driver + USBDDriver_Initialize(&(auddSpeakerDriver.usbdDriver), + &auddSpeakerDriverDescriptors, + auddSpeakerDriverInterfaces); + USBD_Init(); + + // Initialize the third LED to indicate when the audio interface is active + LED_Configure(USBD_LEDOTHER); +} + +//------------------------------------------------------------------------------ +/// Handles audio-specific USB requests sent by the host, and forwards +/// standard ones to the USB device driver. +/// \param request Pointer to a USBGenericRequest instance. +//------------------------------------------------------------------------------ +void AUDDSpeakerDriver_RequestHandler(const USBGenericRequest *request) +{ + unsigned char entity; + unsigned char interface; + + TRACE_INFO_WP("NewReq "); + + // Check if this is a class request + if (USBGenericRequest_GetType(request) == USBGenericRequest_CLASS) { + + // Check if the request is supported + switch (USBGenericRequest_GetRequest(request)) { + + case AUDGenericRequest_SETCUR: + TRACE_INFO_WP( + "sCur(0x%04X) ", + USBGenericRequest_GetIndex(request)); + + // Check the target interface and entity + entity = AUDGenericRequest_GetEntity(request); + interface = AUDGenericRequest_GetInterface(request); + if ((entity == AUDDSpeakerDriverDescriptors_FEATUREUNIT) + && (interface == AUDDSpeakerDriverDescriptors_CONTROL)) { + + AUDDSpeakerDriver_SetFeatureCurrentValue( + entity, + AUDFeatureUnitRequest_GetChannel(request), + AUDFeatureUnitRequest_GetControl(request), + USBGenericRequest_GetLength(request)); + } + else { + + TRACE_WARNING( + "AUDDSpeakerDriver_RequestHandler: Unsupported entity/interface combination (0x%04X)\n\r", + USBGenericRequest_GetIndex(request)); + USBD_Stall(0); + } + break; + + case AUDGenericRequest_GETCUR: + TRACE_INFO_WP( + "gCur(0x%04X) ", + USBGenericRequest_GetIndex(request)); + + // Check the target interface and entity + entity = AUDGenericRequest_GetEntity(request); + interface = AUDGenericRequest_GetInterface(request); + if ((entity == AUDDSpeakerDriverDescriptors_FEATUREUNIT) + && (interface == AUDDSpeakerDriverDescriptors_CONTROL)) { + + AUDDSpeakerDriver_GetFeatureCurrentValue( + entity, + AUDFeatureUnitRequest_GetChannel(request), + AUDFeatureUnitRequest_GetControl(request), + USBGenericRequest_GetLength(request)); + } + else { + + TRACE_WARNING( + "AUDDSpeakerDriver_RequestHandler: Unsupported entity/interface combination (0x%04X)\n\r", + USBGenericRequest_GetIndex(request)); + USBD_Stall(0); + } + break; + + default: + + TRACE_WARNING( + "AUDDSpeakerDriver_RequestHandler: Unsupported request (%d)\n\r", + USBGenericRequest_GetRequest(request)); + USBD_Stall(0); + } + } + // Check if this is a standard request + else if (USBGenericRequest_GetType(request) == USBGenericRequest_STANDARD) { + + // Forward request to the standard handler + USBDDriver_RequestHandler(&(auddSpeakerDriver.usbdDriver), request); + } + // Unsupported request type + else { + + TRACE_WARNING( + "AUDDSpeakerDriver_RequestHandler: Unsupported request type (%d)\n\r", + USBGenericRequest_GetType(request)); + USBD_Stall(0); + } +} + +//------------------------------------------------------------------------------ +/// Reads incoming audio data sent by the USB host into the provided +/// buffer. When the transfer is complete, an optional callback function is +/// invoked. +/// \param buffer Pointer to the data storage buffer. +/// \param length Size of the buffer in bytes. +/// \param callback Optional callback function. +/// \param argument Optional argument to the callback function. +/// \return USBD_STATUS_SUCCESS if the transfer is started successfully; +/// otherwise an error code. +//------------------------------------------------------------------------------ +unsigned char AUDDSpeakerDriver_Read(void *buffer, + unsigned int length, + TransferCallback callback, + void *argument) +{ + return USBD_Read(AUDDSpeakerDriverDescriptors_DATAOUT, + buffer, + length, + callback, + argument); +} + -- cgit v1.2.3