From c3e4c9a25c2910d2d66d52215b3406b13d5b23d5 Mon Sep 17 00:00:00 2001 From: Yuval Adam Date: Sun, 29 Jun 2014 12:34:32 +0300 Subject: Add more board models --- boards/dk-tm4c129x/drivers/usb_sound.c | 769 +++++++++++++++++++++++++++++++++ 1 file changed, 769 insertions(+) create mode 100644 boards/dk-tm4c129x/drivers/usb_sound.c (limited to 'boards/dk-tm4c129x/drivers/usb_sound.c') diff --git a/boards/dk-tm4c129x/drivers/usb_sound.c b/boards/dk-tm4c129x/drivers/usb_sound.c new file mode 100644 index 0000000..3a858bf --- /dev/null +++ b/boards/dk-tm4c129x/drivers/usb_sound.c @@ -0,0 +1,769 @@ +//***************************************************************************** +// +// usb_sound.c - USB host audio handling functions. +// +// Copyright (c) 2013-2014 Texas Instruments Incorporated. All rights reserved. +// Software License Agreement +// +// Texas Instruments (TI) is supplying this software for use solely and +// exclusively on TI's microcontroller products. The software is owned by +// TI and/or its suppliers, and is protected under applicable copyright +// laws. You may not combine this software with "viral" open-source +// software in order to form a larger program. +// +// THIS SOFTWARE IS PROVIDED "AS IS" AND WITH ALL FAULTS. +// NO WARRANTIES, WHETHER EXPRESS, IMPLIED OR STATUTORY, INCLUDING, BUT +// NOT LIMITED TO, IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE APPLY TO THIS SOFTWARE. TI SHALL NOT, UNDER ANY +// CIRCUMSTANCES, BE LIABLE FOR SPECIAL, INCIDENTAL, OR CONSEQUENTIAL +// DAMAGES, FOR ANY REASON WHATSOEVER. +// +// This is part of revision 2.1.0.12573 of the DK-TM4C129X Firmware Package. +// +//***************************************************************************** + +#include +#include +#include "inc/hw_types.h" +#include "inc/hw_memmap.h" +#include "drivers/usb_sound.h" +#include "driverlib/gpio.h" +#include "driverlib/sysctl.h" +#include "driverlib/udma.h" +#include "driverlib/usb.h" +#include "usblib/usblib.h" +#include "usblib/usbmsc.h" +#include "usblib/host/usbhost.h" +#include "usblib/host/usbhaudio.h" + +//***************************************************************************** +// +// The size of the host controller's memory pool in bytes. +// +//***************************************************************************** +#define HCD_MEMORY_SIZE 768 + +//***************************************************************************** +// +// The memory pool to provide to the Host controller driver. +// +//***************************************************************************** +uint8_t g_pHCDPool[HCD_MEMORY_SIZE]; + +//***************************************************************************** +// +// The instance data for the USB host audio driver. +// +//***************************************************************************** +tUSBHostAudioInstance *g_psAudioInstance; + +//***************************************************************************** +// +// Declare the USB Events driver interface. +// +//***************************************************************************** +DECLARE_EVENT_DRIVER(g_sUSBEventDriver, 0, 0, USBHCDEvents); + +//***************************************************************************** +// +// This structure holds the state information for the USB audio device. +// +//***************************************************************************** +static struct +{ + // + // Save the application provided callback function. + // + tUSBBufferCallback pfnCallbackOut; + + // + // Save the application provided callback function. + // + tUSBBufferCallback pfnCallbackIn; + + // + // The event callback for the application. + // + tEventCallback pfnCallbackEvent; + + // + // Volume control multipliers calculated from the information received + // from the audio device. + // + uint32_t pui32Steps[3]; + + // + // The currently pending audio device events. + // + uint32_t ui32EventFlags; + + // + // The current state for the audio device. + // + volatile enum + { + // + // No device is present. + // + eStateNoDevice, + + // + // Audio device is ready. + // + eStateDeviceReady, + + // + // An unsupported device has been attached. + // + eStateUnknownDevice, + + // + // A power fault has occurred. + // + eStatePowerFault + } + iState; + +} g_sAudioState; + +//***************************************************************************** +// +// These defines are used with the ui32EventFlags in the g_sAudioState +// structure. +// +//***************************************************************************** +#define EVENT_OPEN 0x00000001 +#define EVENT_CLOSE 0x00000002 + +//***************************************************************************** +// +// The global that holds all of the host drivers in use in the application. +// In this case, only the host audio class is loaded. +// +//***************************************************************************** +static tUSBHostClassDriver const * const g_ppHostClassDrivers[] = +{ + &g_sUSBHostAudioClassDriver, + &g_sUSBEventDriver +}; + +//***************************************************************************** +// +// This global holds the number of class drivers in the g_ppHostClassDrivers +// list. +// +//***************************************************************************** +static const uint32_t g_ui32NumHostClassDrivers = + sizeof(g_ppHostClassDrivers) / sizeof(tUSBHostClassDriver *); + +//***************************************************************************** +// +// This function was the callback function registered with the USB host audio +// class driver. The only two events that are handled at this point are the +// USBH_AUDIO_EVENT_OPEN and USBH_AUDIO_EVENT_CLOSE which indicate that a new +// audio device has been found or that an existing audio device has been +// disconnected. +// +//***************************************************************************** +static void +AudioCallback(tUSBHostAudioInstance *psAudioInstance, uint32_t ui32Event, + uint32_t ui32MsgParam, void *pvBuffer) +{ + switch(ui32Event) + { + // + // New USB audio device has been enabled. + // + case USBH_AUDIO_EVENT_OPEN: + { + // + // Set the EVENT_OPEN flag and let the main routine handle it. + // + HWREGBITW(&g_sAudioState.ui32EventFlags, EVENT_OPEN) = 1; + + break; + } + + // + // USB audio device has been removed. + // + case USBH_AUDIO_EVENT_CLOSE: + { + // + // Set the EVENT_CLOSE flag and let the main routine handle it. + // + HWREGBITW(&g_sAudioState.ui32EventFlags, EVENT_CLOSE) = 1; + + break; + } + default: + { + break; + } + } +} + +//***************************************************************************** +// +// Initializes the sound output. +// +// \param ui32Flags is unused as this point but is included for future +// functionality. +// \param pfnCallback is the event callback function for audio devices. +// +// This function prepares the sound driver to enumerate an audio device and +// prepares to play audio once a valid audio device is detected. The +// \e pfnCallback function can be used to receive callbacks when there are +// changes related to the audio device. The ui32Event parameter to the +// callback is one of the SOUND_EVENT_* values. +// +// \return None +// +//***************************************************************************** +void +USBSoundInit(uint32_t ui32Flags, tEventCallback pfnCallback) +{ + // + // Initialize the USB stack mode to force host mode. + // + USBStackModeSet(0, eUSBModeForceHost, 0); + + // + // Register the host class drivers. + // + USBHCDRegisterDrivers(0, g_ppHostClassDrivers, g_ui32NumHostClassDrivers); + + // + // Open an instance of the audio class driver. + // + g_psAudioInstance = USBHostAudioOpen(0, AudioCallback); + + // + // Initialize the power configuration. This sets the power enable signal + // to be active high and does not enable the power fault. + // + USBHCDPowerConfigInit(0, USBHCD_VBUS_AUTO_HIGH | USBHCD_VBUS_FILTER); + + // + // Initialize the USB controller for host mode operation. + // + USBHCDInit(0, g_pHCDPool, HCD_MEMORY_SIZE); + + // + // Save the event callback function. + // + g_sAudioState.pfnCallbackEvent = pfnCallback; +} + +//***************************************************************************** +// +// Sets the volume of the audio device. +// +// \param ui32Percent is the volume percentage, which must be between 0% +// (silence) and 100% (full volume), inclusive. +// +// This function sets the volume of the sound output to a value between +// silence (0%) and full volume (100%). +// +// \return None. +// +//***************************************************************************** +void +USBSoundVolumeSet(uint32_t ui32Percent) +{ + uint32_t ui32Value; + + // + // Ignore volume changes if there is no device present. + // + if(g_sAudioState.iState == eStateDeviceReady) + { + // + // Scale the voltage percentage to the decibel range provided by the + // USB audio device. + // + ui32Value = (g_sAudioState.pui32Steps[1] * ui32Percent) / 100; + USBHostAudioVolumeSet(g_psAudioInstance, 0, 1, ui32Value); + + ui32Value = (g_sAudioState.pui32Steps[2] * ui32Percent) / 100; + USBHostAudioVolumeSet(g_psAudioInstance, 0, 2, ui32Value); + } +} + +//***************************************************************************** +// +// Returns the current volume level. +// +// \param ui32Channel is the 0 based channel number to query. +// +// This function returns the current volume, specified as a percentage between +// 0% (silence) and 100% (full volume), inclusive. The \e ui32Channel value +// starts with 0 which is the master audio volume control interface. The +// remaining \e ui32Channel values provide access to various other audio +// channels, with 1 and 2 being left and right audio channels. +// +// \return Returns the current volume. +// +//***************************************************************************** +uint32_t +USBSoundVolumeGet(uint32_t ui32Channel) +{ + uint32_t ui32Volume; + + // + // Initialize the return value in case there is no USB device present. + // + ui32Volume = 0xffffffff; + + // + // Ignore volume request if there is no device present. + // + if(g_sAudioState.iState == eStateDeviceReady) + { + ui32Volume = USBHostAudioVolumeGet(g_psAudioInstance, 0, ui32Channel); + } + + return(ui32Volume); +} + +//***************************************************************************** +// +// This sets the current output audio format of the USB audio device. +// +// \param ui32SampleRate is the sample rate. +// \param ui32BitsPerSample is the number of bits per sample. +// \param ui32Channels is the number of channels. +// +// This sets the current audio format for the USB device that is currently +// connected. If there is no USB device connected or the format is not +// supported then the function returns a non-zero value. The function +// returns zero if the USB audio device was successfully configured to the +// requested audio format. +// +// \return Returns zero if the format was successfully set or returns an +// non-zero value if the format was not able to be set. +// +//***************************************************************************** +uint32_t +USBSoundOutputFormatSet(uint32_t ui32SampleRate, + uint32_t ui32BitsPerSample, uint32_t ui32Channels) +{ + // + // Just return if there is no device at this time. + // + if(g_sAudioState.iState != eStateDeviceReady) + { + return(1); + } + + // + // Call the USB Host Audio function to set the format. + // + return(USBHostAudioFormatSet(g_psAudioInstance, ui32SampleRate, + ui32BitsPerSample, ui32Channels, + USBH_AUDIO_FORMAT_OUT)); +} + +//***************************************************************************** +// +// This sets the current input audio format of the USB audio device +// +// \param ui32SampleRate is the sample rate. +// \param ui32BitsPerSample is the number of bits per sample. +// \param ui32Channels is the number of channels. +// +// This sets the current format for the USB device that is currently connect. +// If there is no USB device connected or the format is not supported then the +// function returns 0. The function returns 1 if the USB audio device +// was successfully configured to the requested format. +// +// \return Returns 1 if the format was successfully set or returns 0 if the +// format was not changed. +// +//***************************************************************************** +uint32_t +USBSoundInputFormatSet(uint32_t ui32SampleRate, + uint32_t ui32BitsPerSample, uint32_t ui32Channels) +{ + // + // Just return if there is no device at this time. + // + if(g_sAudioState.iState != eStateDeviceReady) + { + return(0); + } + + return(USBHostAudioFormatSet(g_psAudioInstance, ui32SampleRate, + ui32BitsPerSample, ui32Channels, + USBH_AUDIO_FORMAT_IN)); +} + +//***************************************************************************** +// +// Returns the current sample rate. +// +// This function returns the sample rate that was set by a call to +// USBSoundSetFormat(). This is needed to retrieve the exact sample rate that is +// in use in case the requested rate could not be matched exactly. +// +// \return The current sample rate in samples/second. +// +//***************************************************************************** +uint32_t +USBSoundOutputFormatGet(uint32_t ui32SampleRate, uint32_t ui32Bits, + uint32_t ui32Channels) +{ + // + // Just return if there is no device at this time. + // + if(g_sAudioState.iState != eStateDeviceReady) + { + return(0); + } + + return(USBHostAudioFormatGet(g_psAudioInstance, ui32SampleRate, ui32Bits, + ui32Channels, USBH_AUDIO_FORMAT_OUT)); +} + +//***************************************************************************** +// +// Returns the current sample rate. +// +// This function returns the sample rate that was set by a call to +// USBSoundSetFormat(). This is needed to retrieve the exact sample rate that is +// in use in case the requested rate could not be matched exactly. +// +// \return The current sample rate in samples/second. +// +//***************************************************************************** +uint32_t +USBSoundInputFormatGet(uint32_t ui32SampleRate, uint32_t ui32Bits, + uint32_t ui32Channels) +{ + // + // Just return if there is no device at this time. + // + if(g_sAudioState.iState != eStateDeviceReady) + { + return(0); + } + + return(USBHostAudioFormatGet(g_psAudioInstance, ui32SampleRate, ui32Bits, + ui32Channels, USBH_AUDIO_FORMAT_IN)); +} + +//***************************************************************************** +// +// This is the generic callback from host stack. +// +// \param pvData is actually a pointer to a tEventInfo structure. +// +// This function is called to inform the application when a USB event has +// occurred that is outside those related to the audio device. At this +// point this is used to detect unsupported devices being inserted and removed. +// It is also used to inform the application when a power fault has occurred. +// This function is required when the g_USBGenerii8EventDriver is included in +// the host controller driver array that is passed in to the +// USBHCDRegisterDrivers() function. +// +// \return None. +// +//***************************************************************************** +void +USBHCDEvents(void *pvData) +{ + tEventInfo *psEventInfo; + + // + // Cast this pointer to its actual type. + // + psEventInfo = (tEventInfo *)pvData; + + switch(psEventInfo->ui32Event) + { + // + // Unknown device detected. + // + case USB_EVENT_UNKNOWN_CONNECTED: + { + // + // An unknown device was detected. + // + g_sAudioState.iState = eStateUnknownDevice; + + // + // Call the general event handler if present. + // + if(g_sAudioState.pfnCallbackEvent) + { + g_sAudioState.pfnCallbackEvent(SOUND_EVENT_UNKNOWN_DEV, 1); + } + + break; + } + + // + // Device unplugged. + // + case USB_EVENT_DISCONNECTED: + { + // + // Handle the case where an unknown device is disconnected. + // + if(g_sAudioState.iState == eStateUnknownDevice) + { + g_sAudioState.iState = eStateNoDevice; + + // + // Call the general event handler if present. + // + if(g_sAudioState.pfnCallbackEvent) + { + g_sAudioState.pfnCallbackEvent(SOUND_EVENT_UNKNOWN_DEV, 0); + } + } + else + { + // + // Call the general event handler if present. + // + if(g_sAudioState.pfnCallbackEvent) + { + g_sAudioState.pfnCallbackEvent(SOUND_EVENT_DISCONNECT, 0); + } + } + + break; + } + + // + // A power fault has occurred. + // + case USB_EVENT_POWER_FAULT: + { + // + // No power means no device is present. + // + g_sAudioState.iState = eStatePowerFault; + + break; + } + default: + { + break; + } + } +} + +//***************************************************************************** +// +// This function passes along a buffer callback from the USB host audio driver +// so that the application can process or release the buffers. +// +//***************************************************************************** +void +USBHostAudioCallback(tUSBHostAudioInstance *psAudioInstance, + uint32_t ui32Event, uint32_t ui32Param, void *pvBuffer) +{ + // + // Only call the callback if it is actually present. + // + if(g_sAudioState.pfnCallbackOut) + { + g_sAudioState.pfnCallbackOut(pvBuffer, ui32Event, ui32Param); + } + + // + // Only call the callback if it is actually present. + // + if(g_sAudioState.pfnCallbackIn) + { + g_sAudioState.pfnCallbackIn(pvBuffer, ui32Event, ui32Param); + } +} + +//***************************************************************************** +// +// Starts output of a block of PCM audio samples. +// +// \param pvBuffer is a pointer to the audio data to play. +// \param ui32Size is the length of the data in bytes. +// \param pfnCallback is a function to call when this buffer has be played. +// +// This function starts the output of a block of PCM audio samples. +// +// \return This function returns a non-zero value if the buffer was accepted, +// and returns zero if the buffer was not accepted. +// +//***************************************************************************** +uint32_t +USBSoundBufferOut(const void *pvBuffer, uint32_t ui32Size, + tUSBBufferCallback pfnCallback) +{ + // + // If there is no device present or there is a pending buffer then just + // return with a failure. + // + if(g_sAudioState.iState != eStateDeviceReady) + { + return(0); + } + + // + // Save this buffer callback. + // + g_sAudioState.pfnCallbackOut = pfnCallback; + + // + // Pass the buffer aint32_t to the USB host audio driver for playback. + // + return(USBHostAudioPlay(g_psAudioInstance, (void *)pvBuffer, ui32Size, + USBHostAudioCallback)); +} + +//***************************************************************************** +// +// Requests a new block of PCM audio samples from a USB audio device. +// +// \param pvBuffer is a pointer to a location to store the audio data. +// \param ui32Size is the size of the pvData buffer in bytes. +// \param pfnCallback is a function to call when this buffer has new data. +// +// This function request a new block of PCM audio samples from a USB audio +// device. +// +// \return This function returns a non-zero value if the buffer was accepted, +// and returns zero if the buffer was not accepted. +// +//***************************************************************************** +uint32_t +USBSoundBufferIn(const void *pvBuffer, uint32_t ui32Size, + tUSBBufferCallback pfnCallback) +{ + // + // If there is no device present or there is a pending buffer then just + // return with a failure. + // + if(g_sAudioState.iState != eStateDeviceReady) + { + return(0); + } + + // + // Save this buffer callback. + // + g_sAudioState.pfnCallbackIn = pfnCallback; + + // + // Pass the buffer aint32_t to the USB host audio driver for input. + // + return(USBHostAudioRecord(g_psAudioInstance, (void *)pvBuffer, ui32Size, + USBHostAudioCallback)); +} + +//***************************************************************************** +// +// This function reads the audio volume settings for the USB audio device and +// saves them so that the volume can be scaled correctly. +// +//***************************************************************************** +static void +GetVolumeParameters(void) +{ + uint32_t ui32Max, ui32Min, ui32Res, ui32Channel; + + for(ui32Channel = 0; ui32Channel < 3; ui32Channel++) + { + ui32Max = USBHostAudioVolumeMaxGet(g_psAudioInstance, 0, ui32Channel); + ui32Min = USBHostAudioVolumeMinGet(g_psAudioInstance, 0, ui32Channel); + ui32Res = USBHostAudioVolumeResGet(g_psAudioInstance, 0, ui32Channel); + + g_sAudioState.pui32Steps[ui32Channel] = (ui32Max - ui32Min) / ui32Res; + } +} + +//***************************************************************************** +// +// The main routine for handling USB audio, this should be called periodically +// by the main program and pass in the amount of time in milliseconds that has +// elapsed since the last call. +// +//***************************************************************************** +void +USBSoundMain(void) +{ + // + // Tell the OTG library code how much time has passed in + // milliseconds since the last call. + // + USBHCDMain(); + + switch(g_sAudioState.iState) + { + // + // This is the running state where buttons are checked and the + // screen is updated. + // + case eStateDeviceReady: + { if(HWREGBITW(&g_sAudioState.ui32EventFlags, EVENT_CLOSE)) + { + HWREGBITW(&g_sAudioState.ui32EventFlags, EVENT_CLOSE) = 0; + g_sAudioState.iState = eStateNoDevice; + + // + // Call the general event handler if present. + // + if(g_sAudioState.pfnCallbackEvent) + { + g_sAudioState.pfnCallbackEvent(SOUND_EVENT_DISCONNECT, 0); + } + } + break; + } + + // + // If there is no device then just wait for one. + // + case eStateNoDevice: + { + if(HWREGBITW(&g_sAudioState.ui32EventFlags, EVENT_OPEN)) + { + g_sAudioState.iState = eStateDeviceReady; + + HWREGBITW(&g_sAudioState.ui32EventFlags, EVENT_OPEN) = 0; + + GetVolumeParameters(); + + // + // Call the general event handler if present. + // + if(g_sAudioState.pfnCallbackEvent) + { + g_sAudioState.pfnCallbackEvent(SOUND_EVENT_READY, 0); + } + } + break; + } + + // + // An unknown device was connected. + // + case eStateUnknownDevice: + { + break; + } + + // + // Something has caused a power fault. + // + case eStatePowerFault: + { + break; + } + + default: + { + break; + } + } +} -- cgit v1.3.1