diff options
| author | Yuval Adam <yuv.adm@gmail.com> | 2014-06-29 12:34:32 +0300 |
|---|---|---|
| committer | Yuval Adam <yuv.adm@gmail.com> | 2014-06-29 12:34:32 +0300 |
| commit | c3e4c9a25c2910d2d66d52215b3406b13d5b23d5 (patch) | |
| tree | added370d1e356901f8579f076e3263fb0464db7 /boards/dk-tm4c129x/drivers/usb_sound.c | |
| parent | 990090a4cc9070837d31e66b58d40f0c3d038741 (diff) | |
Add more board models
Diffstat (limited to 'boards/dk-tm4c129x/drivers/usb_sound.c')
| -rw-r--r-- | boards/dk-tm4c129x/drivers/usb_sound.c | 769 |
1 files changed, 769 insertions, 0 deletions
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 <stdbool.h>
+#include <stdint.h>
+#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;
+ }
+ }
+}
|
