summaryrefslogtreecommitdiff
path: root/usblib/host
diff options
context:
space:
mode:
authorYuval Adam <yuv.adm@gmail.com>2014-03-16 14:41:11 +0200
committerYuval Adam <yuv.adm@gmail.com>2014-03-16 14:41:11 +0200
commit990090a4cc9070837d31e66b58d40f0c3d038741 (patch)
treecf1b905082c364e9b223e0c5058566103138dae5 /usblib/host
parent7f4da522479c0f00126219f0c23b804c3a93d7a6 (diff)
Add usblib and utils
Diffstat (limited to 'usblib/host')
-rw-r--r--usblib/host/usbhaudio.c1557
-rw-r--r--usblib/host/usbhaudio.h163
-rw-r--r--usblib/host/usbhhid.c746
-rw-r--r--usblib/host/usbhhid.h166
-rw-r--r--usblib/host/usbhhidkeyboard.c752
-rw-r--r--usblib/host/usbhhidkeyboard.h89
-rw-r--r--usblib/host/usbhhidmouse.c452
-rw-r--r--usblib/host/usbhhidmouse.h81
-rw-r--r--usblib/host/usbhhub.c1522
-rw-r--r--usblib/host/usbhhub.h174
-rw-r--r--usblib/host/usbhmsc.c756
-rw-r--r--usblib/host/usbhmsc.h99
-rw-r--r--usblib/host/usbhost.h295
-rw-r--r--usblib/host/usbhostenum.c6284
-rw-r--r--usblib/host/usbhostpriv.h201
-rw-r--r--usblib/host/usbhscsi.c777
-rw-r--r--usblib/host/usbhscsi.h87
17 files changed, 14201 insertions, 0 deletions
diff --git a/usblib/host/usbhaudio.c b/usblib/host/usbhaudio.c
new file mode 100644
index 0000000..129130c
--- /dev/null
+++ b/usblib/host/usbhaudio.c
@@ -0,0 +1,1557 @@
+//*****************************************************************************
+//
+// usbhaudio.c - USB host audio driver.
+//
+// Copyright (c) 2010-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 Tiva USB Library.
+//
+//*****************************************************************************
+
+#include <stdbool.h>
+#include <stdint.h>
+#include "inc/hw_types.h"
+#include "driverlib/usb.h"
+#include "usblib/usblib.h"
+#include "usblib/usblibpriv.h"
+#include "usblib/usbaudio.h"
+#include "usblib/host/usbhost.h"
+#include "usblib/host/usbhostpriv.h"
+#include "usblib/host/usbhaudio.h"
+
+//*****************************************************************************
+//
+//! \addtogroup usblib_host_class
+//! @{
+//
+//*****************************************************************************
+
+//*****************************************************************************
+//
+// These defines are used with the USBHostAudioFormatSet()
+// USBHostAudioFormatGet() to parse out interface number and alternate
+// setting number for an interface.
+//
+//*****************************************************************************
+#define INTERFACE_NUM_M 0x000000FF
+#define INTERFACE_ALTSETTING_M 0x0000FF00
+#define INTERFACE_ALTSETTING_S 8
+
+//*****************************************************************************
+//
+// Used to indicate an invalid interface descriptor number.
+//
+//*****************************************************************************
+#define INVALID_INTERFACE 0xffffffff
+
+//*****************************************************************************
+//
+// Forward declarations for the driver open and close calls.
+//
+//*****************************************************************************
+static void *USBAudioOpen(tUSBHostDevice *psDevice);
+static void USBAudioClose(void *pvInstance);
+
+//*****************************************************************************
+//
+// This is the structure for an instance of a USB host audio driver.
+//
+//*****************************************************************************
+struct tUSBHostAudioInstance
+{
+ //
+ // Save the device instance.
+ //
+ tUSBHostDevice *psDevice;
+
+ //
+ // Used to save the call back.
+ //
+ tUSBHostAudioCallback pfnCallback;
+
+ //
+ // This is the control interface.
+ //
+ uint8_t ui8IControl;
+
+ //
+ // This is the output streaming interface.
+ //
+ uint8_t ui8OutInterface;
+
+ //
+ // This is the currently selected active output interface used with
+ // ui8OutInterface interface.
+ //
+ uint8_t ui8OutAltSetting;
+
+ //
+ // This is the streaming interface.
+ //
+ uint8_t ui8InInterface;
+
+ //
+ // This is the currently selected active input interface used with
+ // ui8InInterface interface.
+ //
+ uint8_t ui8InAltSetting;
+
+ //
+ // The Isochronous endpoint addresses.
+ //
+ uint8_t ui8IsochInAddress;
+ uint8_t ui8IsochOutAddress;
+
+ tACInputTerminal *psInTerminal;
+ tACOutputTerminal *psOutTerminal;
+
+ //
+ // Holds the identifier for the Feature Unit for controlling volume.
+ //
+ uint8_t ui8VolumeID;
+
+ tACFeatureUnit *psFeatureUnit;
+
+ //
+ // Holds what types of controls are enabled on the device.
+ //
+ uint16_t pui16Controls[3];
+
+ //
+ // Isochronous IN pipe.
+ //
+ uint32_t ui32IsochInPipe;
+ uint16_t ui16PipeSizeIn;
+ tUSBHostAudioCallback pfnInCallback;
+ void *pvInBuffer;
+
+ //
+ // Isochronous OUT pipe.
+ //
+ uint32_t ui32IsochOutPipe;
+ uint16_t ui16PipeSizeOut;
+ tUSBHostAudioCallback pfnOutCallback;
+ void *pvOutBuffer;
+
+ //
+ // State flags for this audio instance.
+ //
+ uint32_t ui32Flags;
+};
+
+//*****************************************************************************
+//
+// The internal flags for an audio interface.
+//
+//*****************************************************************************
+#define AUDIO_FLAG_OUT_ACTIVE 1 // Audio output is active.
+#define AUDIO_FLAG_IN_ACTIVE 2 // Audio input is active.
+
+//*****************************************************************************
+//
+// The USB Host audio instance.
+//
+//*****************************************************************************
+static tUSBHostAudioInstance g_sAudioDevice =
+{
+ 0
+};
+
+//*****************************************************************************
+//
+//! This constant global structure defines the Audio Class Driver that is
+//! provided with the USB library.
+//
+//*****************************************************************************
+const tUSBHostClassDriver g_sUSBHostAudioClassDriver =
+{
+ USB_CLASS_AUDIO,
+ USBAudioOpen,
+ USBAudioClose,
+ 0
+};
+
+//*****************************************************************************
+//
+// This is the internal function that handles callbacks from the USB IN pipe.
+//
+//*****************************************************************************
+static void
+PipeCallbackIN(uint32_t ui32Pipe, uint32_t ui32Event)
+{
+ //
+ // Only handle the data available callback and pass it on to the
+ // application.
+ //
+ if(ui32Event == USB_EVENT_RX_AVAILABLE)
+ {
+ if(g_sAudioDevice.pfnInCallback)
+ {
+ g_sAudioDevice.pfnInCallback(&g_sAudioDevice,
+ USB_EVENT_RX_AVAILABLE,
+ USBHCDPipeTransferSizeGet(ui32Pipe),
+ g_sAudioDevice.pvInBuffer);
+ }
+ }
+}
+
+//*****************************************************************************
+//
+// This is the internal function that handles callbacks from the USB OUT pipe.
+//
+//*****************************************************************************
+static void
+PipeCallbackOUT(uint32_t ui32Pipe, uint32_t ui32Event)
+{
+ //
+ // Only handle the transmit complete callback and pass it on to the
+ // application.
+ //
+ if(ui32Event == USB_EVENT_TX_COMPLETE)
+ {
+ if(g_sAudioDevice.pfnOutCallback)
+ {
+ g_sAudioDevice.pfnOutCallback(&g_sAudioDevice,
+ USB_EVENT_TX_COMPLETE, 0,
+ g_sAudioDevice.pvOutBuffer);
+ }
+ }
+}
+
+//*****************************************************************************
+//
+// Finds a given terminal and type in an audio configuration descriptor.
+//
+//*****************************************************************************
+static tDescriptorHeader *
+AudioTerminalGet(tConfigDescriptor *psConfigDesc, uint32_t ui32Terminal,
+ uint32_t ui32TerminalType)
+{
+ tACOutputTerminal *psOutput;
+ tDescriptorHeader *psHeader;
+ int32_t i32BytesRemaining;
+
+ psHeader = (tDescriptorHeader *)psConfigDesc;
+ i32BytesRemaining = psConfigDesc->wTotalLength;
+
+ while(i32BytesRemaining > 0)
+ {
+ //
+ // Output and input terminals are the same past the bDescriptorSubtype
+ // and wTerminalType that are being searched for.
+ //
+ psOutput = (tACOutputTerminal *)psHeader;
+
+ //
+ // Only CS_INTERFACE descriptors can be a terminal.
+ //
+ if((psHeader->bDescriptorType == USB_DTYPE_CS_INTERFACE) &&
+ (ui32Terminal == psOutput->bDescriptorSubtype))
+ {
+ if((psOutput->bDescriptorSubtype == USB_AI_OUTPUT_TERMINAL) ||
+ (psOutput->bDescriptorSubtype == USB_AI_INPUT_TERMINAL))
+
+ {
+ //
+ // If this was the terminal type that was requested, the
+ // return it.
+ //
+ if(psOutput->wTerminalType == ui32TerminalType)
+ {
+ return(psHeader);
+ }
+ }
+ else if(psOutput->bDescriptorSubtype == USB_AI_FEATURE_UNIT)
+ {
+ return(psHeader);
+ }
+ }
+
+ //
+ // Decrease the bytes remaining by the size of this descriptor.
+ //
+ i32BytesRemaining -= psHeader->bLength;
+
+ //
+ // Move the pointer to the next header.
+ //
+ psHeader = (tDescriptorHeader *)((uint32_t)psHeader +
+ psHeader->bLength);
+ }
+ return((tDescriptorHeader *)0);
+}
+
+//*****************************************************************************
+//
+// This function returns the interface number for the control interface
+// in the structure passed in the psConfigDesc.
+//
+// \param psConfigDescriptor is a pointer to the memory containing a valid
+// configuration descriptor for a device.
+//
+// This function searches a configuration descriptor for a control interface
+// descriptor. The function only search for the first descriptor and then
+// returns when it finds one.
+//
+// \return The first control interface descriptor number for an audio device
+// or INVALID_INTERFACE if no control interface descriptor was found.
+//
+//*****************************************************************************
+static uint32_t
+AudioControlGet(tConfigDescriptor *psConfigDesc)
+{
+ tDescriptorHeader *psHeader;
+ tInterfaceDescriptor *psInterface;
+ uint32_t ui32Interface;
+ int32_t i32Bytes;
+
+ psHeader = (tDescriptorHeader *)psConfigDesc;
+ i32Bytes = psConfigDesc->wTotalLength;
+
+ //
+ // Initialize the interface number to an invalid value.
+ //
+ ui32Interface = INVALID_INTERFACE;
+
+ //
+ // Search the whole configuration descriptor.
+ //
+ while(i32Bytes > 0)
+ {
+ //
+ // Find an interface descriptor and see if it is a control interface.
+ //
+ if(psHeader->bDescriptorType == USB_DTYPE_INTERFACE)
+ {
+ psInterface = (tInterfaceDescriptor *)psHeader;
+
+ //
+ // If this is the control interface then return the value to the
+ // caller.
+ //
+ if(psInterface->bInterfaceSubClass == USB_ASC_AUDIO_CONTROL)
+ {
+ ui32Interface = psInterface->bInterfaceNumber;
+
+ break;
+ }
+ }
+
+ //
+ // Decrease the bytes remaining by the size of this descriptor.
+ //
+ i32Bytes -= psHeader->bLength;
+
+ //
+ // Move the pointer to the next header.
+ //
+ psHeader = (tDescriptorHeader*)((uint32_t)psHeader +
+ psHeader->bLength);
+ }
+ return(ui32Interface);
+}
+
+//*****************************************************************************
+//
+// If it exists, finds the correct audio interface for a given audio format.
+//
+//*****************************************************************************
+static uint32_t
+AudioGetInterface(tUSBHostAudioInstance *psAudioDevice, uint16_t ui16Format,
+ uint32_t ui32SampleRate, uint32_t ui32Bytes,
+ uint32_t ui32Channels, uint32_t ui32Flags)
+{
+ tDescriptorHeader *psHeader;
+ tInterfaceDescriptor *psInterface;
+ tEndpointDescriptor *pINEndpoint, *pOUTEndpoint;
+ tACHeader *pACHeader;
+ tACGeneral *pGeneral;
+ tASFormat *pFormat;
+ tEndpointDescriptor *pEndpoint;
+ uint8_t *pui8Value;
+ uint32_t ui32Value;
+ int32_t i32Bytes, i32Idx;
+
+ //
+ // Initialize the Interface pointer to null.
+ //
+ psInterface = 0;
+ pINEndpoint = 0;
+ pOUTEndpoint = 0;
+
+ //
+ // Start at the top of the configuration descriptor.
+ //
+ psHeader = (tDescriptorHeader *)psAudioDevice->psDevice->psConfigDescriptor;
+
+ i32Bytes = psAudioDevice->psDevice->psConfigDescriptor->wTotalLength;
+
+ while(i32Bytes > 0)
+ {
+ if(psHeader->bDescriptorType == USB_DTYPE_INTERFACE)
+ {
+ //
+ // If a new interface was found and the last one satisfied all
+ // requirements then a valid interface was found so break out.
+ //
+ if(psInterface)
+ {
+ break;
+ }
+
+ //
+ // Get the new interface pointer.
+ //
+ psInterface = (tInterfaceDescriptor *)psHeader;
+
+ //
+ // Reset the endpoints on finding a new interface descriptor.
+ //
+ pINEndpoint = 0;
+ pOUTEndpoint = 0;
+
+ //
+ // If this is not a valid audio streaming interface then reset
+ // the interface pointer to null.
+ //
+ if((psInterface->bNumEndpoints == 0) ||
+ (psInterface->bInterfaceClass != USB_CLASS_AUDIO) ||
+ (psInterface->bInterfaceSubClass != USB_ASC_AUDIO_STREAMING))
+ {
+ psInterface = 0;
+ }
+ }
+ if((psInterface) &&
+ (psHeader->bDescriptorType == USB_DTYPE_CS_INTERFACE))
+ {
+ pACHeader = (tACHeader *)psHeader;
+
+ //
+ // If this is a General descriptor the check if the format matches.
+ //
+ if(pACHeader->bDescriptorSubtype == USB_AS_GENERAL)
+ {
+ //
+ // Just save the pointer to the format descriptor.
+ //
+ pGeneral = (tACGeneral *)psHeader;
+
+ //
+ // If this interface has the wrong format then set it to null
+ // so that the rest of this interface is ignored.
+ //
+ if(pGeneral->wFormatTag != ui16Format)
+ {
+ psInterface = 0;
+ }
+ }
+ else if(pACHeader->bDescriptorSubtype == USB_AS_FORMAT_TYPE)
+ {
+ pFormat = (tASFormat *)psHeader;
+
+ //
+ // If the number of bytes per sample and number of channels do
+ // not match then reset the interface pointer so that the rest
+ // of this interface is ignored.
+ //
+ if((pFormat->bNrChannels != ui32Channels) ||
+ (pFormat->bSubFrameSize != ui32Bytes))
+ {
+ psInterface = 0;
+ }
+ else
+ {
+ pui8Value = &pFormat->tSamFreq;
+
+ //
+ // Attempt to find the sample rate in the sample rate
+ // table for this interface.
+ //
+ for(i32Idx = 0; i32Idx < pFormat->bSamFreqType; i32Idx++)
+ {
+ ui32Value = (*((uint32_t *)&pui8Value[i32Idx * 3]) &
+ 0xffffff);
+
+ if(ui32Value == ui32SampleRate)
+ {
+ break;
+ }
+ }
+
+ //
+ // If the sample rate was not found then set the interface
+ // pointer to null so that the rest of this interface is
+ // ignored.
+ //
+ if(i32Idx == pFormat->bSamFreqType)
+ {
+ psInterface = 0;
+ }
+ }
+ }
+ }
+ else if((psInterface) &&
+ (psHeader->bDescriptorType == USB_DTYPE_ENDPOINT))
+ {
+ pEndpoint = (tEndpointDescriptor *)psHeader;
+
+ //
+ // See what direction is being requested.
+ //
+ if(ui32Flags & USBH_AUDIO_FORMAT_IN)
+ {
+ //
+ // If this is an input endpoint and is just a feed back input
+ // then ignore it.
+ //
+ if(pEndpoint->bEndpointAddress & USB_EP_DESC_IN)
+ {
+ if((pEndpoint->bmAttributes & USB_EP_ATTR_USAGE_M)
+ == USB_EP_ATTR_USAGE_FEEDBACK)
+ {
+ psInterface = 0;
+ }
+ else
+ {
+ //
+ // Save this endpoint as a possible valid endpoint
+ //
+ pINEndpoint = pEndpoint;
+ }
+ }
+ }
+ else
+ {
+ //
+ // If this is an output endpoint and is just a feed back input
+ // then ignore it.
+ //
+ if((pEndpoint->bEndpointAddress & USB_EP_DESC_IN) == 0)
+ {
+ if((pEndpoint->bmAttributes & USB_EP_ATTR_USAGE_M)
+ == USB_EP_ATTR_USAGE_FEEDBACK)
+ {
+ psInterface = 0;
+ }
+ else
+ {
+ //
+ // Save this endpoint as a possible valid endpoint;
+ //
+ pOUTEndpoint = pEndpoint;
+ }
+ }
+ }
+ }
+
+ //
+ // Decrease the bytes remaining by the size of this descriptor.
+ //
+ i32Bytes -= psHeader->bLength;
+
+ //
+ // Move the pointer to the next header.
+ //
+ psHeader = (tDescriptorHeader*)((uint32_t)psHeader +
+ psHeader->bLength);
+ }
+
+ //
+ // If there is still a valid interface then return the values.
+ //
+ if(psInterface)
+ {
+ //
+ // Check a valid IN endpoint descriptor.
+ //
+ if(pINEndpoint)
+ {
+ //
+ // Save the endpoint address.
+ //
+ g_sAudioDevice.ui8IsochInAddress = pINEndpoint->bEndpointAddress &
+ USB_EP_DESC_NUM_M;
+
+ //
+ // If there is no current pipe then just allocate a new one with
+ // the settings for this interface.
+ //
+ if(g_sAudioDevice.ui32IsochInPipe == 0)
+ {
+ //
+ // Allocate the USB Pipe for this Isochronous IN end point.
+ //
+ g_sAudioDevice.ui32IsochInPipe =
+ USBHCDPipeAllocSize(0, USBHCD_PIPE_ISOC_IN_DMA,
+ g_sAudioDevice.psDevice,
+ pINEndpoint->wMaxPacketSize,
+ PipeCallbackIN);
+ }
+ else if(g_sAudioDevice.ui16PipeSizeIn < pINEndpoint->wMaxPacketSize)
+ {
+ //
+ // Free the old endpoint and allocate a new one.
+ //
+ USBHCDPipeFree(g_sAudioDevice.ui32IsochInPipe);
+
+ //
+ // Allocate the USB Pipe for this Isochronous IN end point.
+ //
+ g_sAudioDevice.ui32IsochInPipe =
+ USBHCDPipeAllocSize(0, USBHCD_PIPE_ISOC_IN_DMA,
+ g_sAudioDevice.psDevice,
+ pINEndpoint->wMaxPacketSize,
+ PipeCallbackIN);
+
+ //
+ // Save the new size of the maximum packet size for this
+ // USB pipe.
+ //
+ g_sAudioDevice.ui16PipeSizeIn = pINEndpoint->wMaxPacketSize;
+ }
+
+ //
+ // Configure the USB pipe as a Isochronous IN end point.
+ //
+ USBHCDPipeConfig(g_sAudioDevice.ui32IsochInPipe,
+ pINEndpoint->wMaxPacketSize,
+ 0,
+ g_sAudioDevice.ui8IsochInAddress);
+ }
+
+ //
+ // Check a valid OUT endpoint descriptor.
+ //
+ if(pOUTEndpoint)
+ {
+ //
+ // Save the endpoint address.
+ //
+ g_sAudioDevice.ui8IsochOutAddress =
+ pOUTEndpoint->bEndpointAddress & USB_EP_DESC_NUM_M;
+
+ //
+ // If there is no current pipe then just allocate a new one with
+ // the settings for this interface.
+ //
+ if(g_sAudioDevice.ui32IsochOutPipe == 0)
+ {
+ //
+ // Allocate the USB Pipe for this Isochronous OUT end point.
+ //
+ g_sAudioDevice.ui32IsochOutPipe =
+ USBHCDPipeAllocSize(0, USBHCD_PIPE_ISOC_OUT_DMA,
+ g_sAudioDevice.psDevice,
+ pOUTEndpoint->wMaxPacketSize,
+ PipeCallbackOUT);
+ }
+ else if(g_sAudioDevice.ui16PipeSizeOut <
+ pOUTEndpoint->wMaxPacketSize)
+ {
+ //
+ // Free the old endpoint and allocate a new one.
+ //
+ USBHCDPipeFree(g_sAudioDevice.ui32IsochOutPipe);
+
+ //
+ // Allocate the USB Pipe for this Isochronous OUT end point.
+ //
+ g_sAudioDevice.ui32IsochOutPipe =
+ USBHCDPipeAllocSize(0, USBHCD_PIPE_ISOC_OUT_DMA,
+ g_sAudioDevice.psDevice,
+ pOUTEndpoint->wMaxPacketSize,
+ PipeCallbackOUT);
+
+ //
+ // Save the new size of the maximum packet size for this
+ // USB pipe.
+ //
+ g_sAudioDevice.ui16PipeSizeOut = pOUTEndpoint->wMaxPacketSize;
+ }
+
+ //
+ // Configure the USB pipe as a Isochronous OUT end point.
+ //
+ USBHCDPipeConfig(g_sAudioDevice.ui32IsochOutPipe,
+ pOUTEndpoint->wMaxPacketSize, 0,
+ g_sAudioDevice.ui8IsochOutAddress);
+ }
+
+ return(psInterface->bInterfaceNumber |
+ (psInterface->bAlternateSetting << INTERFACE_ALTSETTING_S));
+ }
+ return(INVALID_INTERFACE);
+}
+
+//*****************************************************************************
+//
+// This function is used to open an instance of the USB host audio driver.
+//
+// \param psDevice is a pointer to the device information structure.
+//
+// This function attempts to open an instance of the USB host audio driver
+// based on the information contained in the psDevice structure. This call
+// fails if there are not sufficient resources to open the device. The
+// function returns a value that should be passed back into USBHostAudioClose()
+// when the driver is no longer needed.
+//
+// \return The function returns a pointer to a USB host audio driver
+// instance.
+//
+//*****************************************************************************
+static void *
+USBAudioOpen(tUSBHostDevice *psDevice)
+{
+ uint32_t ui32Temp;
+ tConfigDescriptor *psConfigDesc;
+
+ //
+ // Don't allow the device to be opened without closing first.
+ //
+ if(g_sAudioDevice.psDevice)
+ {
+ return(0);
+ }
+
+ //
+ // Save the Host device pointer.
+ //
+ g_sAudioDevice.psDevice = psDevice;
+
+ //
+ // Save a shorter name for the configuration descriptor.
+ //
+ psConfigDesc = psDevice->psConfigDescriptor;
+
+ //
+ // Find the input terminal.
+ //
+ g_sAudioDevice.psInTerminal =
+ (tACInputTerminal *)AudioTerminalGet(psConfigDesc,
+ USB_AI_INPUT_TERMINAL,
+ USB_TTYPE_STREAMING);
+
+ //
+ // Find the output terminal.
+ //
+ g_sAudioDevice.psOutTerminal =
+ (tACOutputTerminal *)AudioTerminalGet(psConfigDesc,
+ USB_AI_OUTPUT_TERMINAL,
+ USB_TTYPE_STREAMING);
+
+ //
+ // Find the feature unit.
+ g_sAudioDevice.psFeatureUnit =
+ (tACFeatureUnit *)AudioTerminalGet(psConfigDesc,
+ USB_AI_FEATURE_UNIT, 0);
+
+ //
+ // Need some kind of terminal to send or receive audio from.
+ //
+ if((g_sAudioDevice.psOutTerminal == 0) &&
+ (g_sAudioDevice.psInTerminal == 0))
+ {
+ return(0);
+ }
+
+ //
+ // Find the Audio control interface.
+ //
+ ui32Temp = AudioControlGet(psConfigDesc);
+
+ if(ui32Temp == INVALID_INTERFACE)
+ {
+ return(0);
+ }
+
+ //
+ // Save the control interface index and increment the number
+ // of interfaces that have been found.
+ //
+ g_sAudioDevice.ui8IControl = (uint8_t)ui32Temp;
+
+ //
+ // If the call back exists, call it with an Open event.
+ //
+ if(g_sAudioDevice.pfnCallback != 0)
+ {
+ g_sAudioDevice.pfnCallback(&g_sAudioDevice,
+ USBH_AUDIO_EVENT_OPEN, 0, 0);
+ }
+
+ //
+ // If a feature unit was found, save the ID
+ //
+ if(g_sAudioDevice.psFeatureUnit != 0)
+ {
+ g_sAudioDevice.ui8VolumeID = g_sAudioDevice.psFeatureUnit->bUnitID;
+ }
+
+ //
+ // Allocate the USB Pipe for this Isochronous IN end point.
+ //
+ g_sAudioDevice.ui32IsochInPipe =
+ USBHCDPipeAllocSize(0, USBHCD_PIPE_ISOC_IN_DMA,
+ g_sAudioDevice.psDevice, 256, PipeCallbackIN);
+ g_sAudioDevice.ui16PipeSizeIn = 256;
+
+ //
+ // Allocate the USB Pipe for this Isochronous OUT end point.
+ //
+ g_sAudioDevice.ui32IsochOutPipe =
+ USBHCDPipeAllocSize(0, USBHCD_PIPE_ISOC_OUT_DMA,
+ g_sAudioDevice.psDevice, 256, PipeCallbackOUT);
+ g_sAudioDevice.ui16PipeSizeOut = 256;
+
+ //
+ // Clear the flags.
+ //
+ g_sAudioDevice.ui32Flags = 0;
+
+ //
+ // Return the only instance of this device.
+ //
+ return(&g_sAudioDevice);
+}
+
+//*****************************************************************************
+//
+// This function is used to release an instance of the USB host audio driver.
+//
+// \param pvAudioDevice is an instance pointer that needs to be released.
+//
+// This function frees up any resources in use by the USB host audio
+// driver instance that is passed in. The \e pvAudioDevice pointer should be a
+// valid value that was returned from a call to USBHostAudioOpen().
+//
+// \return None.
+//
+//*****************************************************************************
+static void
+USBAudioClose(void *pvAudioDevice)
+{
+ tUSBHostAudioInstance *psAudioDevice;
+
+ psAudioDevice = (tUSBHostAudioInstance *)pvAudioDevice;
+
+ //
+ // Do nothing if there is not a driver open.
+ //
+ if(psAudioDevice->psDevice == 0)
+ {
+ return;
+ }
+
+ //
+ // Reset the device pointer.
+ //
+ psAudioDevice->psDevice = 0;
+
+ //
+ // Free the Isochronous IN pipe.
+ //
+ if(psAudioDevice->ui32IsochInPipe != 0)
+ {
+ USBHCDPipeFree(psAudioDevice->ui32IsochInPipe);
+ }
+
+ //
+ // Free the Isochronous OUT pipe.
+ //
+ if(psAudioDevice->ui32IsochOutPipe != 0)
+ {
+ USBHCDPipeFree(psAudioDevice->ui32IsochOutPipe);
+ }
+
+ //
+ // If the call back exists then call it.
+ //
+ if(psAudioDevice->pfnCallback != 0)
+ {
+ psAudioDevice->pfnCallback(psAudioDevice, USBH_AUDIO_EVENT_CLOSE, 0,
+ 0);
+ }
+}
+
+//*****************************************************************************
+//
+//! This function should be called before any devices are present to enable
+//! the host audio class driver.
+//!
+//! \param ui32Index is the audio device to open (currently only 0 is
+//! supported).
+//! \param pfnCallback is the driver call back for host audio events.
+//!
+//! This function is called to open an instance of a host audio device and
+//! should provide a valid callback function for host audio events in the
+//! \e pfnCallback parameter. This function must be called before the USB
+//! host code can successfully enumerate an audio device.
+//!
+//! \return This function returns the driver instance to use for the other
+//! host audio functions. If there is no instance available at the time of
+//! this call, this function returns zero.
+//
+//*****************************************************************************
+tUSBHostAudioInstance *
+USBHostAudioOpen(uint32_t ui32Index, tUSBHostAudioCallback pfnCallback)
+{
+ //
+ // Only one audio device is supported at this time and on one instance
+ // is supported so if there is already a call back then fail.
+ //
+ if((ui32Index != 0) || (g_sAudioDevice.pfnCallback))
+ {
+ return(0);
+ }
+
+ //
+ // Save the call back.
+ //
+ g_sAudioDevice.pfnCallback = pfnCallback;
+
+ //
+ // Return the requested device instance.
+ //
+ return(&g_sAudioDevice);
+}
+
+//*****************************************************************************
+//
+//! This function should be called to release an audio device instance.
+//!
+//! \param psAudioInstance is the device instance that is to be released.
+//!
+//! This function is called when a host audio device needs to be released.
+//! This could be in preparation for shutdown or a switch to USB device mode,
+//! for example. Following this call, the audio device is available and can
+//! be opened again using a call to USBHostAudioOpen(). After calling this
+//! function, the host audio driver will no longer provide any callbacks or
+//! accept calls to other audio driver APIs.
+//!
+//! \return None.
+//
+//*****************************************************************************
+void
+USBHostAudioClose(tUSBHostAudioInstance *psAudioInstance)
+{
+ //
+ // Close the audio device.
+ //
+ USBAudioClose(psAudioInstance);
+
+ //
+ // Clear the call back indicating that the device is now closed.
+ //
+ psAudioInstance->pfnCallback = 0;
+}
+
+//*****************************************************************************
+//
+// This function is used to request settings from a given audio interface.
+//
+// \param psAudioDevice is the audio device instance to access.
+// \param ui32Interface is the interface to access.
+// \param ui32Channel is the channel number to access.
+// \param ui32Request is the audio device request.
+//
+// This function is used to get volume control parameters from a given
+// interface and on a given channel. The \e ui32Interface is the interface to
+// make the request specified by \e ui32Channel and \e ui32Request. The
+// \e ui32Request parameter must be one of the USB_AC_GET_* values.
+//
+// \return This function returns the requested value.
+//
+//*****************************************************************************
+static uint32_t
+VolumeSettingGet(tUSBHostAudioInstance *psAudioDevice, uint32_t ui32Interface,
+ uint32_t ui32Channel, uint32_t ui32Request)
+{
+ uint32_t ui32Value;
+ tUSBRequest sSetupPacket;
+
+ ui32Value = 0;
+
+ //
+ // This is a Class specific Interface IN request.
+ //
+ sSetupPacket.bmRequestType = USB_RTYPE_DIR_IN | USB_RTYPE_CLASS |
+ USB_RTYPE_INTERFACE;
+
+ //
+ // Request a Device Descriptor.
+ //
+ sSetupPacket.bRequest = (ui32Request & 0xff);
+
+ //
+ // Request for a string descriptor.
+ //
+ sSetupPacket.wValue = VOLUME_CONTROL | (ui32Channel & 0xff);
+
+ //
+ // Set the language ID.
+ //
+ sSetupPacket.wIndex = (psAudioDevice->ui8VolumeID << 8) |
+ (ui32Interface & 0xff);
+
+ //
+ // Only request the space available.
+ //
+ sSetupPacket.wLength = 2;
+
+ //
+ // Put the setup packet in the buffer.
+ //
+ USBHCDControlTransfer(0, &sSetupPacket, psAudioDevice->psDevice,
+ (uint8_t *)&ui32Value, 4,
+ psAudioDevice->psDevice->sDeviceDescriptor.bMaxPacketSize0);
+
+ return(ui32Value);
+}
+
+//*****************************************************************************
+//
+//! This function is used to get the current volume setting for a given
+//! audio device.
+//!
+//! \param psAudioInstance is an instance of the USB audio device.
+//! \param ui32Interface is the interface number to use to query the current
+//! volume setting.
+//! \param ui32Channel is the 0 based channel number to query.
+//!
+//! The function is used to retrieve the current volume setting for an audio
+//! device on the channel specified by \e ui32Channel. The \e ui32Interface is
+//! ignored for now and should be set to 0 to access the default audio control
+//! interface. 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.
+//!
+//! \note On devices that do not support volume control interfaces, this
+//! call returns 0, indicating a 0db setting.
+//!
+//! \return Returns the current volume setting for the requested interface.
+//
+//*****************************************************************************
+uint32_t
+USBHostAudioVolumeGet(tUSBHostAudioInstance *psAudioInstance,
+ uint32_t ui32Interface, uint32_t ui32Channel)
+{
+ return(VolumeSettingGet(psAudioInstance, ui32Interface, ui32Channel,
+ USB_AC_GET_CUR));
+}
+
+//*****************************************************************************
+//
+//! This function is used to get the maximum volume setting for a given
+//! audio device.
+//!
+//! \param psAudioInstance is an instance of the USB audio device.
+//! \param ui32Interface is the interface number to use to query the maximum
+//! volume control value.
+//! \param ui32Channel is the 0 based channel number to query.
+//!
+//! The function is used to retrieve the maximum volume setting for an audio
+//! device on the channel specified by \e ui32Channel. The \e ui32Interface is
+//! ignored for now and should be set to 0 to access the default audio control
+//! interface. 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.
+//!
+//! \note On devices that do not support volume control interfaces, this
+//! call returns 0, indicating a 0db setting.
+//!
+//! \return Returns the maximum volume setting for the requested interface.
+//
+//*****************************************************************************
+uint32_t
+USBHostAudioVolumeMaxGet(tUSBHostAudioInstance *psAudioInstance,
+ uint32_t ui32Interface, uint32_t ui32Channel)
+{
+ return(VolumeSettingGet(psAudioInstance, ui32Interface, ui32Channel,
+ USB_AC_GET_MAX));
+}
+
+//*****************************************************************************
+//
+//! This function is used to get the minimum volume setting for a given
+//! audio device.
+//!
+//! \param psAudioInstance is an instance of the USB audio device.
+//! \param ui32Interface is the interface number to use to query the minimum
+//! volume control value.
+//! \param ui32Channel is the 0 based channel number to query.
+//!
+//! The function is used to retrieve the minimum volume setting for an audio
+//! device on the channel specified by \e ui32Channel. The \e ui32Interface is
+//! ignored for now and should be set to 0 to access the default audio control
+//! interface. 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.
+//!
+//! \note On devices that do not support volume control interfaces, this
+//! call returns 0, indicating a 0db setting.
+//!
+//! \return Returns the minimum volume setting for the requested interface.
+//
+//*****************************************************************************
+uint32_t
+USBHostAudioVolumeMinGet(tUSBHostAudioInstance *psAudioInstance,
+ uint32_t ui32Interface, uint32_t ui32Channel)
+{
+ return(VolumeSettingGet(psAudioInstance, ui32Interface, ui32Channel,
+ USB_AC_GET_MIN));
+}
+
+//*****************************************************************************
+//
+//! This function is used to get the volume control resolution for a given
+//! audio device.
+//!
+//! \param psAudioInstance is an instance of the USB audio device.
+//! \param ui32Interface is the interface number to use to query the resolution
+//! for the volume control.
+//! \param ui32Channel is the 0 based channel number to query.
+//!
+//! The function is used to retrieve the volume control resolution for an audio
+//! device on the channel specified by \e ui32Channel. The \e ui32Interface is
+//! ignored for now and should be set to 0 to access the default audio control
+//! interface. 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.
+//!
+//! \note On devices that do not support volume control interfaces, this
+//! call returns 0, indicating a 0db setting.
+//!
+//! \return Returns the volume control resolution for the requested interface.
+//
+//*****************************************************************************
+uint32_t
+USBHostAudioVolumeResGet(tUSBHostAudioInstance *psAudioInstance,
+ uint32_t ui32Interface, uint32_t ui32Channel)
+{
+ return(VolumeSettingGet(psAudioInstance, ui32Interface, ui32Channel,
+ USB_AC_GET_RES));
+}
+
+//*****************************************************************************
+//
+//! This function is used to set the current volume setting for a given
+//! audio device.
+//!
+//! \param psAudioInstance is an instance of the USB audio device.
+//! \param ui32Interface is the interface number to use to set the current
+//! volume setting.
+//! \param ui32Channel is the 0 based channel number to query.
+//! \param ui32Value is the value to write to the USB audio device.
+//!
+//! The function is used to set the current volume setting for an audio
+//! device on the channel specified by \e ui32Channel. The \e ui32Interface is
+//! ignored for now and should be set to 0 to access the default audio control
+//! interface. 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.
+//!
+//! \note On devices that do not support volume control interfaces, this
+//! call returns 0, indicating a 0db setting.
+//!
+//! \return None.
+//
+//*****************************************************************************
+void
+USBHostAudioVolumeSet(tUSBHostAudioInstance *psAudioInstance,
+ uint32_t ui32Interface, uint32_t ui32Channel,
+ uint32_t ui32Value)
+{
+ tUSBRequest sSetupPacket;
+
+ //
+ // This is a Class specific Interface OUT request.
+ //
+ sSetupPacket.bmRequestType = USB_RTYPE_DIR_OUT | USB_RTYPE_CLASS |
+ USB_RTYPE_INTERFACE;
+
+ //
+ // Request is to set the current value.
+ //
+ sSetupPacket.bRequest = USB_AC_SET_CUR;
+
+ //
+ // Request the volume control.
+ //
+ sSetupPacket.wValue = VOLUME_CONTROL | (ui32Channel & 0xff);
+
+ //
+ // Set Volume control ID and interface to 0.
+ //
+ sSetupPacket.wIndex = psAudioInstance->ui8VolumeID << 8;
+
+ //
+ // Only request the space available.
+ //
+ sSetupPacket.wLength = 2;
+
+ //
+ // Put the setup packet in the buffer.
+ //
+ USBHCDControlTransfer(0, &sSetupPacket, psAudioInstance->psDevice,
+ (uint8_t *)&ui32Value, 2,
+ psAudioInstance->psDevice->sDeviceDescriptor.bMaxPacketSize0);
+}
+
+//*****************************************************************************
+//
+//! This function is called to determine if an audio format is supported by the
+//! connected USB Audio device.
+//!
+//! \param psAudioInstance is the device instance for this call.
+//! \param ui32SampleRate is the sample rate of the audio stream.
+//! \param ui32Bits is the number of bits per sample in the audio stream.
+//! \param ui32Channels is the number of channels in the audio stream.
+//! \param ui32Flags is a set of flags to determine what type of interface to
+//! retrieve.
+//!
+//! This function is called when an application needs to determine which audio
+//! formats are supported by a USB audio device that has been connected. The
+//! \e psAudioInstance value that is used with this call is the value that was
+//! returned from the USBHostAudioOpen() function. This call checks the
+//! USB audio device to determine if it can support the values provided in the
+//! \e ui32SampleRate, \e ui32Bits, and \e ui32Channels values. The
+//! \e ui32Flags currently only supports either the \b USBH_AUDIO_FORMAT_IN or
+//! \b USBH_AUDIO_FORMAT_OUT values that indicates if a request is for an
+//! audio input and an audio output. If the format is supported this
+//! function returns zero, and this function returns a non-zero value if the
+//! format is not supported. This function does not set the current output or
+//! input format.
+//!
+//! \return A value of zero indicates the supplied format is supported and
+//! a non-zero value indicates that the format is not supported.
+//
+//*****************************************************************************
+uint32_t
+USBHostAudioFormatGet(tUSBHostAudioInstance *psAudioInstance,
+ uint32_t ui32SampleRate, uint32_t ui32Bits,
+ uint32_t ui32Channels, uint32_t ui32Flags)
+{
+ //
+ // Look for the requested format.
+ //
+ if(AudioGetInterface(psAudioInstance, USB_ADF_PCM, ui32SampleRate,
+ ui32Bits >> 3, ui32Channels, ui32Flags) !=
+ INVALID_INTERFACE)
+ {
+ return(0);
+ }
+ return(1);
+}
+
+//*****************************************************************************
+//
+//! This function is called to set the current sample rate on an audio
+//! interface.
+//!
+//! \param psAudioInstance specifies the device instance for this call.
+//! \param ui32SampleRate is the sample rate in Hz.
+//! \param ui32Bits is the number of bits per sample.
+//! \param ui32Channels is then number of audio channels.
+//! \param ui32Flags is a set of flags that determine the access type.
+//!
+//! This function is called when to set the current audio output or input
+//! format for a USB audio device. The \e psAudioInstance value that is used
+//! with this call is the value that was returned from the USBHostAudioOpen()
+//! function. The application can use this call to insure that the audio
+//! format is supported and set the format at the same time. If the
+//! application is just checking for supported rates, then it should call the
+//! USBHostAudioFormatGet().
+//!
+//! \note This function must be called before attempting to send or receive
+//! audio with the USBHostAudioPlay() or USBHostAudioRecord() functions.
+//!
+//! \return A non-zero value indicates the supplied format is not supported and
+//! a zero value indicates that the format was supported and has been
+//! configured.
+//
+//*****************************************************************************
+uint32_t
+USBHostAudioFormatSet(tUSBHostAudioInstance *psAudioInstance,
+ uint32_t ui32SampleRate, uint32_t ui32Bits,
+ uint32_t ui32Channels, uint32_t ui32Flags)
+{
+ uint32_t ui32Interface;
+
+ //
+ // Look for the requested format.
+ //
+ ui32Interface = AudioGetInterface(psAudioInstance, USB_ADF_PCM,
+ ui32SampleRate, ui32Bits >> 3,
+ ui32Channels, ui32Flags);
+
+ if(ui32Interface == INVALID_INTERFACE)
+ {
+ return(1);
+ }
+
+ //
+ // Determine if this is an input or output request.
+ //
+ if(ui32Flags & USBH_AUDIO_FORMAT_IN)
+ {
+ //
+ // Get the active interface number and alternate setting for this
+ // format.
+ //
+ psAudioInstance->ui8InInterface =
+ (uint8_t)(ui32Interface & INTERFACE_NUM_M);
+ psAudioInstance->ui8InAltSetting =
+ (uint8_t)((ui32Interface & INTERFACE_ALTSETTING_M) >>
+ INTERFACE_ALTSETTING_S);
+ }
+ else
+ {
+ //
+ // Get the active interface number and alternate setting for this
+ // format.
+ //
+ psAudioInstance->ui8OutInterface =
+ (uint8_t)(ui32Interface & INTERFACE_NUM_M);
+ psAudioInstance->ui8OutAltSetting =
+ (uint8_t)((ui32Interface & INTERFACE_ALTSETTING_M) >>
+ INTERFACE_ALTSETTING_S);
+ }
+ return(0);
+}
+
+//*****************************************************************************
+//
+//! This function is called to send an audio buffer to the USB audio device.
+//!
+//! \param psAudioInstance specifies the device instance for this call.
+//! \param pvBuffer is the audio buffer to send.
+//! \param ui32Size is the size of the buffer in bytes.
+//! \param pfnCallback is a pointer to a callback function that is called
+//! when the buffer can be used again.
+//!
+//! This function is called when an application needs to schedule a new buffer
+//! for output to the USB audio device. Since this call schedules the transfer
+//! and returns immediately, the application should provide a \e pfnCallback
+//! function to be notified when the buffer can be used again by the
+//! application. The \e pfnCallback function provided is called with the
+//! \e pvBuffer parameter set to the \e pvBuffer provided by this call, the
+//! \e ui32Param can be ignored and the \e ui32Event parameter is
+//! \b USB_EVENT_TX_COMPLETE.
+//!
+//! \return This function returns the number of bytes that were scheduled
+//! to be sent. If this function returns zero then there was no USB audio
+//! device present or the request could not be satisfied at this time.
+//
+//*****************************************************************************
+int32_t
+USBHostAudioPlay(tUSBHostAudioInstance *psAudioInstance, void *pvBuffer,
+ uint32_t ui32Size, tUSBHostAudioCallback pfnCallback)
+{
+ uint32_t ui32Bytes;
+
+ //
+ // Make sure that there is a device present.
+ //
+ if(psAudioInstance->psDevice == 0)
+ {
+ return(0);
+ }
+
+ //
+ // If the audio output interface is not active then select the current
+ // active audio interface.
+ //
+ if(HWREGBITW(&psAudioInstance->ui32Flags, AUDIO_FLAG_OUT_ACTIVE) == 0)
+ {
+ //
+ // Indicate the active audio interface has been selected.
+ //
+ HWREGBITW(&psAudioInstance->ui32Flags, AUDIO_FLAG_OUT_ACTIVE) = 1;
+
+ //
+ // Configure the USB audio device to use the selected audio interface.
+ //
+ USBHCDSetInterface(0, (uint32_t)psAudioInstance->psDevice,
+ psAudioInstance->ui8OutInterface,
+ psAudioInstance->ui8OutAltSetting);
+ }
+
+ //
+ // Save the callback function and the buffer pointer.
+ //
+ psAudioInstance->pfnOutCallback = pfnCallback;
+ psAudioInstance->pvOutBuffer = (void *)pvBuffer;
+
+ //
+ // Schedule the data to be written out to the FIFO.
+ //
+ ui32Bytes = USBHCDPipeSchedule(psAudioInstance->ui32IsochOutPipe, pvBuffer,
+ ui32Size);
+
+ //
+ // Return the number of bytes scheduled to be sent.
+ //
+ return(ui32Bytes);
+}
+
+//*****************************************************************************
+//
+//! This function is called to provide an audio buffer to the USB audio device
+//! for audio input.
+//!
+//! \param psAudioInstance specifies the device instance for this call.
+//! \param pvBuffer is the audio buffer to send.
+//! \param ui32Size is the size of the buffer in bytes.
+//! \param pfnCallback is a pointer to a callback function that is called
+//! when the buffer has been filled.
+//!
+//! This function is called when an application needs to schedule a new buffer
+//! for input from the USB audio device. Since this call schedules the
+//! transfer and returns immediately, the application should provide a
+//! \e pfnCallback function to be notified when the buffer has been filled with
+//! audio data. When the \e pfnCallback function is called, the \e pvBuffer
+//! parameter is set to \e pvBuffer provided in this call, the \e ui32Param is
+//! the number of valid bytes in the pvBuffer and the \e ui32Event is set to
+//! \b USB_EVENT_RX_AVAILABLE.
+//!
+//! \return This function returns the number of bytes that were scheduled
+//! to be sent. If this function returns zero then there was no USB audio
+//! device present or the device does not support audio input.
+//
+//*****************************************************************************
+int32_t
+USBHostAudioRecord(tUSBHostAudioInstance *psAudioInstance, void *pvBuffer,
+ uint32_t ui32Size, tUSBHostAudioCallback pfnCallback)
+{
+ uint32_t ui32Bytes;
+
+ //
+ // Make sure that there is a device present.
+ //
+ if(psAudioInstance->psDevice == 0)
+ {
+ return(0);
+ }
+
+ //
+ // If the audio input interface is not active then select the current
+ // active audio interface.
+ //
+ if(HWREGBITW(&psAudioInstance->ui32Flags, AUDIO_FLAG_IN_ACTIVE) == 0)
+ {
+ //
+ // Indicate the active audio interface has been selected.
+ //
+ HWREGBITW(&psAudioInstance->ui32Flags, AUDIO_FLAG_IN_ACTIVE) = 1;
+
+ //
+ // Configure the USB audio device to use the selected audio interface.
+ //
+ USBHCDSetInterface(0, (uint32_t)psAudioInstance->psDevice,
+ psAudioInstance->ui8InInterface,
+ psAudioInstance->ui8InAltSetting);
+ }
+
+ //
+ // Save the callback function and the buffer pointer.
+ //
+ psAudioInstance->pfnInCallback = pfnCallback;
+ psAudioInstance->pvInBuffer = (void *)pvBuffer;
+
+ //
+ // Schedule the data to be read from the FIFO.
+ //
+ ui32Bytes = USBHCDPipeSchedule(psAudioInstance->ui32IsochInPipe, pvBuffer,
+ ui32Size);
+
+ //
+ // Return the number of bytes scheduled to be sent.
+ //
+ return(ui32Bytes);
+}
+
+//*****************************************************************************
+//
+//! This function forwards an LPM request for a device to enter L1 sleep state.
+//!
+//! \param psAudioInstance is the audio device instance that was returned
+//! from the call to USBHostAudioOpen().
+//!
+//! This function forwards a request from an application to the audio device
+//! class to request that a device enter the LPM L1 sleep state. The
+//! caller must check the return value to see if the request can be
+//! attempted at this time. If another LPM transaction is busy on this or
+//! another device, then this function returns \b USBHCD_LPM_PENDING. If
+//! the LPM request was scheduled to be sent the function returns
+//! \b USBHCD_LPM_AVAIL. The caller should check the USBHCDLPMStatus()
+//! function to determine if the request completed successfully or if there
+//! was an error.
+//!
+//! \return This function returns the following values:
+//! - \b USBHCD_LPM_AVAIL - The transition to L1 state is scheduled to be sent.
+//! - \b USBHCD_LPM_PENDING - There is already an LPM request pending.
+//
+//*****************************************************************************
+uint32_t
+USBHostAudioLPMSleep(tUSBHostAudioInstance *psAudioInstance)
+{
+ //
+ // Call the host controller function to send the sleep command.
+ //
+ return(USBHCDLPMSleep(psAudioInstance->psDevice));
+}
+
+//*****************************************************************************
+//
+//! This function returns the current status of an LPM request.
+//!
+//! \param psAudioInstance is the audio device instance that was returned
+//! from the call to USBHostAudioOpen().
+//!
+//! This function returns the current status of LPM requests for a given
+//! device. This is called to determine if a previous request completed
+//! successfully or if there was an error.
+//!
+//! \return This function returns the following values:
+//! - \b USBHCD_LPM_AVAIL - There are no pending LPM requests on this specific
+//! device or the last request completed successfully.
+//! - \b USBHCD_LPM_ERROR - The last LPM request for this device did not
+//! complete successfully.
+//! - \b USBHCD_LPM_PENDING - The last LPM request has not completed.
+//
+//*****************************************************************************
+uint32_t
+USBHostAudioLPMStatus(tUSBHostAudioInstance *psAudioInstance)
+{
+ //
+ // Call the host controller function to get the current LPM status.
+ //
+ return(USBHCDLPMStatus(psAudioInstance->psDevice));
+}
+
+//*****************************************************************************
+//
+// Close the Doxygen group.
+//! @}
+//
+//*****************************************************************************
+
diff --git a/usblib/host/usbhaudio.h b/usblib/host/usbhaudio.h
new file mode 100644
index 0000000..fc768ee
--- /dev/null
+++ b/usblib/host/usbhaudio.h
@@ -0,0 +1,163 @@
+//*****************************************************************************
+//
+// usbhaudio.h - USB host audio class driver.
+//
+// Copyright (c) 2010-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 Tiva USB Library.
+//
+//*****************************************************************************
+
+#ifndef __USBHAUDIO_H__
+#define __USBHAUDIO_H__
+
+//*****************************************************************************
+//
+// If building with a C++ compiler, make all of the definitions in this header
+// have a C binding.
+//
+//*****************************************************************************
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+//*****************************************************************************
+//
+//! \addtogroup usblib_host_class
+//! @{
+//
+//*****************************************************************************
+
+//*****************************************************************************
+//
+// USB host audio specific events
+//
+//*****************************************************************************
+
+//*****************************************************************************
+//
+//! This USB host audio event indicates that the device is connected and
+//! ready to send or receive buffers. The \e pvBuffer and \e ui32Param
+//! values are not used in this event.
+//
+//*****************************************************************************
+#define USBH_AUDIO_EVENT_OPEN (USBH_AUDIO_EVENT_BASE + 0)
+
+//*****************************************************************************
+//
+//! This USB host audio event indicates that the previously connected device
+//! has been disconnected. The \e pvBuffer and \e ui32Param values are not used
+//! in this event.
+//
+//*****************************************************************************
+#define USBH_AUDIO_EVENT_CLOSE (USBH_AUDIO_EVENT_BASE + 1)
+
+//*****************************************************************************
+//
+// This definition is used with the USBHostAudioFormatGet() and
+// USBHostAudioFormatSet() API's to determine if the audio input is being
+// accesses(USBH_AUDIO_FORMAT_IN set) or audio output(USBH_AUDIO_FORMAT clear).
+//
+//*****************************************************************************
+#define USBH_AUDIO_FORMAT_IN 0x00000001
+#define USBH_AUDIO_FORMAT_OUT 0x00000000
+
+typedef struct
+{
+ uint8_t ui8Channels;
+ uint8_t ui8Bits;
+ uint32_t ui32SampleRate;
+}
+tUSBAudioFormat;
+
+typedef struct tUSBHostAudioInstance tUSBHostAudioInstance;
+
+//*****************************************************************************
+//
+// The prototype for the host USB Audio driver callback function.
+//
+//*****************************************************************************
+typedef void (*tUSBHostAudioCallback)(tUSBHostAudioInstance *psAudioInstance,
+ uint32_t ui32Event,
+ uint32_t ui32MsgParam,
+ void *pvMsgData);
+
+//*****************************************************************************
+//
+// API Function Prototypes
+//
+//*****************************************************************************
+extern tUSBHostAudioInstance * USBHostAudioOpen(uint32_t ui32Index,
+ tUSBHostAudioCallback pfnCallback);
+extern void USBHostAudioClose(tUSBHostAudioInstance *psAudioInstance);
+extern int32_t USBHostAudioPlay(tUSBHostAudioInstance *psAudioInstance,
+ void *pvBuffer, uint32_t ui32Size,
+ tUSBHostAudioCallback pfnCallback);
+
+extern uint32_t USBHostAudioFormatGet(tUSBHostAudioInstance *psAudioInstance,
+ uint32_t ui32SampleRate,
+ uint32_t ui32Bits, uint32_t ui32Channels,
+ uint32_t ui32Flags);
+extern uint32_t USBHostAudioFormatSet(tUSBHostAudioInstance *psAudioInstance,
+ uint32_t ui32SampleRate,
+ uint32_t ui32Bits, uint32_t ui32Channels,
+ uint32_t ui32Flags);
+
+extern int32_t USBHostAudioRecord(tUSBHostAudioInstance *psAudioInstance,
+ void *pvBuffer, uint32_t ui32Size,
+ tUSBHostAudioCallback pfnAudioCallback);
+
+extern uint32_t USBHostAudioVolumeGet(tUSBHostAudioInstance *psAudioInstance,
+ uint32_t ui32Interface,
+ uint32_t ui32Channel);
+
+extern void USBHostAudioVolumeSet(tUSBHostAudioInstance *psAudioInstance,
+ uint32_t ui32Interface, uint32_t ui32Channel,
+ uint32_t ui32Value);
+
+extern uint32_t USBHostAudioVolumeMaxGet(tUSBHostAudioInstance *psAudioInstance,
+ uint32_t ui32Interface,
+ uint32_t ui32Channel);
+
+extern uint32_t USBHostAudioVolumeMinGet(tUSBHostAudioInstance *psAudioInstance,
+ uint32_t ui32Interface,
+ uint32_t ui32Channel);
+
+extern uint32_t USBHostAudioVolumeResGet(tUSBHostAudioInstance *psAudioInstance,
+ uint32_t ui32Interface,
+ uint32_t ui32Channel);
+extern uint32_t USBHostAudioLPMSleep(tUSBHostAudioInstance *psAudioInstance);
+extern uint32_t USBHostAudioLPMStatus(tUSBHostAudioInstance *psAudioInstance);
+
+//*****************************************************************************
+//
+//! @}
+//
+//*****************************************************************************
+
+//*****************************************************************************
+//
+// Mark the end of the C bindings section for C++ compilers.
+//
+//*****************************************************************************
+#ifdef __cplusplus
+}
+#endif
+
+#endif
+
diff --git a/usblib/host/usbhhid.c b/usblib/host/usbhhid.c
new file mode 100644
index 0000000..bfbea85
--- /dev/null
+++ b/usblib/host/usbhhid.c
@@ -0,0 +1,746 @@
+//*****************************************************************************
+//
+// usbhhid.c - This file contains the host HID driver.
+//
+// Copyright (c) 2008-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 Tiva USB Library.
+//
+//*****************************************************************************
+
+#include <stdbool.h>
+#include <stdint.h>
+#include "inc/hw_types.h"
+#include "driverlib/usb.h"
+#include "usblib/usblib.h"
+#include "usblib/usblibpriv.h"
+#include "usblib/usbhid.h"
+#include "usblib/host/usbhost.h"
+#include "usblib/host/usbhostpriv.h"
+#include "usblib/host/usbhhid.h"
+
+static void * HIDDriverOpen(tUSBHostDevice *psDevice);
+static void HIDDriverClose(void *pvInstance);
+
+//*****************************************************************************
+//
+//! \addtogroup usblib_host_class
+//! @{
+//
+//*****************************************************************************
+
+//*****************************************************************************
+//
+// If the user has not explicitly stated the maximum number of HID devices to
+// support, we assume that we need to support up to the maximum number of USB
+// devices that the build is configured for.
+//
+//*****************************************************************************
+#ifndef MAX_HID_DEVICES
+#define MAX_HID_DEVICES MAX_USB_DEVICES
+#endif
+
+//*****************************************************************************
+//
+// This is the structure that holds all of the data for a given instance of
+// a HID device.
+//
+//*****************************************************************************
+struct tHIDInstance
+{
+ //
+ // Save the device instance.
+ //
+ tUSBHostDevice *psDevice;
+
+ //
+ // Used to save the callback.
+ //
+ tUSBCallback pfnCallback;
+
+ //
+ // Callback data provided by caller.
+ //
+ void *pvCBData;
+
+ //
+ // Used to remember what type of device was registered.
+ //
+ tHIDSubClassProtocol iDeviceType;
+
+ //
+ // Interrupt IN pipe.
+ //
+ uint32_t ui32IntInPipe;
+};
+
+//*****************************************************************************
+//
+// The instance data storage for attached hid devices.
+//
+//*****************************************************************************
+static tHIDInstance g_psHIDDevice[MAX_HID_DEVICES];
+
+//*****************************************************************************
+//
+//! This constant global structure defines the HID Class Driver that is
+//! provided with the USB library.
+//
+//*****************************************************************************
+const tUSBHostClassDriver g_sUSBHIDClassDriver =
+{
+ USB_CLASS_HID,
+ HIDDriverOpen,
+ HIDDriverClose,
+ 0
+};
+
+//*****************************************************************************
+//
+//! This function is used to open an instance of a HID device.
+//!
+//! \param iDeviceType is the type of device that should be loaded for this
+//! instance of the HID device.
+//! \param pfnCallback is the function that will be called whenever changes
+//! are detected for this device.
+//! \param pvCBData is the data that will be returned in when the
+//! \e pfnCallback function is called.
+//!
+//! This function creates an instance of an specific type of HID device. The
+//! \e iDeviceType parameter is one subclass/protocol values of the types
+//! specified in enumerated types tHIDSubClassProtocol. Only devices that
+//! enumerate with this type will be called back via the \e pfnCallback
+//! function. The \e pfnCallback parameter is the callback function for any
+//! events that occur for this device type. The \e pfnCallback function must
+//! point to a valid function of type \e tUSBCallback for this call to complete
+//! successfully. To release this device instance the caller of USBHHIDOpen()
+//! should call USBHHIDClose() and pass in the value returned from the
+//! USBHHIDOpen() call.
+//!
+//! \return This function returns and instance value that should be used with
+//! any other APIs that require an instance value. If a value of 0 is returned
+//! then the device instance could not be created.
+//
+//*****************************************************************************
+tHIDInstance *
+USBHHIDOpen(tHIDSubClassProtocol iDeviceType, tUSBCallback pfnCallback,
+ void *pvCBData)
+{
+ uint32_t ui32Loop;
+
+ //
+ // Find a free device instance structure.
+ //
+ for(ui32Loop = 0; ui32Loop < MAX_HID_DEVICES; ui32Loop++)
+ {
+ if(g_psHIDDevice[ui32Loop].iDeviceType == eUSBHHIDClassNone)
+ {
+ //
+ // Save the instance data for this device.
+ //
+ g_psHIDDevice[ui32Loop].pfnCallback = pfnCallback;
+ g_psHIDDevice[ui32Loop].iDeviceType = iDeviceType;
+ g_psHIDDevice[ui32Loop].pvCBData = pvCBData;
+
+ //
+ // Return the device instance pointer.
+ //
+ return(&g_psHIDDevice[ui32Loop]);
+ }
+ }
+
+ //
+ // If we get here, there are no space device slots so return NULL to
+ // indicate a problem.
+ //
+ return(0);
+}
+
+//*****************************************************************************
+//
+//! This function is used to release an instance of a HID device.
+//!
+//! \param psHIDInstance is the instance value for a HID device to release.
+//!
+//! This function releases an instance of a HID device that was created by a
+//! call to USBHHIDOpen(). This call is required to allow other HID devices
+//! to be enumerated after another HID device has been disconnected. The
+//! \e psHIDInstance parameter should hold the value that was returned from
+//! the previous call to USBHHIDOpen().
+//!
+//! \return None.
+//
+//*****************************************************************************
+void
+USBHHIDClose(tHIDInstance *psHIDInstance)
+{
+ //
+ // Disable any more notifications from the HID layer.
+ //
+ psHIDInstance->pfnCallback = 0;
+
+ //
+ // Mark this device slot as free.
+ //
+ psHIDInstance->iDeviceType = eUSBHHIDClassNone;
+}
+
+//*****************************************************************************
+//
+// This function handles callbacks for the interrupt IN endpoint.
+//
+//*****************************************************************************
+static void
+HIDIntINCallback(uint32_t ui32Pipe, uint32_t ui32Event)
+{
+ int32_t i32Dev;
+
+ switch (ui32Event)
+ {
+ //
+ // Handles a request to schedule a new request on the interrupt IN
+ // pipe.
+ //
+ case USB_EVENT_SCHEDULER:
+ {
+ USBHCDPipeSchedule(ui32Pipe, 0, 1);
+ break;
+ }
+ //
+ // Called when new data is available on the interrupt IN pipe.
+ //
+ case USB_EVENT_RX_AVAILABLE:
+ {
+ //
+ // Determine which device this notification is intended for.
+ //
+ for(i32Dev = 0; i32Dev < MAX_HID_DEVICES; i32Dev++)
+ {
+ //
+ // Does this device own the pipe we have been passed?
+ //
+ if(g_psHIDDevice[i32Dev].ui32IntInPipe == ui32Pipe)
+ {
+ //
+ // Yes - send the report data to the USB host HID device
+ // class driver.
+ //
+ g_psHIDDevice[i32Dev].pfnCallback(
+ g_psHIDDevice[i32Dev].pvCBData,
+ USB_EVENT_RX_AVAILABLE, ui32Pipe, 0);
+ }
+ }
+
+ break;
+ }
+ }
+}
+
+//*****************************************************************************
+//
+//! This function is used to open an instance of the HID driver.
+//!
+//! \param psDevice is a pointer to the device information structure.
+//!
+//! This function will attempt to open an instance of the HID driver based on
+//! the information contained in the psDevice structure. This call can fail if
+//! there are not sufficient resources to open the device. The function will
+//! return a value that should be passed back into USBHIDClose() when the
+//! driver is no longer needed.
+//!
+//! \return The function will return a pointer to a HID driver instance.
+//
+//*****************************************************************************
+static void *
+HIDDriverOpen(tUSBHostDevice *psDevice)
+{
+ int32_t i32Idx, i32Dev;
+ tEndpointDescriptor *psEndpointDescriptor;
+ tInterfaceDescriptor *psInterface;
+
+ //
+ // Get the interface descriptor.
+ //
+ psInterface = USBDescGetInterface(psDevice->psConfigDescriptor, 0, 0);
+
+ //
+ // Search the currently open instances for one that supports the protocol
+ // of this device.
+ //
+ for(i32Dev = 0; i32Dev < MAX_HID_DEVICES; i32Dev++)
+ {
+ if(g_psHIDDevice[i32Dev].iDeviceType ==
+ psInterface->bInterfaceProtocol)
+ {
+ //
+ // Save the device pointer.
+ //
+ g_psHIDDevice[i32Dev].psDevice = psDevice;
+
+ for(i32Idx = 0; i32Idx < 3; i32Idx++)
+ {
+ //
+ // Get the first endpoint descriptor.
+ //
+ psEndpointDescriptor = USBDescGetInterfaceEndpoint(psInterface,
+ i32Idx,
+ 256);
+
+ //
+ // If no more endpoints then break out.
+ //
+ if(psEndpointDescriptor == 0)
+ {
+ break;
+ }
+
+ //
+ // Interrupt
+ //
+ if((psEndpointDescriptor->bmAttributes & USB_EP_ATTR_TYPE_M) ==
+ USB_EP_ATTR_INT)
+ {
+ //
+ // Interrupt IN.
+ //
+ if(psEndpointDescriptor->bEndpointAddress & USB_EP_DESC_IN)
+ {
+ g_psHIDDevice[i32Dev].ui32IntInPipe =
+ USBHCDPipeAlloc(0, USBHCD_PIPE_INTR_IN,
+ psDevice, HIDIntINCallback);
+ USBHCDPipeConfig(g_psHIDDevice[i32Dev].ui32IntInPipe,
+ psEndpointDescriptor->wMaxPacketSize,
+ psEndpointDescriptor->bInterval,
+ (psEndpointDescriptor->bEndpointAddress &
+ USB_EP_DESC_NUM_M));
+ }
+ }
+ }
+
+ //
+ // If there is a callback function call it to inform the application that
+ // the device has been enumerated.
+ //
+ if(g_psHIDDevice[i32Dev].pfnCallback != 0)
+ {
+ g_psHIDDevice[i32Dev].pfnCallback(
+ g_psHIDDevice[i32Dev].pvCBData,
+ USB_EVENT_CONNECTED,
+ (uint32_t)&g_psHIDDevice[i32Dev], 0);
+ }
+
+ //
+ // Save the device pointer.
+ //
+ g_psHIDDevice[i32Dev].psDevice = psDevice;
+
+ return (&g_psHIDDevice[i32Dev]);
+ }
+ }
+
+ //
+ // If we get here, no user has registered an interest in this particular
+ // HID device so we return an error.
+ //
+ return(0);
+}
+
+//*****************************************************************************
+//
+//! This function is used to release an instance of the HID driver.
+//!
+//! \param pvInstance is an instance pointer that needs to be released.
+//!
+//! This function will free up any resources in use by the HID driver instance
+//! that is passed in. The \e pvInstance pointer should be a valid value that
+//! was returned from a call to USBHIDOpen().
+//!
+//! \return None.
+//
+//*****************************************************************************
+static void
+HIDDriverClose(void *pvInstance)
+{
+ tHIDInstance *psInst;
+
+ //
+ // Get our instance pointer.
+ //
+ psInst = (tHIDInstance *)pvInstance;
+
+ //
+ // Reset the device pointer.
+ //
+ psInst->psDevice = 0;
+
+ //
+ // Free the Interrupt IN pipe.
+ //
+ if(psInst->ui32IntInPipe != 0)
+ {
+ USBHCDPipeFree(psInst->ui32IntInPipe);
+ }
+
+ //
+ // If the callback exists, call it with a DISCONNECTED event.
+ //
+ if(psInst->pfnCallback != 0)
+ {
+ psInst->pfnCallback(psInst->pvCBData, USB_EVENT_DISCONNECTED,
+ (uint32_t)pvInstance, 0);
+ }
+}
+
+//*****************************************************************************
+//
+//! This function is used to set the idle timeout for a HID device.
+//!
+//! \param psHIDInstance is the value that was returned from the call to
+//! USBHHIDOpen().
+//! \param ui8Duration is the duration of the timeout in milliseconds.
+//! \param ui8ReportID is the report identifier to set the timeout on.
+//!
+//! This function will send the Set Idle command to a HID device to set the
+//! idle timeout for a given report. The length of the timeout is specified
+//! by the \e ui8Duration parameter and the report the timeout for is in the
+//! \e ui8ReportID value.
+//!
+//! \return Always returns 0.
+//
+//*****************************************************************************
+uint32_t
+USBHHIDSetIdle(tHIDInstance *psHIDInstance, uint8_t ui8Duration,
+ uint8_t ui8ReportID)
+{
+ tUSBRequest sSetupPacket;
+
+ //
+ // This is a Class specific interface OUT request.
+ //
+ sSetupPacket.bmRequestType = USB_RTYPE_DIR_OUT | USB_RTYPE_CLASS |
+ USB_RTYPE_INTERFACE;
+
+ //
+ // Request a Device Descriptor.
+ //
+ sSetupPacket.bRequest = USBREQ_SET_IDLE;
+ sSetupPacket.wValue = (ui8Duration << 8) | ui8ReportID;
+
+ //
+ // Set this on interface 1.
+ //
+ sSetupPacket.wIndex = 0;
+
+ //
+ // This is always 0 for this request.
+ //
+ sSetupPacket.wLength = 0;
+
+ //
+ // Put the setup packet in the buffer.
+ //
+ return(USBHCDControlTransfer(0, &sSetupPacket, psHIDInstance->psDevice,
+ 0, 0, MAX_PACKET_SIZE_EP0));
+}
+
+//*****************************************************************************
+//
+//! This function can be used to retrieve the report descriptor for a given
+//! device instance.
+//!
+//! \param psHIDInstance is the value that was returned from the call to
+//! USBHHIDOpen().
+//! \param pui8Buffer is the memory buffer to use to store the report
+//! descriptor.
+//! \param ui32Size is the size in bytes of the buffer pointed to by
+//! \e pui8Buffer.
+//!
+//! This function is used to return a report descriptor from a HID device
+//! instance so that it can determine how to interpret reports that are
+//! returned from the device indicated by the \e psHIDInstance parameter.
+//! This call is blocking and will return the number of bytes read into the
+//! \e pui8Buffer.
+//!
+//! \return Returns the number of bytes read into the \e pui8Buffer.
+//
+//*****************************************************************************
+uint32_t
+USBHHIDGetReportDescriptor(tHIDInstance *psHIDInstance, uint8_t *pui8Buffer,
+ uint32_t ui32Size)
+{
+ tUSBRequest sSetupPacket;
+ uint32_t ui32Bytes;
+
+ //
+ // This is a Standard Device IN request.
+ //
+ sSetupPacket.bmRequestType = USB_RTYPE_DIR_IN | USB_RTYPE_STANDARD |
+ USB_RTYPE_INTERFACE;
+
+ //
+ // Request a Report Descriptor.
+ //
+ sSetupPacket.bRequest = USBREQ_GET_DESCRIPTOR;
+ sSetupPacket.wValue = USB_HID_DTYPE_REPORT << 8;
+
+ //
+ // Index is always 0 for device requests.
+ //
+ sSetupPacket.wIndex = 0;
+
+ //
+ // All devices must have at least an 8 byte max packet size so just ask
+ // for 8 bytes to start with.
+ //
+ sSetupPacket.wLength = ui32Size;
+
+ //
+ // Now get the full descriptor now that the actual maximum packet size
+ // is known.
+ //
+ ui32Bytes = USBHCDControlTransfer(0, &sSetupPacket,
+ psHIDInstance->psDevice, pui8Buffer, ui32Size,
+ psHIDInstance->psDevice->sDeviceDescriptor.bMaxPacketSize0);
+
+ return(ui32Bytes);
+}
+
+//*****************************************************************************
+//
+//! This function is used to set or clear the boot protocol state of a device.
+//!
+//! \param psHIDInstance is the value that was returned from the call to
+//! USBHHIDOpen().
+//! \param ui32BootProtocol is either zero or non-zero to indicate which
+//! protocol to use for the device.
+//!
+//! A USB host device can use this function to set the protocol for a connected
+//! HID device. This is commonly used to set keyboards and mice into their
+//! simplified boot protocol modes to fix the report structure to a know
+//! state.
+//!
+//! \return This function returns 0.
+//
+//*****************************************************************************
+uint32_t
+USBHHIDSetProtocol(tHIDInstance *psHIDInstance, uint32_t ui32BootProtocol)
+{
+ tUSBRequest sSetupPacket;
+
+ //
+ // This is a Standard Device IN request.
+ //
+ sSetupPacket.bmRequestType = USB_RTYPE_DIR_OUT | USB_RTYPE_CLASS |
+ USB_RTYPE_INTERFACE;
+
+ //
+ // Request a Report Descriptor.
+ //
+ sSetupPacket.bRequest = USBREQ_SET_PROTOCOL;
+
+ if(ui32BootProtocol)
+ {
+ //
+ // Boot Protocol.
+ //
+ sSetupPacket.wValue = 0;
+ }
+ else
+ {
+ //
+ // Report Protocol.
+ //
+ sSetupPacket.wValue = 1;
+ }
+
+ //
+ // Index is always 0 for device requests.
+ //
+ sSetupPacket.wIndex = 0;
+
+ //
+ // Always 0.
+ //
+ sSetupPacket.wLength = 0;
+
+ //
+ // Now get the full descriptor now that the actual maximum packet size
+ // is known.
+ //
+ USBHCDControlTransfer(0, &sSetupPacket, psHIDInstance->psDevice, 0, 0,
+ psHIDInstance->psDevice->sDeviceDescriptor.bMaxPacketSize0);
+
+ return(0);
+}
+
+//*****************************************************************************
+//
+//! This function is used to retrieve a report from a HID device.
+//!
+//! \param psHIDInstance is the value that was returned from the call to
+//! USBHHIDOpen().
+//! \param ui32Interface is the interface to retrieve the report from.
+//! \param pui8Data is the memory buffer to use to store the report.
+//! \param ui32Size is the size in bytes of the buffer pointed to by
+//! \e pui8Buffer.
+//!
+//! This function is used to retrieve a report from a USB pipe. It is usually
+//! called when the USB HID layer has detected a new data available in a USB
+//! pipe. The USB HID host device code will receive a
+//! \b USB_EVENT_RX_AVAILABLE event when data is available, allowing the
+//! callback function to retrieve the data.
+//!
+//! \return Returns the number of bytes read from report.
+//
+//*****************************************************************************
+uint32_t
+USBHHIDGetReport(tHIDInstance *psHIDInstance, uint32_t ui32Interface,
+ uint8_t *pui8Data, uint32_t ui32Size)
+{
+ //
+ // Read the Data out.
+ //
+ ui32Size = USBHCDPipeReadNonBlocking(psHIDInstance->ui32IntInPipe,
+ pui8Data, ui32Size);
+
+ //
+ // Return the number of bytes read from the interrupt in pipe.
+ //
+ return(ui32Size);
+}
+
+//*****************************************************************************
+//
+//! This function is used to send a report to a HID device.
+//!
+//! \param psHIDInstance is the value that was returned from the call to
+//! USBHHIDOpen().
+//! \param ui32Interface is the interface to send the report to.
+//! \param pui8Data is the memory buffer to use to store the report.
+//! \param ui32Size is the size in bytes of the buffer pointed to by
+//! \e pui8Buffer.
+//!
+//! This function is used to send a report to a USB HID device. It can be
+//! only be called from outside the callback context as this function will not
+//! return from the call until the data has been sent successfully.
+//!
+//! \return Returns the number of bytes sent to the device.
+//
+//*****************************************************************************
+uint32_t
+USBHHIDSetReport(tHIDInstance *psHIDInstance, uint32_t ui32Interface,
+ uint8_t *pui8Data, uint32_t ui32Size)
+{
+ tUSBRequest sSetupPacket;
+
+ //
+ // This is a class specific OUT request.
+ //
+ sSetupPacket.bmRequestType = USB_RTYPE_DIR_OUT | USB_RTYPE_CLASS |
+ USB_RTYPE_INTERFACE;
+
+ //
+ // Request a Report Descriptor.
+ //
+ sSetupPacket.bRequest = USBREQ_SET_REPORT;
+ sSetupPacket.wValue = USB_HID_REPORT_OUTPUT << 8;
+
+ //
+ // Index is always 0 for device requests.
+ //
+ sSetupPacket.wIndex = (uint16_t)ui32Interface;
+
+ //
+ // Always 0.
+ //
+ sSetupPacket.wLength = ui32Size;
+
+ //
+ // Now get the full descriptor now that the actual maximum packet size
+ // is known.
+ //
+ USBHCDControlTransfer(0, &sSetupPacket, psHIDInstance->psDevice,
+ pui8Data, ui32Size,
+ psHIDInstance->psDevice->sDeviceDescriptor.bMaxPacketSize0);
+
+ return(ui32Size);
+}
+
+//*****************************************************************************
+//
+//! This function forwards an LPM request for a device to enter L1 sleep state.
+//!
+//! \param psHIDInstance is the HID instance that was returned from the call
+//! to USBHHIDOpen().
+//!
+//! This function forwards a request from a HID device class to the host
+//! controller to request that a device enter the LPM L1 sleep state. The
+//! caller must check the return value to see if the request can be
+//! attempted at this time. If another LPM transaction is busy on this or
+//! another device, then this function returns \b USBHCD_LPM_PENDING. If
+//! the LPM request was scheduled to be sent the function returns
+//! \b USBHCD_LPM_AVAIL. The caller should check the USBHCDLPMStatus()
+//! function to determine if the request completed successfully or if there
+//! was an error.
+//!
+//! \return This function returns the following values:
+//! - USBHCD_LPM_AVAIL - The transition to L1 state is scheduled to be sent.
+//! - USBHCD_LPM_PENDING - There is already an LPM request pending.
+//
+//*****************************************************************************
+uint32_t
+USBHHIDLPMSleep(tHIDInstance *psHIDInstance)
+{
+ //
+ // Forward the request to the control endpoint of the device.
+ //
+ return(USBHCDLPMSleep(psHIDInstance->psDevice));
+}
+
+//*****************************************************************************
+//
+//! This function returns the current status of an LPM request.
+//!
+//! \param psHIDInstance is the HID instance that was returned from the call
+//! to USBHHIDOpen().
+//!
+//! This function returns the current status of LPM requests for a given
+//! device. This is called to determine if a previous request completed
+//! successfully or if there was an error.
+//!
+//! \return This function returns the following values:
+//! - \b USBHCD_LPM_AVAIL - There are no pending LPM requests on this specific
+//! device or the last request completed successfully.
+//! - \b USBHCD_LPM_ERROR - The last LPM request for this device did not
+//! complete successfully.
+//! - \b USBHCD_LPM_PENDING - The last LPM request has not completed.
+//
+//*****************************************************************************
+uint32_t
+USBHHIDLPMStatus(tHIDInstance *psHIDInstance)
+{
+ //
+ // Call the host controller function to get the current LPM status.
+ //
+ return(USBHCDLPMStatus(psHIDInstance->psDevice));
+}
+
+//*****************************************************************************
+//
+//! @}
+//
+//*****************************************************************************
diff --git a/usblib/host/usbhhid.h b/usblib/host/usbhhid.h
new file mode 100644
index 0000000..f2df536
--- /dev/null
+++ b/usblib/host/usbhhid.h
@@ -0,0 +1,166 @@
+//*****************************************************************************
+//
+// usbhhid.h - This hold the host driver for hid class.
+//
+// Copyright (c) 2008-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 Tiva USB Library.
+//
+//*****************************************************************************
+
+#ifndef __USBHHID_H__
+#define __USBHHID_H__
+
+//*****************************************************************************
+//
+// If building with a C++ compiler, make all of the definitions in this header
+// have a C binding.
+//
+//*****************************************************************************
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+//*****************************************************************************
+//
+//! \addtogroup usblib_host_class
+//! @{
+//
+//*****************************************************************************
+
+typedef struct tHIDInstance tHIDInstance;
+
+//*****************************************************************************
+//
+// These defines are the the events that will be passed in the ui32Event
+// parameter of the callback from the driver.
+//
+//*****************************************************************************
+#define USBH_EVENT_HID_SETRPT USBH_HID_EVENT_BASE + 0
+#define USBH_EVENT_HID_REPORT USBH_HID_EVENT_BASE + 1
+
+//
+//! The HID keyboard detected a key being pressed.
+//
+#define USBH_EVENT_HID_KB_PRESS USBH_HID_EVENT_BASE + 16
+
+//
+//! The HID keyboard detected a key being released.
+//
+#define USBH_EVENT_HID_KB_REL USBH_HID_EVENT_BASE + 17
+
+//
+//! The HID keyboard detected one of the keyboard modifiers being pressed.
+//
+#define USBH_EVENT_HID_KB_MOD USBH_HID_EVENT_BASE + 18
+
+//
+//! A button was pressed on a HID mouse.
+//
+#define USBH_EVENT_HID_MS_PRESS USBH_HID_EVENT_BASE + 32
+
+//
+//! A button was released on a HID mouse.
+//
+#define USBH_EVENT_HID_MS_REL USBH_HID_EVENT_BASE + 33
+
+//
+//! The HID mouse detected movement in the X direction.
+//
+#define USBH_EVENT_HID_MS_X USBH_HID_EVENT_BASE + 34
+
+//
+//! The HID mouse detected movement in the Y direction.
+//
+#define USBH_EVENT_HID_MS_Y USBH_HID_EVENT_BASE + 35
+
+//*****************************************************************************
+//
+//! The following values are used to register callbacks to the USB HOST HID
+//! device class layer.
+//
+//*****************************************************************************
+typedef enum
+{
+ //
+ //! No device should be used. This value should not be used by
+ //! applications.
+ //
+ eUSBHHIDClassNone = 0,
+
+ //
+ //! This is a keyboard device.
+ //
+ eUSBHHIDClassKeyboard,
+
+ //
+ //! This is a mouse device.
+ //
+ eUSBHHIDClassMouse,
+
+ //
+ //! This is a vendor specific device.
+ //
+ eUSBHHIDClassVendor
+}
+tHIDSubClassProtocol;
+
+//*****************************************************************************
+//
+// Close the Doxygen group.
+//! @}
+//
+//*****************************************************************************
+
+//*****************************************************************************
+//
+// Prototypes.
+//
+//*****************************************************************************
+extern tHIDInstance * USBHHIDOpen(tHIDSubClassProtocol iDeviceType,
+ tUSBCallback pfnCallback,
+ void *pvCBData);
+extern void USBHHIDClose(tHIDInstance *psHIDInstance);
+extern uint32_t USBHHIDGetReportDescriptor(tHIDInstance *psHIDInstance,
+ uint8_t *pui8Buffer,
+ uint32_t ui32Size);
+extern uint32_t USBHHIDSetIdle(tHIDInstance *psHIDInstance, uint8_t ui8Duration,
+ uint8_t ui8ReportID);
+extern uint32_t USBHHIDSetProtocol(tHIDInstance *psHIDInstance,
+ uint32_t ui32BootProtocol);
+extern uint32_t USBHHIDSetReport(tHIDInstance *psHIDInstance,
+ uint32_t ui32Interface, uint8_t *pui8Data,
+ uint32_t ui32Size);
+extern uint32_t USBHHIDGetReport(tHIDInstance *psHIDInstance,
+ uint32_t ui32Interface, uint8_t *pui8Data,
+ uint32_t ui32Size);
+extern uint32_t USBHHIDLPMSleep(tHIDInstance *psHIDInstance);
+extern uint32_t USBHHIDLPMStatus(tHIDInstance *psHIDInstance);
+
+extern const tUSBHostClassDriver g_sUSBHIDClassDriver;
+
+//*****************************************************************************
+//
+// Mark the end of the C bindings section for C++ compilers.
+//
+//*****************************************************************************
+#ifdef __cplusplus
+}
+#endif
+
+#endif // __USBHHID_H__
diff --git a/usblib/host/usbhhidkeyboard.c b/usblib/host/usbhhidkeyboard.c
new file mode 100644
index 0000000..08f2b6a
--- /dev/null
+++ b/usblib/host/usbhhidkeyboard.c
@@ -0,0 +1,752 @@
+//*****************************************************************************
+//
+// usbhhidkeyboard.c - This file holds the application interfaces for USB
+// keyboard devices.
+//
+// Copyright (c) 2008-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 Tiva USB Library.
+//
+//*****************************************************************************
+
+#include <stdbool.h>
+#include <stdint.h>
+#include "inc/hw_types.h"
+#include "usblib/usblib.h"
+#include "usblib/host/usbhost.h"
+#include "usblib/usbhid.h"
+#include "usblib/host/usbhhid.h"
+#include "usblib/host/usbhhidkeyboard.h"
+
+//*****************************************************************************
+//
+//! \addtogroup usblib_host_device
+//! @{
+//
+//*****************************************************************************
+
+//*****************************************************************************
+//
+// Prototypes for local functions.
+//
+//*****************************************************************************
+static uint32_t USBHKeyboardCallback(void *pvKeyboard, uint32_t ui32Event,
+ uint32_t ui32MsgParam, void *pvMsgData);
+
+//*****************************************************************************
+//
+// The size of a USB keyboard report.
+//
+//*****************************************************************************
+#define USBHKEYB_REPORT_SIZE 8
+
+//*****************************************************************************
+//
+// These are the flags for the tUSBHKeyboard.ui32HIDFlags member variable.
+//
+//*****************************************************************************
+#define USBHKEYB_DEVICE_PRESENT 0x00000001
+
+//*****************************************************************************
+//
+// This is the structure definition for a keyboard device instance.
+//
+//*****************************************************************************
+struct tUSBHKeyboard
+{
+ //
+ // Global flags for an instance of a keyboard.
+ //
+ uint32_t ui32HIDFlags;
+
+ //
+ // The applications registered callback.
+ //
+ tUSBHIDKeyboardCallback pfnCallback;
+
+ //
+ // The HID instance pointer for this keyboard instance.
+ //
+ tHIDInstance *psHIDInstance;
+
+ //
+ // NUM_LOCK, CAPS_LOCK, SCROLL_LOCK, COMPOSE or KANA keys.
+ //
+ uint8_t ui8KeyModSticky;
+
+ //
+ // This is the current state of the keyboard modifier keys.
+ //
+ uint8_t ui8KeyModState;
+
+ //
+ // This holds the keyboard usage codes for keys that are being held down.
+ //
+ uint8_t pui8KeyState[6];
+
+ //
+ // This is a local buffer to hold the current HID report that comes up
+ // from the HID driver layer.
+ //
+ uint8_t pui8Buffer[USBHKEYB_REPORT_SIZE];
+};
+
+//*****************************************************************************
+//
+// This is the per instance information for a keyboard device.
+//
+//*****************************************************************************
+static tUSBHKeyboard g_sUSBHKeyboard =
+{
+ 0
+};
+
+//*****************************************************************************
+//
+//! This function is used open an instance of a keyboard.
+//!
+//! \param pfnCallback is the callback function to call when new events occur
+//! with the keyboard returned.
+//! \param pui8Buffer is the memory used by the keyboard to interact with the
+//! USB keyboard.
+//! \param ui32Size is the size of the buffer provided by \e pui8Buffer.
+//!
+//! This function is used to open an instance of the keyboard. The value
+//! returned from this function should be used as the instance identifier for
+//! all other USBHKeyboard calls. The \e pui8Buffer memory buffer is used to
+//! access the keyboard. The buffer size required is at least enough to hold
+//! a normal report descriptor for the device. If there is not enough space
+//! only a partial report descriptor will be read out.
+//!
+//! \return Returns the instance identifier for the keyboard that is attached.
+//! If there is no keyboard present this will return 0.
+//
+//*****************************************************************************
+tUSBHKeyboard *
+USBHKeyboardOpen(tUSBHIDKeyboardCallback pfnCallback, uint8_t *pui8Buffer,
+ uint32_t ui32Size)
+{
+ //
+ // Save the callback and data pointers.
+ //
+ g_sUSBHKeyboard.pfnCallback = pfnCallback;
+
+ //
+ // Save the instance pointer for the HID device that was opened.
+ //
+ g_sUSBHKeyboard.psHIDInstance =
+ USBHHIDOpen(eUSBHHIDClassKeyboard, USBHKeyboardCallback,
+ (void *)&g_sUSBHKeyboard);
+
+ return(&g_sUSBHKeyboard);
+}
+
+//*****************************************************************************
+//
+//! This function is used close an instance of a keyboard.
+//!
+//! \param psKbInstance is the instance value for this keyboard.
+//!
+//! This function is used to close an instance of the keyboard that was opened
+//! with a call to USBHKeyboardOpen(). The \e psKbInstance value is the
+//! value that was returned when the application called USBHKeyboardOpen().
+//!
+//! \return This function returns 0 to indicate success any non-zero value
+//! indicates an error condition.
+//
+//*****************************************************************************
+uint32_t
+USBHKeyboardClose(tUSBHKeyboard *psKbInstance)
+{
+ //
+ // Reset the callback to null.
+ //
+ psKbInstance->pfnCallback = 0;
+
+ //
+ // Call the HID driver layer to close out this instance.
+ //
+ USBHHIDClose(psKbInstance->psHIDInstance);
+
+ return(0);
+}
+
+//*****************************************************************************
+//
+//! This function is used to map a USB usage ID to a printable character.
+//!
+//! \param psKbInstance is the instance value for this keyboard.
+//! \param psTable is the table to use to map the usage ID to characters.
+//! \param ui8UsageID is the USB usage ID to map to a character.
+//!
+//! This function is used to map a USB usage ID to a character. The provided
+//! \e psTable is used to perform the mapping and is described by the
+//! tHIDKeyboardUsageTable type defined structure. See the documentation on
+//! the tHIDKeyboardUsageTable structure for more details on the internals of
+//! this structure. This function uses the current state of the shift keys
+//! and the Caps Lock key to modify the data returned by this function. The
+//! psTable structure has values indicating which keys are modified by Caps
+//! and alternate values for shifted cases. The number of bytes returned from
+//! Lock this function depends on the \e psTable structure passed in as it
+//! holds the number of bytes per character in the table.
+//!
+//! \return Returns the character value for the given usage id.
+//
+//*****************************************************************************
+uint32_t
+USBHKeyboardUsageToChar(tUSBHKeyboard *psKbInstance,
+ const tHIDKeyboardUsageTable *psTable,
+ uint8_t ui8UsageID)
+{
+ uint32_t ui32Value, ui32Offset, ui32Shift;
+ const uint8_t *pui8KeyBoardMap;
+ const uint16_t *pui16KeyBoardMap;
+
+ //
+ // The added offset for the shifted character value.
+ //
+ ui32Shift = 0;
+
+ //
+ // Offset in the table for the character.
+ //
+ ui32Offset = (ui8UsageID * psTable->ui8BytesPerChar * 2);
+
+ //
+ // Handle the case where CAPS lock has been set.
+ //
+ if(psKbInstance->ui8KeyModSticky &= HID_KEYB_CAPS_LOCK)
+ {
+ //
+ // See if this usage ID is modified by Caps Lock by checking the packed
+ // bit array in the pui32ShiftState member of the psTable array.
+ //
+ if((psTable->pui32CapsLock[ui8UsageID >> 5]) >>
+ (ui8UsageID & 0x1f) & 1)
+ {
+ ui32Shift = psTable->ui8BytesPerChar;
+ }
+ }
+
+ //
+ // Now handle if a shift key is being held.
+ //
+ if((psKbInstance->ui8KeyModState & 0x22) != 0)
+ {
+ //
+ // Not shifted yet so we need to shift.
+ //
+ if(ui32Shift == 0)
+ {
+ ui32Shift = psTable->ui8BytesPerChar;
+ }
+ else
+ {
+ //
+ // Unshift because CAPS LOCK and shift were pressed.
+ //
+ ui32Shift = 0;
+ }
+ }
+
+ //
+ // One byte per character.
+ //
+ if(psTable->ui8BytesPerChar == 1)
+ {
+ //
+ // Get the base address of the table.
+ //
+ pui8KeyBoardMap = psTable->pvCharMapping;
+
+ ui32Value = pui8KeyBoardMap[ui32Offset + ui32Shift];
+ }
+ //
+ // Two bytes per character.
+ //
+ else if(psTable->ui8BytesPerChar == 2)
+ {
+ //
+ // Get the base address of the table.
+ //
+ pui16KeyBoardMap = (uint16_t *)psTable->pvCharMapping;
+
+ ui32Value = pui16KeyBoardMap[ui32Offset + ui32Shift];
+ }
+ //
+ // All other sizes are unsupported for now.
+ //
+ else
+ {
+ ui32Value = 0;
+ }
+
+ return(ui32Value);
+}
+
+//*****************************************************************************
+//
+//! This function is used to set one of the fixed modifier keys on a keyboard.
+//!
+//! \param psKbInstance is the instance value for this keyboard.
+//! \param ui32Modifiers is a bit mask of the modifiers to set on the keyboard.
+//!
+//! This function is used to set the modifier key states on a keyboard. The
+//! \e ui32Modifiers value is a bitmask of the following set of values:
+//! - \b HID_KEYB_NUM_LOCK
+//! - \b HID_KEYB_CAPS_LOCK
+//! - \b HID_KEYB_SCROLL_LOCK
+//! - \b HID_KEYB_COMPOSE
+//! - \b HID_KEYB_KANA
+//!
+//! Not all of these will be supported on all keyboards however setting values
+//! on a keyboard that does not have them should have no effect. The
+//! \e psKbInstance value is the value that was returned when the application
+//! called USBHKeyboardOpen(). If the value \b HID_KEYB_CAPS_LOCK is used it
+//! will modify the values returned from the USBHKeyboardUsageToChar()
+//! function.
+//!
+//! \return This function returns 0 to indicate success any non-zero value
+//! indicates an error condition.
+//
+//*****************************************************************************
+uint32_t
+USBHKeyboardModifierSet(tUSBHKeyboard *psKbInstance, uint32_t ui32Modifiers)
+{
+ //
+ // Remember the fact that this is set.
+ //
+ psKbInstance->ui8KeyModSticky = (uint8_t)ui32Modifiers;
+
+ //
+ // Set the LEDs on the keyboard.
+ //
+ USBHHIDSetReport(psKbInstance->psHIDInstance, 0,
+ (uint8_t *)&ui32Modifiers, 1);
+
+ return(0);
+}
+
+//*****************************************************************************
+//
+//! This function is used to initialize a keyboard interface after a keyboard
+//! has been detected.
+//!
+//! \param psKbInstance is the instance value for this keyboard.
+//!
+//! This function should be called after receiving a \b USB_EVENT_CONNECTED
+//! event in the callback function provided by USBHKeyboardOpen(), however this
+//! function should only be called outside the callback function. This will
+//! initialize the keyboard interface and determine the keyboard's
+//! layout and how it reports keys to the USB host controller. The
+//! \e psKbInstance value is the value that was returned when the application
+//! called USBHKeyboardOpen(). This function only needs to be called once
+//! per connection event but it should be called every time a
+//! \b USB_EVENT_CONNECTED event occurs.
+//!
+//! \return This function returns 0 to indicate success any non-zero value
+//! indicates an error condition.
+//
+//*****************************************************************************
+uint32_t
+USBHKeyboardInit(tUSBHKeyboard *psKbInstance)
+{
+ uint8_t ui8ModData;
+ int32_t i32Idx;
+
+ //
+ // Set the initial rate to only update on keyboard state changes.
+ //
+ USBHHIDSetIdle(psKbInstance->psHIDInstance, 0, 0);
+
+ //
+ // Read out the Report Descriptor from the keyboard and parse it for
+ // the format of the reports coming back from the keyboard.
+ //
+ USBHHIDGetReportDescriptor(psKbInstance->psHIDInstance,
+ psKbInstance->pui8Buffer,
+ USBHKEYB_REPORT_SIZE);
+
+ //
+ // Set the keyboard to boot protocol.
+ //
+ USBHHIDSetProtocol(psKbInstance->psHIDInstance, 1);
+
+ //
+ // Used to clear the initial state of all on keyboard modifiers.
+ //
+ ui8ModData = 0;
+
+ //
+ // Update the keyboard LED state.
+ //
+ USBHHIDSetReport(psKbInstance->psHIDInstance, 0, &ui8ModData, 1);
+
+ //
+ // Reset the key state.
+ //
+ for(i32Idx = 0;
+ i32Idx < sizeof(psKbInstance->pui8KeyState) / sizeof(uint8_t);
+ i32Idx++)
+ {
+ psKbInstance->pui8KeyState[i32Idx] =0;
+ }
+
+ return(0);
+}
+
+//*****************************************************************************
+//
+//! This function is used to set the automatic poll rate of the keyboard.
+//!
+//! \param psKbInstance is the instance value for this keyboard.
+//! \param ui32PollRate is the rate in ms to cause the keyboard to update the
+//! host regardless of no change in key state.
+//!
+//! This function will allow an application to tell the keyboard how often it
+//! should send updates to the USB host controller regardless of any changes
+//! in keyboard state. The \e psKbInstance value is the value that was
+//! returned when the application called USBHKeyboardOpen(). The
+//! \e ui32PollRate is the new value in ms for the update rate on the keyboard.
+//! This value is initially set to 0 which indicates that the keyboard should
+//! only to update when the keyboard state changes. Any value other than 0 can
+//! be used to force the keyboard to generate auto-repeat sequences for the
+//! application.
+//!
+//! \return This function returns 0 to indicate success any non-zero value
+//! indicates an error condition.
+//
+//*****************************************************************************
+uint32_t
+USBHKeyboardPollRateSet(tUSBHKeyboard *psKbInstance, uint32_t ui32PollRate)
+{
+ //
+ // Send the Set Idle command to the USB keyboard.
+ //
+ USBHHIDSetIdle(psKbInstance->psHIDInstance, ui32PollRate, 0);
+
+ return(0);
+}
+
+//*****************************************************************************
+//
+// This is an internal function used to modify the current keyboard state.
+//
+// This function checks for changes in the keyboard state due to a new report
+// being received from the device. It first checks if this is a "roll-over"
+// case by seeing if 0x01 is in the first position of the new keyboard report.
+// This indicates that too many keys were pressed to handle and to ignore this
+// report. Next the keyboard modifier state is stored and if any changes are
+// detected a \b USBH_EVENT_HID_KB_MOD event is sent back to the application.
+// Then this function will check for any keys that have been released and send
+// a \b USBH_EVENT_HID_KB_REL even for each of these keys. The last check is
+// for any new keys that are pressed and a \b USBH_EVENT_HID_KB_PRESS event
+// will be sent for each new key pressed.
+//
+// \return None.
+//
+//*****************************************************************************
+static void
+UpdateKeyboardState(tUSBHKeyboard *psKbInstance)
+{
+ int32_t i32NewKey, i32OldKey;
+
+ //
+ // rollover code so ignore this buffer.
+ //
+ if(psKbInstance->pui8Buffer[2] == 0x01)
+ {
+ return;
+ }
+
+ //
+ // Handle the keyboard modifier states.
+ //
+ if(psKbInstance->ui8KeyModState != psKbInstance->pui8Buffer[0])
+ {
+ //
+ // Notify the application of the event.
+ //
+ psKbInstance->pfnCallback(0, USBH_EVENT_HID_KB_MOD,
+ psKbInstance->pui8Buffer[0], 0);
+
+ //
+ // Save the new state of the modifier keys.
+ //
+ psKbInstance->ui8KeyModState = psKbInstance->pui8Buffer[0];
+ }
+
+ //
+ // This loop checks for keys that have been released to make room for new
+ // ones that may have been pressed.
+ //
+ for(i32OldKey = 0; i32OldKey < 6; i32OldKey++)
+ {
+ //
+ // If there is no old key pressed in this entry go to the next one.
+ //
+ if(psKbInstance->pui8KeyState[i32OldKey] == 0)
+ {
+ continue;
+ }
+
+ //
+ // Check if this old key is still in the list of currently pressed
+ // keys.
+ //
+ for(i32NewKey = 2; i32NewKey < 8; i32NewKey++)
+ {
+ //
+ // Break out if the key is still present.
+ //
+ if(psKbInstance->pui8Buffer[i32NewKey] ==
+ psKbInstance->pui8KeyState[i32OldKey])
+ {
+ break;
+ }
+ }
+ //
+ // If the old key was no longer in the list of pressed keys then
+ // notify the application of the key release.
+ //
+ if(i32NewKey == 8)
+ {
+ //
+ // Send the key release notification to the application.
+ //
+ psKbInstance->pfnCallback(0, USBH_EVENT_HID_KB_REL,
+ psKbInstance->pui8KeyState[i32OldKey],
+ 0);
+ //
+ // Remove the old key from the currently held key list.
+ //
+ psKbInstance->pui8KeyState[i32OldKey] = 0;
+
+ }
+ }
+
+ //
+ // This loop checks for new keys that have been pressed.
+ //
+ for(i32NewKey = 2; i32NewKey < 8; i32NewKey++)
+ {
+ //
+ // The new list is empty so no new keys are pressed.
+ //
+ if(psKbInstance->pui8Buffer[i32NewKey] == 0)
+ {
+ break;
+ }
+
+ //
+ // This loop checks if the current key was already pressed.
+ //
+ for(i32OldKey = 0; i32OldKey < 6; i32OldKey++)
+ {
+ //
+ // If it is in both lists then it was already pressed so ignore it.
+ //
+ if(psKbInstance->pui8Buffer[i32NewKey] ==
+ psKbInstance->pui8KeyState[i32OldKey])
+ {
+ break;
+ }
+ }
+ //
+ // The key in the new list was not found so it is new.
+ //
+ if(i32OldKey == 6)
+ {
+ //
+ // Look for a free location to store this key usage code.
+ //
+ for(i32OldKey = 0; i32OldKey < 6; i32OldKey++)
+ {
+ //
+ // If an empty location is found, store it and notify the
+ // application.
+ //
+ if(psKbInstance->pui8KeyState[i32OldKey] == 0)
+ {
+ //
+ // Save the newly pressed key.
+ //
+ psKbInstance->pui8KeyState[i32OldKey] =
+ psKbInstance->pui8Buffer[i32NewKey];
+
+ //
+ // Notify the application of the new key that has been
+ // pressed.
+ //
+ psKbInstance->pfnCallback( 0, USBH_EVENT_HID_KB_PRESS,
+ psKbInstance->pui8Buffer[i32NewKey],
+ 0);
+
+ break;
+ }
+ }
+ }
+ }
+}
+
+//*****************************************************************************
+//
+//! This function handles event callbacks from the USB HID driver layer.
+//!
+//! \param pvKeyboard is the pointer that was passed in to the USBHHIDOpen()
+//! call.
+//! \param ui32Event is the event that has been passed up from the HID driver.
+//! \param ui32MsgParam has meaning related to the \e ui32Event that occurred.
+//! \param pvMsgData has meaning related to the \e ui32Event that occurred.
+//!
+//! This function will receive all event updates from the HID driver layer.
+//! The keyboard driver itself will mostly be concerned with report callbacks
+//! from the HID driver layer and parsing them into keystrokes for the
+//! application that has registered for callbacks with the USBHKeyboardOpen()
+//! call.
+//!
+//! \return Non-zero values should be assumed to indicate an error condition.
+//
+//*****************************************************************************
+static uint32_t
+USBHKeyboardCallback(void *pvKeyboard, uint32_t ui32Event,
+ uint32_t ui32MsgParam, void *pvMsgData)
+{
+ tUSBHKeyboard *psKbInstance;
+
+ //
+ // Recover the pointer to the instance data.
+ //
+ psKbInstance = (tUSBHKeyboard *)pvKeyboard;
+
+ switch (ui32Event)
+ {
+ //
+ // New keyboard has been connected so notify the application.
+ //
+ case USB_EVENT_CONNECTED:
+ {
+ //
+ // Remember that a keyboard is present.
+ //
+ psKbInstance->ui32HIDFlags |= USBHKEYB_DEVICE_PRESENT;
+
+ //
+ // Notify the application that a new keyboard was connected.
+ //
+ psKbInstance->pfnCallback(0, ui32Event, ui32MsgParam, pvMsgData);
+
+ break;
+ }
+ case USB_EVENT_DISCONNECTED:
+ {
+ //
+ // No keyboard is present.
+ //
+ psKbInstance->ui32HIDFlags &= ~USBHKEYB_DEVICE_PRESENT;
+
+ //
+ // Notify the application that the keyboard was disconnected.
+ //
+ psKbInstance->pfnCallback(0, ui32Event, ui32MsgParam, pvMsgData);
+
+ break;
+ }
+ case USB_EVENT_RX_AVAILABLE:
+ {
+ //
+ // New keyboard report structure was received.
+ //
+ USBHHIDGetReport(psKbInstance->psHIDInstance, 0,
+ psKbInstance->pui8Buffer,
+ USBHKEYB_REPORT_SIZE);
+
+ //
+ // Update the application on the changes in the keyboard state.
+ //
+ UpdateKeyboardState(psKbInstance);
+
+ break;
+ }
+ }
+ return(0);
+}
+
+//*****************************************************************************
+//
+//! This function forwards an LPM request for a device to enter L1 sleep state.
+//!
+//! \param psKbInstance is the HID keyboard instance that was
+//! returned from the call to USBHKeyboardOpen().
+//!
+//! This function forwards a request from an application to the HID device
+//! class to request that a device enter the LPM L1 sleep state. The
+//! caller must check the return value to see if the request can be
+//! attempted at this time. If another LPM transaction is busy on this or
+//! another device, then this function returns \b USBHCD_LPM_PENDING. If
+//! the LPM request was scheduled to be sent the function returns
+//! \b USBHCD_LPM_AVAIL. The caller should check the USBHCDLPMStatus()
+//! function to determine if the request completed successfully or if there
+//! was an error.
+//!
+//! \return This function returns the following values:
+//! - \b USBHCD_LPM_AVAIL - The transition to L1 state is scheduled to be sent.
+//! - \b USBHCD_LPM_PENDING - There is already an LPM request pending.
+//
+//*****************************************************************************
+uint32_t
+USBHKeyboardLPMSleep(tUSBHKeyboard *psKbInstance)
+{
+ //
+ // Call the HID function to send the sleep command.
+ //
+ return(USBHHIDLPMSleep(psKbInstance->psHIDInstance));
+}
+
+//*****************************************************************************
+//
+//! This function returns the current status of an LPM request.
+//!
+//! \param psKbInstance is the HID keyboard instance that was
+//! returned from the call to USBHKeyboardOpen().
+//!
+//! This function returns the current status of LPM requests for a given
+//! device. This is called to determine if a previous request completed
+//! successfully or if there was an error.
+//!
+//! \return This function returns the following values:
+//! - \b USBHCD_LPM_AVAIL - There are no pending LPM requests on this specific
+//! device or the last request completed successfully.
+//! - \b USBHCD_LPM_ERROR - The last LPM request for this device did not
+//! complete successfully.
+//! - \b USBHCD_LPM_PENDING - The last LPM request has not completed.
+//
+//*****************************************************************************
+uint32_t
+USBHKeyboardLPMStatus(tUSBHKeyboard *psKbInstance)
+{
+ //
+ // Call the HID function to get the current LPM status.
+ //
+ return(USBHHIDLPMStatus(psKbInstance->psHIDInstance));
+}
+
+//*****************************************************************************
+//
+//! @}
+//
+//*****************************************************************************
diff --git a/usblib/host/usbhhidkeyboard.h b/usblib/host/usbhhidkeyboard.h
new file mode 100644
index 0000000..09852f1
--- /dev/null
+++ b/usblib/host/usbhhidkeyboard.h
@@ -0,0 +1,89 @@
+//*****************************************************************************
+//
+// usbhhidkeyboard.h - This file holds the application interfaces for USB
+// keyboard devices.
+//
+// Copyright (c) 2008-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 Tiva USB Library.
+//
+//*****************************************************************************
+
+#ifndef __USBHHIDKEYBOARD_H__
+#define __USBHHIDKEYBOARD_H__
+
+//*****************************************************************************
+//
+// If building with a C++ compiler, make all of the definitions in this header
+// have a C binding.
+//
+//*****************************************************************************
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+//*****************************************************************************
+//
+//! \addtogroup usblib_host_device
+//! @{
+//
+//*****************************************************************************
+
+typedef struct tUSBHKeyboard tUSBHKeyboard;
+
+//*****************************************************************************
+//
+// The prototype for the host USB Keyboard driver callback function.
+//
+//*****************************************************************************
+typedef void (*tUSBHIDKeyboardCallback)(tUSBHKeyboard *psKbInstance,
+ uint32_t ui32Event,
+ uint32_t ui32MsgParam,
+ void *pvMsgData);
+
+extern tUSBHKeyboard * USBHKeyboardOpen(tUSBHIDKeyboardCallback pfnCallback,
+ uint8_t *pui8Buffer,
+ uint32_t ui32BufferSize);
+extern uint32_t USBHKeyboardClose(tUSBHKeyboard *psKbInstance);
+extern uint32_t USBHKeyboardInit(tUSBHKeyboard *psKbInstance);
+extern uint32_t USBHKeyboardModifierSet(tUSBHKeyboard *psKbInstance,
+ uint32_t ui32Modifiers);
+extern uint32_t USBHKeyboardPollRateSet(tUSBHKeyboard *psKbInstance,
+ uint32_t ui32PollRate);
+extern uint32_t USBHKeyboardLPMSleep(tUSBHKeyboard *psKbInstance);
+extern uint32_t USBHKeyboardLPMStatus(tUSBHKeyboard *psKbInstance);
+extern uint32_t USBHKeyboardUsageToChar(tUSBHKeyboard *psKbInstance,
+ const tHIDKeyboardUsageTable *psTable,
+ uint8_t ui8UsageID);
+
+//*****************************************************************************
+//
+//! @}
+//
+//*****************************************************************************
+
+//*****************************************************************************
+//
+// Mark the end of the C bindings section for C++ compilers.
+//
+//*****************************************************************************
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/usblib/host/usbhhidmouse.c b/usblib/host/usbhhidmouse.c
new file mode 100644
index 0000000..f1eb8d5
--- /dev/null
+++ b/usblib/host/usbhhidmouse.c
@@ -0,0 +1,452 @@
+//*****************************************************************************
+//
+// usbhhidmouse.c - This file holds the application interfaces for USB
+// mouse devices.
+//
+// Copyright (c) 2008-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 Tiva USB Library.
+//
+//*****************************************************************************
+
+#include <stdbool.h>
+#include <stdint.h>
+#include "inc/hw_types.h"
+#include "usblib/usblib.h"
+#include "usblib/host/usbhost.h"
+#include "usblib/usbhid.h"
+#include "usblib/host/usbhhid.h"
+#include "usblib/host/usbhhidmouse.h"
+
+//*****************************************************************************
+//
+//! \addtogroup usblib_host_device
+//! @{
+//
+//*****************************************************************************
+
+//*****************************************************************************
+//
+// Prototypes for local functions.
+//
+//*****************************************************************************
+static uint32_t USBHMouseCallback(void *pvMouse, uint32_t ui32Event,
+ uint32_t ui32MsgParam, void *pvMsgData);
+
+//*****************************************************************************
+//
+// The size of a USB mouse report.
+//
+//*****************************************************************************
+#define USBHMS_REPORT_SIZE 4
+
+//*****************************************************************************
+//
+// These are the flags for the tUSBHMouse.ui32HIDFlags member variable.
+//
+//*****************************************************************************
+#define USBHMS_DEVICE_PRESENT 0x00000001
+
+//*****************************************************************************
+//
+// This is the structure definition for a mouse device instance.
+//
+//*****************************************************************************
+struct tUSBHMouse
+{
+ //
+ // Global flags for an instance of a mouse.
+ //
+ uint32_t ui32HIDFlags;
+
+ //
+ // The applications registered callback.
+ //
+ tUSBHIDMouseCallback pfnCallback;
+
+ //
+ // The current state of the buttons.
+ //
+ uint8_t ui8Buttons;
+
+ //
+ // This is a local buffer to hold the current HID report that comes up
+ // from the HID driver layer.
+ //
+ uint8_t pui8Buffer[USBHMS_REPORT_SIZE];
+
+ //
+ // Heap data for the mouse currently used to read the HID Report
+ // Descriptor.
+ //
+ uint8_t *pui8Heap;
+
+ //
+ // Size of the heap in bytes.
+ //
+ uint32_t ui32HeapSize;
+
+ //
+ // This is the instance value for the HID device that will be used for the
+ // mouse.
+ //
+ tHIDInstance *psHIDInstance;
+};
+
+//*****************************************************************************
+//
+// This is the per instance information for a mouse device.
+//
+//*****************************************************************************
+static tUSBHMouse g_sUSBHMouse =
+{
+ 0
+};
+
+//*****************************************************************************
+//
+//! This function is used open an instance of a mouse.
+//!
+//! \param pfnCallback is the callback function to call when new events occur
+//! with the mouse returned.
+//! \param pui8Buffer is the memory used by the driver to interact with the
+//! USB mouse.
+//! \param ui32Size is the size of the buffer provided by \e pui8Buffer.
+//!
+//! This function is used to open an instance of the mouse. The value
+//! returned from this function should be used as the instance identifier for
+//! all other USBHMouse calls. The \e pui8Buffer memory buffer is used to
+//! access the mouse. The buffer size required is at least enough to hold
+//! a normal report descriptor for the device.
+//!
+//! \return Returns the instance identifier for the mouse that is attached.
+//! If there is no mouse present this will return 0.
+//
+//*****************************************************************************
+tUSBHMouse *
+USBHMouseOpen(tUSBHIDMouseCallback pfnCallback, uint8_t *pui8Buffer,
+ uint32_t ui32Size)
+{
+ //
+ // Save the callback and data pointers.
+ //
+ g_sUSBHMouse.pfnCallback = pfnCallback;
+
+ //
+ // Save the instance pointer for the HID device that was opened.
+ //
+ g_sUSBHMouse.psHIDInstance = USBHHIDOpen(eUSBHHIDClassMouse,
+ USBHMouseCallback,
+ (void *)&g_sUSBHMouse);
+
+ //
+ // Save the heap buffer and size.
+ //
+ g_sUSBHMouse.pui8Heap = pui8Buffer;
+ g_sUSBHMouse.ui32HeapSize = ui32Size;
+
+ return(&g_sUSBHMouse);
+}
+
+//*****************************************************************************
+//
+//! This function is used close an instance of a mouse.
+//!
+//! \param psMsInstance is the instance value for this mouse.
+//!
+//! This function is used to close an instance of the mouse that was opened
+//! with a call to USBHMouseOpen(). The \e psMsInstance value is the value
+//! that was returned when the application called USBHMouseOpen().
+//!
+//! \return Returns 0.
+//
+//*****************************************************************************
+uint32_t
+USBHMouseClose(tUSBHMouse *psMsInstance)
+{
+ //
+ // Reset the callback to null.
+ //
+ psMsInstance->pfnCallback = 0;
+
+ //
+ // Call the HID driver layer to close out this instance.
+ //
+ USBHHIDClose(psMsInstance->psHIDInstance);
+
+ return(0);
+}
+
+//*****************************************************************************
+//
+//! This function is used to initialize a mouse interface after a mouse has
+//! been detected.
+//!
+//! \param psMsInstance is the instance value for this mouse.
+//!
+//! This function should be called after receiving a \b USB_EVENT_CONNECTED
+//! event in the callback function provided by USBHMouseOpen(), however it
+//! should only be called outside of the callback function. This will
+//! initialize the mouse interface and determine how it reports events to the
+//! USB host controller. The \e psMsInstance value is the value that was
+//! returned when the application called USBHMouseOpen(). This function only
+//! needs to be called once per connection event but it should be called every
+//! time a \b USB_EVENT_CONNECTED event occurs.
+//!
+//! \return Non-zero values should be assumed to indicate an error condition.
+//
+//*****************************************************************************
+uint32_t
+USBHMouseInit(tUSBHMouse *psMsInstance)
+{
+ //
+ // Set the initial rate to only update on mouse state changes.
+ //
+ USBHHIDSetIdle(psMsInstance->psHIDInstance, 0, 0);
+
+ //
+ // Read out the Report Descriptor from the mouse and parse it for
+ // the format of the reports coming back from the mouse.
+ //
+ USBHHIDGetReportDescriptor(psMsInstance->psHIDInstance,
+ psMsInstance->pui8Heap,
+ psMsInstance->ui32HeapSize);
+
+ //
+ // Set the mouse to boot protocol.
+ //
+ USBHHIDSetProtocol(psMsInstance->psHIDInstance, 1);
+
+ return(0);
+}
+
+//*****************************************************************************
+//
+// This function handles updating the state of the mouse buttons and axis.
+//
+// \param psMsInstance is the pointer to an instance of the mouse data.
+//
+// This function will check for updates to buttons or X/Y movements and send
+// callbacks to the mouse callback function.
+//
+// \return None.
+//
+//*****************************************************************************
+static void
+UpdateMouseState(tUSBHMouse *psMsInstance)
+{
+ uint32_t ui32Button;
+
+ if(psMsInstance->pui8Buffer[0] != psMsInstance->ui8Buttons)
+ {
+ for(ui32Button = 1; ui32Button <= 0x4; ui32Button <<= 1)
+ {
+ if(((psMsInstance->pui8Buffer[0] & ui32Button) != 0) &&
+ ((psMsInstance->ui8Buttons & ui32Button) == 0))
+ {
+ //
+ // Send the mouse button press notification to the application.
+ //
+ psMsInstance->pfnCallback(0, USBH_EVENT_HID_MS_PRESS,
+ ui32Button, 0);
+ }
+ if(((psMsInstance->pui8Buffer[0] & ui32Button) == 0) &&
+ ((psMsInstance->ui8Buttons & ui32Button) != 0))
+ {
+ //
+ // Send the mouse button release notification to the
+ // application.
+ //
+ psMsInstance->pfnCallback(0, USBH_EVENT_HID_MS_REL,
+ ui32Button, 0);
+ }
+ }
+
+ //
+ // Save the new state.
+ //
+ psMsInstance->ui8Buttons = psMsInstance->pui8Buffer[0];
+ }
+
+ if(psMsInstance->pui8Buffer[1] != 0)
+ {
+ //
+ // Send the mouse button release notification to the
+ // application.
+ //
+ psMsInstance->pfnCallback(0, USBH_EVENT_HID_MS_X,
+ (uint32_t)psMsInstance->pui8Buffer[1], 0);
+ }
+
+ if(psMsInstance->pui8Buffer[2] != 0)
+ {
+ //
+ // Send the mouse button release notification to the
+ // application.
+ //
+ psMsInstance->pfnCallback(0, USBH_EVENT_HID_MS_Y,
+ (uint32_t)psMsInstance->pui8Buffer[2], 0);
+ }
+}
+
+//*****************************************************************************
+//
+//! This function handles event callbacks from the USB HID driver layer.
+//!
+//! \param pvMouse is the pointer that was passed in to the USBHHIDOpen()
+//! call.
+//! \param ui32Event is the event that has been passed up from the HID driver.
+//! \param ui32MsgParam has meaning related to the \e ui32Event that occurred.
+//! \param pvMsgData has meaning related to the \e ui32Event that occurred.
+//!
+//! This function will receive all event updates from the HID driver layer.
+//! The mouse driver itself will mostly be concerned with report callbacks
+//! from the HID driver layer and parsing them into keystrokes for the
+//! application that has registered for callbacks with the USBHMouseOpen()
+//! call.
+//!
+//! \return Non-zero values should be assumed to indicate an error condition.
+//
+//*****************************************************************************
+uint32_t
+USBHMouseCallback(void *pvMouse, uint32_t ui32Event,
+ uint32_t ui32MsgParam, void *pvMsgData)
+{
+ tUSBHMouse *psMsInstance;
+
+ //
+ // Recover the pointer to the instance data.
+ //
+ psMsInstance = (tUSBHMouse *)pvMouse;
+
+ switch(ui32Event)
+ {
+ //
+ // New mouse has been connected so notify the application.
+ //
+ case USB_EVENT_CONNECTED:
+ {
+ //
+ // Remember that a mouse is present.
+ //
+ psMsInstance->ui32HIDFlags |= USBHMS_DEVICE_PRESENT;
+
+ //
+ // Notify the application that a new mouse was connected.
+ //
+ psMsInstance->pfnCallback(0, ui32Event, ui32MsgParam, pvMsgData);
+
+ break;
+ }
+ case USB_EVENT_DISCONNECTED:
+ {
+ //
+ // No mouse is present.
+ //
+ psMsInstance->ui32HIDFlags &= ~USBHMS_DEVICE_PRESENT;
+
+ //
+ // Notify the application that the mouse was disconnected.
+ //
+ psMsInstance->pfnCallback(0, ui32Event, ui32MsgParam, pvMsgData);
+
+ break;
+ }
+ case USB_EVENT_RX_AVAILABLE:
+ {
+ //
+ // New mouse report structure was received.
+ //
+ USBHHIDGetReport(psMsInstance->psHIDInstance, 0,
+ psMsInstance->pui8Buffer, USBHMS_REPORT_SIZE);
+
+ //
+ // Update the current state of the mouse and notify the application
+ // of any changes.
+ //
+ UpdateMouseState(psMsInstance);
+
+ break;
+ }
+ }
+ return(0);
+}
+
+//*****************************************************************************
+//
+//! This function forwards an LPM request for a device to enter L1 sleep state.
+//!
+//! \param psMsInstance is the HID keyboard instance that was returned
+//! from the call to USBHMouseOpen().
+//!
+//! This function forwards a request from an application to the HID device
+//! class to request that a device enter the LPM L1 sleep state. The
+//! caller must check the return value to see if the request can be
+//! attempted at this time. If another LPM transaction is busy on this or
+//! another device, then this function returns \b USBHCD_LPM_PENDING. If
+//! the LPM request was scheduled to be sent the function returns
+//! \b USBHCD_LPM_AVAIL. The caller should check the USBHCDLPMStatus()
+//! function to determine if the request completed successfully or if there
+//! was an error.
+//!
+//! \return This function returns the following values:
+//! - \b USBHCD_LPM_AVAIL - The transition to L1 state is scheduled to be sent.
+//! - \b USBHCD_LPM_PENDING - There is already an LPM request pending.
+//
+//*****************************************************************************
+uint32_t
+USBHMouseLPMSleep(tUSBHMouse *psMsInstance)
+{
+ //
+ // Call the HID function to send the sleep command.
+ //
+ return(USBHHIDLPMSleep(psMsInstance->psHIDInstance));
+}
+
+//*****************************************************************************
+//
+//! This function returns the current status of an LPM request.
+//!
+//! \param psMsInstance is the HID keyboard instance that was returned
+//! from the call to USBHMouseOpen().
+//!
+//! This function returns the current status of LPM requests for a given
+//! device. This is called to determine if a previous request completed
+//! successfully or if there was an error.
+//!
+//! \return This function returns the following values:
+//! - \b USBHCD_LPM_AVAIL - There are no pending LPM requests on this specific
+//! device or the last request completed successfully.
+//! - \b USBHCD_LPM_ERROR - The last LPM request for this device did not
+//! complete successfully.
+//! - \b USBHCD_LPM_PENDING - The last LPM request has not completed.
+//
+//*****************************************************************************
+uint32_t
+USBHMouseLPMStatus(tUSBHMouse *psMsInstance)
+{
+ //
+ // Call the HID function to get the current LPM status.
+ //
+ return(USBHHIDLPMStatus(psMsInstance->psHIDInstance));
+}
+
+//*****************************************************************************
+//
+//! @}
+//
+//*****************************************************************************
diff --git a/usblib/host/usbhhidmouse.h b/usblib/host/usbhhidmouse.h
new file mode 100644
index 0000000..295f6c1
--- /dev/null
+++ b/usblib/host/usbhhidmouse.h
@@ -0,0 +1,81 @@
+//*****************************************************************************
+//
+// usbhhidmouse.h - This file holds the application interfaces for USB
+// mouse devices.
+//
+// Copyright (c) 2008-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 Tiva USB Library.
+//
+//*****************************************************************************
+
+#ifndef __USBHHIDMOUSE_H__
+#define __USBHHIDMOUSE_H__
+
+//*****************************************************************************
+//
+// If building with a C++ compiler, make all of the definitions in this header
+// have a C binding.
+//
+//*****************************************************************************
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+//*****************************************************************************
+//
+//! \addtogroup usblib_host_device
+//! @{
+//
+//*****************************************************************************
+
+typedef struct tUSBHMouse tUSBHMouse;
+
+//*****************************************************************************
+//
+// The prototype for the host USB mouse driver callback function.
+//
+//*****************************************************************************
+typedef void (*tUSBHIDMouseCallback)(tUSBHMouse *psMsInstance,
+ uint32_t ui32Event,
+ uint32_t ui32MsgParam,
+ void *pvMsgData);
+
+extern tUSBHMouse * USBHMouseOpen(tUSBHIDMouseCallback pfnCallback,
+ uint8_t *pui8Buffer, uint32_t ui32Size);
+extern uint32_t USBHMouseClose(tUSBHMouse *psMsInstance);
+extern uint32_t USBHMouseInit(tUSBHMouse *psMsInstance);
+extern uint32_t USBHMouseLPMSleep(tUSBHMouse *psMsInstance);
+extern uint32_t USBHMouseLPMStatus(tUSBHMouse *psMsInstance);
+
+//*****************************************************************************
+//
+//! @}
+//
+//*****************************************************************************
+
+//*****************************************************************************
+//
+// Mark the end of the C bindings section for C++ compilers.
+//
+//*****************************************************************************
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/usblib/host/usbhhub.c b/usblib/host/usbhhub.c
new file mode 100644
index 0000000..8042dfc
--- /dev/null
+++ b/usblib/host/usbhhub.c
@@ -0,0 +1,1522 @@
+//*****************************************************************************
+//
+// usbhhub.c - This file contains the host HID driver.
+//
+// Copyright (c) 2011-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 Tiva USB Library.
+//
+//*****************************************************************************
+
+#include <stdbool.h>
+#include <stdint.h>
+#include "inc/hw_types.h"
+#include "inc/hw_ints.h"
+#include "inc/hw_sysctl.h"
+#include "driverlib/usb.h"
+#include "driverlib/interrupt.h"
+#include "driverlib/rom_map.h"
+#include "driverlib/rtos_bindings.h"
+#include "usblib/usblib.h"
+#include "usblib/host/usbhost.h"
+#include "usblib/host/usbhostpriv.h"
+#include "usblib/host/usbhhub.h"
+#ifdef INCLUDE_DEBUG_OUTPUT
+#include "utils/uartstdio.h"
+#define DEBUG_OUTPUT UARTprintf
+#else
+#define DEBUG_OUTPUT while(0)((int (*)(char *, ...))0)
+#endif
+
+//*****************************************************************************
+//
+//! \addtogroup usblib_host_class
+//! @{
+//
+//*****************************************************************************
+
+#ifdef ewarm
+#pragma pack(1)
+#endif
+
+//*****************************************************************************
+//
+//! The USB standard hub descriptor structure. Full documentation for the
+//! contents of this structure can be found in chapter 11.23.2.1 of the USB
+//! 2.0 specification.
+//
+//*****************************************************************************
+typedef struct
+{
+ //
+ //! The total number of bytes in the descriptor (including this field).
+ //
+ uint8_t bLength;
+
+ //
+ //! The descriptor type. For a hub descriptor, this will be USB_DTYPE_HUB
+ //! (0x29 or 41 decimal).
+ //
+ uint8_t bDescType;
+
+ //
+ //! The number of downstream-facing ports that the hub supports.
+ //
+ uint8_t bNbrPorts;
+
+ //
+ //! Characteristics of the hub device including its power switching
+ //! capabilities and over-current protection mode.
+ //
+ uint16_t wHubCharacteristics;
+
+ //
+ //! The time between the start of the power-on sequence for a port and
+ //! the power to the port becoming stable. This is expressed in 2mS units.
+ //
+ uint8_t bPwrOn2PwrGood;
+
+ //
+ //! The maximum current requirement for the hub circuitry in mA.
+ //
+ uint8_t bHubContrCurrent;
+
+ //
+ //! The last two fields in the structure are bit masks indicating which
+ //! downstream ports support removable devices and, following this, another
+ //! obsolete field from USB1.0 related to port power control. Each field
+ //! is byte aligned and contains a bit for each hub port. This structure
+ //! definition is set up with enough storage to handle ROOT_HUB_MAX_PORTS
+ //! ports but beware that the actual size of each field is dependent upon
+ //! the bNbrPorts field above.
+ //
+ uint8_t PortInfo[((ROOT_HUB_MAX_PORTS + 7) / 8) * 2];
+}
+PACKED tUsbHubDescriptor;
+
+#ifdef ewarm
+#pragma pack()
+#endif
+
+//*****************************************************************************
+//
+// This structure holds all data specific to a single hub port.
+//
+//*****************************************************************************
+typedef struct
+{
+ //
+ // The handle used by the HCD layer to identify this device.
+ //
+ uint32_t ui32DevHandle;
+
+ //
+ // The current state of the port.
+ //
+ volatile tHubPortState iState;
+
+ //
+ // General counter used in various states.
+ //
+ volatile uint32_t ui32Count;
+
+ //
+ // A flag used to indicate that the downstream device is a low speed
+ // device.
+ //
+ bool bLowSpeed;
+
+ //
+ // The speed of the device on this port.
+ //
+ uint32_t ui32Speed;
+
+ //
+ // This flag is set if the hub reports that a change is pending on this
+ // port.
+ //
+ volatile bool bChanged;
+}
+tHubPort;
+
+//*****************************************************************************
+//
+// USB hub flags values for tHubInstance.ui32Flags.
+//
+//*****************************************************************************
+#define USBLIB_HUB_ACTIVE 0x00000001
+#define USBLIB_HUB_HS 0x00000002
+#define USBLIB_HUB_MULTI_TT 0x00000004
+
+//*****************************************************************************
+//
+// This is the structure that holds all of the data for a given instance of
+// a Hub device.
+//
+//*****************************************************************************
+struct tHubInstance
+{
+ //
+ // Save the device instance.
+ //
+ tUSBHostDevice *psDevice;
+
+ //
+ // Used to save the callback function pointer.
+ //
+ tUSBHHubCallback pfnCallback;
+
+ //
+ // Callback data provided by caller.
+ //
+ uint32_t ui32CBData;
+
+ //
+ // Interrupt IN pipe.
+ //
+ uint32_t ui32IntInPipe;
+
+ //
+ // Hub characteristics as reported in the class-specific hub descriptor.
+ //
+ uint16_t ui16HubCharacteristics;
+
+ //
+ // The number of downstream-facing ports the hub supports.
+ //
+ uint8_t ui8NumPorts;
+
+ //
+ // The number of ports on the hub that we can actually talk to. This will
+ // be the smaller of the number of ports on the hub and MAX_USB_DEVICES.
+ //
+ uint8_t ui8NumPortsInUse;
+
+ //
+ // The size of a status change packet sent by the hub. This is determined
+ // from the number of ports supported by the hub.
+ //
+ uint8_t ui8ReportSize;
+
+ //
+ // Flags indicating whether the hub is connected.
+ //
+ uint32_t ui32Flags;
+
+ //
+ // Flag indicating that a device is currently in process of being
+ // enumerated.
+ //
+ volatile bool bEnumerationBusy;
+
+ //
+ // This is valid if bEnumerationBusy is set and indicates the port
+ // that is in the process of enumeration.
+ //
+ uint8_t ui8EnumIdx;
+
+ //
+ // The state of each of the ports we support on the hub.
+ //
+ tHubPort psPorts[MAX_USB_DEVICES];
+
+ //
+ // The interrupt number for this instance.
+ //
+ uint32_t ui32IntNum;
+};
+
+//*****************************************************************************
+//
+//! Forward references to the hub class driver functions.
+//
+//*****************************************************************************
+static void *HubDriverOpen(tUSBHostDevice *psDevice);
+static void HubDriverClose(void *pvHubDevice);
+
+//*****************************************************************************
+//
+//! This constant global structure defines the Hub Class Driver that is
+//! provided with the USB library.
+//
+//*****************************************************************************
+const tUSBHostClassDriver g_sUSBHubClassDriver =
+{
+ USB_CLASS_HUB,
+ HubDriverOpen,
+ HubDriverClose,
+ 0
+};
+
+//*****************************************************************************
+//
+// The instance data storage for attached hub.
+//
+//*****************************************************************************
+static tHubInstance g_sRootHub;
+
+//*****************************************************************************
+//
+// Hub and port state change flags as reported via the hub's IN endpoint.
+//
+//*****************************************************************************
+static volatile uint32_t g_ui32ChangeFlags;
+
+//
+// Note: The following assumes ROOT_HUB_MAX_PORTS is less than 32!
+//
+static uint32_t g_ui32HubChanges;
+
+//*****************************************************************************
+//
+// This function is called to set the operating speed of a given port.
+//
+// \param ui8Port is the port number for this request.
+// \param ui32Speed is one of the HUB_FEATURE_PORT_* values.
+//
+// This function sets the operating speed of the hub port specified in the
+// \e ui8Port parameter. A \e ui8Port value of 0 is an access to the hub
+// itself and not one of the hub ports. The \e ui32Speed value is one of the
+// \b USB_EP_SPEED_ values.
+//
+// \return None.
+//
+//*****************************************************************************
+static void
+USBHubPortSpeedSet(uint8_t ui8Port, uint32_t ui32Speed)
+{
+ g_sRootHub.psPorts[ui8Port].ui32Speed = ui32Speed;
+}
+
+//*****************************************************************************
+//
+// This function is called to send a request to the hub to set a feature on
+// a given port.
+//
+// \param psHubInstance is the hub device instance.
+// \param ui8Port is the port number for this request.
+// \param ui16Feature is one of the HUB_FEATURE_PORT_* values.
+//
+// This function will send the set feature request to the hub indicated by the
+// \e psHubInstance parameter. The \e ui8Port value indicates which port
+// number to send this request to and can range from 0 to the number of valid
+// ports on the given hub. A \e ui8Port value of 0 is an access to the hub
+// itself and not one of the hub ports. The \e ui16Feature is the feature
+// request toset on the given port. For example, a \e ui16Feature value of
+// \e HUB_FEATURE_PORT_RESET and \e ui8Port value of 1 will cause reset
+// signaling to hub port 1.
+//
+// \return None.
+//
+//*****************************************************************************
+static void
+HubSetPortFeature(tHubInstance *psHubInstance, uint8_t ui8Port,
+ uint16_t ui16Feature)
+{
+ tUSBRequest sSetupPacket;
+ tUSBHostDevice *psDevice;
+
+ //
+ // Retrieve the hub instance and device pointer.
+ //
+ psDevice = psHubInstance->psDevice;
+
+ //
+ // This is a standard OUT request.
+ //
+ sSetupPacket.bmRequestType = USB_RTYPE_DIR_OUT | USB_RTYPE_CLASS |
+ USB_RTYPE_OTHER;
+
+ //
+ // Set the field to clear the requested port feature.
+ //
+ sSetupPacket.bRequest = USBREQ_SET_FEATURE;
+ sSetupPacket.wValue = ui16Feature;
+ sSetupPacket.wIndex = ui8Port;
+ sSetupPacket.wLength = 0;
+
+ //
+ // Send the request.
+ //
+ USBHCDControlTransfer(0, &sSetupPacket, psDevice, 0, 0,
+ psDevice->sDeviceDescriptor.bMaxPacketSize0);
+}
+
+//*****************************************************************************
+//
+// This function is called to send a request to the hub to clear a feature on
+// a given port.
+//
+// \param psHubInstance is the hub device instance.
+// \param ui8Port is the port number for this request.
+// \param ui16Feature is one of the HUB_FEATURE_PORT_* values.
+//
+// This function will send the clear feature request to the hub indicated by
+// the \e psHubInstance parameter. The \e ui8Port value indicates which port
+// number to send this request to and can range from 0 to the number of valid
+// ports on the given hub. A \e ui8Port value of 0 is an access to the hub
+// itself and not one of the hub ports. The \e ui16Feature is the feature
+// request to clear on the given port. For example, a \e ui16Feature value of
+// \e HUB_FEATURE_C_PORT_RESET and \e ui8Port value of 1 will clear the reset
+// complete signaling on hub port 1. Values like the reset feature will
+// remain set until actively cleared by this function.
+//
+// \return None.
+//
+//*****************************************************************************
+static void
+HubClearPortFeature(tHubInstance *psHubInstance, uint8_t ui8Port,
+ uint16_t ui16Feature)
+{
+ tUSBRequest sSetupPacket;
+ tUSBHostDevice *psDevice;
+
+ //
+ // Retrieve the hub instance and device pointer.
+ //
+ psDevice = psHubInstance->psDevice;
+
+ //
+ // This is a standard OUT request.
+ //
+ sSetupPacket.bmRequestType = USB_RTYPE_DIR_OUT | USB_RTYPE_CLASS |
+ USB_RTYPE_OTHER;
+
+ //
+ // Set the field to clear the requested port feature.
+ //
+ sSetupPacket.bRequest = USBREQ_CLEAR_FEATURE;
+ sSetupPacket.wValue = ui16Feature;
+ sSetupPacket.wIndex = ui8Port;
+ sSetupPacket.wLength = 0;
+
+ //
+ // Send the request.
+ //
+ USBHCDControlTransfer(0, &sSetupPacket, psDevice, 0, 0,
+ psDevice->sDeviceDescriptor.bMaxPacketSize0);
+}
+
+//*****************************************************************************
+//
+// This function is used to retrieve the current status of a port on the
+// hub.
+//
+// \param psHubInstance is the hub device instance.
+// \param ui8Port is the port number for this request.
+// \param pui16PortStatus is a pointer to the memory to store the current
+// status of the port.
+// \param pui16PortChange is a pointer to the memory to store the current
+// change status of the ports.
+//
+// This function is used to retrieve the current overall status and change
+// status for the port given in the \e ui8Port parameter. The \e ui8Port value
+// indicates which port number to send this request to and can range from 0 to
+// the number of valid ports on the given hub. A \e ui8Port value of 0 is an
+// access to the hub itself and not one of the hub ports.
+//
+// \return None.
+//
+//*****************************************************************************
+static bool
+HubGetPortStatus(tHubInstance *psHubInstance, uint8_t ui8Port,
+ uint16_t *pui16PortStatus, uint16_t *pui16PortChange)
+{
+ uint32_t ui32Data, ui32Read;
+ tUSBRequest sSetupPacket;
+ tUSBHostDevice *psDevice;
+
+ //
+ // Retrieve the device pointer.
+ //
+ psDevice = psHubInstance->psDevice;
+
+ //
+ // This is a standard OUT request.
+ //
+ sSetupPacket.bmRequestType = USB_RTYPE_DIR_IN | USB_RTYPE_CLASS |
+ USB_RTYPE_OTHER;
+
+ //
+ // Set the fields to get the hub status.
+ //
+ sSetupPacket.bRequest = USBREQ_GET_STATUS;
+ sSetupPacket.wValue = 0;
+ sSetupPacket.wIndex = (uint16_t)ui8Port;
+ sSetupPacket.wLength = 4;
+
+ //
+ // Send the request.
+ //
+ ui32Read = USBHCDControlTransfer(0, &sSetupPacket, psDevice,
+ (uint8_t *)&ui32Data, 4,
+ psDevice->sDeviceDescriptor.bMaxPacketSize0);
+
+ //
+ // Check that we received the correct number of bytes.
+ //
+ if(ui32Read != 4)
+ {
+ return(false);
+ }
+ else
+ {
+ //
+ // We got 4 bytes from the device. Now translate these into the 2
+ // 16-bit values we pass back to the caller.
+ //
+ *pui16PortStatus = (uint16_t)(ui32Data & 0xFFFF);
+ *pui16PortChange = (uint16_t)(ui32Data >> 16);
+
+ DEBUG_OUTPUT("Port %d, status 0x%04x, change 0x%04x\n", ui8Port,
+ *pui16PortStatus, *pui16PortChange);
+ }
+
+ //
+ // All is well.
+ //
+ return(true);
+}
+
+//*****************************************************************************
+//
+// This function handles callbacks for the interrupt IN endpoint for the hub
+// device.
+//
+//*****************************************************************************
+static void
+HubIntINCallback(uint32_t ui32Pipe, uint32_t ui32Event)
+{
+ switch (ui32Event)
+ {
+ //
+ // Handles a request to schedule a new request on the interrupt IN
+ // pipe.
+ //
+ case USB_EVENT_SCHEDULER:
+ {
+ //
+ // Set things up to read the next change indication from the hub.
+ //
+ USBHCDPipeSchedule(ui32Pipe, (uint8_t *)&g_ui32HubChanges,
+ (uint32_t)g_sRootHub.ui8ReportSize);
+ break;
+ }
+
+ //
+ // Called when new data is available on the interrupt IN pipe.
+ //
+ case USB_EVENT_RX_AVAILABLE:
+ {
+ //
+ // For data transfers on INT IN endpoints, we need to acknowledge
+ // the data from this callback.
+ //
+ USBHCDPipeDataAck(ui32Pipe);
+
+ //
+ // Update our global "ports needing service" flags with the latest
+ // information we have just received.
+ //
+ g_ui32ChangeFlags |= g_ui32HubChanges;
+
+ //
+ // Send the report data to the USB host hub device class driver if
+ // we have been given a callback function.
+ //
+ if(g_sRootHub.pfnCallback)
+ {
+ g_sRootHub.pfnCallback((void *)g_sRootHub.ui32CBData,
+ USB_EVENT_RX_AVAILABLE,
+ ui32Pipe, &g_ui32HubChanges);
+ }
+
+ break;
+ }
+ case USB_EVENT_ERROR:
+ {
+ break;
+ }
+ }
+}
+
+//*****************************************************************************
+//
+// Query the class-specific hub descriptor.
+//
+//*****************************************************************************
+static bool
+GetHubDescriptor(tUsbHubDescriptor *psDesc)
+{
+ uint32_t ui32Read;
+ tUSBRequest sSetupPacket;
+ tUSBHostDevice *psDevice;
+
+ //
+ // Retrieve the device pointer.
+ //
+ psDevice = g_sRootHub.psDevice;
+
+ //
+ // This is a standard OUT request.
+ //
+ sSetupPacket.bmRequestType = USB_RTYPE_DIR_IN | USB_RTYPE_CLASS |
+ USB_RTYPE_DEVICE;
+
+ //
+ // Set the fields to get the hub descriptor. Initially, we request only
+ // the first 4 bytes of the descriptor. This will give us the size which
+ // we use to determine how many bytes to read to get the full descriptor.
+ // This is necessary since we don't know how many ports the hub can support
+ // and we only support up to MAX_USB_DEVICES.
+ //
+ sSetupPacket.bRequest = USBREQ_GET_DESCRIPTOR;
+ sSetupPacket.wValue = (USB_DTYPE_HUB << 8);
+ sSetupPacket.wIndex = 0;
+ sSetupPacket.wLength = sizeof(tUsbHubDescriptor);
+
+ //
+ // Send the request.
+ //
+ ui32Read = USBHCDControlTransfer(0, &sSetupPacket, psDevice,
+ (void *)psDesc, sizeof(tUsbHubDescriptor),
+ psDevice->sDeviceDescriptor.bMaxPacketSize0);
+
+ //
+ // Make sure we got at least some data.
+ //
+ if(ui32Read == 0)
+ {
+ return(false);
+ }
+
+ //
+ // All is well.
+ //
+ return(true);
+}
+
+//*****************************************************************************
+//
+// Open an instance of the hub driver. This is called when the USB host
+// has enumerated a new hub device.
+//
+//*****************************************************************************
+static void *
+HubDriverOpen(tUSBHostDevice *psDevice)
+{
+ tEndpointDescriptor *psEndpointDescriptor;
+ tInterfaceDescriptor *psInterface;
+ tUsbHubDescriptor sHubDesc;
+ bool bRetcode;
+ uint32_t ui32Loop;
+
+ //
+ // If we are already talking to a hub, fail the call. We only support
+ // a single hub.
+ //
+ if(g_sRootHub.ui32Flags & USBLIB_HUB_ACTIVE)
+ {
+ return(0);
+ }
+
+ //
+ // Get pointers to the device descriptors we need to look at.
+ //
+ psInterface = USBDescGetInterface(psDevice->psConfigDescriptor, 0, 0);
+ psEndpointDescriptor = USBDescGetInterfaceEndpoint(psInterface, 0,
+ psDevice->ui32ConfigDescriptorSize);
+
+ //
+ // If there are no endpoints, something is wrong since a hub must have
+ // a single INT endpoint for signaling.
+ //
+ if(psEndpointDescriptor == 0)
+ {
+ return 0;
+ }
+
+ //
+ // Make sure we really are talking to a hub.
+ //
+ if((psInterface->bInterfaceClass != USB_CLASS_HUB) ||
+ (psInterface->bInterfaceSubClass != 0))
+ {
+ //
+ // Something is wrong - this isn't a hub or, if it is, we don't
+ // understand the protocol it is using.
+ //
+ return(0);
+ }
+
+ //
+ // Remember that this is a high speed hub with either single or multiple
+ // transaction translators.
+ //
+ if(psInterface->bInterfaceProtocol == USB_HUB_PROTOCOL_SINGLE)
+ {
+ g_sRootHub.ui32Flags |= USBLIB_HUB_HS;
+ }
+ else if(psInterface->bInterfaceProtocol == USB_HUB_PROTOCOL_MULTI)
+ {
+ g_sRootHub.ui32Flags |= USBLIB_HUB_HS | USBLIB_HUB_MULTI_TT;
+ }
+
+ //
+ // Remember the device information for later.
+ //
+ g_sRootHub.psDevice = psDevice;
+
+ //
+ // A hub must support an interrupt endpoint so check this.
+ //
+ if((psEndpointDescriptor->bmAttributes & USB_EP_ATTR_TYPE_M) ==
+ USB_EP_ATTR_INT)
+ {
+ //
+ // The endpoint is the correct type. Is it an IN endpoint?
+ //
+ if(psEndpointDescriptor->bEndpointAddress & USB_EP_DESC_IN)
+ {
+ //
+ // Yes - all is well with the hub endpoint so allocate a pipe to
+ // handle traffic from the hub.
+ //
+ g_sRootHub.ui32IntInPipe = USBHCDPipeAlloc(0, USBHCD_PIPE_INTR_IN,
+ psDevice,
+ HubIntINCallback);
+ USBHCDPipeConfig(g_sRootHub.ui32IntInPipe,
+ psEndpointDescriptor->wMaxPacketSize,
+ psEndpointDescriptor->bInterval,
+ psEndpointDescriptor->bEndpointAddress &
+ USB_EP_DESC_NUM_M);
+ }
+ }
+
+ //
+ // Did we allocate the endpoint successfully?
+ //
+ if(!g_sRootHub.ui32IntInPipe)
+ {
+ //
+ // No - return an error.
+ //
+ return 0;
+ }
+
+ //
+ // Assuming we have a callback, call it to tell the owner that a hub is
+ // now connected.
+ //
+ if(g_sRootHub.pfnCallback != 0)
+ {
+ g_sRootHub.pfnCallback((void *)g_sRootHub.ui32CBData,
+ USB_EVENT_CONNECTED, (uint32_t)&g_sRootHub, 0);
+ }
+
+ //
+ // Get the hub descriptor and store information we'll need for later.
+ //
+ bRetcode = GetHubDescriptor(&sHubDesc);
+ if(bRetcode)
+ {
+
+ //
+ // We read the descriptor successfully so extract the parts we need.
+ //
+ g_sRootHub.ui8NumPorts = sHubDesc.bNbrPorts;
+ g_sRootHub.ui16HubCharacteristics = sHubDesc.wHubCharacteristics;
+ g_sRootHub.ui8NumPortsInUse =
+ (sHubDesc.bNbrPorts > MAX_USB_DEVICES) ? MAX_USB_DEVICES :
+ sHubDesc.bNbrPorts;
+
+ //
+ // The size of the status change report that the hub sends is dependent
+ // upon the number of ports that the hub supports. Calculate this by
+ // adding 1 to the number of ports (bit 0 of the report is the hub
+ // status, higher bits are one per port) then dividing by 8 (bits per
+ // byte) and rounding up.
+ //
+ g_sRootHub.ui8ReportSize = ((sHubDesc.bNbrPorts + 1) + 7) / 8;
+
+ //
+ // Enable power to all ports on the hub.
+ //
+ for(ui32Loop = 1; ui32Loop <= sHubDesc.bNbrPorts; ui32Loop++)
+ {
+ //
+ // Turn on power to this port.
+ //
+ HubSetPortFeature(&g_sRootHub, ui32Loop,
+ HUB_FEATURE_PORT_POWER);
+ }
+
+ //
+ // Clear out our port state structures.
+ //
+ for(ui32Loop = 0; ui32Loop < MAX_USB_DEVICES; ui32Loop++)
+ {
+ g_sRootHub.psPorts[ui32Loop].bChanged = false;
+ g_sRootHub.psPorts[ui32Loop].iState = ePortIdle;
+ }
+ }
+ else
+ {
+ //
+ // Oops - we can't read the hub descriptor! Tidy up and return
+ // an error.
+ //
+ USBHCDPipeFree(g_sRootHub.ui32IntInPipe);
+ g_sRootHub.pfnCallback = 0;
+ g_sRootHub.ui32Flags &= ~USBLIB_HUB_ACTIVE;
+ return(0);
+ }
+
+ //
+ // If we get here, all is well so remember that the hub is connected and
+ // active.
+ //
+ g_sRootHub.ui32Flags |= USBLIB_HUB_ACTIVE;
+
+ //
+ // Return our instance data pointer to the caller to use as a handle.
+ //
+ return((void *)&g_sRootHub);
+}
+
+//*****************************************************************************
+//
+// Close an instance of the hub driver.
+//
+//*****************************************************************************
+static void
+HubDriverClose(void *pvHubDevice)
+{
+ uint32_t ui32Loop;
+
+ //
+ // No device so just exit.
+ //
+ if(g_sRootHub.psDevice == 0)
+ {
+ return;
+ }
+
+ //
+ // Disconnect any devices that are currently connected to the hub.
+ //
+ for(ui32Loop = 0; ui32Loop < MAX_USB_DEVICES; ui32Loop++)
+ {
+ //
+ // Does this port have a device connected to it that we have previously
+ // reported to the host control layer?h
+ //
+ if((g_sRootHub.psPorts[ui32Loop].iState == ePortActive) ||
+ (g_sRootHub.psPorts[ui32Loop].iState == ePortResetWait) ||
+ (g_sRootHub.psPorts[ui32Loop].iState == ePortEnumerated) ||
+ (g_sRootHub.psPorts[ui32Loop].iState == ePortError))
+ {
+ //
+ // Yes - tell the host controller to disconnect the device.
+ //
+ USBHCDHubDeviceDisconnected(0,
+ g_sRootHub.psPorts[ui32Loop].ui32DevHandle);
+
+ }
+
+ //
+ // Make sure that the state returns to idle.
+ //
+ g_sRootHub.psPorts[ui32Loop].iState = ePortIdle;
+
+ }
+
+ //
+ // Reset the device pointer.
+ //
+ g_sRootHub.psDevice = 0;
+
+ //
+ // Mark the hub as absent.
+ //
+ g_sRootHub.ui32Flags &= ~USBLIB_HUB_ACTIVE;
+
+ //
+ // Note that we are not in the middle of enumerating anything.
+ //
+ g_sRootHub.bEnumerationBusy = false;
+
+ //
+ // Free the Interrupt IN pipe.
+ //
+ if(g_sRootHub.ui32IntInPipe != 0)
+ {
+ USBHCDPipeFree(g_sRootHub.ui32IntInPipe);
+ }
+
+ //
+ // If the callback exists, call it with a DISCONNECTED event.
+ //
+ if(g_sRootHub.pfnCallback != 0)
+ {
+ g_sRootHub.pfnCallback((void *)g_sRootHub.ui32CBData,
+ USB_EVENT_DISCONNECTED, (uint32_t)&g_sRootHub,
+ 0);
+ }
+}
+
+//*****************************************************************************
+//
+// Perform any processing required as a result of a change in the reset
+// signaling for a given port.
+//
+//*****************************************************************************
+static void
+HubDriverReset(uint8_t ui8Port, bool bResetActive)
+{
+ //
+ // Did the reset sequence end or begin?
+ //
+ if(!bResetActive)
+ {
+ //
+ // The reset ended. Now wait for at least 10ms before signaling
+ // USB enumeration code that a new device is waiting to be enumerated.
+ //
+ g_sRootHub.psPorts[ui8Port].iState = ePortResetWait;
+
+ //
+ // Set the wait to 10ms (10 frames) from now.
+ //
+ g_sRootHub.psPorts[ui8Port].ui32Count = 10;
+ }
+ else
+ {
+ //
+ // Was this device previously active?
+ //
+ if(g_sRootHub.psPorts[ui8Port].iState == ePortActive)
+ {
+ USBHCDHubDeviceDisconnected(0,
+ g_sRootHub.psPorts[ui8Port].ui32DevHandle);
+ }
+
+ //
+ // The reset is active so mark our port as in reset.
+ //
+ g_sRootHub.psPorts[ui8Port].iState = ePortResetActive;
+ }
+}
+
+//*****************************************************************************
+//
+// Start the process of enumerating a new device by issuing a reset to the
+// appropriate downstream port.
+//
+//*****************************************************************************
+static void
+HubDriverDeviceReset(uint8_t ui8Port)
+{
+ DEBUG_OUTPUT("Starting enumeration for port %d\n", ui8Port);
+
+ //
+ // Record the fact that we are in the process of enumerating a device.
+ //
+ g_sRootHub.bEnumerationBusy = true;
+
+ //
+ // Save the port that is being enumerated.
+ //
+ g_sRootHub.ui8EnumIdx = ui8Port;
+
+ //
+ // Mark the port as being reset.
+ //
+ g_sRootHub.psPorts[ui8Port].iState = ePortResetActive;
+
+ //
+ // Initiate a reset on the relevant port to start the enumeration process.
+ //
+ HubSetPortFeature(&g_sRootHub, ui8Port, HUB_FEATURE_PORT_RESET);
+}
+
+//*****************************************************************************
+//
+// A new device has been connected to the hub. Allocate resources to manage
+// it and pass details back to the main USB host enumeration code to have the
+// device enumerated.
+//
+//*****************************************************************************
+static void
+HubDriverDeviceConnect(uint8_t ui8Port)
+{
+ DEBUG_OUTPUT("HubDriverDeviceConnect\n");
+
+ //
+ // We've allocated a port table entry so fill it in then initiate a reset
+ // on the device.
+ //
+ g_sRootHub.psPorts[ui8Port].bChanged = false;
+
+ //
+ // Mark the port as having a device present but not enumerated.
+ //
+ DEBUG_OUTPUT("Deferring enumeration for port %d\n", ui8Port);
+ g_sRootHub.psPorts[ui8Port].iState = ePortConnected;
+
+ //
+ // Wait 100ms to reset the device.
+ //
+ g_sRootHub.psPorts[ui8Port].ui32Count = 100;
+}
+
+//*****************************************************************************
+//
+// An existing device has been removed from the hub. Tidy up and let the main
+// USB host code know so that it can free device resources.
+//
+//*****************************************************************************
+static void
+HubDriverDeviceDisconnect(uint8_t ui8Port)
+{
+ //
+ // This is a device we are currently managing. Have we already informed
+ // the host controller that it is present?
+ //
+ if((g_sRootHub.psPorts[ui8Port].iState == ePortActive) ||
+ (g_sRootHub.psPorts[ui8Port].iState == ePortResetWait) ||
+ (g_sRootHub.psPorts[ui8Port].iState == ePortEnumerated) ||
+ (g_sRootHub.psPorts[ui8Port].iState == ePortError))
+ {
+ //
+ // Yes - tell the host controller that the device is not longer
+ // connected.
+ //
+ USBHCDHubDeviceDisconnected(0,
+ g_sRootHub.psPorts[ui8Port].ui32DevHandle);
+ }
+
+ //
+ // If the device was being enumerated, make sure we clear the flag
+ // indicating that an enumeration is still ongoing.
+ //
+ if((g_sRootHub.psPorts[ui8Port].iState == ePortResetActive) ||
+ (g_sRootHub.psPorts[ui8Port].iState == ePortResetWait) ||
+ (g_sRootHub.psPorts[ui8Port].iState == ePortActive))
+ {
+ g_sRootHub.bEnumerationBusy = false;
+ }
+
+ //
+ // Free up the port state structure.
+ //
+ g_sRootHub.psPorts[ui8Port].iState = ePortIdle;
+}
+
+//*****************************************************************************
+//
+// This function is called periodically by USBHCDMain(). We use it to handle
+// the hub port state machine.
+//
+//*****************************************************************************
+void
+USBHHubMain(void)
+{
+ uint16_t ui16Status, ui16Changed;
+ uint_fast8_t ui8Port;
+ bool bRetcode;
+
+ //
+ // If the hub is not present, just return.
+ //
+ if((g_sRootHub.ui32Flags & USBLIB_HUB_ACTIVE) == 0)
+ {
+ return;
+ }
+
+ //
+ // Initialize the status variables.
+ //
+ ui16Status = 0;
+ ui16Changed = 0;
+
+ //
+ // The hub is active and something changed. Check to see which port changed
+ // state and handle as necessary.
+ //
+ for(ui8Port = 0; ui8Port <= g_sRootHub.ui8NumPortsInUse; ui8Port++)
+ {
+ //
+ // Decrement any wait counter if there is one present.
+ //
+ if(g_sRootHub.psPorts[ui8Port].ui32Count != 0)
+ {
+ g_sRootHub.psPorts[ui8Port].ui32Count--;
+ }
+
+ //
+ // Is this port waiting to be enumerated and is the last device
+ // enumeration finished?
+ //
+ if((g_sRootHub.psPorts[ui8Port].iState == ePortConnected) &&
+ (!g_sRootHub.bEnumerationBusy) &&
+ (g_sRootHub.psPorts[ui8Port].ui32Count == 0))
+ {
+ //
+ // Yes - start the enumeration processing for this device.
+ //
+ HubDriverDeviceReset(ui8Port);
+ }
+
+ //
+ // If the state is ePortResetWait then the hub is waiting before
+ // accessing device as the USB 2.0 specification requires.
+ //
+ if((g_sRootHub.psPorts[ui8Port].iState == ePortResetWait) &&
+ (g_sRootHub.psPorts[ui8Port].ui32Count == 0))
+ {
+ //
+ // Start the enumeration process if the timeout has passed and
+ // the hub is waiting to start enumerating the device.
+ //
+ g_sRootHub.psPorts[ui8Port].iState = ePortActive;
+
+ //
+ // Call the main host controller layer to have it enumerate the
+ // newly connected device.
+ //
+ g_sRootHub.psPorts[ui8Port].ui32DevHandle =
+ USBHCDHubDeviceConnected(0, 1, ui8Port,
+ g_sRootHub.psPorts[ui8Port].ui32Speed);
+ }
+
+ //
+ // If an enumeration is in progress and the loop is not on the port
+ // being enumerated then skip the port.
+ //
+ if(g_sRootHub.bEnumerationBusy &&
+ (g_sRootHub.ui8EnumIdx != ui8Port))
+ {
+ continue;
+ }
+
+ //
+ // Did something change for this particular port?
+ //
+ if(g_ui32ChangeFlags & (1 << ui8Port))
+ {
+ //
+ // Yes - query the port status.
+ //
+ bRetcode = HubGetPortStatus(&g_sRootHub, ui8Port, &ui16Status,
+ &ui16Changed);
+
+ //
+ // Clear this change with the USB interrupt temporarily disabled to
+ // ensure that we do not clear a flag that the interrupt routine
+ // has just set.
+ //
+ OS_INT_DISABLE(g_sRootHub.ui32IntNum);
+ g_ui32ChangeFlags &= ~(1 << ui8Port);
+ OS_INT_ENABLE(g_sRootHub.ui32IntNum);
+
+ //
+ // If there was an error, go on and look at the next bit.
+ //
+ if(!bRetcode)
+ {
+ continue;
+ }
+
+ //
+ // Now consider what changed and handle it as necessary.
+ //
+
+ //
+ // Was a device connected to or disconnected from the port?
+ //
+ if(ui16Changed & HUB_PORT_CHANGE_DEVICE_PRESENT)
+ {
+ DEBUG_OUTPUT("Connection change on port %d\n", ui8Port);
+
+ //
+ // Clear the condition.
+ //
+ HubClearPortFeature(&g_sRootHub, ui8Port,
+ HUB_FEATURE_C_PORT_CONNECTION);
+
+ //
+ // Was a device connected or disconnected?
+ //
+ if(ui16Status & HUB_PORT_STATUS_DEVICE_PRESENT)
+ {
+ DEBUG_OUTPUT("Connected\n");
+
+ //
+ // A device was connected.
+ //
+ HubDriverDeviceConnect(ui8Port);
+ }
+ else
+ {
+ DEBUG_OUTPUT("Disconnected\n");
+
+ //
+ // A device was disconnected.
+ //
+ HubDriverDeviceDisconnect(ui8Port);
+ }
+ }
+
+ //
+ // Did a reset on the port complete?
+ //
+ if(ui16Changed & HUB_PORT_CHANGE_RESET)
+ {
+ //
+ // Clear the condition.
+ //
+ HubClearPortFeature(&g_sRootHub, ui8Port,
+ HUB_FEATURE_C_PORT_RESET);
+
+ //
+ // Yes - query the port status.
+ //
+ bRetcode = HubGetPortStatus(&g_sRootHub, ui8Port,
+ &ui16Status, &ui16Changed);
+
+ DEBUG_OUTPUT("Reset %s for port %d\n",
+ ((ui16Status & HUB_PORT_STATUS_RESET) ? "asserted" :
+ "deasserted"), ui8Port);
+
+ //
+ // Handle the reset case.
+ //
+ HubDriverReset(ui8Port, (ui16Status & HUB_PORT_STATUS_RESET) ?
+ true : false);
+
+ //
+ // A device was connected.
+ //
+ if(ui16Status & HUB_PORT_STATUS_LOW_SPEED)
+ {
+ USBHubPortSpeedSet(ui8Port, USB_EP_SPEED_LOW);
+ }
+ else if(ui16Status & HUB_PORT_STATUS_HIGH_SPEED)
+ {
+ USBHubPortSpeedSet(ui8Port, USB_EP_SPEED_HIGH);
+ }
+ else
+ {
+ USBHubPortSpeedSet(ui8Port, USB_EP_SPEED_FULL);
+ }
+ }
+
+ //
+ // Did an over-current reset on the port complete?
+ //
+ if(ui16Changed & HUB_PORT_CHANGE_OVER_CURRENT)
+ {
+ DEBUG_OUTPUT("Port %d over current.\n", ui8Port);
+
+ //
+ // Currently we ignore this and just clear the condition.
+ //
+ HubClearPortFeature(&g_sRootHub, ui8Port,
+ HUB_FEATURE_C_PORT_OVER_CURRENT);
+ }
+
+ //
+ // Has the port been enabled or disabled?
+ //
+ if(ui16Changed & HUB_PORT_CHANGE_ENABLED)
+ {
+ DEBUG_OUTPUT("Enable change for port %d.\n", ui8Port);
+
+ //
+ // Currently we ignore this and just clear the condition.
+ //
+ HubClearPortFeature(&g_sRootHub, ui8Port,
+ HUB_FEATURE_C_PORT_ENABLE);
+ }
+
+ //
+ // Has the port been suspended or resumed?
+ //
+ if(ui16Changed & HUB_PORT_CHANGE_SUSPENDED)
+ {
+ DEBUG_OUTPUT("Suspend change for port %d.\n", ui8Port);
+
+ //
+ // Currently we ignore this and just clear the condition.
+ //
+ HubClearPortFeature(&g_sRootHub, ui8Port,
+ HUB_FEATURE_C_PORT_SUSPEND);
+ }
+ }
+ }
+}
+
+//*****************************************************************************
+//
+//! Informs the hub class driver that a downstream device has been enumerated.
+//!
+//! \param ui8Hub is the address of the hub to which the downstream device
+//! is attached.
+//! \param ui8Port is the port on the hub to which the downstream device is
+//! attached.
+//!
+//! This function is called by the host controller driver to inform the hub
+//! class driver that a downstream device has been enumerated successfully.
+//! The hub driver then moves on and continues enumeration of any other newly
+//! connected devices.
+//!
+//! \return None.
+//
+//*****************************************************************************
+void
+USBHHubEnumerationComplete(uint8_t ui8Hub, uint8_t ui8Port)
+{
+ DEBUG_OUTPUT("Enumeration complete for hub %d, port %d\n", ui8Hub, ui8Port);
+
+ //
+ // Record the fact that the device is up and running.
+ //
+ g_sRootHub.psPorts[ui8Port].iState = ePortEnumerated;
+
+ //
+ // Clear the flag we use to defer further enumerations. This will cause
+ // the next connected device (if any) to start enumeration on the next
+ // call to USBHHubMain().
+ //
+ g_sRootHub.bEnumerationBusy = false;
+}
+
+//*****************************************************************************
+//
+//! Informs the hub class driver that a downstream device failed to enumerate.
+//!
+//! \param ui8Hub is the address of the hub to which the downstream device
+//! is attached.
+//! \param ui8Port is the port on the hub to which the downstream device is
+//! attached.
+//!
+//! This function is called by the host controller driver to inform the hub
+//! class driver that an attempt to enumerate a downstream device has failed.
+//! The hub driver then cleans up and continues enumeration of any other newly
+//! connected devices.
+//!
+//! \return None.
+//
+//*****************************************************************************
+void
+USBHHubEnumerationError(uint8_t ui8Hub, uint8_t ui8Port)
+{
+ DEBUG_OUTPUT("Enumeration error for hub %d, port %d\n", ui8Hub, ui8Port);
+
+ //
+ // Record the fact that the device is not working correctly.
+ //
+ g_sRootHub.psPorts[ui8Port].iState = ePortError;
+
+ //
+ // Clear the flag we use to defer further enumerations. This will cause
+ // the next connected device (if any) to start enumeration on the next
+ // call to USBHHubMain().
+ //
+ g_sRootHub.bEnumerationBusy = false;
+}
+
+//*****************************************************************************
+//
+//! This function is used to enable the host hub class driver before any
+//! devices are present.
+//!
+//! \param pfnCallback is the driver call back for host hub events.
+//!
+//! This function is called to open an instance of a host hub device and
+//! provides a valid callback function for host hub events in the
+//! \e pfnCallback parameter. This function must be called before the USB
+//! host code can successfully enumerate a hub device or any devices attached
+//! to the hub. The \e pui8HubPool is memory provided to the hub class to
+//! manage the devices that are connected to the hub. The \e ui32PoolSize is
+//! the number of bytes and should be at least 32 bytes per device including
+//! the hub device itself. A simple formula for providing memory to the hub
+//! class is \b MAX_USB_DEVICES * 32 bytes of data to allow for proper
+//! enumeration of connected devices. The value for \b MAX_USB_DEVICES is
+//! defined in the usblib.h file and controls the number of devices
+//! supported by the USB library. The \e ui32NumHubs parameter
+//! defaults to one and only one buffer of size tHubInstance is required to
+//! be passed in the \e psHubInstance parameter.
+//!
+//! \note Changing the value of \b MAX_USB_DEVICES requires a rebuild of the
+//! USB library to have an effect on the library.
+//!
+//! \return This function returns the driver instance to use for the other
+//! host hub functions. If there is no instance available at the time of
+//! this call, this function returns zero.
+//
+//*****************************************************************************
+tHubInstance *
+USBHHubOpen(tUSBHHubCallback pfnCallback)
+{
+ //
+ // Only one hub is supported.
+ //
+ if(g_sRootHub.pfnCallback)
+ {
+ DEBUG_OUTPUT("USBHHubOpen failed - already connected.\n");
+ return(0);
+ }
+
+ //
+ // Save the instance data for this device.
+ //
+ g_sRootHub.pfnCallback = pfnCallback;
+
+ DEBUG_OUTPUT("USBHHubOpen completed.\n");
+
+ //
+ // Return the device instance pointer.
+ //
+ return(&g_sRootHub);
+}
+
+//*****************************************************************************
+//
+//! This function is used to release a hub device instance.
+//!
+//! \param psHubInstance is the hub device instance that is to be released.
+//!
+//! This function is called when an instance of the hub device must be
+//! released. This function is typically made in preparation for shutdown or a
+//! switch to function as a USB device when in OTG mode. Following this call,
+//! the hub device is no longer available, but it can be opened again using a
+//! call to USBHHubOpen(). After calling USBHHubClose(), the host hub driver
+//! no longer provides any callbacks or accepts calls to other hub driver APIs.
+//!
+//! \return None.
+//
+//*****************************************************************************
+void
+USBHHubClose(tHubInstance *psHubInstance)
+{
+ //
+ // Forget the instance pointer and callback.
+ //
+ psHubInstance->psDevice = 0;
+ psHubInstance->pfnCallback = 0;
+
+ DEBUG_OUTPUT("USBHHubClose completed.\n");
+}
+
+//*****************************************************************************
+//
+// This function is used to initialize the Hub driver. This is an internal
+// function that should not be called by the application.
+//
+//*****************************************************************************
+void
+USBHHubInit(void)
+{
+ //
+ // Initialize Hub state.
+ //
+ g_ui32ChangeFlags = 0;
+ g_ui32HubChanges = 0;
+
+ if(g_sRootHub.psDevice != 0)
+ {
+ //
+ // Save the USB interrupt number.
+ //
+ g_sRootHub.ui32IntNum = INT_USB0_TM4C123;
+
+ //
+ // These devices have a different USB interrupt number.
+ //
+ if(CLASS_IS_TM4C129)
+ {
+ g_sRootHub.ui32IntNum = INT_USB0_TM4C129;
+ }
+ }
+}
+
+//*****************************************************************************
+//
+//! This function forwards an LPM request for a device to enter L1 sleep state.
+//!
+//! \param psHubInstance is the hub device instance that was returned
+//! from the call to USBHHubOpen().
+//!
+//! This function forwards a request from an application to the hub device
+//! class to request that a device enter the LPM L1 sleep state. The
+//! caller must check the return value to see if the request can be
+//! attempted at this time. If another LPM transaction is busy on this or
+//! another device, then this function returns \b USBHCD_LPM_PENDING. If
+//! the LPM request was scheduled to be sent the function returns
+//! \b USBHCD_LPM_AVAIL. The caller should check the USBHCDLPMStatus()
+//! function to determine if the request completed successfully or if there
+//! was an error.
+//!
+//! \return This function returns the following values:
+//! - \b USBHCD_LPM_AVAIL - The transition to L1 state is scheduled to be sent.
+//! - \b USBHCD_LPM_PENDING - There is already an LPM request pending.
+//
+//*****************************************************************************
+uint32_t
+USBHHubLPMSleep(tHubInstance *psHubInstance)
+{
+ //
+ // Call the host controller function to send the sleep command.
+ //
+ return(USBHCDLPMSleep(psHubInstance->psDevice));
+}
+
+//*****************************************************************************
+//
+//! This function returns the current status of an LPM request.
+//!
+//! \param psHubInstance is the hub device instance that was returned
+//! from the call to USBHHubOpen().
+//!
+//! This function returns the current status of LPM requests for a given
+//! device. This is called to determine if a previous request completed
+//! successfully or if there was an error.
+//!
+//! \return This function returns the following values:
+//! - \b USBHCD_LPM_AVAIL - There are no pending LPM requests on this specific
+//! device or the last request completed successfully.
+//! - \b USBHCD_LPM_ERROR - The last LPM request for this device did not
+//! complete successfully.
+//! - \b USBHCD_LPM_PENDING - The last LPM request has not completed.
+//
+//*****************************************************************************
+uint32_t
+USBHHubLPMStatus(tHubInstance *psHubInstance)
+{
+ //
+ // Call the host controller function to get the current LPM status.
+ //
+ return(USBHCDLPMStatus(psHubInstance->psDevice));
+}
+
+//*****************************************************************************
+//
+//! @}
+//
+//*****************************************************************************
diff --git a/usblib/host/usbhhub.h b/usblib/host/usbhhub.h
new file mode 100644
index 0000000..17a3c08
--- /dev/null
+++ b/usblib/host/usbhhub.h
@@ -0,0 +1,174 @@
+//*****************************************************************************
+//
+// usbhhub.h - This hold the host driver for hid class.
+//
+// Copyright (c) 2011-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 Tiva USB Library.
+//
+//*****************************************************************************
+
+#ifndef __USBHHUB_H__
+#define __USBHHUB_H__
+
+//*****************************************************************************
+//
+// If building with a C++ compiler, make all of the definitions in this header
+// have a C binding.
+//
+//*****************************************************************************
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+typedef struct tHubInstance tHubInstance;
+
+extern const tUSBHostClassDriver g_sUSBHubClassDriver;
+
+//*****************************************************************************
+//
+// The USB standard allows for up to 127 downstream ports on a single hub.
+// This would require rather more memory than we would like to set aside so the
+// default configuration of the hub driver supports hubs with up to 7
+// downstream-facing ports. In practice, this should be more than enough
+// since this covers the vast majority of consumer hubs. Note that, by
+// default, we will only support 4 devices so you can't fully populate a 7 port
+// hub and have everything work.
+//
+// Feel free to change this but bad things will happen if you increase it above
+// 31 since we assume the reports will always fit inside a 4 byte buffer.
+//
+//*****************************************************************************
+#define ROOT_HUB_MAX_PORTS 7
+
+//*****************************************************************************
+//
+// Values used as the ui16Feature parameter to USBHHubClearHubFeature().
+//
+//*****************************************************************************
+#define HUB_FEATURE_C_HUB_LOCAL_POWER \
+ 0
+#define HUB_FEATURE_C_HUB_OVER_CURRENT \
+ 1
+
+//*****************************************************************************
+//
+// Values used as the ui16Feature parameter to USBHHubSetPortFeature() and
+// USBHHubClearPortFeature().
+//
+//*****************************************************************************
+#define HUB_FEATURE_PORT_CONNECTION \
+ 0
+#define HUB_FEATURE_PORT_ENABLE 1
+#define HUB_FEATURE_PORT_SUSPEND \
+ 2
+#define HUB_FEATURE_PORT_OVER_CURRENT \
+ 3
+#define HUB_FEATURE_PORT_RESET 4
+#define HUB_FEATURE_PORT_POWER 8
+#define HUB_FEATURE_PORT_LOW_SPEED \
+ 9
+#define HUB_FEATURE_C_PORT_CONNECTION \
+ 16
+#define HUB_FEATURE_C_PORT_ENABLE \
+ 17
+#define HUB_FEATURE_C_PORT_SUSPEND \
+ 18
+#define HUB_FEATURE_C_PORT_OVER_CURRENT \
+ 19
+#define HUB_FEATURE_C_PORT_RESET \
+ 20
+#define HUB_FEATURE_PORT_TEST 21
+#define HUB_FEATURE_PORT_INDICATOR \
+ 22
+
+//*****************************************************************************
+//
+// Values returned via the *pui16HubStatus and *pui16HubChange parameters
+// passed to USBHHubGetHubStatus(). These may be ORed together into the
+// returned status value.
+//
+//*****************************************************************************
+#define HUB_STATUS_PWR_LOST 1
+#define HUB_STATUS_OVER_CURRENT 2
+
+//*****************************************************************************
+//
+// Values returned via the *pui16PortStatus parameter passed to
+// USBHHubGetPortStatus(). These may be ORed together into the returned status
+// value.
+//
+//*****************************************************************************
+#define HUB_PORT_STATUS_DEVICE_PRESENT \
+ 0x0001
+#define HUB_PORT_STATUS_ENABLED 0x0002
+#define HUB_PORT_STATUS_SUSPENDED \
+ 0x0004
+#define HUB_PORT_STATUS_OVER_CURRENT \
+ 0x0008
+#define HUB_PORT_STATUS_RESET 0x0010
+#define HUB_PORT_STATUS_POWERED 0x0100
+#define HUB_PORT_STATUS_LOW_SPEED \
+ 0x0200
+#define HUB_PORT_STATUS_HIGH_SPEED \
+ 0x0400
+#define HUB_PORT_STATUS_TEST_MODE \
+ 0x0800
+#define HUB_PORT_STATUS_INDICATOR_CONTROL \
+ 0x1000
+
+//*****************************************************************************
+//
+// Values returned via the *pui16PortChange parameter passed to
+// USBHHubGetPortStatus(). These may be ORed together into the returned status
+// value.
+//
+//*****************************************************************************
+#define HUB_PORT_CHANGE_DEVICE_PRESENT \
+ 0x0001
+#define HUB_PORT_CHANGE_ENABLED 0x0002
+#define HUB_PORT_CHANGE_SUSPENDED \
+ 0x0004
+#define HUB_PORT_CHANGE_OVER_CURRENT \
+ 0x0008
+#define HUB_PORT_CHANGE_RESET 0x0010
+
+//*****************************************************************************
+//
+// The prototype for the USB Hub host driver callback function.
+//
+//*****************************************************************************
+typedef void (*tUSBHHubCallback)(tHubInstance *psHubInstance,
+ uint32_t ui32Event, uint32_t ui32MsgParam,
+ void *pvMsgData);
+
+//*****************************************************************************
+//
+// Public function prototypes for the HUB class driver.
+//
+//*****************************************************************************
+extern tHubInstance * USBHHubOpen(tUSBHHubCallback pfnCallback);
+extern void USBHHubClose(tHubInstance *psHubInstance);
+extern uint32_t USBHHubLPMSleep(tHubInstance *psHubInstance);
+extern uint32_t USBHHubLPMStatus(tHubInstance *psHubInstance);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif // __USBHHUB_H__
diff --git a/usblib/host/usbhmsc.c b/usblib/host/usbhmsc.c
new file mode 100644
index 0000000..9ef72fa
--- /dev/null
+++ b/usblib/host/usbhmsc.c
@@ -0,0 +1,756 @@
+//*****************************************************************************
+//
+// usbhmsc.c - USB MSC host driver.
+//
+// Copyright (c) 2008-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 Tiva USB Library.
+//
+//*****************************************************************************
+
+#include <stdbool.h>
+#include <stdint.h>
+#include "inc/hw_types.h"
+#include "driverlib/usb.h"
+#include "usblib/usblib.h"
+#include "usblib/usblibpriv.h"
+#include "usblib/usbmsc.h"
+#include "usblib/host/usbhost.h"
+#include "usblib/host/usbhostpriv.h"
+#include "usblib/host/usbhmsc.h"
+#include "usblib/host/usbhscsi.h"
+
+//*****************************************************************************
+//
+//! \addtogroup usblib_host_class
+//! @{
+//
+//*****************************************************************************
+
+//*****************************************************************************
+//
+// Forward declarations for the driver open and close calls.
+//
+//*****************************************************************************
+static void *USBHMSCOpen(tUSBHostDevice *psDevice);
+static void USBHMSCClose(void *pvInstance);
+
+//*****************************************************************************
+//
+// This is the structure for an instance of a USB MSC host driver.
+//
+//*****************************************************************************
+struct tUSBHMSCInstance
+{
+ //
+ // Save the device instance.
+ //
+ tUSBHostDevice *psDevice;
+
+ //
+ // Used to save the callback.
+ //
+ tUSBHMSCCallback pfnCallback;
+
+ //
+ // The Maximum LUNs
+ //
+ uint32_t ui32MaxLUN;
+
+ //
+ // The total number of blocks associated with this device.
+ //
+ uint32_t ui32NumBlocks;
+
+ //
+ // The size of the blocks associated with this device.
+ //
+ uint32_t ui32BlockSize;
+
+ //
+ // Bulk IN pipe.
+ //
+ uint32_t ui32BulkInPipe;
+
+ //
+ // Bulk OUT pipe.
+ //
+ uint32_t ui32BulkOutPipe;
+};
+
+//*****************************************************************************
+//
+// The array of USB MSC host drivers.
+//
+//*****************************************************************************
+static tUSBHMSCInstance g_sUSBHMSCDevice =
+{
+ 0
+};
+
+//*****************************************************************************
+//
+//! This constant global structure defines the Mass Storage Class Driver that
+//! is provided with the USB library.
+//
+//*****************************************************************************
+const tUSBHostClassDriver g_sUSBHostMSCClassDriver =
+{
+ USB_CLASS_MASS_STORAGE,
+ USBHMSCOpen,
+ USBHMSCClose,
+ 0
+};
+
+//*****************************************************************************
+//
+//! This function is used to open an instance of the MSC driver.
+//!
+//! \param psDevice is a pointer to the device information structure.
+//!
+//! This function will attempt to open an instance of the MSC driver based on
+//! the information contained in the \e psDevice structure. This call can fail
+//! if there are not sufficient resources to open the device. The function
+//! returns a value that should be passed back into USBMSCClose() when the
+//! driver is no longer needed.
+//!
+//! \return The function will return a pointer to a MSC driver instance.
+//
+//*****************************************************************************
+static void *
+USBHMSCOpen(tUSBHostDevice *psDevice)
+{
+ int32_t i32Idx;
+ tEndpointDescriptor *psEndpointDescriptor;
+ tInterfaceDescriptor *psInterface;
+
+ //
+ // Don't allow the device to be opened without closing first.
+ //
+ if(g_sUSBHMSCDevice.psDevice)
+ {
+ return(0);
+ }
+
+ //
+ // Save the device pointer.
+ //
+ g_sUSBHMSCDevice.psDevice = psDevice;
+
+ //
+ // Get the interface descriptor.
+ //
+ psInterface = USBDescGetInterface(psDevice->psConfigDescriptor, 0, 0);
+
+ //
+ // Loop through the endpoints of the device.
+ //
+ for(i32Idx = 0; i32Idx < 3; i32Idx++)
+ {
+ //
+ // Get the first endpoint descriptor.
+ //
+ psEndpointDescriptor =
+ USBDescGetInterfaceEndpoint(psInterface, i32Idx,
+ psDevice->ui32ConfigDescriptorSize);
+
+ //
+ // If no more endpoints then break out.
+ //
+ if(psEndpointDescriptor == 0)
+ {
+ break;
+ }
+
+ //
+ // See if this is a bulk endpoint.
+ //
+ if((psEndpointDescriptor->bmAttributes & USB_EP_ATTR_TYPE_M) ==
+ USB_EP_ATTR_BULK)
+ {
+ //
+ // See if this is bulk IN or bulk OUT.
+ //
+ if(psEndpointDescriptor->bEndpointAddress & USB_EP_DESC_IN)
+ {
+ //
+ // Allocate the USB Pipe for this Bulk IN endpoint.
+ //
+ g_sUSBHMSCDevice.ui32BulkInPipe =
+ USBHCDPipeAllocSize(0, USBHCD_PIPE_BULK_IN_DMA,
+ psDevice,
+ psEndpointDescriptor->wMaxPacketSize,
+ 0);
+ //
+ // Configure the USB pipe as a Bulk IN endpoint.
+ //
+ USBHCDPipeConfig(g_sUSBHMSCDevice.ui32BulkInPipe,
+ psEndpointDescriptor->wMaxPacketSize,
+ 0,
+ (psEndpointDescriptor->bEndpointAddress &
+ USB_EP_DESC_NUM_M));
+ }
+ else
+ {
+ //
+ // Allocate the USB Pipe for this Bulk OUT endpoint.
+ //
+ g_sUSBHMSCDevice.ui32BulkOutPipe =
+ USBHCDPipeAllocSize(0, USBHCD_PIPE_BULK_OUT_DMA,
+ psDevice,
+ psEndpointDescriptor->wMaxPacketSize,
+ 0);
+ //
+ // Configure the USB pipe as a Bulk OUT endpoint.
+ //
+ USBHCDPipeConfig(g_sUSBHMSCDevice.ui32BulkOutPipe,
+ psEndpointDescriptor->wMaxPacketSize,
+ 0,
+ (psEndpointDescriptor->bEndpointAddress &
+ USB_EP_DESC_NUM_M));
+ }
+ }
+ }
+
+ //
+ // If the callback exists, call it with an Open event.
+ //
+ if(g_sUSBHMSCDevice.pfnCallback != 0)
+ {
+ g_sUSBHMSCDevice.pfnCallback(&g_sUSBHMSCDevice, MSC_EVENT_OPEN, 0);
+ }
+
+
+ g_sUSBHMSCDevice.ui32MaxLUN = 0xffffffff;
+
+ //
+ // Return the only instance of this device.
+ //
+ return(&g_sUSBHMSCDevice);
+}
+
+//*****************************************************************************
+//
+//! This function is used to release an instance of the MSC driver.
+//!
+//! \param pvInstance is an instance pointer that needs to be released.
+//!
+//! This function will free up any resources in use by the MSC driver instance
+//! that is passed in. The \e pvInstance pointer should be a valid value that
+//! was returned from a call to USBMSCOpen().
+//!
+//! \return None.
+//
+//*****************************************************************************
+static void
+USBHMSCClose(void *pvInstance)
+{
+ //
+ // Do nothing if there is not a driver open.
+ //
+ if(g_sUSBHMSCDevice.psDevice == 0)
+ {
+ return;
+ }
+
+ //
+ // Reset the device pointer.
+ //
+ g_sUSBHMSCDevice.psDevice = 0;
+
+ //
+ // Free the Bulk IN pipe.
+ //
+ if(g_sUSBHMSCDevice.ui32BulkInPipe != 0)
+ {
+ USBHCDPipeFree(g_sUSBHMSCDevice.ui32BulkInPipe);
+ }
+
+ //
+ // Free the Bulk OUT pipe.
+ //
+ if(g_sUSBHMSCDevice.ui32BulkOutPipe != 0)
+ {
+ USBHCDPipeFree(g_sUSBHMSCDevice.ui32BulkOutPipe);
+ }
+
+ //
+ // If the callback exists then call it.
+ //
+ if(g_sUSBHMSCDevice.pfnCallback != 0)
+ {
+ g_sUSBHMSCDevice.pfnCallback(&g_sUSBHMSCDevice, MSC_EVENT_CLOSE, 0);
+ }
+}
+
+//*****************************************************************************
+//
+//! This function retrieves the maximum number of the logical units on a
+//! mass storage device.
+//!
+//! \param psDevice is the device instance pointer for this request.
+//! \param ui32Interface is the interface number on the device specified by the
+//! \e ui32Address parameter.
+//! \param pui8MaxLUN is the byte value returned from the device for the
+//! device's maximum logical unit.
+//!
+//! The device will return one byte of data that contains the maximum LUN
+//! supported by the device. For example, if the device supports four LUNs
+//! then the LUNs would be numbered from 0 to 3 and the return value would be
+//! 3. If no LUN is associated with the device, the value returned shall be 0.
+//!
+//! \return None.
+//
+//*****************************************************************************
+static void
+USBHMSCGetMaxLUN(tUSBHostDevice *psDevice, uint32_t ui32Interface,
+ uint8_t *pui8MaxLUN)
+{
+ tUSBRequest sSetupPacket;
+
+ //
+ // This is a Class specific interface IN request.
+ //
+ sSetupPacket.bmRequestType =
+ USB_RTYPE_DIR_IN | USB_RTYPE_CLASS | USB_RTYPE_INTERFACE;
+
+ //
+ // Request a the Max LUN for this interface.
+ //
+ sSetupPacket.bRequest = USBREQ_GET_MAX_LUN;
+ sSetupPacket.wValue = 0;
+
+ //
+ // Indicate the interface to use.
+ //
+ sSetupPacket.wIndex = (uint16_t)ui32Interface;
+
+ //
+ // Only request a single byte of data.
+ //
+ sSetupPacket.wLength = 1;
+
+ //
+ // Put the setup packet in the buffer and send the command.
+ //
+ if(USBHCDControlTransfer(0, &sSetupPacket, psDevice, pui8MaxLUN, 1,
+ MAX_PACKET_SIZE_EP0) != 1)
+ {
+ *pui8MaxLUN = 0;
+ }
+}
+
+//*****************************************************************************
+//
+//! This function checks if a drive is ready to be accessed.
+//!
+//! \param psMSCInstance is the device instance to use for this read.
+//!
+//! This function checks if the current device is ready to be accessed.
+//! It uses the \e psMSCInstance parameter to determine which device to check
+//! and returns zero when the device is ready. Any non-zero return code
+//! indicates that the device was not ready.
+//!
+//! \return This function returns zero if the device is ready and it
+//! returns a other value if the device is not ready or if an error occurred.
+//
+//*****************************************************************************
+int32_t
+USBHMSCDriveReady(tUSBHMSCInstance *psMSCInstance)
+{
+ uint8_t ui8MaxLUN, pui8Buffer[SCSI_INQUIRY_DATA_SZ];
+ uint32_t ui32Size;
+
+ //
+ // If there is no device present then return an error.
+ //
+ if(psMSCInstance->psDevice == 0)
+ {
+ return(-1);
+ }
+
+ //
+ // Only request the maximum number of LUNs once.
+ //
+ if(g_sUSBHMSCDevice.ui32MaxLUN == 0xffffffff)
+ {
+ //
+ // Get the Maximum LUNs on this device.
+ //
+ USBHMSCGetMaxLUN(g_sUSBHMSCDevice.psDevice,
+ g_sUSBHMSCDevice.psDevice->ui32Interface, &ui8MaxLUN);
+
+ //
+ // Save the Maximum number of LUNs on this device.
+ //
+ g_sUSBHMSCDevice.ui32MaxLUN = ui8MaxLUN;
+ }
+
+ //
+ // Just return if the device is returning not present.
+ //
+ ui32Size = SCSI_REQUEST_SENSE_SZ;
+ if(USBHSCSIRequestSense(psMSCInstance->ui32BulkInPipe,
+ psMSCInstance->ui32BulkOutPipe, pui8Buffer,
+ &ui32Size) != SCSI_CMD_STATUS_PASS)
+ {
+ return(-1);
+ }
+
+ if((pui8Buffer[SCSI_RS_SKEY] == SCSI_RS_KEY_UNIT_ATTN) &&
+ (pui8Buffer[SCSI_RS_SKEY_AD_SKEY] == SCSI_RS_KEY_NOTPRSNT))
+ {
+ return(-1);
+ }
+
+ //
+ // Issue a SCSI Inquiry to get basic information on the device
+ //
+ ui32Size = SCSI_INQUIRY_DATA_SZ;
+ if((USBHSCSIInquiry(psMSCInstance->ui32BulkInPipe,
+ psMSCInstance->ui32BulkOutPipe, pui8Buffer,
+ &ui32Size) != SCSI_CMD_STATUS_PASS))
+ {
+ return(-1);
+ }
+
+ //
+ // Get the size of the drive.
+ //
+ ui32Size = SCSI_INQUIRY_DATA_SZ;
+ if(USBHSCSIReadCapacity(psMSCInstance->ui32BulkInPipe,
+ psMSCInstance->ui32BulkOutPipe, pui8Buffer,
+ &ui32Size) != SCSI_CMD_STATUS_PASS)
+ {
+ //
+ // Get the current sense data from the device to see why it failed
+ // the Read Capacity command.
+ //
+ ui32Size = SCSI_REQUEST_SENSE_SZ;
+ USBHSCSIRequestSense(psMSCInstance->ui32BulkInPipe,
+ psMSCInstance->ui32BulkOutPipe, pui8Buffer,
+ &ui32Size);
+
+ //
+ // If the read capacity failed then check if the drive is ready.
+ //
+ if(USBHSCSITestUnitReady(psMSCInstance->ui32BulkInPipe,
+ psMSCInstance->ui32BulkOutPipe) !=
+ SCSI_CMD_STATUS_PASS)
+ {
+ //
+ // Get the current sense data from the device to see why it failed
+ // the Test Unit Ready command.
+ //
+ ui32Size = SCSI_REQUEST_SENSE_SZ;
+ USBHSCSIRequestSense(psMSCInstance->ui32BulkInPipe,
+ psMSCInstance->ui32BulkOutPipe, pui8Buffer,
+ &ui32Size);
+ }
+
+ return(-1);
+ }
+ else
+ {
+ //
+ // Read the block size out, value is stored big endian.
+ //
+ psMSCInstance->ui32BlockSize =
+ (pui8Buffer[7] | (pui8Buffer[6] << 8) | pui8Buffer[5] << 16 |
+ (pui8Buffer[4] << 24));
+
+ //
+ // Read the block size out.
+ //
+ psMSCInstance->ui32NumBlocks =
+ (pui8Buffer[3] | (pui8Buffer[2] << 8) | pui8Buffer[1] << 16 |
+ (pui8Buffer[0] << 24));
+ }
+
+ //
+ // See if the drive is ready to use.
+ //
+ if(USBHSCSITestUnitReady(psMSCInstance->ui32BulkInPipe,
+ psMSCInstance->ui32BulkOutPipe) !=
+ SCSI_CMD_STATUS_PASS)
+ {
+ //
+ // Get the current sense data from the device to see why it failed
+ // the Test Unit Ready command.
+ //
+ ui32Size = SCSI_REQUEST_SENSE_SZ;
+ USBHSCSIRequestSense(psMSCInstance->ui32BulkInPipe,
+ psMSCInstance->ui32BulkOutPipe, pui8Buffer,
+ &ui32Size);
+
+ return(-1);
+ }
+
+ //
+ // Success.
+ //
+ return(0);
+}
+
+//*****************************************************************************
+//
+//! This function should be called before any devices are present to enable
+//! the mass storage device class driver.
+//!
+//! \param ui32Drive is the drive number to open.
+//! \param pfnCallback is the driver callback for any mass storage events.
+//!
+//! This function is called to open an instance of a mass storage device. It
+//! should be called before any devices are connected to allow for proper
+//! notification of drive connection and disconnection. The \e ui32Drive
+//! parameter is a zero based index of the drives present in the system.
+//! There are a constant number of drives, and this number should only
+//! be greater than 0 if there is a USB hub present in the system. The
+//! application should also provide the \e pfnCallback to be notified of mass
+//! storage related events like device enumeration and device removal.
+//!
+//! \return This function will return the driver instance to use for the other
+//! mass storage functions. If there is no driver available at the time of
+//! this call, this function will return zero.
+//
+//*****************************************************************************
+tUSBHMSCInstance *
+USBHMSCDriveOpen(uint32_t ui32Drive, tUSBHMSCCallback pfnCallback)
+{
+ //
+ // Only the first drive is supported and only one callback is supported.
+ //
+ if((ui32Drive != 0) || (g_sUSBHMSCDevice.pfnCallback))
+ {
+ return(0);
+ }
+
+ //
+ // Save the callback.
+ //
+ g_sUSBHMSCDevice.pfnCallback = pfnCallback;
+
+ //
+ // Return the requested device instance.
+ //
+ return(&g_sUSBHMSCDevice);
+}
+
+//*****************************************************************************
+//
+//! This function should be called to release a drive instance.
+//!
+//! \param psMSCInstance is the device instance that is to be released.
+//!
+//! This function is called when an MSC drive is to be released in preparation
+//! for shutdown or a switch to USB device mode, for example. Following this
+//! call, the drive is available for other clients who may open it again using
+//! a call to USBHMSCDriveOpen().
+//!
+//! \return None.
+//
+//*****************************************************************************
+void
+USBHMSCDriveClose(tUSBHMSCInstance *psMSCInstance)
+{
+ //
+ // Close the drive (if it is already open)
+ //
+ USBHMSCClose((void *)psMSCInstance);
+
+ //
+ // Clear the callback indicating that the device is now closed.
+ //
+ psMSCInstance->pfnCallback = 0;
+}
+
+//*****************************************************************************
+//
+//! This function performs a block read to an MSC device.
+//!
+//! \param psMSCInstance is the device instance to use for this read.
+//! \param ui32LBA is the logical block address to read on the device.
+//! \param pui8Data is a pointer to the returned data buffer.
+//! \param ui32NumBlocks is the number of blocks to read from the device.
+//!
+//! This function will perform a block sized read from the device associated
+//! with the \e psMSCInstance parameter. The \e ui32LBA parameter specifies
+//! the logical block address to read on the device. This function will only
+//! perform \e ui32NumBlocks block sized reads. In most cases this is a read
+//! of 512 bytes of data. The \e *pui8Data buffer should be at least
+//! \e ui32NumBlocks * 512 bytes in size.
+//!
+//! \return The function returns zero for success and any negative value
+//! indicates a failure.
+//
+//*****************************************************************************
+int32_t
+USBHMSCBlockRead(tUSBHMSCInstance *psMSCInstance, uint32_t ui32LBA,
+ uint8_t *pui8Data, uint32_t ui32NumBlocks)
+{
+ uint32_t ui32Size;
+
+ //
+ // If there is no device present then return an error.
+ //
+ if(psMSCInstance->psDevice == 0)
+ {
+ return(-1);
+ }
+
+ //
+ // Calculate the actual byte size of the read.
+ //
+ ui32Size = psMSCInstance->ui32BlockSize * ui32NumBlocks;
+
+ //
+ // Perform the SCSI read command.
+ //
+ if(USBHSCSIRead10(psMSCInstance->ui32BulkInPipe,
+ psMSCInstance->ui32BulkOutPipe, ui32LBA, pui8Data,
+ &ui32Size, ui32NumBlocks) != SCSI_CMD_STATUS_PASS)
+ {
+ return(-1);
+ }
+
+ //
+ // Success.
+ //
+ return(0);
+}
+
+//*****************************************************************************
+//
+//! This function performs a block write to an MSC device.
+//!
+//! \param psMSCInstance is the device instance to use for this write.
+//! \param ui32LBA is the logical block address to write on the device.
+//! \param pui8Data is a pointer to the data to write out.
+//! \param ui32NumBlocks is the number of blocks to write to the device.
+//!
+//! This function will perform a block sized write to the device associated
+//! with the \e psMSCInstance parameter. The \e ui32LBA parameter specifies
+//! the logical block address to write on the device. This function will only
+//! perform \e ui32NumBlocks block sized writes. In most cases this is a write
+//! of 512 bytes of data. The \e *pui8Data buffer should contain at least
+//! \e ui32NumBlocks * 512 bytes in size to prevent unwanted data being written
+//! to the device.
+//!
+//! \return The function returns zero for success and any negative value
+//! indicates a failure.
+//
+//*****************************************************************************
+int32_t
+USBHMSCBlockWrite(tUSBHMSCInstance *psMSCInstance, uint32_t ui32LBA,
+ uint8_t *pui8Data, uint32_t ui32NumBlocks)
+{
+ uint32_t ui32Size;
+
+ //
+ // If there is no device present then return an error.
+ //
+ if(psMSCInstance->psDevice == 0)
+ {
+ return(-1);
+ }
+
+ //
+ // Calculate the actual byte size of the write.
+ //
+ ui32Size = psMSCInstance->ui32BlockSize * ui32NumBlocks;
+
+ //
+ // Perform the SCSI write command.
+ //
+ if(USBHSCSIWrite10(psMSCInstance->ui32BulkInPipe,
+ psMSCInstance->ui32BulkOutPipe, ui32LBA, pui8Data,
+ &ui32Size, ui32NumBlocks) != SCSI_CMD_STATUS_PASS)
+ {
+ return(-1);
+ }
+
+ //
+ // Success.
+ //
+ return(0);
+}
+
+//*****************************************************************************
+//
+//! This function forwards an LPM request for a device to enter L1 sleep state.
+//!
+//! \param psMSCInstance is the host mass storage class instance that was
+//! returned from the call to USBHMSCDriveOpen().
+//!
+//! This function forwards a request from an application to the mass storage
+//! device class to request that a device enter the LPM L1 sleep state. The
+//! caller must check the return value to see if the request can be
+//! attempted at this time. If another LPM transaction is busy on this or
+//! another device, then this function returns \b USBHCD_LPM_PENDING. If
+//! the LPM request was scheduled to be sent the function returns
+//! \b USBHCD_LPM_AVAIL. The caller should check the USBHCDLPMStatus()
+//! function to determine if the request completed successfully or if there
+//! was an error.
+//!
+//! \return This function returns the following values:
+//! - USBHCD_LPM_AVAIL - The transition to L1 state is scheduled to be sent.
+//! - USBHCD_LPM_PENDING - There is already an LPM request pending.
+//
+//*****************************************************************************
+uint32_t
+USBHMSCLPMSleep(tUSBHMSCInstance *psMSCInstance)
+{
+ //
+ // Call the host controller function to send the sleep command.
+ //
+ return(USBHCDLPMSleep(psMSCInstance->psDevice));
+}
+
+//*****************************************************************************
+//
+//! This function returns the current status of an LPM request.
+//!
+//! \param psMSCInstance is the host mass storage class instance that was
+//! returned from the call to USBHMSCDriveOpen().
+//!
+//! This function returns the current status of LPM requests for a given
+//! device. This is called to determine if a previous request completed
+//! successfully or if there was an error.
+//!
+//! \return This function returns the following values:
+//! - \b USBHCD_LPM_AVAIL - There are no pending LPM requests on this specific
+//! device or the last request completed successfully.
+//! - \b USBHCD_LPM_ERROR - The last LPM request for this device did not
+//! complete successfully.
+//! - \b USBHCD_LPM_PENDING - The last LPM request has not completed.
+//
+//*****************************************************************************
+uint32_t
+USBHMSCLPMStatus(tUSBHMSCInstance *psMSCInstance)
+{
+ //
+ // Call the host controller function to get the current LPM status.
+ //
+ return(USBHCDLPMStatus(psMSCInstance->psDevice));
+}
+
+//*****************************************************************************
+//
+// Close the Doxygen group.
+//! @}
+//
+//*****************************************************************************
diff --git a/usblib/host/usbhmsc.h b/usblib/host/usbhmsc.h
new file mode 100644
index 0000000..f163b71
--- /dev/null
+++ b/usblib/host/usbhmsc.h
@@ -0,0 +1,99 @@
+//*****************************************************************************
+//
+// usbhmsc.h - Definitions for the USB MSC host driver.
+//
+// Copyright (c) 2008-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 Tiva USB Library.
+//
+//*****************************************************************************
+
+#ifndef __USBHMSC_H__
+#define __USBHMSC_H__
+
+//*****************************************************************************
+//
+// If building with a C++ compiler, make all of the definitions in this header
+// have a C binding.
+//
+//*****************************************************************************
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+//*****************************************************************************
+//
+//! \addtogroup usblib_host_class
+//! @{
+//
+//*****************************************************************************
+
+typedef struct tUSBHMSCInstance tUSBHMSCInstance;
+
+//*****************************************************************************
+//
+// These defines are the the events that will be passed in the \e ui32Event
+// parameter of the callback from the driver.
+//
+//*****************************************************************************
+#define MSC_EVENT_OPEN 1
+#define MSC_EVENT_CLOSE 2
+
+//*****************************************************************************
+//
+// The prototype for the USB MSC host driver callback function.
+//
+//*****************************************************************************
+typedef void (*tUSBHMSCCallback)(tUSBHMSCInstance *psMSCInstance,
+ uint32_t ui32Event,
+ void *pvEventData);
+
+//*****************************************************************************
+//
+// Prototypes for the USB MSC host driver APIs.
+//
+//*****************************************************************************
+extern tUSBHMSCInstance * USBHMSCDriveOpen(uint32_t ui32Drive,
+ tUSBHMSCCallback pfnCallback);
+extern void USBHMSCDriveClose(tUSBHMSCInstance *psMSCInstance);
+extern int32_t USBHMSCDriveReady(tUSBHMSCInstance *psMSCInstance);
+extern int32_t USBHMSCBlockRead(tUSBHMSCInstance *psMSCInstance,
+ uint32_t ui32LBA, uint8_t *pui8Data,
+ uint32_t ui32NumBlocks);
+extern int32_t USBHMSCBlockWrite(tUSBHMSCInstance *psMSCInstance,
+ uint32_t ui32LBA, uint8_t *pui8Data,
+ uint32_t ui32NumBlocks);
+extern uint32_t USBHMSCLPMSleep(tUSBHMSCInstance *psMSCInstance);
+extern uint32_t USBHMSCLPMStatus(tUSBHMSCInstance *psMSCInstance);
+
+//*****************************************************************************
+//
+//! @}
+//
+//*****************************************************************************
+
+//*****************************************************************************
+//
+// Mark the end of the C bindings section for C++ compilers.
+//
+//*****************************************************************************
+#ifdef __cplusplus
+}
+#endif
+
+#endif // __USBHMSC_H__
diff --git a/usblib/host/usbhost.h b/usblib/host/usbhost.h
new file mode 100644
index 0000000..1d4c455
--- /dev/null
+++ b/usblib/host/usbhost.h
@@ -0,0 +1,295 @@
+//*****************************************************************************
+//
+// usbhost.h - Host specific definitions for the USB host library.
+//
+// Copyright (c) 2008-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 Tiva USB Library.
+//
+//*****************************************************************************
+
+#ifndef __USBHOST_H__
+#define __USBHOST_H__
+
+//*****************************************************************************
+//
+// If building with a C++ compiler, make all of the definitions in this header
+// have a C binding.
+//
+//*****************************************************************************
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+//*****************************************************************************
+//
+//! \addtogroup usblib_hcd
+//! @{
+//
+//*****************************************************************************
+
+//*****************************************************************************
+//
+// This is the type used to identify what the pipe is currently in use for.
+//
+//*****************************************************************************
+#define USBHCD_PIPE_UNUSED 0x00100000
+#define USBHCD_PIPE_CONTROL 0x00130000
+#define USBHCD_PIPE_BULK_OUT 0x00210000
+#define USBHCD_PIPE_BULK_IN 0x00220000
+#define USBHCD_PIPE_INTR_OUT 0x00410000
+#define USBHCD_PIPE_INTR_IN 0x00420000
+#define USBHCD_PIPE_ISOC_OUT 0x00810000
+#define USBHCD_PIPE_ISOC_IN 0x00820000
+#define USBHCD_PIPE_ISOC_OUT_DMA 0x01810000
+#define USBHCD_PIPE_ISOC_IN_DMA 0x01820000
+#define USBHCD_PIPE_BULK_OUT_DMA 0x01210000
+#define USBHCD_PIPE_BULK_IN_DMA 0x01220000
+
+//*****************************************************************************
+//
+// These are the defines that are used with USBHCDPowerConfigInit().
+//
+//*****************************************************************************
+#define USBHCD_FAULT_LOW 0x00000010
+#define USBHCD_FAULT_HIGH 0x00000030
+#define USBHCD_FAULT_VBUS_NONE 0x00000000
+#define USBHCD_FAULT_VBUS_TRI 0x00000140
+#define USBHCD_FAULT_VBUS_DIS 0x00000400
+#define USBHCD_VBUS_MANUAL 0x00000004
+#define USBHCD_VBUS_AUTO_LOW 0x00000002
+#define USBHCD_VBUS_AUTO_HIGH 0x00000003
+#define USBHCD_VBUS_FILTER 0x00010000
+
+//*****************************************************************************
+//
+// These are the defines that are used with USBHCDLPMStatus().
+//
+//*****************************************************************************
+#define USBHCD_LPM_AVAIL 0x00000000
+#define USBHCD_LPM_ERROR 0x00000001
+#define USBHCD_LPM_PENDING 0x00000002
+
+//*****************************************************************************
+//
+//! This macro is used to declare an instance of an Event driver for the USB
+//! library.
+//!
+//! \param VarName is the name of the variable.
+//! \param pfnOpen is the callback for the Open call to this driver. This
+//! value is currently reserved and should be set to 0.
+//! \param pfnClose is the callback for the Close call to this driver. This
+//! value is currently reserved and should be set to 0.
+//! \param pfnEvent is the callback that will be called for various USB events.
+//!
+//! The first parameter is the actual name of the variable that will
+//! be declared by this macro. The second and third parameter are reserved
+//! for future functionality and are unused and should be set to zero. The
+//! last parameter is the actual callback function and is specified as
+//! a function pointer of the type:
+//!
+//! \verbatim
+//! void (*pfnEvent)(void *pvData);
+//! \endverbatim
+//!
+//! When the \e pfnEvent function is called the void pointer that is passed in
+//! as a parameter should be cast to a pointer to a structure of type
+//! tEventInfo. This will contain the event that caused the pfnEvent function
+//! to be called.
+//
+//*****************************************************************************
+#define DECLARE_EVENT_DRIVER(VarName, pfnOpen, pfnClose, pfnEvent) \
+void IntFn(void *pvData); \
+const tUSBHostClassDriver VarName = \
+{ \
+ USB_CLASS_EVENTS, \
+ 0, \
+ 0, \
+ pfnEvent \
+}
+
+//*****************************************************************************
+//
+// This is the type definition a callback for events on USB Pipes allocated
+// by USBHCDPipeAlloc().
+//
+// \param ui32Pipe is well the pipe
+// \param ui32Event is well the event
+//
+// This prototype is used by any Pipe callbacks that are used in the host
+// class drivers. These functions typically handle data events like
+// USB_EVENT_RX_AVAILABLE or USB_EVENT_TX_COMPLETE but can be sent other events
+// depending on the USB host class in use. See the documentation for the
+// individual classes for the valid events for that class.
+//
+// \return None.
+//
+//*****************************************************************************
+typedef void (* tHCDPipeCallback)(uint32_t ui32Pipe, uint32_t ui32Event);
+
+//*****************************************************************************
+//
+// Predeclare the private tUSBHostDevice structure.
+//
+//*****************************************************************************
+typedef struct tUSBHostDevice tUSBHostDevice;
+
+//*****************************************************************************
+//
+//! This structure defines a USB host class driver interface, it is parsed to
+//! find a USB class driver once a USB device is enumerated.
+//
+//*****************************************************************************
+typedef struct
+{
+ //
+ //! The interface class that this device class driver supports.
+ //
+ uint32_t ui32InterfaceClass;
+
+ //
+ //! The function is called when this class of device has been detected.
+ //
+ void *(*pfnOpen)(tUSBHostDevice *psDevice);
+
+ //
+ //! The function is called when the device, originally opened with a call
+ //! to the pfnOpen function, is disconnected.
+ //
+ void (*pfnClose)(void *pvInstance);
+
+ //
+ //! This is the optional interrupt handler that will be called when an
+ //! endpoint associated with this device instance generates an interrupt.
+ //
+ void (*pfnIntHandler)(void *pvInstance);
+}
+tUSBHostClassDriver;
+
+//*****************************************************************************
+//
+// Close the Doxygen group.
+//! @}
+//
+//*****************************************************************************
+
+//*****************************************************************************
+//
+// If the g_USBEventDriver is included in the host controller driver list then
+// this function must be provided by the application.
+//
+//*****************************************************************************
+extern void USBHCDEvents(void *pvData);
+
+//*****************************************************************************
+//
+// Prototypes for the USB Host controller APIs.
+//
+//*****************************************************************************
+extern void USBHCDMain(void);
+extern int32_t USBHCDEventEnable(uint32_t ui32Index, void *pvEventDriver,
+ uint32_t ui32Event);
+extern int32_t USBHCDEventDisable(uint32_t ui32Index, void *pvEventDriver,
+ uint32_t ui32Event);
+extern void USBHCDInit(uint32_t ui32Index, void *pvData,
+ uint32_t ui32Size);
+extern void USBHCDPowerConfigInit(uint32_t ui32Index,
+ uint32_t ui32Flags);
+extern uint32_t USBHCDPowerConfigGet(uint32_t ui32Index);
+extern uint32_t USBHCDPowerConfigSet(uint32_t ui32Index,
+ uint32_t ui32Config);
+extern uint32_t USBHCDPowerAutomatic(uint32_t ui32Index);
+extern void USBHCDRegisterDrivers(uint32_t ui32Index,
+ const tUSBHostClassDriver * const *ppsHClassDrvrs,
+ uint32_t ui32NumDrivers);
+extern void USBHCDTerm(uint32_t ui32Index);
+extern void USBHCDSetConfig(uint32_t ui32Index, uint32_t ui32Device,
+ uint32_t ui32Configuration);
+extern void USBHCDSetInterface(uint32_t ui32Index, uint32_t ui32Device,
+ uint32_t ui32Interface,
+ uint32_t ui32AltSetting);
+extern void USBHCDSuspend(uint32_t ui32Index);
+extern void USBHCDResume(uint32_t ui32Index);
+extern void USBHCDReset(uint32_t ui32Index);
+extern void USBHCDPipeFree(uint32_t ui32Pipe);
+extern uint32_t USBHCDPipeAlloc(uint32_t ui32Index,
+ uint32_t ui32EndpointType,
+ tUSBHostDevice *psDevice,
+ tHCDPipeCallback pfnCallback);
+extern uint32_t USBHCDPipeAllocSize(uint32_t ui32Index,
+ uint32_t ui32EndpointType,
+ tUSBHostDevice *psDevice,
+ uint32_t ui32FIFOSize,
+ tHCDPipeCallback pfnCallback);
+extern uint32_t USBHCDPipeConfig(uint32_t ui32Pipe, uint32_t ui32MaxPayload,
+ uint32_t ui32Interval,
+ uint32_t ui32TargetEndpoint);
+extern uint32_t USBHCDPipeStatus(uint32_t ui32Pipe);
+extern uint32_t USBHCDPipeWrite(uint32_t ui32Pipe, uint8_t *pui8Data,
+ uint32_t ui32Size);
+extern uint32_t USBHCDPipeRead(uint32_t ui32Pipe, uint8_t *pui8Data,
+ uint32_t ui32Size);
+extern uint32_t USBHCDPipeSchedule(uint32_t ui32Pipe, uint8_t *pui8Data,
+ uint32_t ui32Size);
+extern uint32_t USBHCDPipeTransferSizeGet(uint32_t ui32Pipe);
+extern void USBHCDPipeDataAck(uint32_t ui32Pipe);
+extern uint32_t USBHCDPipeReadNonBlocking(uint32_t ui32Pipe, uint8_t *pui8Data,
+ uint32_t ui32Size);
+extern uint32_t USBHCDStringDescriptorGet(tUSBHostDevice *psDevice,
+ uint8_t *pui8Buffer,
+ uint32_t ui32Size,
+ uint32_t ui32LangID,
+ uint32_t ui32StringIndex);
+extern uint32_t USBHCDControlTransfer(uint32_t ui32Index,
+ tUSBRequest *psSetupPacket,
+ tUSBHostDevice *psDevice,
+ uint8_t *pui8Data, uint32_t ui32Size,
+ uint32_t ui32MaxPacketSize);
+extern void USB0HostIntHandler(void);
+
+extern uint8_t USBHCDDevHubPort(uint32_t ui32Instance);
+extern uint8_t USBHCDDevAddress(uint32_t ui32Instance);
+extern uint8_t USBHCDDevClass(uint32_t ui32Instance, uint32_t ui32Interface);
+extern uint8_t USBHCDDevSubClass(uint32_t ui32Instance,
+ uint32_t ui32Interface);
+extern uint8_t USBHCDDevProtocol(uint32_t ui32Instance,
+ uint32_t ui32Interface);
+extern bool USBHCDFeatureSet(uint32_t ui32Index, uint32_t ui32Feature,
+ void *pvFeature);
+extern uint32_t USBHCDLPMSleep(tUSBHostDevice *psDevice);
+extern void USBHCDLPMResume(uint32_t ui32Index);
+
+//*****************************************************************************
+//
+// The host class drivers supported by the USB library.
+//
+//*****************************************************************************
+extern const tUSBHostClassDriver g_sUSBHostMSCClassDriver;
+extern const tUSBHostClassDriver g_sUSBHIDClassDriver;
+extern const tUSBHostClassDriver g_sUSBHostAudioClassDriver;
+
+//*****************************************************************************
+//
+// Mark the end of the C bindings section for C++ compilers.
+//
+//*****************************************************************************
+#ifdef __cplusplus
+}
+#endif
+
+#endif // __USBHOST_H__
diff --git a/usblib/host/usbhostenum.c b/usblib/host/usbhostenum.c
new file mode 100644
index 0000000..69b8c39
--- /dev/null
+++ b/usblib/host/usbhostenum.c
@@ -0,0 +1,6284 @@
+//*****************************************************************************
+//
+// usbhostenum.c - Device enumeration code for the USB host library.
+//
+// Copyright (c) 2008-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 Tiva USB Library.
+//
+//*****************************************************************************
+
+#include <stdbool.h>
+#include <stdint.h>
+#include "inc/hw_ints.h"
+#include "inc/hw_memmap.h"
+#include "inc/hw_sysctl.h"
+#include "inc/hw_types.h"
+#include "driverlib/rom.h"
+#include "driverlib/rom_map.h"
+#include "driverlib/debug.h"
+#include "driverlib/interrupt.h"
+#include "driverlib/sysctl.h"
+#include "driverlib/usb.h"
+#include "driverlib/rtos_bindings.h"
+#include "usblib/usblib.h"
+#include "usblib/usblibpriv.h"
+#include "usblib/usbulpi.h"
+#include "usblib/host/usbhost.h"
+#include "usblib/host/usbhostpriv.h"
+#include "usblib/host/usbhhub.h"
+
+#ifdef INCLUDE_DEBUG_OUTPUT
+#include "utils/uartstdio.h"
+#define DEBUG_OUTPUT UARTprintf
+#else
+#define DEBUG_OUTPUT while(0)((int32_t (*)(char *, ...))0)
+#endif
+
+//*****************************************************************************
+//
+//! \addtogroup usblib_hcd
+//! @{
+//
+//*****************************************************************************
+
+//*****************************************************************************
+//
+// External prototypes.
+//
+//*****************************************************************************
+extern tUSBMode g_iUSBMode;
+
+extern void OTGDeviceDisconnect(uint32_t ui32Index);
+
+//*****************************************************************************
+//
+// Internal function prototypes.
+//
+//*****************************************************************************
+static void USBHCDEP0StateTx(void);
+static void USBHCDEnumHandler(void);
+static void USBHCDClearFeature(uint32_t ui32DevAddress, uint32_t ui32Endpoint,
+ uint32_t ui32Feature);
+
+//*****************************************************************************
+//
+// Automatic power enable.
+//
+//*****************************************************************************
+#define USB_HOST_PWREN_AUTO 0x00000002
+
+//*****************************************************************************
+//
+// Flags used to signal between the interrupt handler and USBHCDMain().
+//
+//*****************************************************************************
+#define INT_EVENT_VBUS_ERR 0x01
+#define INT_EVENT_CONNECT 0x02
+#define INT_EVENT_DISCONNECT 0x04
+#define INT_EVENT_POWER_FAULT 0x08
+#define INT_EVENT_SOF 0x10
+#define INT_EVENT_ENUM 0x20
+#define INT_EVENT_LPM_PEND 0x40
+#define INT_EVENT_LPM 0x80
+
+//*****************************************************************************
+//
+// Flags used with the tUSBHostDevice.ui32Flags structure member.
+//
+//*****************************************************************************
+#define USBHDEV_FLAG_NOTIFYINT 0x00000001
+#define USBHDEV_FLAG_LPMPEND 0x00000002
+#define USBHDEV_FLAG_LPMERROR 0x00000004
+#define USBHDEV_FLAG_ALLOCATED 0x80000000
+
+//*****************************************************************************
+//
+// This holds the current power configuration that is used when USBHCDInit()
+// is called.
+//
+//*****************************************************************************
+static uint32_t g_ui32PowerConfig = USBHCD_VBUS_AUTO_HIGH;
+
+//*****************************************************************************
+//
+// The states for endpoint 0 during enumeration.
+//
+//*****************************************************************************
+typedef enum
+{
+ //
+ // The USB device is waiting on a request from the host controller on
+ // endpoint 0.
+ //
+ eEP0StateIdle,
+
+ //
+ // Setup packet is expecting data IN.
+ //
+ eEP0StateSetupIN,
+
+ //
+ // Setup packet is sending data OUT.
+ //
+ eEP0StateSetupOUT,
+
+ //
+ // The USB device is receiving data from the device due to an SETUP IN
+ // request.
+ //
+ eEP0StateRx,
+
+ //
+ // The USB device has completed the IN or OUT request and is now waiting
+ // for the host to acknowledge the end of the IN/OUT transaction. This
+ // is the status phase for a USB control transaction.
+ //
+ eEP0StateStatus,
+
+ //
+ // This state is for when a response only has a status phase and no
+ // data phase.
+ //
+ eEP0StateStatusIN,
+
+ //
+ // This endpoint has signaled a stall condition and is waiting for the
+ // stall to be acknowledged by the host controller.
+ //
+ eEP0StateStall,
+
+ //
+ // An error has occurred on endpoint 0.
+ //
+ eEP0StateError
+}
+tEP0State;
+
+//*****************************************************************************
+//
+// This structure holds the full state for the device enumeration.
+//
+//*****************************************************************************
+typedef struct
+{
+ //
+ // This is the pointer to the current data being sent out or received
+ // on endpoint 0.
+ //
+ uint8_t *pui8Data;
+
+ //
+ // This is the number of bytes that remain to be sent from or received
+ // into the g_DeviceState.pEP0Data data buffer.
+ //
+ volatile uint32_t ui32BytesRemaining;
+
+ //
+ // The amount of data being sent/received due to a request.
+ //
+ uint32_t ui32DataSize;
+
+ //
+ // This is the current device address in use by endpoint 0.
+ //
+ uint32_t ui32DevAddress;
+
+ //
+ // The maximum packet size for the device responding to the setup packet.
+ //
+ uint32_t ui32MaxPacketSize;
+
+ //
+ // The host controller's state.
+ //
+ tEP0State iState;
+}
+tHostState;
+
+//*****************************************************************************
+//
+// This variable holds the current state of endpoint 0.
+//
+//*****************************************************************************
+static volatile tHostState g_sUSBHEP0State =
+{
+ 0, // pui8Data
+ 0, // ui32BytesRemaining
+ 0, // ui32DataSize
+ 0, // ui32DevAddress
+ 0, // ui32MaxPacketSize
+ eEP0StateIdle // iState
+};
+
+//*****************************************************************************
+//
+// The global delay time for use by SysCtlDelay() function. This is
+// initialized to an appropriate value for a 50MHz clock. The correct value
+// will be set in USBHCDInit().
+//
+//*****************************************************************************
+static uint32_t g_ui32Tickms = 0;
+static volatile uint32_t g_ui32CurrentTick = 0;
+
+//*****************************************************************************
+//
+// This is 480000000/60000000 or a PLL Divide of 8.
+//
+//*****************************************************************************
+static uint32_t g_ui32PLLDiv = 8;
+
+//*****************************************************************************
+//
+// Holds the ULPI configuration.
+//
+//*****************************************************************************
+static uint32_t g_ui32ULPISupport;
+
+//*****************************************************************************
+//
+// The current active drivers.
+//
+//*****************************************************************************
+static int32_t g_pi32USBHActiveDriver[MAX_USB_DEVICES + 1];
+static void *g_ppvDriverInstance[MAX_USB_DEVICES + 1];
+
+//*****************************************************************************
+//
+// This is the structure used to hold the information for a given USB pipe
+// that is attached to a device.
+//
+//*****************************************************************************
+typedef struct
+{
+ //
+ // The current address for this pipe.
+ //
+ tUSBHostDevice *psDevice;
+
+ //
+ // The current address for this pipe.
+ //
+ uint8_t ui8EPNumber;
+
+ //
+ // The DMA channel assigned to this endpoint.
+ //
+ uint8_t ui8DMAChannel;
+
+ //
+ // The current type for this pipe.
+ //
+ uint32_t ui32Type;
+
+ //
+ // The millisecond interval for this pipe.
+ //
+ uint32_t ui32Interval;
+
+ //
+ // The next tick value to trigger and event on this pipe.
+ //
+ uint32_t ui32NextEventTick;
+
+ //
+ // The current call back for this pipe.
+ //
+ tHCDPipeCallback pfnCallback;
+
+ //
+ // The pointer to which IN data must be copied.
+ //
+ uint8_t *pui8ReadPtr;
+
+ //
+ // The size of the buffer pointed to by pui8ReadPtr.
+ //
+ uint32_t ui32ReadSize;
+
+ //
+ // The number of bytes read, which can be less than ui32ReadSize.
+ //
+ uint32_t ui32DataRead;
+
+ //
+ // The state of a given USB pipe.
+ //
+ volatile enum
+ {
+ ePipeReading,
+ ePipeReadDMA,
+ ePipeReadDMAWait,
+ ePipeReadSingle,
+ ePipeDataReady,
+ ePipeDataSent,
+ ePipeWriting,
+ ePipeWriteDMA,
+ ePipeWriteDMASend,
+ ePipeWriteDMAWait,
+ ePipeWriteSingle,
+ ePipeStalled,
+ ePipeError,
+ ePipeIdle,
+ ePipeDisabled
+ }
+ iState;
+
+ //
+ // The actual FIFO offset allocated to this endpoint.
+ //
+ uint16_t ui16FIFOAddr;
+
+ //
+ // The size of the FIFO entry based on the size parameter. These are
+ // equivalent to the USB_FIFO_SZ_* values in usb.h.
+ //
+ uint8_t ui8FIFOSize;
+
+ //
+ // The bit offset in the allocation structure.
+ //
+ uint8_t ui8FIFOBitOffset;
+}
+tUSBHCDPipe;
+
+//*****************************************************************************
+//
+// The internal state of the device.
+//
+//*****************************************************************************
+typedef enum
+{
+ eHCDDevDisconnected,
+ eHCDDevConnected,
+ eHCDDevConnectedHub,
+ eHCDDevRequest,
+ eHCDDevReset,
+ eHCDDevAddressed,
+ eHCDDevConfigured,
+ eHCDDevGetStrings,
+ eHCDDevError,
+ eHCDVBUSError,
+ eHCDPowerFault,
+ eHCDIdle
+}
+tUSBHDeviceState;
+
+static void ProcessUSBDeviceStateMachine(tUSBHDeviceState iOldState,
+ uint32_t ui32DevIndex);
+
+//*****************************************************************************
+//
+// This is a fixed number as it relates to the maximum number of USB pipes
+// available on any USB controller. The actual number on a given device may
+// be less than this number.
+//
+//*****************************************************************************
+#define MAX_NUM_PIPES 15
+
+//*****************************************************************************
+//
+// This is a fixed number as it relates to the number of USB pipes available
+// in the USB controller.
+//
+//*****************************************************************************
+#define MAX_NUM_DMA_CHANNELS 6
+
+//*****************************************************************************
+//
+// Marker for an unused DMA channel slot.
+//
+//*****************************************************************************
+#define USBHCD_DMA_UNUSED 0xff
+
+//*****************************************************************************
+//
+// These definitions are used to manipulate the values returned as allocated
+// USB pipes.
+//
+//*****************************************************************************
+#define EP_PIPE_TYPE_LOW_SPEED 0x02000000
+#define EP_PIPE_USE_UDMA 0x01000000
+#define EP_PIPE_TYPE_ISOC 0x00800000
+#define EP_PIPE_TYPE_INTR 0x00400000
+#define EP_PIPE_TYPE_BULK 0x00200000
+#define EP_PIPE_TYPE_CONTROL 0x00100000
+#define EP_PIPE_TYPE_IN 0x00020000
+#define EP_PIPE_TYPE_OUT 0x00010000
+#define EP_PIPE_IDX_M 0x0000ffff
+
+//*****************************************************************************
+//
+// This creates a USB pipe handle from an index.
+//
+//*****************************************************************************
+#define OUT_PIPE_HANDLE(ui32Idx) \
+ (g_sUSBHCD.psUSBOUTPipes[ui32Idx].ui32Type | \
+ ui32Idx)
+#define IN_PIPE_HANDLE(ui32Idx) (g_sUSBHCD.psUSBINPipes[ui32Idx].ui32Type | \
+ ui32Idx)
+
+//*****************************************************************************
+//
+// Converts from an endpoint specifier to the offset of the endpoint's
+// control/status registers.
+//
+//*****************************************************************************
+#define EP_OFFSET(Endpoint) (Endpoint - 0x10)
+
+//*****************************************************************************
+//
+// This structure holds the state information for a given host controller.
+//
+//*****************************************************************************
+typedef struct
+{
+ uint32_t ui32USBBase;
+
+ tUSBHCDPipe sUSBControlPipe;
+ tUSBHCDPipe psUSBOUTPipes[MAX_NUM_PIPES];
+ tUSBHCDPipe psUSBINPipes[MAX_NUM_PIPES];
+
+ //
+ // Each devices state. We support a total of (MAX_USB_DEVICES + 1) devices
+ // to allow for the use if MAX_USB_DEVICES through a single hub (which is
+ // itself a device).
+ //
+ tUSBHostDevice psUSBDevice[MAX_USB_DEVICES + 1];
+
+ //
+ // Holds the current state of the device.
+ //
+ volatile tUSBHDeviceState piDeviceState[MAX_USB_DEVICES + 1];
+
+ //
+ // Pointer to the memory pool for this controller.
+ //
+ void *pvPool;
+
+ //
+ // The pool size for this controller.
+ //
+ uint32_t ui32PoolSize;
+
+ //
+ // The number of endpoint pairs supported by the controller.
+ //
+ uint32_t ui32NumEndpoints;
+
+ //
+ // The class drivers for this controller.
+ //
+ const tUSBHostClassDriver * const *ppsClassDrivers;
+
+ //
+ // The number of class drivers.
+ //
+ uint32_t ui32NumClassDrivers;
+
+ //
+ // This is the index in the driver list of the event driver.
+ //
+ int32_t i32EventDriver;
+
+ //
+ // These are the generic event information used by the event driver.
+ //
+ uint32_t ui32EventEnables;
+
+ uint32_t ui32Class;
+
+ //
+ // The DMA instance information for this class.
+ //
+ tUSBDMAInstance *psDMAInstance;
+
+ //
+ // The interrupt number for this instance.
+ //
+ uint32_t ui32IntNum;
+
+ //
+ // The pending interrupt events that are processed in USBHCDMain().
+ //
+ uint32_t ui32IntEvents;
+
+ //
+ // Features.
+ //
+ uint32_t ui32Features;
+
+ //
+ // The host initiated resume duration in us.
+ //
+ uint32_t ui32LPMHIRD;
+}
+tUSBHCD;
+
+//*****************************************************************************
+//
+// The global to hold all of the state information for a given host controller.
+//
+//*****************************************************************************
+static tUSBHCD g_sUSBHCD;
+
+//*****************************************************************************
+//
+// Allocates the memory needed to support configuration descriptors for
+// devices.
+//
+//*****************************************************************************
+uint32_t
+ConfigDescAlloc(tUSBHostDevice *psDevice, uint32_t ui32Size)
+{
+ uint32_t ui32Idx, ui32BlockSize, ui32PoolSize;
+ uint8_t *pui8Pool;
+
+ if(g_sUSBHCD.psUSBDevice[0].psConfigDescriptor == 0)
+ {
+ //
+ // 32 bit align the allocation.
+ //
+ ui32Size = (ui32Size + 3) & ~3;
+
+ if(g_sUSBHCD.ui32PoolSize < ui32Size)
+ {
+ return(0);
+ }
+
+ //
+ // Allocate the root connection to the device.
+ //
+ g_sUSBHCD.psUSBDevice[0].psConfigDescriptor = g_sUSBHCD.pvPool;
+ g_sUSBHCD.psUSBDevice[0].ui32ConfigDescriptorSize = ui32Size;
+
+ //
+ // Allocate the hub memory pools (these can end up null).
+ //
+ pui8Pool = (uint8_t *)g_sUSBHCD.pvPool + ui32Size;
+ ui32PoolSize = g_sUSBHCD.ui32PoolSize - ui32Size;
+
+ //
+ // Divide the pool up into blocks, one for each supported port. We make
+ // sure that each block is a multiple of 4 bytes.
+ //
+ ui32BlockSize = (ui32PoolSize / MAX_USB_DEVICES) & ~3;
+ for(ui32Idx = 1; ui32Idx < MAX_USB_DEVICES; ui32Idx++)
+ {
+ g_sUSBHCD.psUSBDevice[ui32Idx].psConfigDescriptor =
+ (tConfigDescriptor *)(pui8Pool +
+ (ui32Idx * ui32BlockSize));
+ g_sUSBHCD.psUSBDevice[ui32Idx].ui32ConfigDescriptorSize =
+ ui32BlockSize;
+ }
+ }
+ return(ui32Size);
+}
+
+//*****************************************************************************
+//
+// Frees the memory needed to support configuration descriptors for
+// devices.
+//
+//*****************************************************************************
+void
+ConfigDescFree(tUSBHostDevice *psDevice)
+{
+ uint32_t ui32Idx;
+
+ //
+ // If this is the root device then deallocate.
+ //
+ if(&g_sUSBHCD.psUSBDevice[0] == psDevice)
+ {
+ for(ui32Idx = 0; ui32Idx < MAX_USB_DEVICES; ui32Idx++)
+ {
+ g_sUSBHCD.psUSBDevice[ui32Idx].ui32Flags &=
+ ~USBHDEV_FLAG_ALLOCATED;
+ g_sUSBHCD.psUSBDevice[ui32Idx].psConfigDescriptor = 0;
+ g_sUSBHCD.psUSBDevice[ui32Idx].ui32ConfigDescriptorSize = 0;
+ }
+ }
+}
+
+//*****************************************************************************
+//
+// Return the device index from a ui32Instance value passed from an external
+// source.
+//
+//*****************************************************************************
+static uint8_t
+HCDInstanceToDevIndex(uint32_t ui32Instance)
+{
+ uint32_t ui32DevIndex;
+
+ //
+ // Get the device instance from the instance value.
+ //
+ ui32DevIndex = (ui32Instance & 0xff);
+
+ //
+ // If the above math went negative or is too large just return 0xff.
+ //
+ if(ui32DevIndex > MAX_USB_DEVICES)
+ {
+ ui32DevIndex = 0xff;
+ }
+
+ return(ui32DevIndex);
+}
+
+//=============================================================================
+//
+// This is the internal function that will map an event to a valid event flag.
+//
+// \param ui32Event specifies which event flag to retrieve.
+//
+// \return The event flag or 0 if there is no support event flag for the
+// event specified by the \e ui32Event parameter.
+//
+//=============================================================================
+static uint32_t
+GetEventFlag(uint32_t ui32Event)
+{
+ uint32_t ui32EventFlag;
+
+ ui32EventFlag = 0;
+
+ //
+ // Search for a valid event flag for the requested event.
+ //
+ switch(ui32Event)
+ {
+ case USB_EVENT_SOF:
+ {
+ ui32EventFlag |= USBHCD_EVFLAG_SOF;
+ break;
+ }
+ case USB_EVENT_CONNECTED:
+ {
+ ui32EventFlag |= USBHCD_EVFLAG_CONNECT;
+ break;
+ }
+ case USB_EVENT_DISCONNECTED:
+ {
+ ui32EventFlag |= USBHCD_EVFLAG_DISCNCT;
+ break;
+ }
+ case USB_EVENT_UNKNOWN_CONNECTED:
+ {
+ ui32EventFlag |= USBHCD_EVFLAG_UNKCNCT;
+ break;
+ }
+ case USB_EVENT_POWER_FAULT:
+ {
+ ui32EventFlag |= USBHCD_EVFLAG_PWRFAULT;
+ break;
+ }
+ case USB_EVENT_POWER_DISABLE:
+ {
+ ui32EventFlag |= USBHCD_EVFLAG_PWRDIS;
+ break;
+ }
+ case USB_EVENT_POWER_ENABLE:
+ {
+ ui32EventFlag |= USBHCD_EVFLAG_PWREN;
+ break;
+ }
+ default:
+ {
+ break;
+ }
+ }
+ return(ui32EventFlag);
+}
+
+//=============================================================================
+//
+//! This function is called to enable a specific USB HCD event notification.
+//!
+//! \param ui32Index specifies which USB controller to use.
+//! \param pvEventDriver is the event driver structure that was passed into
+//! the USBHCDRegisterDrivers() function as part of the array of
+//! tUSBHostClassDriver structures.
+//! \param ui32Event is the event to enable.
+//!
+//! This function is called to enable event callbacks for a specific USB HCD
+//! event. The requested event is passed in the \e ui32Event parameter. Not
+//! all events can be enables so the function will return zero if the event
+//! provided cannot be enabled. The \e pvEventDriver is a pointer to the
+//! event driver structure that the caller passed into the
+//! USBHCDRegisterDrivers() function. This structure is typically declared
+//! with the DECLARE_EVENT_DRIVER() macro and included as part of the array
+//! of pointers to tUSBHostClassDriver structures that is passed to the
+//! USBHCDRegisterDrivers() function.
+//!
+//! \return This function returns a non-zero number if the event was
+//! successfully enabled and returns zero if the event cannot be enabled.
+//
+//=============================================================================
+int32_t
+USBHCDEventEnable(uint32_t ui32Index, void *pvEventDriver, uint32_t ui32Event)
+{
+ int32_t i32Ret;
+ uint32_t ui32EventFlag;
+
+ ASSERT(ui32Index == 0);
+
+ //
+ // Default the return to fail the call unless a valid event is found.
+ //
+ i32Ret = 0;
+
+ //
+ // Get the event flag for this event.
+ //
+ ui32EventFlag = GetEventFlag(ui32Event);
+
+ //
+ // Check if there was an event flag for the corresponding event.
+ //
+ if(ui32EventFlag)
+ {
+ //
+ // Set the enable for this event.
+ //
+ g_sUSBHCD.ui32EventEnables |= ui32EventFlag;
+
+ //
+ // Indicate that the event was valid and is now enabled.
+ //
+ i32Ret = 1;
+ }
+
+ return(i32Ret);
+}
+
+//=============================================================================
+//
+//! This function is called to disable a specific USB HCD event notification.
+//!
+//! \param ui32Index specifies which USB controller to use.
+//! \param pvEventDriver is the event driver structure that was passed into
+//! the USBHCDRegisterDrivers() function as part of the array of
+//! tUSBHostClassDriver structures.
+//! \param ui32Event is the event to disable.
+//!
+//! This function is called to disable event callbacks for a specific USB HCD
+//! event. The requested event is passed in the \e ui32Event parameter. Not
+//! all events can be enables so the function will return zero if the event
+//! provided cannot be enabled. The \e pvEventDriver is a pointer to the
+//! event driver structure that the caller passed into the
+//! USBHCDRegisterDrivers() function. This structure is typically declared
+//! with the DECLARE_EVENT_DRIVER() macro and included as part of the array
+//! of pointers to tUSBHostClassDriver structures that is passed to the
+//! USBHCDRegisterDrivers() function.
+//!
+//! \return This function returns a non-zero number if the event was
+//! successfully disabled and returns zero if the event cannot be disabled.
+//
+//=============================================================================
+int32_t
+USBHCDEventDisable(uint32_t ui32Index, void *pvEventDriver, uint32_t ui32Event)
+{
+ int32_t i32Ret;
+ uint32_t ui32EventFlag;
+
+ ASSERT(ui32Index == 0);
+
+ //
+ // Default the return to fail the call unless a valid event is found.
+ //
+ i32Ret = 0;
+
+ //
+ // Get the event flag for this event.
+ //
+ ui32EventFlag = GetEventFlag(ui32Event);
+
+ //
+ // Check if there was an event flag for the corresponding event.
+ //
+ if(ui32EventFlag)
+ {
+ //
+ // Clear the enable for this event.
+ //
+ g_sUSBHCD.ui32EventEnables &= ~ui32EventFlag;
+
+ //
+ // Indicate that the event was valid and is now disabled.
+ //
+ i32Ret = 1;
+ }
+
+ return(i32Ret);
+}
+
+//*****************************************************************************
+//
+// If there is an event driver this function will send out a generic connection
+// event USB_EVENT_UNKNOWN_CONNECTED indicating that an unknown connection
+// event has occurred.
+//
+//*****************************************************************************
+static void
+SendUnknownConnect(uint32_t ui32Index, uint32_t ui32Class)
+{
+ tEventInfo sEvent;
+
+ //
+ // If there is an event driver registered and it has a event handler and
+ // the USBHCD_EVFLAG_UNKCNCT is enabled then call the function.
+ //
+ sEvent.ui32Event = USB_EVENT_UNKNOWN_CONNECTED;
+ sEvent.ui32Instance = ui32Class;
+ InternalUSBHCDSendEvent(0, &sEvent, USBHCD_EVFLAG_UNKCNCT);
+}
+
+//*****************************************************************************
+//
+// Internal memory allocation space is two 32-bit values where each
+// bit represents a 64 byte block in the FIFO. This requires 64 bits for
+// the 4096 bytes of FIFO available.
+//
+//*****************************************************************************
+static uint32_t g_pui32Alloc[2];
+
+//*****************************************************************************
+//
+// This function handles freeing FIFO memory that has been allocated using the
+// FIFOAlloc() function.
+//
+//*****************************************************************************
+static void
+FIFOFree(tUSBHCDPipe *psUSBPipe)
+{
+ uint32_t ui32Mask;
+
+ //
+ // Calculate the mask value to use to clear off the allocated blocks used
+ // by the USB pipe specified by psUSBPipe.
+ //
+ ui32Mask = (1 << (psUSBPipe->ui8FIFOSize - 2)) - 1;
+ ui32Mask = ui32Mask << psUSBPipe->ui8FIFOBitOffset;
+
+ //
+ // Determine which 32 bit word to access based on the size.
+ //
+ if(psUSBPipe->ui8FIFOSize > USB_FIFO_SZ_64)
+ {
+ //
+ // If the FIFO size is greater than 64 then use the upper 32 bits.
+ //
+ g_pui32Alloc[1] &= ~ui32Mask;
+ }
+ else
+ {
+ //
+ // If the FIFO size is less than or equal to 64 then use the lower
+ // 32 bits.
+ //
+ g_pui32Alloc[0] &= ~ui32Mask;
+ }
+}
+
+//*****************************************************************************
+//
+// This function is used to allocate FIFO memory to a given USB pipe.
+//
+// \param psUSBPipe is the USB pipe that needs FIFO memory allocated.
+// \param ui32Size is the minimum size in bytes of the FIFO to allocate.
+//
+// This function will allocate \e ui32Size bytes to the USB pipe in the
+// \e psUSBPipe parameter. The function will fill the psUSBPipe structure
+// members ui8FIFOSize and ui8FIFOAddr with values that can be used with the
+// USBFIFOConfigSet() API. This allocation uses a first fit algorithm.
+//
+// \return This function returns the size of the block allocated.
+//
+//*****************************************************************************
+static uint32_t
+FIFOAlloc(tUSBHCDPipe *psUSBPipe, uint32_t ui32Size)
+{
+ uint32_t ui32Blocks, ui32Start, ui32BlockSize, ui32Temp, ui32Index;
+ uint16_t ui16FIFOAddr;
+
+ //
+ // Save which 32 bit value to access, the upper is for blocks greater
+ // than 64 and the lower is for block 64 or less.
+ //
+ if(ui32Size > 64)
+ {
+ ui32Index = 1;
+ }
+ else
+ {
+ ui32Index = 0;
+ }
+
+ //
+ // Initial FIFO address is 0.
+ //
+ ui16FIFOAddr = 0;
+
+ //
+ // Initialize the bit pattern and bit location.
+ //
+ ui32Blocks = 1;
+ ui32Start = 0;
+
+ //
+ // The initial block size is always the minimum size of 64 bytes.
+ //
+ ui32BlockSize = 64;
+
+ //
+ // The initial size and offset are 64 and 0.
+ //
+ psUSBPipe->ui8FIFOBitOffset = 0;
+ psUSBPipe->ui8FIFOSize = 3;
+
+ //
+ // Scan through 32 bits looking for a memory block large enough to fill
+ // the request.
+ //
+ while(ui16FIFOAddr <= 32)
+ {
+ //
+ // If the pattern is zero then it is a possible match.
+ //
+ if((g_pui32Alloc[ui32Index] & ui32Blocks) == 0)
+ {
+ //
+ // If the size is large enough then save it and break out of the
+ // loop.
+ //
+ if(ui32BlockSize >= ui32Size)
+ {
+ //
+ // Mark the memory as allocated.
+ //
+ g_pui32Alloc[ui32Index] |= ui32Blocks;
+
+ break;
+ }
+
+ //
+ // Increment the size of the FIFO block.
+ //
+ psUSBPipe->ui8FIFOSize++;
+
+ //
+ // Add in a new bit to the size of the allocation.
+ //
+ ui32Blocks = ui32Blocks | (ui32Blocks << 1) ;
+
+ //
+ // Double the current size.
+ //
+ ui32BlockSize <<= 1;
+
+ }
+ else
+ {
+ //
+ // Need to start over looking because the last allocation match
+ // failed, so reset the bit offset to the current location and the
+ // size to 64 bytes.
+ //
+ psUSBPipe->ui8FIFOBitOffset = ui16FIFOAddr;
+ psUSBPipe->ui8FIFOSize = 3;
+
+ //
+ // Reset the block size to the minimum (64 bytes).
+ //
+ ui32BlockSize = 64;
+
+ //
+ // Store the current starting bit location and set the block mask
+ // to this value.
+ //
+ ui32Start = 1 << ui16FIFOAddr;
+ ui32Blocks = ui32Start;
+ }
+
+ //
+ // Increase the address of the FIFO offset.
+ //
+ ui16FIFOAddr++;
+ }
+
+ //
+ // If there was no block large enough then fail this call.
+ //
+ if(ui16FIFOAddr > 32)
+ {
+ ui32BlockSize = 0;
+ psUSBPipe->ui16FIFOAddr = 0;
+ psUSBPipe->ui8FIFOBitOffset = 0;
+ psUSBPipe->ui8FIFOSize = 0;
+ }
+ else
+ {
+ //
+ // Calculate the offset in the FIFO.
+ //
+ ui32Temp = psUSBPipe->ui8FIFOBitOffset * 64;
+
+ //
+ // Sizes greater than 64 are allocated in the second half of the FIFO
+ // memory space.
+ //
+ if(ui32Size > 64)
+ {
+ ui32Temp += 2048;
+ }
+
+ //
+ // Convert this to the value that can be set in the USB controller.
+ //
+ psUSBPipe->ui16FIFOAddr = (uint16_t)ui32Temp;
+ }
+ return(ui32BlockSize);
+}
+
+//*****************************************************************************
+//
+//! This function returns the current byte count of a USB HCD pipe.
+//!
+//! \param ui32Pipe is the allocated endpoint to modify.
+//!
+//! This call returns the current or last byte count for a transfer using the
+//! pipe specified by the \e ui32Pipe parameter. This is typically used to
+//! determine the actual byte count received when a \b USB_EVENT_RX_AVAILABLE
+//! occurs.
+//!
+//! \return If the call was successful, this function returns the number of
+//! bytes transfered by the USB pipe.
+//
+//*****************************************************************************
+uint32_t
+USBHCDPipeTransferSizeGet(uint32_t ui32Pipe)
+{
+ uint32_t ui32Index;
+
+ //
+ // Get the index number from the allocated pipe.
+ //
+ ui32Index = (ui32Pipe & EP_PIPE_IDX_M);
+
+ return(g_sUSBHCD.psUSBINPipes[ui32Index].ui32DataRead);
+}
+
+//*****************************************************************************
+//
+//! This function is used to allocate a USB HCD pipe.
+//!
+//! \param ui32Index specifies which USB controller to use.
+//! \param ui32EndpointType is the type of endpoint that this pipe will be
+//! communicating with.
+//! \param psDevice is the device instance associated with this endpoint.
+//! \param ui32Size is the size of the FIFO in bytes.
+//! \param pfnCallback is the function that will be called when events occur on
+//! this USB Pipe.
+//!
+//! Since there are a limited number of USB HCD pipes that can be used in the
+//! host controller, this function is used to temporarily or permanently
+//! acquire one of the endpoints. Unlike the USBHCDPipeAlloc() function this
+//! function allows the caller to specify the size of the FIFO allocated to
+//! this endpoint in the \e ui32Size parameter. This function also provides a
+//! method to register a callback for status changes on this endpoint. If no
+//! callbacks are desired then the \e pfnCallback function should be set to 0.
+//! The callback should be used when using the USBHCDPipeSchedule() function
+//! so that the caller is notified when the action is complete.
+//!
+//! \return This function returns a value indicating which pipe was reserved.
+//! If the value is 0 then there were no pipes currently available. This value
+//! should be passed to any USBHCDPipe APIs to indicate which pipe is being
+//! accessed.
+//
+//*****************************************************************************
+uint32_t
+USBHCDPipeAllocSize(uint32_t ui32Index, uint32_t ui32EndpointType,
+ tUSBHostDevice *psDevice, uint32_t ui32Size,
+ tHCDPipeCallback pfnCallback)
+{
+ int32_t i32Idx;
+
+ uint32_t ui32HubAddr;
+
+ ASSERT(ui32Index == 0);
+
+ //
+ // Find a USB pipe that is free.
+ //
+ for(i32Idx = 0; i32Idx < MAX_NUM_PIPES; i32Idx++)
+ {
+ //
+ // Handle OUT Pipes.
+ //
+ if(ui32EndpointType & EP_PIPE_TYPE_OUT)
+ {
+ //
+ // A zero address indicates free.
+ //
+ if(g_sUSBHCD.psUSBOUTPipes[i32Idx].psDevice == 0)
+ {
+ //
+ // Set up uDMA for the pipe.
+ //
+ if(ui32EndpointType & EP_PIPE_USE_UDMA)
+ {
+ //
+ // Allocate a DMA channel to the endpoint.
+ //
+ g_sUSBHCD.psUSBOUTPipes[i32Idx].ui8DMAChannel =
+ USBLibDMAChannelAllocate(g_sUSBHCD.psDMAInstance,
+ IndexToUSBEP(i32Idx + 1),
+ ui32Size,
+ USB_DMA_EP_TX |
+ USB_DMA_EP_HOST);
+
+ //
+ // If no DMA channel was available then just disable DMA
+ // on this pipe.
+ //
+ if(g_sUSBHCD.psUSBOUTPipes[i32Idx].ui8DMAChannel == 0)
+ {
+ ui32EndpointType &= ~EP_PIPE_USE_UDMA;
+ }
+ }
+
+ //
+ // Save the endpoint type and device address and callback
+ // function.
+ //
+ g_sUSBHCD.psUSBOUTPipes[i32Idx].ui32Type = ui32EndpointType;
+ g_sUSBHCD.psUSBOUTPipes[i32Idx].psDevice = psDevice;
+ g_sUSBHCD.psUSBOUTPipes[i32Idx].pfnCallback = pfnCallback;
+
+ //
+ // Clear out any pending status on this endpoint in case it
+ // was in use before a allowing a new device class to use it.
+ //
+ MAP_USBHostEndpointStatusClear(USB0_BASE,
+ IndexToUSBEP(i32Idx + 1),
+ USB_HOST_OUT_STATUS);
+
+ //
+ // Make sure to reset the data toggle.
+ //
+ USBEndpointDataToggleClear(USB0_BASE, IndexToUSBEP(i32Idx + 1),
+ USB_EP_HOST_OUT);
+
+ //
+ // Initialize the endpoint as idle.
+ //
+ g_sUSBHCD.psUSBOUTPipes[i32Idx].iState = ePipeIdle;
+
+ //
+ // Allocate space in the FIFO for this endpoint.
+ //
+ if(FIFOAlloc(&g_sUSBHCD.psUSBOUTPipes[i32Idx], ui32Size) != 0)
+ {
+ //
+ // Configure the FIFO.
+ //
+ MAP_USBFIFOConfigSet(USB0_BASE,
+ IndexToUSBEP(i32Idx + 1),
+ g_sUSBHCD.psUSBOUTPipes[i32Idx].ui16FIFOAddr,
+ g_sUSBHCD.psUSBOUTPipes[i32Idx].ui8FIFOSize,
+ USB_EP_HOST_OUT);
+ }
+
+ //
+ // Set the function address for this endpoint.
+ //
+ MAP_USBHostAddrSet(USB0_BASE, IndexToUSBEP(i32Idx + 1),
+ psDevice->ui32Address, USB_EP_HOST_OUT);
+
+ //
+ // Set the hub and port address for the endpoint.
+ //
+ ui32HubAddr = psDevice->ui8Hub | (psDevice->ui8HubPort << 8);
+ USBHostHubAddrSet(USB0_BASE, IndexToUSBEP(i32Idx + 1),
+ ui32HubAddr, (USB_EP_HOST_OUT |
+ psDevice->ui32Speed));
+ break;
+ }
+ }
+ //
+ // Handle IN Pipes.
+ //
+ else if(ui32EndpointType & EP_PIPE_TYPE_IN)
+ {
+ //
+ // A zero address indicates free.
+ //
+ if(g_sUSBHCD.psUSBINPipes[i32Idx].psDevice == 0)
+ {
+ //
+ // Set up uDMA for the pipe.
+ //
+ if(ui32EndpointType & EP_PIPE_USE_UDMA)
+ {
+ //
+ // Allocate a DMA channel to the endpoint.
+ //
+ g_sUSBHCD.psUSBINPipes[i32Idx].ui8DMAChannel =
+ USBLibDMAChannelAllocate(g_sUSBHCD.psDMAInstance,
+ IndexToUSBEP(i32Idx + 1),
+ ui32Size,
+ USB_DMA_EP_RX |
+ USB_DMA_EP_HOST);
+
+ //
+ // If no DMA channel was available then just disable DMA
+ // on this pipe.
+ //
+ if(g_sUSBHCD.psUSBINPipes[i32Idx].ui8DMAChannel == 0)
+ {
+ ui32EndpointType &= ~EP_PIPE_USE_UDMA;
+ }
+ }
+
+ //
+ // Save the endpoint type and device address and callback
+ // function.
+ //
+ g_sUSBHCD.psUSBINPipes[i32Idx].ui32Type = ui32EndpointType;
+ g_sUSBHCD.psUSBINPipes[i32Idx].psDevice = psDevice;
+ g_sUSBHCD.psUSBINPipes[i32Idx].pfnCallback = pfnCallback;
+
+ //
+ // Clear out any pending status on this endpoint in case it
+ // was in use before a allowing a new device class to use it.
+ //
+ MAP_USBHostEndpointStatusClear(USB0_BASE,
+ IndexToUSBEP(i32Idx + 1),
+ USB_HOST_IN_STATUS);
+
+ //
+ // Make sure to reset the data toggle.
+ //
+ USBEndpointDataToggleClear(USB0_BASE, IndexToUSBEP(i32Idx + 1),
+ USB_EP_HOST_IN);
+
+ //
+ // Allocate space in the FIFO for this endpoint.
+ //
+ if(FIFOAlloc(&g_sUSBHCD.psUSBINPipes[i32Idx], ui32Size) != 0)
+ {
+ //
+ // Configure the FIFO.
+ //
+ MAP_USBFIFOConfigSet(USB0_BASE,
+ IndexToUSBEP(i32Idx + 1),
+ g_sUSBHCD.psUSBINPipes[i32Idx].ui16FIFOAddr,
+ g_sUSBHCD.psUSBINPipes[i32Idx].ui8FIFOSize,
+ USB_EP_HOST_IN);
+ }
+
+ //
+ // Set the function address for this endpoint.
+ //
+ MAP_USBHostAddrSet(USB0_BASE, IndexToUSBEP(i32Idx + 1),
+ psDevice->ui32Address, USB_EP_HOST_IN);
+
+ //
+ // Set the hub and port address for the endpoint.
+ //
+ ui32HubAddr = psDevice->ui8Hub | (psDevice->ui8HubPort << 8);
+ USBHostHubAddrSet(USB0_BASE, IndexToUSBEP(i32Idx + 1),
+ ui32HubAddr, (USB_EP_HOST_IN |
+ psDevice->ui32Speed));
+
+ //
+ // Reset the state of the pipe to idle.
+ //
+ g_sUSBHCD.psUSBINPipes[i32Idx].iState = ePipeIdle;
+
+ break;
+ }
+ }
+ }
+
+ //
+ // Did not find a free pipe.
+ //
+ if(i32Idx == MAX_NUM_PIPES)
+ {
+ return(0);
+ }
+
+ //
+ // Return the pipe index and type that was allocated.
+ //
+ return(ui32EndpointType | i32Idx);
+}
+
+//*****************************************************************************
+//
+//! This function is used to allocate a USB HCD pipe.
+//!
+//! \param ui32Index specifies which USB controller to use.
+//! \param ui32EndpointType is the type of endpoint that this pipe will be
+//! communicating with.
+//! \param psDevice is the device instance associated with this endpoint.
+//! \param pfnCallback is the function that will be called when events occur on
+//! this USB Pipe.
+//!
+//! Since there are a limited number of USB HCD pipes that can be used in the
+//! host controller, this function is used to temporarily or permanently
+//! acquire one of the endpoints. It also provides a method to register a
+//! callback for status changes on this endpoint. If no callbacks are desired
+//! then the \e pfnCallback function should be set to 0. The callback should
+//! be used when using the USBHCDPipeSchedule() function so that the caller is
+//! notified when the action is complete.
+//!
+//! \return This function returns a value indicating which pipe was reserved.
+//! If the value is 0 then there were no pipes currently available. This value
+//! should be passed to any USBHCDPipe APIs to indicate which pipe is being
+//! accessed.
+//
+//*****************************************************************************
+uint32_t
+USBHCDPipeAlloc(uint32_t ui32Index, uint32_t ui32EndpointType,
+ tUSBHostDevice *psDevice, tHCDPipeCallback pfnCallback)
+{
+ //
+ // The old API allocated only 64 bytes to each endpoint.
+ //
+ return(USBHCDPipeAllocSize(ui32Index, ui32EndpointType, psDevice, 64,
+ pfnCallback));
+}
+
+//*****************************************************************************
+//
+//! This function is used to configure a USB HCD pipe.
+//!
+//! This should be called after allocating a USB pipe with a call to
+//! USBHCDPipeAlloc(). It is used to set the configuration associated with an
+//! endpoint like the max payload and target endpoint. The \e ui32MaxPayload
+//! parameter is typically read directly from the devices endpoint descriptor
+//! and is expressed in bytes.
+//!
+//! Setting the \e ui32Interval parameter depends on the type of endpoint being
+//! configured. For endpoints that do not need to use the \e ui32Interval
+//! parameter \e ui32Interval should be set to 0. For Bulk \e ui32Interval is
+//! a value from 2-16 and will set the NAK timeout value as
+//! 2^(\e ui32Interval-1) frames. For interrupt endpoints \e ui32Interval is a
+//! value from 1-255 and is the count in frames between polling the endpoint.
+//! For isochronous endpoints \e ui32Interval ranges from 1-16 and is the
+//! polling interval in frames represented as 2^(\e ui32Interval-1) frames.
+//!
+//! \param ui32Pipe is the allocated endpoint to modify.
+//! \param ui32MaxPayload is maximum data that can be handled per transaction.
+//! \param ui32Interval is the polling interval for data transfers expressed in
+//! frames.
+//! \param ui32TargetEndpoint is the target endpoint on the device to
+//! communicate with.
+//!
+//! \return If the call was successful, this function returns zero any other
+//! value indicates an error.
+//
+//*****************************************************************************
+uint32_t
+USBHCDPipeConfig(uint32_t ui32Pipe, uint32_t ui32MaxPayload,
+ uint32_t ui32Interval, uint32_t ui32TargetEndpoint)
+{
+ uint32_t ui32Flags;
+ uint32_t ui32Index;
+
+ //
+ // Get the index number from the allocated pipe.
+ //
+ ui32Index = (ui32Pipe & EP_PIPE_IDX_M);
+
+ //
+ // Set the direction.
+ //
+ if(ui32Pipe & EP_PIPE_TYPE_OUT)
+ {
+ //
+ // Set the mode for this endpoint.
+ //
+ if(g_sUSBHCD.psUSBOUTPipes[ui32Index].ui32Type & EP_PIPE_TYPE_BULK)
+ {
+ ui32Flags = USB_EP_MODE_BULK;
+ }
+ else if(g_sUSBHCD.psUSBOUTPipes[ui32Index].ui32Type &
+ EP_PIPE_TYPE_INTR)
+ {
+ ui32Flags = USB_EP_MODE_INT;
+ }
+ else if(g_sUSBHCD.psUSBOUTPipes[ui32Index].ui32Type &
+ EP_PIPE_TYPE_ISOC)
+ {
+ ui32Flags = USB_EP_MODE_ISOC;
+ }
+ else
+ {
+ ui32Flags = USB_EP_MODE_CTRL;
+ }
+
+ ui32Flags |= USB_EP_HOST_OUT;
+
+ g_sUSBHCD.psUSBOUTPipes[ui32Index].ui8EPNumber =
+ (uint8_t)ui32TargetEndpoint;
+
+ //
+ // Save the interval and the next tick to trigger a scheduler event.
+ //
+ g_sUSBHCD.psUSBOUTPipes[ui32Index].ui32Interval = ui32Interval;
+ g_sUSBHCD.psUSBOUTPipes[ui32Index].ui32NextEventTick =
+ ui32Interval + g_ui32CurrentTick;
+
+ //
+ // Set the device speed.
+ //
+ ui32Flags |= (g_sUSBHCD.psUSBOUTPipes[ui32Index].psDevice->ui32Speed);
+
+ //
+ // Set up the appropriate flags if uDMA is used.
+ //
+ if(ui32Pipe & EP_PIPE_USE_UDMA)
+ {
+ ui32Flags |= USB_EP_DMA_MODE_0 | USB_EP_AUTO_SET;
+ }
+ }
+ else
+ {
+ //
+ // Set the mode for this endpoint.
+ //
+ if(g_sUSBHCD.psUSBINPipes[ui32Index].ui32Type & EP_PIPE_TYPE_BULK)
+ {
+ ui32Flags = USB_EP_MODE_BULK;
+ }
+ else if(g_sUSBHCD.psUSBINPipes[ui32Index].ui32Type & EP_PIPE_TYPE_INTR)
+ {
+ ui32Flags = USB_EP_MODE_INT;
+ }
+ else if(g_sUSBHCD.psUSBINPipes[ui32Index].ui32Type & EP_PIPE_TYPE_ISOC)
+ {
+ ui32Flags = USB_EP_MODE_ISOC;
+ }
+ else
+ {
+ ui32Flags = USB_EP_MODE_CTRL;
+ }
+ ui32Flags |= USB_EP_HOST_IN;
+
+ g_sUSBHCD.psUSBINPipes[ui32Index].ui8EPNumber =
+ (uint8_t)ui32TargetEndpoint;
+
+ //
+ // Save the interval and the next tick to trigger a scheduler event.
+ //
+ g_sUSBHCD.psUSBINPipes[ui32Index].ui32Interval = ui32Interval;
+ g_sUSBHCD.psUSBINPipes[ui32Index].ui32NextEventTick =
+ ui32Interval + g_ui32CurrentTick;
+
+ //
+ // Set the device speed.
+ //
+ ui32Flags |= g_sUSBHCD.psUSBINPipes[ui32Index].psDevice->ui32Speed;
+ //
+ // Set up the appropriate flags if uDMA is used.
+ //
+ if(ui32Pipe & EP_PIPE_USE_UDMA)
+ {
+ ui32Flags |= USB_EP_DMA_MODE_1 | USB_EP_AUTO_CLEAR |
+ USB_EP_AUTO_REQUEST;
+ }
+ }
+
+
+ //
+ // Configure the endpoint according to the flags determined above.
+ //
+ USBHostEndpointConfig(USB0_BASE,
+ IndexToUSBEP((ui32Pipe & EP_PIPE_IDX_M) + 1),
+ ui32MaxPayload, ui32Interval, ui32TargetEndpoint,
+ ui32Flags);
+
+ return(0);
+}
+
+//*****************************************************************************
+//
+//! This function is used to return the current status of a USB HCD pipe.
+//!
+//! This function will return the current status for a given USB pipe. If
+//! there is no status to report this call will simply return
+//! \b USBHCD_PIPE_NO_CHANGE.
+//!
+//! \param ui32Pipe is the USB pipe for this status request.
+//!
+//! \return This function returns the current status for the given endpoint.
+//! This will be one of the \b USBHCD_PIPE_* values.
+//
+//*****************************************************************************
+uint32_t
+USBHCDPipeStatus(uint32_t ui32Pipe)
+{
+ return(0);
+}
+
+//*****************************************************************************
+//
+//! This function is used to write data to a USB HCD pipe.
+//!
+//! \param ui32Pipe is the USB pipe to put data into.
+//! \param pui8Data is a pointer to the data to send.
+//! \param ui32Size is the amount of data to send.
+//!
+//! This function will block until it has sent as much data as was
+//! requested using the USB pipe's FIFO. The caller should have registered a
+//! callback with the USBHCDPipeAlloc() call in order to be informed when the
+//! data has been transmitted. The value returned by this function can be less
+//! than the \e ui32Size requested if the USB pipe has less space available
+//! than this request is making.
+//!
+//! \return This function returns the number of bytes that were scheduled to
+//! be sent on the given USB pipe.
+//
+//*****************************************************************************
+uint32_t
+USBHCDPipeWrite(uint32_t ui32Pipe, uint8_t *pui8Data, uint32_t ui32Size)
+{
+ uint32_t ui32Endpoint, ui32RemainingBytes, ui32ByteToSend, ui32PipeIdx;
+ bool bUseDMA;
+
+ //
+ // Determine which endpoint interface that this pipe is using.
+ //
+ ui32Endpoint = IndexToUSBEP((EP_PIPE_IDX_M & ui32Pipe) + 1);
+
+ //
+ // Get index used for looking up pipe data
+ //
+ ui32PipeIdx = ui32Pipe & EP_PIPE_IDX_M;
+
+ //
+ // Set the total number of bytes to send out.
+ //
+ ui32RemainingBytes = ui32Size;
+
+ //
+ // Default to using DMA.
+ //
+ bUseDMA = false;
+
+ //
+ // Initialize the bytes to send to all of the remaining bytes.
+ //
+ ui32ByteToSend = ui32RemainingBytes;
+
+ //
+ // Send all of the requested data.
+ //
+ while(ui32RemainingBytes != 0)
+ {
+ //
+ // If uDMA is not enabled for this pipe, or if the uDMA workaround
+ // is applied, then don't use uDMA for this transfer.
+ //
+ if(ui32Pipe & EP_PIPE_USE_UDMA)
+ {
+ //
+ // Disable the USB interrupt.
+ //
+ OS_INT_DISABLE(g_sUSBHCD.ui32IntNum);
+
+ //
+ // Start the DMA transfer.
+ //
+ if(USBLibDMATransfer(g_sUSBHCD.psDMAInstance,
+ g_sUSBHCD.psUSBOUTPipes[ui32PipeIdx].ui8DMAChannel,
+ pui8Data, ui32RemainingBytes) != 0)
+ {
+ if(ui32RemainingBytes < 64)
+ {
+ g_sUSBHCD.psUSBOUTPipes[ui32PipeIdx].iState =
+ ePipeWriteDMASend;
+ }
+ else if((ui32RemainingBytes % 64) == 0)
+ {
+ g_sUSBHCD.psUSBOUTPipes[ui32PipeIdx].iState =
+ ePipeWriteDMA;
+ }
+ else
+ {
+ g_sUSBHCD.psUSBOUTPipes[ui32PipeIdx].iState =
+ ePipeWriteDMASend;
+ }
+
+ bUseDMA = true;
+ }
+
+ //
+ // Enable the USB interrupt.
+ //
+ OS_INT_ENABLE(g_sUSBHCD.ui32IntNum);
+ }
+
+ if(bUseDMA == false)
+ {
+ //
+ // Only send 64 bytes at a time if not using DMA.
+ //
+ if(ui32ByteToSend > 64)
+ {
+ ui32ByteToSend = 64;
+ }
+ else
+ {
+ //
+ // Send the requested number of bytes.
+ //
+ ui32ByteToSend = ui32RemainingBytes;
+ }
+
+ //
+ // Start a write request.
+ //
+ g_sUSBHCD.psUSBOUTPipes[ui32PipeIdx].iState = ePipeWriting;
+
+ //
+ // Disable uDMA on the USB endpoint
+ //
+ MAP_USBEndpointDMADisable(USB0_BASE, ui32Endpoint,
+ USB_EP_HOST_OUT);
+
+ //
+ // Put the data in the buffer.
+ //
+ MAP_USBEndpointDataPut(USB0_BASE, ui32Endpoint, pui8Data,
+ ui32ByteToSend);
+
+ //
+ // Schedule the data to be sent.
+ //
+ MAP_USBEndpointDataSend(USB0_BASE, ui32Endpoint, USB_TRANS_OUT);
+ }
+
+ //
+ // Wait for a status change.
+ //
+ while(1)
+ {
+ //
+ // If an error event occurs then exit out of the loop.
+ //
+ if(g_sUSBHCD.ui32IntEvents & (INT_EVENT_DISCONNECT |
+ INT_EVENT_VBUS_ERR |
+ INT_EVENT_POWER_FAULT))
+ {
+ //
+ // Set the pipe state to error.
+ //
+ g_sUSBHCD.psUSBOUTPipes[ui32PipeIdx].iState = ePipeError;
+
+ //
+ // Needs to be set to exit out of large while loop.
+ //
+ ui32RemainingBytes = 0;
+
+ break;
+ }
+ //
+ // If the data was successfully sent then decrement the count and
+ // continue.
+ //
+ else if(g_sUSBHCD.psUSBOUTPipes[ui32PipeIdx].iState ==
+ ePipeDataSent)
+ {
+ //
+ // Decrement the remaining data and advance the pointer.
+ //
+ ui32RemainingBytes -= ui32ByteToSend;
+ pui8Data += ui32ByteToSend;
+
+ //
+ // If there are less than 64 bytes to send then this is the
+ // last of the data to go out.
+ //
+ if(ui32RemainingBytes < 64)
+ {
+ ui32ByteToSend = ui32RemainingBytes;
+ }
+ break;
+ }
+ else if(g_sUSBHCD.psUSBOUTPipes[ui32PipeIdx].iState ==
+ ePipeStalled)
+ {
+ //
+ // Zero out the size so that the caller knows that no data was
+ // written.
+ //
+ ui32Size = 0;
+
+ //
+ // Needs to be set to exit out of large while loop.
+ //
+ ui32RemainingBytes = 0;
+
+ //
+ // If DMA is being used, then disable the channel.
+ //
+ if(bUseDMA == true)
+ {
+ //
+ // Disable the DMA channel.
+ //
+ USBLibDMAChannelDisable(g_sUSBHCD.psDMAInstance,
+ g_sUSBHCD.psUSBOUTPipes[ui32PipeIdx].ui8DMAChannel);
+ }
+
+ //
+ // This is the actual endpoint number.
+ //
+ USBHCDClearFeature(
+ g_sUSBHCD.psUSBOUTPipes[ui32PipeIdx].psDevice->ui32Address,
+ ui32Pipe, USB_FEATURE_EP_HALT);
+
+ //
+ // If there was a stall, then no more data is coming so break
+ // out.
+ //
+ break;
+ }
+ else if(g_sUSBHCD.psUSBOUTPipes[ui32PipeIdx].iState == ePipeError)
+ {
+ //
+ // An error occurred so stop this transaction and set the
+ // number of bytes to zero.
+ //
+ ui32Size = 0;
+
+ //
+ // Needs to be set to exit out of large while loop.
+ //
+ ui32RemainingBytes = 0;
+
+ break;
+ }
+ }
+ }
+
+ //
+ // Go Idle once this state has been reached.
+ //
+ g_sUSBHCD.psUSBOUTPipes[ui32PipeIdx].iState = ePipeIdle;
+
+ return(ui32Size);
+}
+
+//*****************************************************************************
+//
+//! This function is used to schedule and IN transaction on a USB HCD pipe.
+//!
+//! \param ui32Pipe is the USB pipe to read data from.
+//! \param pui8Data is a pointer to store the data that is received.
+//! \param ui32Size is the size in bytes of the buffer pointed to by
+//! \e pui8Data.
+//!
+//! This function will not block depending on the type of pipe passed in will
+//! schedule either a send of data to the device or a read of data from the
+//! device. In either case the amount of data will be limited to what will
+//! fit in the FIFO for a given endpoint.
+//!
+//! \return This function returns the number of bytes that were sent in the
+//! case of a transfer of data or it will return 0 for a request on a USB IN
+//! pipe.
+//
+//*****************************************************************************
+uint32_t
+USBHCDPipeSchedule(uint32_t ui32Pipe, uint8_t *pui8Data, uint32_t ui32Size)
+{
+ uint32_t ui32Endpoint, ui32PipeIdx;
+
+ //
+ // Get index used for looking up pipe data
+ //
+ ui32PipeIdx = ui32Pipe & EP_PIPE_IDX_M;
+
+ //
+ // Determine which endpoint interface that this pipe is using.
+ //
+ ui32Endpoint = IndexToUSBEP((EP_PIPE_IDX_M & ui32Pipe) + 1);
+
+ if(ui32Pipe & EP_PIPE_TYPE_OUT)
+ {
+ //
+ // Check if uDMA is enabled on this pipe.
+ //
+ if(ui32Pipe & EP_PIPE_USE_UDMA)
+ {
+ //
+ // Start a write request.
+ //
+ g_sUSBHCD.psUSBOUTPipes[EP_PIPE_IDX_M & ui32Pipe].iState =
+ ePipeWriteDMASend;
+
+ USBLibDMATransfer(g_sUSBHCD.psDMAInstance,
+ g_sUSBHCD.psUSBOUTPipes[ui32PipeIdx].ui8DMAChannel,
+ pui8Data, ui32Size);
+ }
+ else
+ {
+ //
+ // Start a write request.
+ //
+ g_sUSBHCD.psUSBOUTPipes[EP_PIPE_IDX_M & ui32Pipe].iState =
+ ePipeWriting;
+
+ //
+ // Put the data in the buffer.
+ //
+ MAP_USBEndpointDataPut(USB0_BASE, ui32Endpoint, pui8Data,
+ ui32Size);
+
+ //
+ // Schedule the data to be sent.
+ //
+ MAP_USBEndpointDataSend(USB0_BASE, ui32Endpoint, USB_TRANS_OUT);
+ }
+ }
+ else
+ {
+ //
+ // If uDMA is not enabled for this pipe, or if the uDMA workaround
+ // is applied, then do not use uDMA for this transfer.
+ //
+ if((ui32Pipe & EP_PIPE_USE_UDMA) == 0)
+ {
+ //
+ // Start a read request.
+ //
+ g_sUSBHCD.psUSBINPipes[EP_PIPE_IDX_M & ui32Pipe].iState =
+ ePipeReading;
+
+ //
+ // Disable uDMA on the endpoint
+ //
+ MAP_USBEndpointDMADisable(USB0_BASE, ui32Endpoint, USB_EP_HOST_IN);
+ }
+ //
+ // Otherwise, uDMA should be used for this transfer, so set up
+ // the uDMA channel in advance of triggering the IN request.
+ //
+ else
+ {
+ g_sUSBHCD.psUSBINPipes[EP_PIPE_IDX_M & ui32Pipe].iState =
+ ePipeReadDMA;
+
+ USBLibDMATransfer(g_sUSBHCD.psDMAInstance,
+ g_sUSBHCD.psUSBINPipes[ui32PipeIdx].ui8DMAChannel,
+ pui8Data, ui32Size);
+ }
+
+ //
+ // Remember details of the buffer into which the data will be read.
+ //
+ g_sUSBHCD.psUSBINPipes[ui32PipeIdx].pui8ReadPtr = pui8Data;
+ g_sUSBHCD.psUSBINPipes[ui32PipeIdx].ui32ReadSize = ui32Size;
+
+ //
+ // Trigger a request for data from the device.
+ //
+ MAP_USBHostRequestIN(USB0_BASE, ui32Endpoint);
+
+ //
+ // No data was put into or read from the buffer.
+ //
+ ui32Size = 0;
+ }
+ return(ui32Size);
+}
+
+//*****************************************************************************
+//
+//! This function is used to read data from a USB HCD pipe.
+//!
+//! \param ui32Pipe is the USB pipe to read data from.
+//! \param pui8Data is a pointer to store the data that is received.
+//! \param ui32Size is the size in bytes of the buffer pointed to by
+//! \e pui8Data.
+//!
+//! This function will not block and will only read as much data as requested
+//! or as much data is currently available from the USB pipe. The caller
+//! should have registered a callback with the USBHCDPipeAlloc() call in order
+//! to be informed when the data has been received. The value returned by this
+//! function can be less than the \e ui32Size requested if the USB pipe has
+//! less data available than was requested.
+//!
+//! \return This function returns the number of bytes that were returned in the
+//! \e pui8Data buffer.
+//
+//*****************************************************************************
+uint32_t
+USBHCDPipeReadNonBlocking(uint32_t ui32Pipe, uint8_t *pui8Data,
+ uint32_t ui32Size)
+{
+ uint32_t ui32Endpoint;
+
+ //
+ // Determine which endpoint interface that this pipe is using.
+ //
+ ui32Endpoint = IndexToUSBEP((EP_PIPE_IDX_M & ui32Pipe) + 1);
+
+ //
+ // Read the data out of the USB endpoint interface.
+ //
+ MAP_USBEndpointDataGet(USB0_BASE, ui32Endpoint, pui8Data, &ui32Size);
+
+ //
+ // Acknowledge that the data was read from the endpoint.
+ //
+ MAP_USBHostEndpointDataAck(USB0_BASE, ui32Endpoint);
+
+ //
+ // Go Idle once this state has been reached.
+ //
+ g_sUSBHCD.psUSBINPipes[EP_PIPE_IDX_M & ui32Pipe].iState = ePipeIdle;
+
+ return(ui32Size);
+}
+
+//*****************************************************************************
+//
+//! This function acknowledges data received via an interrupt IN pipe.
+//!
+//! \param ui32Pipe is the USB INT pipe whose last packet is to be
+//! acknowledged.
+//!
+//! This function is used to acknowledge reception of data on an interrupt IN
+//! pipe. A transfer on an interrupt IN endpoint is scheduled via a call to
+//! USBHCDPipeSchedule() and the application is notified when data is received
+//! using a \b USB_EVENT_RX_AVAILABLE event. In the handler for this event,
+//! the application must call USBHCDPipeDataAck() to have the USB controller
+//! ACK the data from the device and complete the transaction.
+//!
+//! \return None.
+//
+//*****************************************************************************
+void
+USBHCDPipeDataAck(uint32_t ui32Pipe)
+{
+ uint32_t ui32Endpoint;
+
+ //
+ // Determine which endpoint interface that this pipe is using.
+ //
+ ui32Endpoint = IndexToUSBEP((EP_PIPE_IDX_M & ui32Pipe) + 1);
+
+ //
+ // Acknowledge that the data was read from the endpoint.
+ //
+ USBHostEndpointDataAck(USB0_BASE, ui32Endpoint);
+
+ //
+ // Go Idle once this state has been reached.
+ //
+ g_sUSBHCD.psUSBINPipes[EP_PIPE_IDX_M & ui32Pipe].iState = ePipeIdle;
+}
+
+//*****************************************************************************
+//
+//! This function is used to read data from a USB HCD pipe.
+//!
+//! \param ui32Pipe is the USB pipe to read data from.
+//! \param pui8Data is a pointer to store the data that is received.
+//! \param ui32Size is the size in bytes of the buffer pointed to by
+//! \e pui8Data.
+//!
+//! This function will block and will only return when it has read as much data
+//! as requested from the USB pipe. The caller must register a callback with
+//! the USBHCDPipeAlloc() call in order to be informed when the data has been
+//! received. If the caller provides a non-zero pointer in the \e pui8Data
+//! parameter then the data is copied into the buffer before the callback
+//! occurs. If the caller provides a zero in \e pui8Data parameter
+//! then the caller is responsible for reading the data out of the FIFO when
+//! the \b USB_EVENT_RX_AVAILABLE callback event occurs. The value returned
+//! by this function can be less than the \e ui32Size requested if the USB pipe
+//! has less data available than was requested.
+//!
+//! \return This function returns the number of bytes that were returned in the
+//! \e pui8Data buffer.
+//
+//*****************************************************************************
+uint32_t
+USBHCDPipeRead(uint32_t ui32Pipe, uint8_t *pui8Data, uint32_t ui32Size)
+{
+ uint32_t ui32Endpoint, ui32RemainingBytes, ui32BytesRead, ui32PipeIdx;
+ bool bUseDMA;
+
+ //
+ // Get index used for looking up pipe data
+ //
+ ui32PipeIdx = ui32Pipe & EP_PIPE_IDX_M;
+
+ //
+ // Initialized the number of bytes read.
+ //
+ ui32BytesRead = 0;
+
+ //
+ // Determine which endpoint interface that this pipe is using.
+ //
+ ui32Endpoint = IndexToUSBEP(ui32PipeIdx + 1);
+
+ //
+ // Set the remaining bytes to received.
+ //
+ ui32RemainingBytes = ui32Size;
+
+ //
+ // Default to using DMA.
+ //
+ bUseDMA = true;
+
+ //
+ // Continue until all data requested has been received.
+ //
+ while(ui32RemainingBytes != 0)
+ {
+ //
+ // Start a read request.
+ //
+ g_sUSBHCD.psUSBINPipes[ui32PipeIdx].iState = ePipeReading;
+
+ //
+ // Try the DMA transfer should be used for this transfer, so set up
+ // the uDMA channel in advance of triggering the IN request.
+ //
+ if(ui32Pipe & EP_PIPE_USE_UDMA)
+ {
+ //
+ // Disable the USB interrupt.
+ //
+ OS_INT_DISABLE(g_sUSBHCD.ui32IntNum);
+
+ if(USBLibDMATransfer(g_sUSBHCD.psDMAInstance,
+ g_sUSBHCD.psUSBINPipes[ui32PipeIdx].ui8DMAChannel,
+ pui8Data, ui32Size) != 0)
+ {
+ g_sUSBHCD.psUSBINPipes[ui32PipeIdx].iState = ePipeReadDMA;
+
+ ui32BytesRead = ui32Size;
+ }
+ else
+ {
+ bUseDMA = false;
+ }
+
+ //
+ // Disable the USB interrupt.
+ //
+ OS_INT_ENABLE(g_sUSBHCD.ui32IntNum);
+ }
+
+ //
+ // If unable to use DMA then get ready to transfer without DMA.
+ //
+ if(bUseDMA == false)
+ {
+ //
+ // Disable uDMA on the endpoint
+ //
+ MAP_USBEndpointDMADisable(USB0_BASE, ui32Endpoint, USB_EP_HOST_IN);
+
+ //
+ // Set up for the next transaction.
+ //
+ g_sUSBHCD.psUSBINPipes[ui32PipeIdx].pui8ReadPtr = pui8Data;
+ g_sUSBHCD.psUSBINPipes[ui32PipeIdx].ui32ReadSize =
+ (ui32RemainingBytes < 64) ? ui32RemainingBytes : 64;
+ }
+
+ //
+ // Trigger a request for data from the device.
+ //
+ MAP_USBHostRequestIN(USB0_BASE, ui32Endpoint);
+
+ //
+ // Wait for a status change.
+ //
+ while(1)
+ {
+ //
+ // Check if the device stalled the request.
+ //
+ if(g_sUSBHCD.psUSBINPipes[ui32PipeIdx].iState == ePipeStalled)
+ {
+ //
+ // Zero out the size so that the caller knows that no data was
+ // read.
+ //
+ ui32Size = 0;
+
+ //
+ // There are also no remaining bytes to read.
+ //
+ ui32RemainingBytes = 0;
+
+ //
+ // If DMA is being used, then disable the channel.
+ //
+ if(bUseDMA == true)
+ {
+ USBLibDMAChannelDisable(
+ g_sUSBHCD.psDMAInstance,
+ g_sUSBHCD.psUSBINPipes[ui32PipeIdx].ui8DMAChannel);
+ }
+
+ //
+ // This is the actual endpoint number.
+ //
+ USBHCDClearFeature(
+ g_sUSBHCD.psUSBINPipes[ui32PipeIdx].psDevice->ui32Address,
+ ui32Pipe, USB_FEATURE_EP_HALT);
+
+ //
+ // If there was a stall, then no more data is coming so break
+ // out.
+ //
+ break;
+ }
+
+ //
+ // If any error event occurs then exit out of the loop.
+ //
+ if(g_sUSBHCD.ui32IntEvents & (INT_EVENT_DISCONNECT |
+ INT_EVENT_VBUS_ERR |
+ INT_EVENT_POWER_FAULT))
+ {
+ //
+ // Set the pipe state to error.
+ //
+ g_sUSBHCD.psUSBINPipes[ui32PipeIdx].iState = ePipeError;
+ break;
+ }
+
+ //
+ // If data is ready then return it.
+ //
+ if(g_sUSBHCD.psUSBINPipes[ui32PipeIdx].iState == ePipeDataReady)
+ {
+ //
+ // If not using DMA then read the data from the USB. Otherwise
+ // the data will already be in the buffer.
+ //
+ if(bUseDMA == false)
+ {
+ //
+ // Compute bytes to transfer and set up transfer
+ //
+ ui32BytesRead =
+ ui32RemainingBytes > 64 ? 64 : ui32RemainingBytes;
+
+ //
+ // Acknowledge that the data was read from the endpoint.
+ //
+ MAP_USBHostEndpointDataAck(USB0_BASE, ui32Endpoint);
+ }
+
+ //
+ // Subtract the number of bytes read from the bytes remaining.
+ //
+ ui32RemainingBytes -= ui32BytesRead;
+
+ //
+ // If there were less than 64 bytes read, then this was a short
+ // packet and no more data will be returned.
+ //
+ if(ui32BytesRead < 64)
+ {
+ //
+ // Subtract off the bytes that were not received and exit
+ // the loop.
+ //
+ ui32Size = ui32Size - ui32RemainingBytes;
+ break;
+ }
+ else
+ {
+ //
+ // Move the buffer ahead to receive more data into the
+ // buffer.
+ //
+ pui8Data += 64;
+ }
+ break;
+ }
+ else if(g_sUSBHCD.psUSBINPipes[ui32PipeIdx].iState == ePipeError)
+ {
+ //
+ // An error occurred so stop this transaction and set the
+ // number of bytes to zero.
+ //
+ ui32Size = 0;
+ ui32RemainingBytes = 0;
+
+ break;
+ }
+ else if((g_sUSBHCD.psUSBINPipes[ui32PipeIdx].iState ==
+ ePipeReadDMAWait) &&
+ (USBLibDMAChannelStatus(g_sUSBHCD.psDMAInstance,
+ g_sUSBHCD.psUSBINPipes[ui32PipeIdx].ui8DMAChannel) &
+ USBLIBSTATUS_DMA_COMPLETE))
+ {
+ break;
+ }
+ }
+ }
+
+ //
+ // Go Idle once this state has been reached.
+ //
+ g_sUSBHCD.psUSBINPipes[ui32PipeIdx].iState = ePipeIdle;
+
+ return(ui32Size);
+}
+
+//*****************************************************************************
+//
+//! This function is used to release a USB pipe.
+//!
+//! \param ui32Pipe is the allocated USB pipe to release.
+//!
+//! This function is used to release a USB pipe that was allocated by a call to
+//! USBHCDPipeAlloc() for use by some other device endpoint in the system.
+//! Freeing an unallocated or invalid pipe will not generate an error and will
+//! instead simply return.
+//!
+//! \return None.
+//
+//*****************************************************************************
+void
+USBHCDPipeFree(uint32_t ui32Pipe)
+{
+ uint32_t ui32Index;
+
+ //
+ // Get the index number from the allocated pipe.
+ //
+ ui32Index = (ui32Pipe & EP_PIPE_IDX_M);
+
+ if(ui32Pipe & EP_PIPE_TYPE_OUT)
+ {
+ //
+ // Clear the address and type for this endpoint to free it up.
+ //
+ g_sUSBHCD.psUSBOUTPipes[ui32Index].psDevice = 0;
+ g_sUSBHCD.psUSBOUTPipes[ui32Index].ui32Type = 0;
+ g_sUSBHCD.psUSBOUTPipes[ui32Index].pfnCallback = 0;
+
+ //
+ // Check if this pipe has allocated a DMA channel.
+ //
+ if(g_sUSBHCD.psUSBOUTPipes[ui32Index].ui8DMAChannel !=
+ USBHCD_DMA_UNUSED)
+ {
+ //
+ // Release the DMA channel associated with this endpoint.
+ //
+ USBLibDMAChannelRelease(g_sUSBHCD.psDMAInstance,
+ g_sUSBHCD.psUSBOUTPipes[ui32Index].ui8DMAChannel);
+
+ //
+ // Clear out the current channel in use by this pipe.
+ //
+ g_sUSBHCD.psUSBOUTPipes[ui32Index].ui8DMAChannel =
+ USBHCD_DMA_UNUSED;
+ }
+
+ //
+ // Free up the FIFO memory used by this endpoint.
+ //
+ if(g_sUSBHCD.psUSBOUTPipes[ui32Index].ui8FIFOSize)
+ {
+ FIFOFree(&g_sUSBHCD.psUSBOUTPipes[ui32Index]);
+ }
+
+ //
+ // Set the function address for this endpoint back to zero.
+ //
+ USBHostAddrSet(USB0_BASE, IndexToUSBEP(ui32Index + 1),
+ 0, USB_EP_HOST_OUT);
+
+ //
+ // Set the hub and port address for the endpoint back to zero and the
+ // speed back to LOW.
+ //
+ USBHostHubAddrSet(USB0_BASE, IndexToUSBEP(ui32Index + 1),
+ 0, (USB_EP_HOST_OUT | USB_EP_SPEED_LOW));
+ }
+ else if(ui32Pipe & EP_PIPE_TYPE_IN)
+ {
+ //
+ // Clear the address and type for this endpoint to free it up.
+ //
+ g_sUSBHCD.psUSBINPipes[ui32Index].psDevice = 0;
+ g_sUSBHCD.psUSBINPipes[ui32Index].ui32Type = 0;
+ g_sUSBHCD.psUSBINPipes[ui32Index].pfnCallback = 0;
+
+ //
+ // Check if this pipe has allocated a DMA channel.
+ //
+ if(g_sUSBHCD.psUSBINPipes[ui32Index].ui8DMAChannel !=
+ USBHCD_DMA_UNUSED)
+ {
+ //
+ // Release the DMA channel associated with this endpoint.
+ //
+ USBLibDMAChannelRelease(g_sUSBHCD.psDMAInstance,
+ g_sUSBHCD.psUSBINPipes[ui32Index].ui8DMAChannel);
+
+ //
+ // Clear out the current channel in use by this pipe.
+ //
+ g_sUSBHCD.psUSBINPipes[ui32Index].ui8DMAChannel =
+ USBHCD_DMA_UNUSED;
+ }
+
+ //
+ // Free up the FIFO memory used by this endpoint.
+ //
+ if(g_sUSBHCD.psUSBINPipes[ui32Pipe & EP_PIPE_IDX_M].ui8FIFOSize)
+ {
+ FIFOFree(&g_sUSBHCD.psUSBINPipes[ui32Pipe & EP_PIPE_IDX_M]);
+ }
+
+ //
+ // Set the function address for this endpoint back to zero.
+ //
+ USBHostAddrSet(USB0_BASE, IndexToUSBEP(ui32Index + 1),
+ 0, USB_EP_HOST_IN);
+
+ //
+ // Set the hub and port address for the endpoint back to zero and the
+ // speed back to LOW.
+ //
+ USBHostHubAddrSet(USB0_BASE, IndexToUSBEP(ui32Index + 1),
+ 0, (USB_EP_HOST_IN | USB_EP_SPEED_LOW));
+
+ //
+ // Clear any pending IN transactions.
+ //
+ USBHostRequestINClear(USB0_BASE, IndexToUSBEP(ui32Index + 1));
+ }
+}
+
+//*****************************************************************************
+//
+// This internal function initializes the HCD code.
+//
+// \param ui32Index specifies which USB controller to use.
+// \param pvPool is a pointer to the data to use as a memory pool for this
+// controller.
+// \param ui32PoolSize is the size in bytes of the buffer passed in as pvPool.
+//
+// This function will perform all the necessary operations to allow the USB
+// host controller to begin enumeration and communication with a device. This
+// function should typically be called once at the start of an application
+// before any other calls are made to the host controller.
+//
+// \return None.
+//
+//*****************************************************************************
+static void
+USBHCDInitInternal(uint32_t ui32Index, void *pvPool, uint32_t ui32PoolSize)
+{
+ int32_t i32Idx;
+
+ ASSERT(ui32Index == 0);
+
+ //
+ // Get the number of endpoints supported by this device.
+ //
+ g_sUSBHCD.ui32NumEndpoints = USBNumEndpointsGet(USB0_BASE);
+
+ //
+ // The first 64 Bytes are allocated to endpoint 0.
+ //
+ g_pui32Alloc[0] = 1;
+ g_pui32Alloc[1] = 0;
+
+ //
+ // Save the base address for this controller.
+ //
+ g_sUSBHCD.ui32USBBase = USB0_BASE;
+
+ //
+ // Save the USB interrupt number.
+ //
+ g_sUSBHCD.ui32IntNum = INT_USB0_TM4C123;
+
+ //
+ // These devices have a different USB interrupt number.
+ //
+ if(CLASS_IS_TM4C129)
+ {
+ g_sUSBHCD.ui32IntNum = INT_USB0_TM4C129;
+ }
+
+ //
+ // All Pipes are unused at start.
+ //
+ for(i32Idx = 0; i32Idx < MAX_NUM_PIPES; i32Idx++)
+ {
+ g_sUSBHCD.psUSBINPipes[i32Idx].psDevice = 0;
+ g_sUSBHCD.psUSBINPipes[i32Idx].ui32Type = USBHCD_PIPE_UNUSED;
+ g_sUSBHCD.psUSBINPipes[i32Idx].ui8DMAChannel = USBHCD_DMA_UNUSED;
+ g_sUSBHCD.psUSBOUTPipes[i32Idx].psDevice = 0;
+ g_sUSBHCD.psUSBOUTPipes[i32Idx].ui32Type = USBHCD_PIPE_UNUSED;
+ g_sUSBHCD.psUSBOUTPipes[i32Idx].ui8DMAChannel = USBHCD_DMA_UNUSED;
+ }
+
+ //
+ // Make sure that the hub driver is initialized since it is called even
+ // if it is not present in the system.
+ //
+ USBHHubInit();
+
+ //
+ // Initialize the DMA interface.
+ //
+ g_sUSBHCD.psDMAInstance = USBLibDMAInit(g_sUSBHCD.ui32USBBase);
+
+ //
+ // Initialized the device structures.
+ //
+ for(i32Idx = 0; i32Idx <= MAX_USB_DEVICES; i32Idx++)
+ {
+ //
+ // Clear the configuration descriptor and state.
+ //
+ g_sUSBHCD.piDeviceState[i32Idx] = eHCDIdle;
+ g_sUSBHCD.psUSBDevice[i32Idx].psConfigDescriptor = 0;
+ g_sUSBHCD.psUSBDevice[i32Idx].bConfigRead = false;
+
+ //
+ // Initialize the device descriptor.
+ //
+ g_sUSBHCD.psUSBDevice[i32Idx].sDeviceDescriptor.bLength = 0;
+ g_sUSBHCD.psUSBDevice[i32Idx].sDeviceDescriptor.bMaxPacketSize0 = 0;
+
+ //
+ // Initialize the device address.
+ //
+ g_sUSBHCD.psUSBDevice[i32Idx].ui32Address = 0;
+
+ //
+ // Set the current interface to 0.
+ //
+ g_sUSBHCD.psUSBDevice[i32Idx].ui32Interface = 0;
+
+ //
+ // Clear the active driver for the device.
+ //
+ g_pi32USBHActiveDriver[i32Idx] = -1;
+
+ //
+ // Initialize the device flags.
+ //
+ g_sUSBHCD.psUSBDevice[i32Idx].ui32Flags = 0;
+ }
+
+ //
+ // Allocate the memory needed for reading descriptors.
+ //
+ g_sUSBHCD.pvPool = pvPool;
+ g_sUSBHCD.ui32PoolSize = ui32PoolSize;
+
+ //
+ // Initialize the device class.
+ //
+ g_sUSBHCD.ui32Class = USB_CLASS_EVENTS;
+
+ //
+ // Default enable connect, disconnect, unknown device and power fault
+ // event notifications.
+ //
+ g_sUSBHCD.ui32EventEnables = USBHCD_EVFLAG_CONNECT |
+ USBHCD_EVFLAG_UNKCNCT |
+ USBHCD_EVFLAG_DISCNCT |
+ USBHCD_EVFLAG_PWRFAULT |
+ USBHCD_EVFLAG_PWREN |
+ USBHCD_EVFLAG_PWRDIS;
+
+ //
+ // Initialize the USB tick module.
+ //
+ InternalUSBTickInit();
+
+ //
+ // Only do hardware update if the stack is in Host mode, do not touch the
+ // hardware for OTG mode operation.
+ //
+ if((g_iUSBMode == eUSBModeHost) || (g_iUSBMode == eUSBModeForceHost))
+ {
+ //
+ // Configure the End point 0.
+ //
+ USBHostEndpointConfig(USB0_BASE, USB_EP_0, 64, 0, 0,
+ (USB_EP_MODE_CTRL | USB_EP_SPEED_FULL |
+ USB_EP_HOST_OUT));
+
+ //
+ // Enable USB Interrupts.
+ //
+ MAP_USBIntEnableControl(USB0_BASE, USB_INTCTRL_RESET |
+ USB_INTCTRL_DISCONNECT |
+ USB_INTCTRL_SOF |
+ USB_INTCTRL_SESSION |
+ USB_INTCTRL_BABBLE |
+ USB_INTCTRL_CONNECT |
+ USB_INTCTRL_RESUME |
+ USB_INTCTRL_SUSPEND |
+ USB_INTCTRL_VBUS_ERR |
+ USB_INTCTRL_POWER_FAULT);
+
+ MAP_USBIntEnableEndpoint(USB0_BASE, USB_INTEP_ALL);
+
+ //
+ // Enable the USB interrupt.
+ //
+ OS_INT_ENABLE(g_sUSBHCD.ui32IntNum);
+
+ //
+ // There is no automatic power in pure host mode.
+ //
+ USBHCDPowerConfigSet(ui32Index, (g_ui32PowerConfig &
+ ~USB_HOST_PWREN_AUTO));
+
+ //
+ // Force the power on as well as this point.
+ //
+ MAP_USBHostPwrEnable(USB0_BASE);
+
+ //
+ // This is required to get into host mode on some parts.
+ //
+ USBOTGSessionRequest(USB0_BASE, true);
+ }
+
+ //
+ // Configure LPM if it is enabled.
+ //
+ if(g_sUSBHCD.ui32Features & USBLIB_FEATURE_LPM_EN)
+ {
+ if(g_sUSBHCD.ui32Features & USBLIB_FEATURE_LPM_RMT_WAKE)
+ {
+ USBHostLPMConfig(USB0_BASE, g_sUSBHCD.ui32LPMHIRD,
+ USB_DEV_LPM_LS_L1 | USB_DEV_LPM_LS_RMTWAKE);
+ }
+ else
+ {
+ USBHostLPMConfig(USB0_BASE, g_sUSBHCD.ui32LPMHIRD,
+ USB_DEV_LPM_LS_L1);
+ }
+
+ //
+ // Enable USB interrupts for LPM mode, these enables have no effect on
+ // devices that do not support LPM.
+ //
+ USBLPMIntEnable(USB0_BASE, USB_INTLPM_ERROR | USB_INTLPM_RESUME |
+ USB_INTLPM_INCOMPLETE | USB_INTLPM_ACK |
+ USB_INTLPM_NYET | USB_INTLPM_STALL);
+ }
+}
+
+//*****************************************************************************
+//
+//! This function is used to set the power pin and power fault configuration.
+//!
+//! \param ui32Index specifies which USB controller to use.
+//! \param ui32PwrConfig is the power configuration to use for the application.
+//!
+//! This function must be called before HCDInit() is called so that the power
+//! pin configuration can be set before power is enabled. The \e ui32PwrConfig
+//! flags specify the power fault level sensitivity, the power fault action,
+//! and the power enable pin level and source.
+//!
+//! One of the following can be selected as the power fault level sensitivity:
+//!
+//! - \b USBHCD_FAULT_LOW - An external power fault is indicated by the pin
+//! being driven low.
+//! - \b USBHCD_FAULT_HIGH - An external power fault is indicated by the pin
+//! being driven high.
+//!
+//! One of the following can be selected as the power fault action:
+//!
+//! - \b USBHCD_FAULT_VBUS_NONE - No automatic action when power fault
+//! detected.
+//! - \b USBHCD_FAULT_VBUS_TRI - Automatically Tri-state the USBnEPEN pin on a
+//! power fault.
+//! - \b USBHCD_FAULT_VBUS_DIS - Automatically drive the USBnEPEN pin to it's
+//! inactive state on a power fault.
+//!
+//! One of the following can be selected as the power enable level and source:
+//!
+//! - \b USBHCD_VBUS_MANUAL - Power control is completely managed by the
+//! application, the USB library will provide a
+//! power callback to request power state changes.
+//! - \b USBHCD_VBUS_AUTO_LOW - USBEPEN is driven low by the USB controller
+//! automatically if USBOTGSessionRequest() has
+//! enabled a session.
+//! - \b USBHCD_VBUS_AUTO_HIGH - USBEPEN is driven high by the USB controller
+//! automatically if USBOTGSessionRequest() has
+//! enabled a session.
+//!
+//! If \b USBHCD_VBUS_MANUAL is used then the application must provide an
+//! event driver to receive the \b USB_EVENT_POWER_ENABLE and
+//! \b USB_EVENT_POWER_DISABLE events and enable and disable power to VBUS when
+//! requested by the USB library. The application should respond to a power
+//! control callback by enabling or disabling VBUS as soon as possible and
+//! before returning from the callback function.
+//!
+//! \note The following values should no longer be used with the USB
+//! library: \b USB_HOST_PWRFLT_LOW, \b USB_HOST_PWRFLT_HIGH,
+//! \b USB_HOST_PWRFLT_EP_NONE, \b USB_HOST_PWRFLT_EP_TRI,
+//! \b USB_HOST_PWRFLT_EP_LOW, \b USB_HOST_PWRFLT_EP_HIGH,
+//! \b USB_HOST_PWREN_LOW, \b USB_HOST_PWREN_HIGH, \b USB_HOST_PWREN_VBLOW, and
+//! \b USB_HOST_PWREN_VBHIGH.
+//!
+//! \return None.
+//
+//*****************************************************************************
+void
+USBHCDPowerConfigInit(uint32_t ui32Index, uint32_t ui32PwrConfig)
+{
+ ASSERT(ui32Index == 0);
+
+ //
+ // Save the value as it will be used later.
+ //
+ g_ui32PowerConfig = ui32PwrConfig;
+}
+
+//*****************************************************************************
+//
+//! This function is used to get the power pin and power fault configuration.
+//!
+//! \param ui32Index specifies which USB controller to use.
+//!
+//! This function will return the current power control pin configuration as
+//! set by the USBHCDPowerConfigInit() function or the defaults if not yet set.
+//! See the USBHCDPowerConfigInit() documentation for the meaning of the bits
+//! that are returned by this function.
+//!
+//! \return The configuration of the power control pins.
+//!
+//*****************************************************************************
+uint32_t
+USBHCDPowerConfigGet(uint32_t ui32Index)
+{
+ ASSERT(ui32Index == 0);
+
+ //
+ // Save the value as it will be used later.
+ //
+ return(g_ui32PowerConfig);
+}
+
+//*****************************************************************************
+//
+//! This function is used to set the power pin and power fault configuration.
+//!
+//! \param ui32Index specifies which USB controller to use.
+//! \param ui32Config specifies which USB power configuration to use.
+//!
+//! This function will set the current power control pin configuration as
+//! set by the USBHCDPowerConfigInit() function or the defaults if not yet set.
+//! See the USBHCDPowerConfigInit() documentation for the meaning of the bits
+//! that are set by this function.
+//!
+//! \return Returns zero to indicate the power setting is now active.
+//!
+//*****************************************************************************
+uint32_t
+USBHCDPowerConfigSet(uint32_t ui32Index, uint32_t ui32Config)
+{
+ ASSERT(ui32Index == 0);
+
+ //
+ // Remember the current setting.
+ //
+ g_ui32PowerConfig = ui32Config;
+
+ //
+ // Clear out the two flag bits.
+ //
+ ui32Config = g_ui32PowerConfig & ~(USBHCD_VBUS_MANUAL |
+ USBHCD_FAULT_VBUS_DIS);
+
+ //
+ // If there is an automatic disable power action specified then set the
+ // polarity of the signal to match EPEN.
+ //
+ if(g_ui32PowerConfig & USBHCD_FAULT_VBUS_DIS)
+ {
+ //
+ // Insure that the assumption below is true.
+ //
+ ASSERT((USBHCD_VBUS_AUTO_HIGH & 1) == 1);
+ ASSERT((USBHCD_VBUS_AUTO_LOW & 1) == 0);
+
+ //
+ // This is taking advantage of the difference between
+ // USBHCD_VBUS_AUTO_LOW and USBHCD_VBUS_AUTO_HIGH being that bit
+ // one is set when EPEN is active high.
+ //
+ if(g_ui32PowerConfig & 1)
+ {
+ g_ui32PowerConfig |= USB_HOST_PWRFLT_EP_LOW;
+ ui32Config |= USB_HOST_PWRFLT_EP_LOW;
+ }
+ else
+ {
+ g_ui32PowerConfig |= USB_HOST_PWRFLT_EP_HIGH;
+ ui32Config |= USB_HOST_PWRFLT_EP_HIGH;
+ }
+ }
+
+ //
+ // Initialize the power configuration.
+ //
+ MAP_USBHostPwrConfig(USB0_BASE, ui32Config);
+
+ //
+ // If not in manual mode then just turn on power.
+ //
+ if((g_ui32PowerConfig & USBHCD_VBUS_MANUAL) == 0)
+ {
+ //
+ // Power the USB bus.
+ //
+ MAP_USBHostPwrEnable(USB0_BASE);
+ }
+
+ //
+ // Return success.
+ //
+ return(0);
+}
+
+//*****************************************************************************
+//
+//! This function returns if the current power settings will automatically
+//! handle enabling and disabling VBUS power.
+//!
+//! \param ui32Index specifies which USB controller to query.
+//!
+//! This function returns if the current power control pin configuration will
+//! automatically apply power or whether it will be left to the application
+//! to turn on power when it is notified.
+//!
+//! \return A non-zero value indicates that power is automatically applied and
+//! a value of zero indicates that the application must manually apply power.
+//!
+//*****************************************************************************
+uint32_t
+USBHCDPowerAutomatic(uint32_t ui32Index)
+{
+ //
+ // Check if the controller is automatically applying power or not.
+ //
+ if(g_ui32PowerConfig & USBHCD_VBUS_MANUAL)
+ {
+ return(0);
+ }
+ return(1);
+}
+
+//*****************************************************************************
+//
+//! This function is used to initialize the HCD code.
+//!
+//! \param ui32Index specifies which USB controller to use.
+//! \param pvPool is a pointer to the data to use as a memory pool for this
+//! controller.
+//! \param ui32PoolSize is the size in bytes of the buffer passed in as
+//! \e pvPool.
+//!
+//! This function will perform all the necessary operations to allow the USB
+//! host controller to begin enumeration and communication with devices. This
+//! function should typically be called once at the start of an application
+//! once all of the device and class drivers are ready for normal operation.
+//! This call will start up the USB host controller and any connected device
+//! will immediately start the enumeration sequence.
+//!
+//! The USBStackModeSet() function can be called with eUSBModeHost in order to
+//! cause the USB library to force the USB operating mode to a host controller.
+//! This allows the application to used the USBVBUS and USBID pins as GPIOs on
+//! devices that support forcing OTG to operate as a host only controller. By
+//! default the USB library will assume that the USBVBUS and USBID pins are
+//! configured as USB pins and not GPIOs.
+//!
+//! The memory pool passed to this function must be at least as large as a
+//! typical configuration descriptor for devices that are to be supported.
+//! This value is application-dependent however it should never be less than 32
+//! bytes and, in most cases, should be at least 64 bytes. If there is not
+//! sufficient memory to load a configuration descriptor from a device, the
+//! device will not be recognized by the USB library's host controller driver.
+//!
+//! \return None.
+//
+//*****************************************************************************
+void
+USBHCDInit(uint32_t ui32Index, void *pvPool, uint32_t ui32PoolSize)
+{
+ int32_t i32Driver;
+
+ //
+ // Check the arguments.
+ //
+ ASSERT(ui32Index == 0);
+
+ //
+ // Make sure there is at least enough to read the configuration descriptor.
+ //
+ ASSERT(ui32PoolSize >= sizeof(tConfigDescriptor));
+
+ //
+ // Should not call this if the stack is in device mode.
+ //
+ ASSERT(g_iUSBMode != eUSBModeDevice);
+ ASSERT(g_iUSBMode != eUSBModeForceDevice);
+
+ //
+ // If the mode was not set then default to eUSBModeHost.
+ //
+ if(g_iUSBMode == eUSBModeNone)
+ {
+ g_iUSBMode = eUSBModeHost;
+ }
+
+ //
+ // Reset the USB controller.
+ //
+ MAP_SysCtlPeripheralReset(SYSCTL_PERIPH_USB0);
+
+ //
+ // Enable Clocking to the USB controller.
+ //
+ MAP_SysCtlPeripheralEnable(SYSCTL_PERIPH_USB0);
+
+ //
+ // Turn on USB Phy clock.
+ //
+ MAP_SysCtlUSBPLLEnable();
+
+ //
+ // Set the PLL to USB clock divider.
+ //
+ if(g_ui32PLLDiv == 0)
+ {
+ USBClockEnable(USB0_BASE, g_ui32PLLDiv, USB_CLOCK_EXTERNAL);
+ }
+ else
+ {
+ USBClockEnable(USB0_BASE, g_ui32PLLDiv, USB_CLOCK_INTERNAL);
+ }
+
+ //
+ // Configure ULPI support.
+ //
+ if(g_ui32ULPISupport != USBLIB_FEATURE_ULPI_NONE)
+ {
+ USBULPIEnable(USB0_BASE);
+
+ if(g_ui32ULPISupport & USBLIB_FEATURE_ULPI_HS)
+ {
+ ULPIConfigSet(USB0_BASE, ULPI_CFG_HS);
+ }
+ else
+ {
+ ULPIConfigSet(USB0_BASE, ULPI_CFG_FS);
+ }
+ }
+ else
+ {
+ USBULPIDisable(USB0_BASE);
+ }
+
+ //
+ // If the application not requesting OTG mode then set the mode to forced
+ // host mode. If the mode is actually eUSBModeHost, this will be switched
+ // off when ID pin detection is complete and the ID is no longer in use.
+ //
+ if(g_iUSBMode != eUSBModeOTG)
+ {
+ //
+ // Force Host mode on devices that support force host mode.
+ //
+ MAP_USBHostMode(USB0_BASE);
+ }
+
+ //
+ // Call our internal function to perform the initialization.
+ //
+ USBHCDInitInternal(ui32Index, pvPool, ui32PoolSize);
+
+ //
+ // No event driver is present by default.
+ //
+ g_sUSBHCD.i32EventDriver = -1;
+
+ //
+ // Search through the Host Class driver list for the devices class.
+ //
+ for(i32Driver = 0; i32Driver < g_sUSBHCD.ui32NumClassDrivers; i32Driver++)
+ {
+ if(g_sUSBHCD.ppsClassDrivers[i32Driver]->ui32InterfaceClass ==
+ USB_CLASS_EVENTS)
+ {
+ //
+ // Event driver was found so remember it.
+ //
+ g_sUSBHCD.i32EventDriver = i32Driver;
+ }
+ }
+
+ //
+ // Get the number of ticks per millisecond, this is only used by blocking
+ // delays using the SysCtlDelay() function.
+ //
+ if(g_ui32Tickms == 0)
+ {
+ if(CLASS_IS_TM4C129)
+ {
+ g_ui32Tickms = 120000000 / 3000;
+ }
+ else
+ {
+ g_ui32Tickms = 80000000 / 3000;
+ }
+ }
+}
+
+//*****************************************************************************
+//
+//! This function is used to initialize the HCD class driver list.
+//!
+//! \param ui32Index specifies which USB controller to use.
+//! \param ppsHClassDrvs is an array of host class drivers that are
+//! supported on this controller.
+//! \param ui32NumDrivers is the number of entries in the \e pHostClassDrivers
+//! array.
+//!
+//! This function will set the host classes supported by the host controller
+//! specified by the \e ui32Index parameter. This function should be called
+//! before enabling the host controller driver with the USBHCDInit() function.
+//!
+//! \return None.
+//
+//*****************************************************************************
+void
+USBHCDRegisterDrivers(uint32_t ui32Index,
+ const tUSBHostClassDriver * const *ppsHClassDrvs,
+ uint32_t ui32NumDrivers)
+{
+ ASSERT(ui32Index == 0);
+
+ //
+ // Save the class drivers.
+ //
+ g_sUSBHCD.ppsClassDrivers = ppsHClassDrvs;
+
+ //
+ // Save the number of class drivers.
+ //
+ g_sUSBHCD.ui32NumClassDrivers = ui32NumDrivers;
+}
+
+//*****************************************************************************
+//
+//! This function is used to terminate the HCD code.
+//!
+//! \param ui32Index specifies which USB controller to release.
+//!
+//! This function will clean up the USB host controller and disable it in
+//! preparation for shutdown or a switch to USB device mode. Once this call is
+//! made, \e USBHCDInit() may be called to reinitialize the controller and
+//! prepare for host mode operation.
+//!
+//! \return None.
+//
+//*****************************************************************************
+void
+USBHCDTerm(uint32_t ui32Index)
+{
+ int32_t i32Idx;
+
+ ASSERT(ui32Index == 0);
+
+ //
+ // End the session.
+ //
+ USBOTGSessionRequest(USB0_BASE, false);
+
+ //
+ // Remove power from the USB bus.
+ //
+ MAP_USBHostPwrDisable(USB0_BASE);
+
+ //
+ // Disable USB interrupts.
+ //
+ OS_INT_DISABLE(g_sUSBHCD.ui32IntNum);
+
+ MAP_USBIntDisableControl(USB0_BASE, USB_INTCTRL_ALL);
+
+ MAP_USBIntDisableEndpoint(USB0_BASE, USB_INTEP_ALL);
+
+ //
+ // Set the host controller state back to it's initial values.
+ //
+ for(i32Idx = 0; i32Idx < MAX_NUM_PIPES; i32Idx++)
+ {
+ g_sUSBHCD.psUSBINPipes[i32Idx].ui32Type = USBHCD_PIPE_UNUSED;
+ g_sUSBHCD.psUSBOUTPipes[i32Idx].ui32Type = USBHCD_PIPE_UNUSED;
+ }
+
+ //
+ // Free the memory used by the configuration descriptor.
+ //
+ ConfigDescFree(&g_sUSBHCD.psUSBDevice[0]);
+
+ g_sUSBHCD.piDeviceState[0] = eHCDIdle;
+ g_sUSBHCD.psUSBDevice[0].psConfigDescriptor = 0;
+ g_sUSBHCD.psUSBDevice[0].bConfigRead = false;
+ g_sUSBHCD.psUSBDevice[0].sDeviceDescriptor.bLength = 0;
+ g_sUSBHCD.psUSBDevice[0].sDeviceDescriptor.bMaxPacketSize0 = 0;
+ g_sUSBHCD.psUSBDevice[0].ui32Address = 0;
+ g_sUSBHCD.psUSBDevice[0].ui32Interface = 0;
+ g_sUSBHCD.pvPool = 0;
+ g_sUSBHCD.ui32PoolSize = 0;
+}
+
+//*****************************************************************************
+//
+//! This function generates reset signaling on the USB bus.
+//!
+//! \param ui32Index specifies which USB controller to use.
+//!
+//! This function handles sending out reset signaling on the USB bus. After
+//! returning from this function, any attached device on the USB bus should
+//! have returned to it's reset state.
+//!
+//! \return None.
+//
+//*****************************************************************************
+void
+USBHCDReset(uint32_t ui32Index)
+{
+ ASSERT(ui32Index == 0);
+
+ //
+ // Start the reset signaling.
+ //
+ MAP_USBHostReset(USB0_BASE, 1);
+
+ //
+ // Wait 20ms
+ //
+ OS_DELAY(g_ui32Tickms * 20);
+
+ //
+ // End reset signaling on the bus.
+ //
+ MAP_USBHostReset(USB0_BASE, 0);
+
+ //
+ // Need to wait at least 10ms to let the device recover from
+ // the reset. This is the delay specified in the USB 2.0 spec.
+ // We will hold the reset for 20ms.
+ //
+ OS_DELAY(g_ui32Tickms * 20);
+}
+
+//*****************************************************************************
+//
+//! This function will generate suspend signaling on the USB bus.
+//!
+//! \param ui32Index specifies which USB controller to use.
+//!
+//! This function is used to generate suspend signaling on the USB bus. In
+//! order to leave the suspended state, the application should call
+//! USBHCDResume().
+//!
+//! \return None.
+//
+//*****************************************************************************
+void
+USBHCDSuspend(uint32_t ui32Index)
+{
+ ASSERT(ui32Index == 0);
+
+ //
+ // Start the suspend signaling.
+ //
+ MAP_USBHostSuspend(USB0_BASE);
+}
+
+//*****************************************************************************
+//
+//! This function will generate resume signaling on the USB bus.
+//!
+//! \param ui32Index specifies which USB controller to use.
+//!
+//! This function is used to generate resume signaling on the USB bus in order
+//! to cause USB devices to leave their suspended state. This call should
+//! not be made unless a preceding call to USBHCDSuspend() has been made.
+//!
+//! \return None.
+//
+//*****************************************************************************
+void
+USBHCDResume(uint32_t ui32Index)
+{
+ ASSERT(ui32Index == 0);
+
+ //
+ // Start the resume signaling.
+ //
+ MAP_USBHostResume(USB0_BASE, 1);
+
+ //
+ // Wait 100ms
+ //
+ OS_DELAY(g_ui32Tickms * 100);
+
+ //
+ // End reset signaling on the bus.
+ //
+ MAP_USBHostResume(USB0_BASE, 0);
+}
+
+//*****************************************************************************
+//
+//! This function issues a request for the current configuration descriptor
+//! from a device.
+//!
+//! \param ui32Index specifies which USB controller to use.
+//! \param psDevice is a pointer to the device structure that holds the buffer
+//! to store the configuration descriptor.
+//!
+//! This function will request the configuration descriptor from the device.
+//! The \e psDevice->ConfigDescriptor member variable is used to hold the data
+//! for this request. This buffer will be allocated from the pool provided by
+//! the HCDInit() function. \e psDevice->sDeviceDescriptor.bMaxPacketSize0
+//! should be valid prior to this call in order to correctly receive the
+//! configuration descriptor. If this variable is not valid then this call
+//! will not return accurate data.
+//!
+//! \return The number of bytes returned due to the request. This value can be
+//! zero if the device did not respond.
+//
+//*****************************************************************************
+static uint32_t
+USBHCDGetConfigDescriptor(uint32_t ui32Index, tUSBHostDevice *psDevice)
+{
+ tUSBRequest sSetupPacket;
+ uint32_t ui32Bytes;
+ tConfigDescriptor sConfigDescriptor;
+
+ ASSERT(ui32Index == 0);
+
+ ui32Bytes = 0;
+
+ //
+ // This is a Standard Device IN request.
+ //
+ sSetupPacket.bmRequestType =
+ USB_RTYPE_DIR_IN | USB_RTYPE_STANDARD | USB_RTYPE_DEVICE;
+
+ //
+ // Request a Device Descriptor.
+ //
+ sSetupPacket.bRequest = USBREQ_GET_DESCRIPTOR;
+ sSetupPacket.wValue = USB_DTYPE_CONFIGURATION << 8;
+
+ //
+ // Index is always 0 for device configurations requests.
+ //
+ sSetupPacket.wIndex = 0;
+
+ //
+ // Only ask for the configuration header first to see how big the
+ // whole thing is.
+ //
+ if(!psDevice->bConfigRead)
+ {
+ //
+ // Only request the space available.
+ //
+ sSetupPacket.wLength = sizeof(tConfigDescriptor);
+
+ //
+ // Put the setup packet in the buffer.
+ //
+ ui32Bytes =
+ USBHCDControlTransfer(0, &sSetupPacket, psDevice,
+ (uint8_t *)&sConfigDescriptor,
+ sizeof(tConfigDescriptor),
+ psDevice->sDeviceDescriptor.bMaxPacketSize0);
+ }
+
+ //
+ // If the Configuration header was successfully returned then get the
+ // full configuration descriptor.
+ //
+ if(ui32Bytes == sizeof(tConfigDescriptor))
+ {
+ //
+ // Save the total size and request the full configuration descriptor.
+ //
+ sSetupPacket.wLength = sConfigDescriptor.wTotalLength;
+
+ //
+ // Not enough space to hold this configuration descriptor.
+ //
+ if(ConfigDescAlloc(psDevice, sConfigDescriptor.wTotalLength) == 0)
+ {
+ return(0);
+ }
+
+ //
+ // Don't allow the buffer to be larger than was allocated.
+ //
+ if(sSetupPacket.wLength > psDevice->ui32ConfigDescriptorSize)
+ {
+ return(0);
+ }
+
+ //
+ // Put the setup packet in the buffer.
+ //
+ ui32Bytes =
+ USBHCDControlTransfer(0, &sSetupPacket, psDevice,
+ (uint8_t *)psDevice->psConfigDescriptor,
+ sSetupPacket.wLength,
+ psDevice->sDeviceDescriptor.bMaxPacketSize0);
+
+ //
+ // If we read the descriptor, remember the fact.
+ //
+ if(ui32Bytes)
+ {
+ psDevice->bConfigRead = true;
+ }
+ }
+
+ return(ui32Bytes);
+}
+
+//*****************************************************************************
+//
+//! This function issues a request for a device descriptor from a device.
+//!
+//! \param ui32Index specifies which USB controller to use.
+//! \param psDevice is a pointer to the device structure that holds the buffer
+//! to store the device descriptor into.
+//!
+//! This function will request the device descriptor from the device. The
+//! \e psDevice->sDeviceDescriptor descriptor is used to hold the data for this
+//! request. \e psDevice->sDeviceDescriptor.bMaxPacketSize0 should be
+//! initialized to zero or to the valid maximum packet size if it is known. If
+//! this variable is not set to zero, then this call will determine the maximum
+//! packet size for endpoint 0 and save it in the structure member
+//! bMaxPacketSize0.
+//!
+//! \return The number of bytes returned due to the request. This value can be
+//! zero if the device did not respond.
+//
+//*****************************************************************************
+static uint32_t
+USBHCDGetDeviceDescriptor(uint32_t ui32Index, tUSBHostDevice *psDevice)
+{
+ tUSBRequest sSetupPacket;
+ uint32_t ui32Bytes;
+
+ ASSERT(ui32Index == 0);
+
+ //
+ // This is a Standard Device IN request.
+ //
+ sSetupPacket.bmRequestType =
+ USB_RTYPE_DIR_IN | USB_RTYPE_STANDARD | USB_RTYPE_DEVICE;
+
+ //
+ // Request a Device Descriptor.
+ //
+ sSetupPacket.bRequest = USBREQ_GET_DESCRIPTOR;
+ sSetupPacket.wValue = USB_DTYPE_DEVICE << 8;
+
+ //
+ // Index is always 0 for device requests.
+ //
+ sSetupPacket.wIndex = 0;
+
+ //
+ // All devices must have at least an 8 byte max packet size so just ask
+ // for 8 bytes to start with.
+ //
+ sSetupPacket.wLength = sizeof(tDeviceDescriptor);
+
+ ui32Bytes = 0;
+
+ //
+ // Discover the max packet size for endpoint 0.
+ //
+ if(psDevice->sDeviceDescriptor.bMaxPacketSize0 == 0)
+ {
+ //
+ // Put the setup packet in the buffer.
+ //
+ ui32Bytes =
+ USBHCDControlTransfer(ui32Index, &sSetupPacket, psDevice,
+ (uint8_t *)&(psDevice->sDeviceDescriptor),
+ sizeof(tDeviceDescriptor), 8);
+ }
+
+ //
+ // Now get the full descriptor now that the actual maximum packet size
+ // is known.
+ //
+ if(ui32Bytes < sizeof(tDeviceDescriptor))
+ {
+ sSetupPacket.wLength = (uint16_t)sizeof(tDeviceDescriptor);
+
+ ui32Bytes =
+ USBHCDControlTransfer(ui32Index, &sSetupPacket, psDevice,
+ (uint8_t *)&(psDevice->sDeviceDescriptor),
+ sizeof(tDeviceDescriptor),
+ psDevice->sDeviceDescriptor.bMaxPacketSize0);
+ }
+
+ return(ui32Bytes);
+}
+
+//*****************************************************************************
+//
+//! This function issues a request for a string descriptor from a device.
+//!
+//! \param psDevice is the device for this request.
+//! \param pui8Buffer is the pointer to the buffer to store the requested
+//! string descriptor.
+//! \param ui32Size is the size of the buffer passed in the buffer that will
+//! be used for this request.
+//! \param ui32LangID is the ID of the language for the requested string.
+//! \param ui32StringIndex is the index for the request.
+//!
+//! This function will request a string descriptor from the device of the type
+//! specified in the \e ui32DescriptorType parameter. The \e pui8Descriptor
+//! pointer is the location where the request results will be stored. The
+//! \e ui32Size should be passed in to indicate the size of the
+//! \e pui8Descriptor buffer. The \e ui32DevAddress parameter is used to
+//! specify the device address to communicate with on the USB bus. This value
+//! should be specified as 0 for any non-configured device on the USB bus and
+//! be changed to the address set by a call to USBHCDSetAddress().
+//!
+//! \return The number of bytes returned in the \e pui8Buffer due to the
+//! request. This value can be zero if the device did not respond.
+//
+//*****************************************************************************
+uint32_t
+USBHCDStringDescriptorGet(tUSBHostDevice *psDevice, uint8_t *pui8Buffer,
+ uint32_t ui32Size, uint32_t ui32LangID,
+ uint32_t ui32StringIndex)
+{
+ uint32_t ui32BytesReturned;
+ tUSBRequest sSetupPacket;
+
+ //
+ // Default the number of bytes to zero.
+ //
+ ui32BytesReturned = 0;
+
+ //
+ // This is a Standard Device IN request.
+ //
+ sSetupPacket.bmRequestType =
+ USB_RTYPE_DIR_IN | USB_RTYPE_STANDARD | USB_RTYPE_DEVICE;
+
+ //
+ // Request a Device Descriptor.
+ //
+ sSetupPacket.bRequest = USBREQ_GET_DESCRIPTOR;
+
+ //
+ // Request for a string descriptor.
+ //
+ sSetupPacket.wValue = (USB_DTYPE_STRING << 8) |
+ (uint16_t)ui32StringIndex;
+
+ //
+ // Set the language ID.
+ //
+ sSetupPacket.wIndex = ui32LangID;
+
+ //
+ // Only request the space available.
+ //
+ sSetupPacket.wLength = (uint16_t)ui32Size;
+
+ //
+ // Put the setup packet in the buffer.
+ //
+ ui32BytesReturned =
+ USBHCDControlTransfer(0, &sSetupPacket, psDevice, pui8Buffer, ui32Size,
+ psDevice->sDeviceDescriptor.bMaxPacketSize0);
+
+ //
+ // Return the number of bytes in the string.
+ //
+ return(ui32BytesReturned);
+}
+
+//*****************************************************************************
+//
+//! This function is used to send the set address command to a device.
+//!
+//! \param ui32DevIndex is the index of the device whose address is to be
+//! set. This value must be 0 to indicate that the device is connected
+//! directly to the host controller. Higher values indicate devices connected
+//! via a hub.
+//! \param ui32DevAddress is the new device address to use for a device.
+//!
+//! The USBHCDSetAddress() function is used to set the USB device address, once
+//! a device has been discovered on the bus. This call is typically issued
+//! following a USB reset triggered by a call the USBHCDReset(). The
+//! address passed into this function via the \e ui32DevAddress parameter is
+//! used for all further communications with the device after this function
+//! returns.
+//!
+//! \return None.
+//
+//*****************************************************************************
+void
+USBHCDSetAddress(uint32_t ui32DevIndex, uint32_t ui32DevAddress)
+{
+ tUSBRequest sSetupPacket;
+
+ //
+ // This is a Standard Device OUT request.
+ //
+ sSetupPacket.bmRequestType =
+ USB_RTYPE_DIR_OUT | USB_RTYPE_STANDARD | USB_RTYPE_DEVICE;
+
+ //
+ // Request a Device Descriptor.
+ //
+ sSetupPacket.bRequest = USBREQ_SET_ADDRESS;
+ sSetupPacket.wValue = ui32DevAddress;
+
+ //
+ // Index is always 0 for device requests.
+ //
+ sSetupPacket.wIndex = 0;
+
+ //
+ // Only request the space available.
+ //
+ sSetupPacket.wLength = 0;
+
+ //
+ // Put the setup packet in the buffer.
+ //
+ USBHCDControlTransfer(0, &sSetupPacket,
+ &g_sUSBHCD.psUSBDevice[ui32DevIndex], 0,
+ 0, MAX_PACKET_SIZE_EP0);
+
+ //
+ // Must delay 2ms after setting the address.
+ //
+ OS_DELAY(g_ui32Tickms * 2);
+}
+
+//*****************************************************************************
+//
+//! This function is used to send a Clear Feature request to a device.
+//!
+//! \param ui32DevAddress is the USB bus address of the device that will
+//! receive this request.
+//! \param ui32Pipe is the pipe that will be used to send the request.
+//! \param ui32Feature is one of the USB_FEATURE_* definitions.
+//!
+//! This function will issue a Clear Feature request to the device indicated
+//! by the \e ui32DevAddress parameter. The \e ui32Pipe parameter is the USB
+//! pipe that should be used to send this request. The \e ui32Feature
+//! parameter should be one of the following values:
+//!
+//! * \b USB_FEATURE_EP_HALT is used to end a HALT condition on a devices
+//! endpoint.
+//! * \b USB_FEATURE_REMOTE_WAKE is used to disable a device's remote wake
+//! feature.
+//! * \b USB_FEATURE_TEST_MODE is used take the USB device out of test mode.
+//!
+//! \return None.
+//
+//*****************************************************************************
+void
+USBHCDClearFeature(uint32_t ui32DevAddress, uint32_t ui32Pipe,
+ uint32_t ui32Feature)
+{
+ tUSBRequest sSetupPacket;
+ uint32_t ui32Index;
+
+ //
+ // Get the index number from the allocated pipe.
+ //
+ ui32Index = (ui32Pipe & EP_PIPE_IDX_M);
+
+ //
+ // This is a Standard Device OUT request.
+ //
+ sSetupPacket.bmRequestType =
+ USB_RTYPE_DIR_OUT | USB_RTYPE_STANDARD | USB_RTYPE_ENDPOINT;
+
+ //
+ // Request a Device Descriptor.
+ //
+ sSetupPacket.bRequest = USBREQ_CLEAR_FEATURE;
+ sSetupPacket.wValue = ui32Feature;
+
+ //
+ // Set the endpoint to access.
+ //
+ if(ui32Pipe & EP_PIPE_TYPE_IN)
+ {
+ sSetupPacket.wIndex = g_sUSBHCD.psUSBINPipes[ui32Index].ui8EPNumber |
+ 0x80;
+ }
+ else
+ {
+ sSetupPacket.wIndex = g_sUSBHCD.psUSBOUTPipes[ui32Index].ui8EPNumber;
+ }
+
+ //
+ // This is always 0.
+ //
+ sSetupPacket.wLength = 0;
+
+ //
+ // Put the setup packet in the buffer.
+ //
+ USBHCDControlTransfer(0, &sSetupPacket,
+ &g_sUSBHCD.psUSBDevice[ui32DevAddress - 1], 0, 0,
+ MAX_PACKET_SIZE_EP0);
+
+ //
+ // Set the endpoint to access.
+ //
+ if(ui32Pipe & EP_PIPE_TYPE_IN)
+ {
+ MAP_USBEndpointDataToggleClear(USB0_BASE,
+ IndexToUSBEP(ui32Index + 1),
+ USB_EP_HOST_IN);
+ }
+ else
+ {
+ MAP_USBEndpointDataToggleClear(USB0_BASE,
+ IndexToUSBEP(ui32Index + 1),
+ USB_EP_HOST_OUT);
+ }
+
+ //
+ // Must delay 2ms after clearing the feature.
+ //
+ OS_DELAY(g_ui32Tickms * 2);
+}
+
+//*****************************************************************************
+//
+//! This function is used to set the current configuration for a device.
+//!
+//! \param ui32Index specifies which USB controller to use.
+//! \param ui32Device is the USB device for this function.
+//! \param ui32Configuration is one of the devices valid configurations.
+//!
+//! This function is used to set the current device configuration for a USB
+//! device. The \e ui32Configuration value must be one of the configuration
+//! indexes that was returned in the configuration descriptor from the device,
+//! or a value of 0. If 0 is passed in, the device will return to it's
+//! addressed state and no longer be in a configured state. If the value is
+//! non-zero then the device will change to the requested configuration.
+//!
+//! \return None.
+//
+//*****************************************************************************
+void
+USBHCDSetConfig(uint32_t ui32Index, uint32_t ui32Device,
+ uint32_t ui32Configuration)
+{
+ tUSBRequest sSetupPacket;
+ tUSBHostDevice *psDevice;
+
+ ASSERT(ui32Index == 0);
+
+ psDevice = (tUSBHostDevice *)ui32Device;
+
+ //
+ // This is a Standard Device OUT request.
+ //
+ sSetupPacket.bmRequestType =
+ USB_RTYPE_DIR_OUT | USB_RTYPE_STANDARD | USB_RTYPE_DEVICE;
+
+ //
+ // Request a Device Descriptor.
+ //
+ sSetupPacket.bRequest = USBREQ_SET_CONFIG;
+ sSetupPacket.wValue = ui32Configuration;
+
+ //
+ // Index is always 0 for device requests.
+ //
+ sSetupPacket.wIndex = 0;
+
+ //
+ // Only request the space available.
+ //
+ sSetupPacket.wLength = 0;
+
+ //
+ // Put the setup packet in the buffer.
+ //
+ USBHCDControlTransfer(0, &sSetupPacket, psDevice, 0, 0,
+ MAX_PACKET_SIZE_EP0);
+}
+
+//*****************************************************************************
+//
+//! This function is used to set the current interface and alternate setting
+//! for an interface on a device.
+//!
+//! \param ui32Index specifies which USB controller to use.
+//! \param ui32Device is the USB device for this function.
+//! \param ui32Interface is one of the valid interface numbers for a device.
+//! \param ui32AltSetting is one of the valid alternate interfaces for the
+//! \e ui32Interface number.
+//!
+//! This function is used to change the alternate setting for one of the valid
+//! interfaces on a USB device. The \e ui32Device specifies the device
+//! instance that was returned when the device was connected. This call will
+//! set the USB device's interface based on the \e ui32Interface and
+//! \e ui32AltSetting.
+//!
+//! \b Example: Set the USB device interface 2 to alternate setting 1.
+//!
+//! \verbatim
+//! USBHCDSetInterface(0, ui32Device, 2, 1);
+//! \endverbatim
+//!
+//! \return None.
+//
+//*****************************************************************************
+void
+USBHCDSetInterface(uint32_t ui32Index, uint32_t ui32Device,
+ uint32_t ui32Interface, uint32_t ui32AltSetting)
+{
+ tUSBRequest sSetupPacket;
+ tUSBHostDevice *psDevice;
+
+ ASSERT(ui32Index == 0);
+
+ psDevice = (tUSBHostDevice *)ui32Device;
+
+ //
+ // This is a Standard Device OUT request.
+ //
+ sSetupPacket.bmRequestType =
+ USB_RTYPE_DIR_OUT | USB_RTYPE_STANDARD | USB_RTYPE_INTERFACE;
+
+ //
+ // Request a Device Descriptor.
+ //
+ sSetupPacket.bRequest = USBREQ_SET_INTERFACE;
+
+ //
+ // Index is the interface to access.
+ //
+ sSetupPacket.wIndex = ui32Interface;
+
+ //
+ // wValue is the alternate setting.
+ //
+ sSetupPacket.wValue = ui32AltSetting;
+
+
+ //
+ // Only request the space available.
+ //
+ sSetupPacket.wLength = 0;
+
+ //
+ // Put the setup packet in the buffer.
+ //
+ USBHCDControlTransfer(0, &sSetupPacket, psDevice, 0, 0,
+ MAX_PACKET_SIZE_EP0);
+}
+
+//*****************************************************************************
+//
+// The internal function to see if a new schedule event should occur.
+//
+// This function is called by the main interrupt handler due to start of frame
+// interrupts to determine if a new scheduler event should be sent to the USB
+// pipe.
+//
+// \return None.
+//
+//*****************************************************************************
+void
+USBHostCheckPipes(void)
+{
+ int32_t i32Idx;
+
+ g_ui32CurrentTick++;
+
+ for(i32Idx = 0; i32Idx < g_sUSBHCD.ui32NumEndpoints; i32Idx++)
+ {
+ //
+ // Skip unused pipes.
+ //
+ if(g_sUSBHCD.psUSBINPipes[i32Idx].ui32Type == USBHCD_PIPE_UNUSED)
+ {
+ continue;
+ }
+
+ //
+ // If the tick has expired and it has an interval then update it.
+ //
+ if((g_sUSBHCD.psUSBINPipes[i32Idx].ui32Interval != 0) &&
+ (g_sUSBHCD.psUSBINPipes[i32Idx].ui32NextEventTick ==
+ g_ui32CurrentTick))
+ {
+ //
+ // Schedule the next event.
+ //
+ g_sUSBHCD.psUSBINPipes[i32Idx].ui32NextEventTick +=
+ g_sUSBHCD.psUSBINPipes[i32Idx].ui32Interval;
+
+ //
+ // If the pipe is IDLE and there is a callback, let the higher
+ // level drivers know that a new transfer can be scheduled.
+ //
+ if((g_sUSBHCD.psUSBINPipes[i32Idx].iState == ePipeIdle) &&
+ (g_sUSBHCD.psUSBINPipes[i32Idx].pfnCallback))
+ {
+ g_sUSBHCD.psUSBINPipes[i32Idx].pfnCallback(
+ IN_PIPE_HANDLE(i32Idx),
+ USB_EVENT_SCHEDULER);
+ }
+ }
+ }
+}
+
+//*****************************************************************************
+//
+// The internal USB host mode interrupt handler.
+//
+// \param ui32Index is the USB controller associated with this interrupt.
+// \param ui32Status is the current interrupt status as read via a call to
+// \e USBIntStatusControl().
+//
+// This the main USB interrupt handler called when operating in host mode.
+// This handler will branch the interrupt off to the appropriate handlers
+// depending on the current status of the USB controller.
+//
+// The two-tiered structure for the interrupt handler ensures that it is
+// possible to use the same handler code in both host and OTG modes and
+// means that device code can be excluded from applications that only require
+// support for USB host mode operation.
+//
+// \return None.
+//
+//*****************************************************************************
+void
+USBHostIntHandlerInternal(uint32_t ui32Index, uint32_t ui32Status)
+{
+ uint32_t ui32EPStatus, ui32DMAIntStatus, ui32Idx, ui32DevIndex;
+ static uint32_t ui32SOFDivide = 0;
+ int32_t i32ClassDrvr;
+
+ //
+ // By default, assume we are dealing with the device directly connected
+ // to the host controller and that we need to notify its class driver of
+ // this interrupt.
+ //
+ g_sUSBHCD.psUSBDevice[0].ui32Flags |= USBHDEV_FLAG_NOTIFYINT;
+
+ if(ui32Status & USB_INTCTRL_SOF)
+ {
+ //
+ // Indicate that a start of frame has occurred.
+ //
+ g_sUSBHCD.ui32IntEvents |= INT_EVENT_SOF;
+ }
+
+ //
+ // A power fault has occurred so notify the application.
+ //
+ if(ui32Status & USB_INTCTRL_POWER_FAULT)
+ {
+ //
+ // Indicate that a power fault has occurred.
+ //
+ g_sUSBHCD.ui32IntEvents |= INT_EVENT_POWER_FAULT;
+
+ //
+ // Turn off power to the bus.
+ //
+ MAP_USBHostPwrDisable(USB0_BASE);
+
+ //
+ // Disable USB interrupts.
+ //
+ OS_INT_DISABLE(g_sUSBHCD.ui32IntNum);
+
+ return;
+ }
+
+ //
+ // In the event of a USB VBUS error, end the session and remove power to
+ // the device.
+ //
+ if(ui32Status & USB_INTCTRL_VBUS_ERR)
+ {
+ //
+ // Set the VBUS error event. We deliberately clear all other events
+ // since this one means anything else that is outstanding is
+ // irrelevant.
+ //
+ g_sUSBHCD.ui32IntEvents = INT_EVENT_VBUS_ERR;
+ return;
+ }
+
+ //
+ // Received a reset from the host.
+ //
+ if(ui32Status & USB_INTCTRL_BABBLE)
+ {
+ }
+
+ //
+ // Suspend was signaled on the bus.
+ //
+ if(ui32Status & USB_INTCTRL_SUSPEND)
+ {
+ }
+
+ //
+ // Start the session.
+ //
+ if(ui32Status & USB_INTCTRL_SESSION)
+ {
+ //
+ // Power the USB bus.
+ //
+ MAP_USBHostPwrEnable(USB0_BASE);
+
+ USBOTGSessionRequest(USB0_BASE, true);
+ }
+
+ //
+ // Resume was signaled on the bus.
+ //
+ if(ui32Status & USB_INTCTRL_RESUME)
+ {
+ }
+
+ //
+ // Device connected so tell the main routine to issue a reset.
+ //
+ if(ui32Status & USB_INTCTRL_CONNECT)
+ {
+ //
+ // Set the connect flag and clear disconnect if it happens to be set.
+ //
+ g_sUSBHCD.ui32IntEvents |= INT_EVENT_CONNECT;
+ g_sUSBHCD.ui32IntEvents &= ~INT_EVENT_DISCONNECT;
+
+ //
+ // Power the USB bus.
+ //
+ MAP_USBHostPwrEnable(USB0_BASE);
+ }
+
+ //
+ // Handle the ID detection so that the ID pin can be used as a
+ // GPIO in eUSBModeHost.
+ //
+ if(ui32Status & USB_INTCTRL_MODE_DETECT)
+ {
+ //
+ // If in eUSBModeHost mode then switch back to OTG detection
+ // so that VBUS can be monitored but free up the ID pin.
+ //
+ if(g_iUSBMode == eUSBModeHost)
+ {
+ USBOTGMode(USB0_BASE);
+ }
+ }
+
+ //
+ // Device was unplugged.
+ //
+ if(ui32Status & USB_INTCTRL_DISCONNECT)
+ {
+ //
+ // Set the disconnect flag and clear connect if it happens to be set.
+ //
+ g_sUSBHCD.ui32IntEvents |= INT_EVENT_DISCONNECT;
+ g_sUSBHCD.ui32IntEvents &= ~INT_EVENT_CONNECT;
+ }
+
+ //
+ // Start of Frame was received.
+ //
+ if(ui32Status & USB_INTCTRL_SOF)
+ {
+ //
+ // Increment the global Start of Frame counter.
+ //
+ g_ui32USBSOFCount++;
+
+ //
+ // Increment our SOF divider.
+ //
+ ui32SOFDivide++;
+
+ //
+ // Have we counted enough SOFs to allow us to call the tick function?
+ //
+ if(ui32SOFDivide == USB_SOF_TICK_DIVIDE)
+ {
+ //
+ // Yes - reset the divider and call the SOF tick handler.
+ //
+ ui32SOFDivide = 0;
+ InternalUSBStartOfFrameTick(USB_SOF_TICK_DIVIDE);
+ }
+ }
+
+ //
+ // Handle the LPM interrupt
+ //
+ ui32Status = USBLPMIntStatus(USB0_BASE);
+
+ if(ui32Status)
+ {
+ //
+ // Set the LPM interrupt event and clear the pending event.
+ //
+ g_sUSBHCD.ui32IntEvents |= INT_EVENT_LPM;
+ g_sUSBHCD.ui32IntEvents &= ~INT_EVENT_LPM_PEND;
+
+ //
+ // Anything other than and acknowledge means that the transfer
+ // was not complete for some reason.
+ //
+ for(ui32Idx = 0; ui32Idx < (MAX_USB_DEVICES + 1); ui32Idx++)
+ {
+ if((ui32Status != USB_INTLPM_ACK) &&
+ (g_sUSBHCD.psUSBDevice[ui32Idx].ui32Flags &
+ USBHDEV_FLAG_LPMPEND))
+ {
+ g_sUSBHCD.psUSBDevice[ui32Idx].ui32Flags |=
+ USBHDEV_FLAG_LPMERROR;
+ }
+ g_sUSBHCD.psUSBDevice[ui32Idx].ui32Flags &= ~USBHDEV_FLAG_LPMPEND;
+ }
+ }
+
+ //
+ // Check to see if any DMA transfers are pending
+ //
+ ui32DMAIntStatus = USBLibDMAIntStatus(g_sUSBHCD.psDMAInstance);
+
+ if(ui32DMAIntStatus)
+ {
+ //
+ // Handle any DMA interrupt processing.
+ //
+ USBLibDMAIntHandler(g_sUSBHCD.psDMAInstance, ui32DMAIntStatus);
+
+ for(ui32Idx = 0; ui32Idx < MAX_NUM_PIPES; ui32Idx++)
+ {
+ if((g_sUSBHCD.psUSBINPipes[ui32Idx].iState == ePipeReadDMAWait) ||
+ (g_sUSBHCD.psUSBINPipes[ui32Idx].iState == ePipeReadDMA))
+ {
+ //
+ // If the DMA channel transfer is complete, send an ack.
+ //
+ if(USBLibDMAChannelStatus(g_sUSBHCD.psDMAInstance,
+ g_sUSBHCD.psUSBINPipes[ui32Idx].ui8DMAChannel) ==
+ USBLIBSTATUS_DMA_COMPLETE)
+ {
+ //
+ // Acknowledge the IN request.
+ //
+ MAP_USBHostEndpointDataAck(USB0_BASE,
+ IndexToUSBEP(ui32Idx + 1));
+
+ //
+ // If using uDMA then the endpoint status interrupt will
+ // not occur. So process the data ready event here.
+ //
+ g_sUSBHCD.psUSBINPipes[ui32Idx].iState = ePipeDataReady;
+
+ //
+ // Only call a handler if one is present.
+ //
+ if(g_sUSBHCD.psUSBINPipes[ui32Idx].pfnCallback)
+ {
+ g_sUSBHCD.psUSBINPipes[ui32Idx].pfnCallback(
+ IN_PIPE_HANDLE(ui32Idx), USB_EVENT_RX_AVAILABLE);
+ }
+
+ //
+ // Remember that we need to notify this device's class
+ // driver that an interrupt occurred.
+ //
+ g_sUSBHCD.psUSBINPipes[ui32Idx].psDevice->ui32Flags |=
+ USBHDEV_FLAG_NOTIFYINT;
+ }
+ }
+ else if(g_sUSBHCD.psUSBOUTPipes[ui32Idx].iState ==
+ ePipeWriteDMASend)
+ {
+ //
+ // If the uDMA channel transfer is complete, then tell
+ // the USB controller to go ahead and send the data
+ //
+ if(USBLibDMAChannelStatus(g_sUSBHCD.psDMAInstance,
+ g_sUSBHCD.psUSBOUTPipes[ui32Idx].ui8DMAChannel) &
+ USBLIBSTATUS_DMA_COMPLETE)
+ {
+ MAP_USBEndpointDataSend(USB0_BASE,
+ IndexToUSBEP(ui32Idx + 1),
+ USB_TRANS_OUT);
+
+ //
+ // Now waiting on the final endpoint interrupt.
+ //
+ g_sUSBHCD.psUSBOUTPipes[ui32Idx].iState =
+ ePipeWriteDMAWait;
+ }
+ }
+ else if(g_sUSBHCD.psUSBOUTPipes[ui32Idx].iState == ePipeWriteDMA)
+ {
+ //
+ // Data was transmitted successfully.
+ //
+ g_sUSBHCD.psUSBOUTPipes[ui32Idx].iState = ePipeDataSent;
+
+ //
+ // Only call a handler if one is present.
+ //
+ if(g_sUSBHCD.psUSBOUTPipes[ui32Idx].pfnCallback)
+ {
+ //
+ // Notify the pipe that its last transaction was completed.
+ //
+ g_sUSBHCD.psUSBOUTPipes[ui32Idx].pfnCallback(
+ OUT_PIPE_HANDLE(ui32Idx),
+ USB_EVENT_TX_COMPLETE);
+ }
+ }
+ }
+ }
+
+ //
+ // Get the current endpoint interrupt status.
+ //
+ ui32Status = MAP_USBIntStatusEndpoint(USB0_BASE);
+
+ //
+ // Handle end point 0 interrupts.
+ //
+ if(ui32Status & USB_INTEP_0)
+ {
+ //
+ // Indicate that a start of frame has occurred.
+ //
+ g_sUSBHCD.ui32IntEvents |= INT_EVENT_ENUM;
+ }
+
+ for(ui32Idx = 0; ui32Idx < MAX_NUM_PIPES; ui32Idx++)
+ {
+ //
+ // Check the next pipe, the first time through this will clear out
+ // any interrupts dealing with endpoint zero since it was handled
+ // above.
+ //
+ ui32Status >>= 1;
+
+ //
+ // Break out if there are no more pending interrupts.
+ //
+ if(ui32Status == 0)
+ {
+ break;
+ }
+
+ //
+ // Check the status of the receive(IN) pipes.
+ //
+ if(ui32Status & 0x10000)
+ {
+ //
+ // Clear the status flag for the IN Pipe.
+ //
+ ui32Status &= ~0x10000;
+
+ //
+ // Read the status of the endpoint connected to this pipe.
+ //
+ ui32EPStatus = MAP_USBEndpointStatus(USB0_BASE,
+ IndexToUSBEP(ui32Idx + 1));
+
+ //
+ // Check if the device stalled the request.
+ //
+ if(ui32EPStatus & USB_HOST_IN_STALL)
+ {
+ //
+ // Clear the stall condition on this endpoint pipe.
+ //
+ MAP_USBHostEndpointStatusClear(USB0_BASE,
+ IndexToUSBEP(ui32Idx + 1),
+ USB_HOST_IN_STALL);
+
+ //
+ // Save the STALLED state.
+ //
+ g_sUSBHCD.psUSBINPipes[ui32Idx].iState = ePipeStalled;
+
+ //
+ // Notify the pipe that it was stalled.
+ //
+ if(g_sUSBHCD.psUSBINPipes[ui32Idx].pfnCallback)
+ {
+ g_sUSBHCD.psUSBINPipes[ui32Idx].pfnCallback(
+ IN_PIPE_HANDLE(ui32Idx),
+ USB_EVENT_STALL);
+ }
+ }
+ else if(ui32EPStatus & USB_HOST_IN_ERROR)
+ {
+ //
+ // We can no longer communicate with this device for some
+ // reason. It may have been disconnected from a hub, for
+ // example. Merely clear the status and continue.
+ //
+ USBHostEndpointStatusClear(USB0_BASE,
+ IndexToUSBEP(ui32Idx + 1),
+ USB_HOST_IN_ERROR);
+
+ //
+ // Save the STALLED state.
+ //
+ g_sUSBHCD.psUSBINPipes[ui32Idx].iState = ePipeError;
+
+ //
+ // Notify the pipe that it was stalled.
+ //
+ if(g_sUSBHCD.psUSBINPipes[ui32Idx].pfnCallback)
+ {
+ g_sUSBHCD.psUSBINPipes[ui32Idx].pfnCallback(
+ IN_PIPE_HANDLE(ui32Idx),
+ USB_EVENT_ERROR);
+ }
+ }
+ //
+ // Handle the case where the pipe is reading a single packet.
+ //
+ else if(g_sUSBHCD.psUSBINPipes[ui32Idx].iState == ePipeReadDMA)
+ {
+ void *pvAddr;
+
+ //
+ // Enable the DMA channel and wait for it to complete.
+ //
+ g_sUSBHCD.psUSBINPipes[ui32Idx].iState = ePipeReadDMAWait;
+
+ pvAddr = USBLibDMAAddrGet(g_sUSBHCD.psDMAInstance,
+ g_sUSBHCD.psUSBINPipes[ui32Idx].ui8DMAChannel);
+
+ //
+ // Save the amount of data available.
+ //
+ g_sUSBHCD.psUSBINPipes[ui32Idx].ui32DataRead =
+ USBEndpointDataAvail(USB0_BASE,
+ IndexToUSBEP(ui32Idx + 1));
+
+ //
+ // Only request what is available.
+ //
+ if(g_sUSBHCD.psUSBINPipes[ui32Idx].ui32DataRead <=
+ g_sUSBHCD.psUSBINPipes[ui32Idx].ui32ReadSize)
+ {
+ //
+ // Reset the transfer size.
+ //
+ USBLibDMATransfer(g_sUSBHCD.psDMAInstance,
+ g_sUSBHCD.psUSBINPipes[ui32Idx].ui8DMAChannel,
+ pvAddr,
+ g_sUSBHCD.psUSBINPipes[ui32Idx].ui32DataRead);
+ }
+ else
+ {
+ //
+ // The transfer size did not change, this leaves some
+ // data in the FIFO.
+ //
+ g_sUSBHCD.psUSBINPipes[ui32Idx].ui32DataRead =
+ g_sUSBHCD.psUSBINPipes[ui32Idx].ui32ReadSize;
+ }
+
+ USBLibDMAChannelEnable(
+ g_sUSBHCD.psDMAInstance,
+ g_sUSBHCD.psUSBINPipes[ui32Idx].ui8DMAChannel);
+ }
+ else if(g_sUSBHCD.psUSBINPipes[ui32Idx].iState == ePipeReading)
+ {
+ //
+ // Data is available.
+ //
+ g_sUSBHCD.psUSBINPipes[ui32Idx].iState = ePipeDataReady;
+
+ //
+ // Read the data out of the USB endpoint interface into the
+ // buffer provided by the caller to USBHCDPipeRead() or
+ // USBHCDPipeSchedule() if a buffer was provided already.
+ //
+ if(g_sUSBHCD.psUSBINPipes[ui32Idx].pui8ReadPtr)
+ {
+ g_sUSBHCD.psUSBINPipes[ui32Idx].ui32DataRead =
+ g_sUSBHCD.psUSBINPipes[ui32Idx].ui32ReadSize;
+
+ USBEndpointDataGet(USB0_BASE, IndexToUSBEP(ui32Idx + 1),
+ g_sUSBHCD.psUSBINPipes[ui32Idx].pui8ReadPtr,
+ &g_sUSBHCD.psUSBINPipes[ui32Idx].ui32DataRead);
+ }
+
+ //
+ // Notify the pipe that its last transaction was completed.
+ //
+ if(g_sUSBHCD.psUSBINPipes[ui32Idx].pfnCallback)
+ {
+ g_sUSBHCD.psUSBINPipes[ui32Idx].pfnCallback(
+ IN_PIPE_HANDLE(ui32Idx),
+ USB_EVENT_RX_AVAILABLE);
+ }
+
+ }
+
+ //
+ // Remember that we need to notify this device's class
+ // driver that an interrupt occurred.
+ //
+ g_sUSBHCD.psUSBINPipes[ui32Idx].psDevice->ui32Flags |=
+ USBHDEV_FLAG_NOTIFYINT;
+ }
+
+ //
+ // Check the status of the transmit(OUT) pipes.
+ //
+ if(ui32Status & 1)
+ {
+ //
+ // Read the status of the endpoint connected to this pipe.
+ //
+ ui32EPStatus = MAP_USBEndpointStatus(USB0_BASE,
+ IndexToUSBEP(ui32Idx + 1));
+
+ //
+ // Check if the device stalled the request.
+ //
+ if(ui32EPStatus & USB_HOST_OUT_STALL)
+ {
+ //
+ // Clear the stall condition on this endpoint pipe.
+ //
+ MAP_USBHostEndpointStatusClear(USB0_BASE,
+ IndexToUSBEP(ui32Idx + 1),
+ USB_HOST_OUT_STALL);
+
+ //
+ // Save the STALLED state.
+ //
+ g_sUSBHCD.psUSBOUTPipes[ui32Idx].iState = ePipeStalled;
+
+ //
+ // Only call a handler if one is present.
+ //
+ if(g_sUSBHCD.psUSBOUTPipes[ui32Idx].pfnCallback)
+ {
+ //
+ // Notify the pipe that it was stalled.
+ //
+ g_sUSBHCD.psUSBOUTPipes[ui32Idx].pfnCallback(
+ OUT_PIPE_HANDLE(ui32Idx),
+ USB_EVENT_STALL);
+ }
+ }
+ else if(ui32EPStatus & USB_HOST_OUT_ERROR)
+ {
+ //
+ // Clear the error condition on this endpoint pipe.
+ //
+ MAP_USBHostEndpointStatusClear(USB0_BASE,
+ IndexToUSBEP(ui32Idx + 1),
+ USB_HOST_OUT_ERROR);
+
+ //
+ // Save the Pipes error state.
+ //
+ g_sUSBHCD.psUSBOUTPipes[ui32Idx].iState = ePipeError;
+
+ //
+ // Only call a handler if one is present.
+ //
+ if(g_sUSBHCD.psUSBOUTPipes[ui32Idx].pfnCallback)
+ {
+ //
+ // Notify the pipe that had an error.
+ //
+ g_sUSBHCD.psUSBOUTPipes[ui32Idx].pfnCallback(
+ OUT_PIPE_HANDLE(ui32Idx),
+ USB_EVENT_ERROR);
+ }
+ }
+ else if((g_sUSBHCD.psUSBOUTPipes[ui32Idx].iState ==
+ ePipeWriting) ||
+ (g_sUSBHCD.psUSBOUTPipes[ui32Idx].iState ==
+ ePipeWriteDMAWait))
+ {
+ //
+ // Data was transmitted successfully.
+ //
+ g_sUSBHCD.psUSBOUTPipes[ui32Idx].iState = ePipeDataSent;
+
+ //
+ // Only call a handler if one is present.
+ //
+ if(g_sUSBHCD.psUSBOUTPipes[ui32Idx].pfnCallback)
+ {
+ //
+ // Notify the pipe that its last transaction was completed.
+ //
+ g_sUSBHCD.psUSBOUTPipes[ui32Idx].pfnCallback(
+ OUT_PIPE_HANDLE(ui32Idx),
+ USB_EVENT_TX_COMPLETE);
+ }
+ }
+
+ //
+ // Clear the stall condition on this endpoint pipe.
+ //
+ MAP_USBHostEndpointStatusClear(USB0_BASE,
+ IndexToUSBEP(ui32Idx + 1),
+ ui32EPStatus & USB_HOST_OUT_STATUS);
+ //
+ // Remember that we need to notify this device's class
+ // driver that an interrupt occurred.
+ //
+ if(g_sUSBHCD.psUSBOUTPipes[ui32Idx].psDevice)
+ {
+ g_sUSBHCD.psUSBINPipes[ui32Idx].psDevice->ui32Flags |=
+ USBHDEV_FLAG_NOTIFYINT;
+ }
+ }
+ }
+
+ //
+ // Send back notifications to any class driver whose endpoint required
+ // service during the handler.
+ //
+ for(ui32DevIndex = 0; ui32DevIndex <= MAX_USB_DEVICES; ui32DevIndex++)
+ {
+ //
+ // Which class driver does this device use?
+ //
+ i32ClassDrvr = g_pi32USBHActiveDriver[ui32DevIndex];
+
+ //
+ // If a class driver is in use, and one of its endpoints was serviced
+ // and the class driver has an interrupt callback...
+ //
+ if((i32ClassDrvr >= 0) &&
+ (g_sUSBHCD.psUSBDevice[ui32DevIndex].ui32Flags &
+ USBHDEV_FLAG_NOTIFYINT) &&
+ (g_sUSBHCD.ppsClassDrivers[i32ClassDrvr]->pfnIntHandler))
+ {
+ //
+ // ...call the class driver's interrupt notification callback.
+ //
+ g_sUSBHCD.ppsClassDrivers[i32ClassDrvr]->pfnIntHandler(
+ g_ppvDriverInstance[ui32DevIndex]);
+ }
+ }
+}
+
+//*****************************************************************************
+//
+//! The USB host mode interrupt handler for controller index 0.
+//!
+//! This the main USB interrupt handler entry point. This handler will branch
+//! the interrupt off to the appropriate handlers depending on the current
+//! status of the USB controller. This function must be placed in the
+//! interrupt table in order for the USB Library host stack to function.
+//!
+//! \return None.
+//
+//*****************************************************************************
+void
+USB0HostIntHandler(void)
+{
+ uint32_t ui32Status;
+
+ //
+ // Get the control interrupt status.
+ //
+ ui32Status = MAP_USBIntStatusControl(USB0_BASE);
+
+ //
+ // Call the internal handler to process the interrupts.
+ //
+ USBHostIntHandlerInternal(0, ui32Status);
+}
+
+//*****************************************************************************
+//
+//! This function opens the class driver.
+//!
+//! \param ui32Index specifies which USB controller to use.
+//! \param ui32DeviceNum is the device number for the driver to load.
+//!
+//! This function opens the driver needed based on the class value found in
+//! the device's interface descriptor.
+//!
+//! \return This function returns -1 if no driver is found, or it returns the
+//! index of the driver found in the list of host class drivers.
+//
+//*****************************************************************************
+static int32_t
+USBHCDOpenDriver(uint32_t ui32Index, uint32_t ui32DeviceNum)
+{
+ int32_t i32Driver;
+ uint32_t ui32Class;
+ tInterfaceDescriptor *psInterface;
+ tEventInfo sEvent;
+
+ ASSERT(ui32Index == 0);
+
+ //
+ // Get the interface descriptor.
+ //
+ psInterface = USBDescGetInterface(
+ g_sUSBHCD.psUSBDevice[ui32DeviceNum].psConfigDescriptor,
+ g_sUSBHCD.psUSBDevice[ui32DeviceNum].ui32Interface,
+ USB_DESC_ANY);
+
+ //
+ // Read the interface class.
+ //
+ ui32Class = psInterface->bInterfaceClass;
+
+ //
+ // Search through the Host Class driver list for the devices class.
+ //
+ for(i32Driver = 0; i32Driver < g_sUSBHCD.ui32NumClassDrivers; i32Driver++)
+ {
+ //
+ // If a driver was found call the open for this driver and save which
+ // driver is in use.
+ //
+ if(g_sUSBHCD.ppsClassDrivers[i32Driver]->ui32InterfaceClass ==
+ ui32Class)
+ {
+ //
+ // Call the open function for the class driver.
+ //
+ g_ppvDriverInstance[ui32DeviceNum] =
+ g_sUSBHCD.ppsClassDrivers[i32Driver]->pfnOpen(
+ &g_sUSBHCD.psUSBDevice[ui32DeviceNum]);
+
+ //
+ // If the driver was successfully loaded then break out of the
+ // loop.
+ //
+ if(g_ppvDriverInstance[ui32DeviceNum] != 0)
+ {
+ break;
+ }
+ }
+ }
+
+ //
+ // If no drivers were found then return -1 to indicate an invalid
+ // driver instance.
+ //
+ if(i32Driver == g_sUSBHCD.ui32NumClassDrivers)
+ {
+ //
+ // Send an unknown connection event.
+ //
+ SendUnknownConnect(ui32Index, (ui32Index << 16) | ui32DeviceNum);
+
+ //
+ // Indicate that no driver was found.
+ //
+ i32Driver = -1;
+ }
+ else
+ {
+ //
+ // If the connect event is enabled then send the event.
+ //
+ sEvent.ui32Event = USB_EVENT_CONNECTED;
+ sEvent.ui32Instance = (ui32Index << 16) | ui32DeviceNum;
+ InternalUSBHCDSendEvent(0, &sEvent, USBHCD_EVFLAG_CONNECT);
+ }
+
+ return(i32Driver);
+}
+
+//*****************************************************************************
+//
+// This function will send an event to a registered event driver.
+//
+// \param ui32Index specifies which USB controller to use.
+// \param psEvent is a pointer to the event structure to send.
+//
+// This function is only used internally to the USB library and will check
+// if an event driver is registered and send on the event.
+//
+// Note: This function should not be called outside of the USB library.
+//
+// \return None.
+//
+//*****************************************************************************
+void
+InternalUSBHCDSendEvent(uint32_t ui32Index, tEventInfo *psEvent,
+ uint32_t ui32EvFlag)
+{
+ //
+ // Make sure that an event driver has been registered.
+ //
+ if((g_sUSBHCD.i32EventDriver != -1) &&
+ (g_sUSBHCD.ppsClassDrivers[g_sUSBHCD.i32EventDriver]->pfnIntHandler) &&
+ (g_sUSBHCD.ui32EventEnables & ui32EvFlag))
+ {
+ g_sUSBHCD.ppsClassDrivers[g_sUSBHCD.i32EventDriver]->pfnIntHandler(
+ psEvent);
+ }
+}
+
+//*****************************************************************************
+//
+// This function handles the necessary clean up for device disconnect.
+//
+// \param ui32Index is the device number for the device that was disconnected.
+//
+// This function handles all of the necessary clean up after a device
+// disconnect has been detected by the stack. This includes calling back the
+// appropriate driver if necessary.
+//
+// \return None.
+//
+//*****************************************************************************
+static void
+USBHCDDeviceDisconnected(uint32_t ui32Index, uint32_t ui32DevIndex)
+{
+ tEventInfo sEvent;
+
+ ASSERT(ui32Index == 0);
+ ASSERT(ui32DevIndex <= MAX_USB_DEVICES);
+
+ //
+ // If there is an event driver with a valid event handler and the
+ // USBHCD_EVFLAG_DISCNCT is enabled, then call the registered event
+ // handler.
+ //
+ sEvent.ui32Event = USB_EVENT_DISCONNECTED;
+ sEvent.ui32Instance = (ui32Index << 16) | ui32DevIndex;
+ InternalUSBHCDSendEvent(0, &sEvent, USBHCD_EVFLAG_DISCNCT);
+
+ //
+ // Reset the class.
+ //
+ g_sUSBHCD.ui32Class = USB_CLASS_EVENTS;
+
+ //
+ // Free the memory used by the configuration descriptor.
+ //
+ ConfigDescFree(&g_sUSBHCD.psUSBDevice[ui32DevIndex]);
+
+ g_sUSBHCD.psUSBDevice[ui32DevIndex].ui32Flags = 0;
+ g_sUSBHCD.psUSBDevice[ui32DevIndex].bConfigRead = false;
+
+ //
+ // Reset the max packet size so that this will be re-read from new devices.
+ //
+ g_sUSBHCD.psUSBDevice[ui32DevIndex].sDeviceDescriptor.bMaxPacketSize0 = 0;
+
+ //
+ // No longer have a device descriptor.
+ //
+ g_sUSBHCD.psUSBDevice[ui32DevIndex].sDeviceDescriptor.bLength = 0;
+
+ //
+ // No longer addressed.
+ //
+ g_sUSBHCD.psUSBDevice[ui32DevIndex].ui32Address = 0;
+
+ //
+ // If this was an active driver then close it out.
+ //
+ if(g_pi32USBHActiveDriver[ui32DevIndex] >= 0)
+ {
+ //
+ // Call the driver Close entry point.
+ //
+ g_sUSBHCD.ppsClassDrivers[g_pi32USBHActiveDriver[ui32DevIndex]]->
+ pfnClose(g_ppvDriverInstance[ui32DevIndex]);
+
+ //
+ // No active driver now present.
+ //
+ g_pi32USBHActiveDriver[ui32DevIndex] = -1;
+ g_ppvDriverInstance[ui32DevIndex] = 0;
+ }
+
+ //
+ // This call is necessary for OTG controllers to know that the host
+ // stack has completed handling the disconnect of the device before
+ // removing power and returning to a state that can allow OTG
+ // negotiations once again.
+ // We only do this if the disconnected device
+ // was attached directly to us (device index 0).
+ //
+ if((ui32DevIndex == 0) && (g_iUSBMode == eUSBModeOTG))
+ {
+ OTGDeviceDisconnect(0);
+ }
+}
+
+//*****************************************************************************
+//
+//! This function is the main routine for the Host Controller Driver.
+//!
+//! This function is the main routine for the host controller driver, and must
+//! be called periodically by the main application outside of a callback
+//! context. This allows for a simple cooperative system to access the the
+//! host controller driver interface without the need for an RTOS. All time
+//! critical operations are handled in interrupt context but all blocking
+//! operations are run from the this function to allow them to block and wait
+//! for completion without holding off other interrupts.
+//!
+//! \return None.
+//
+//*****************************************************************************
+void
+USBHCDMain(void)
+{
+ tUSBHDeviceState iOldState;
+ int32_t i32Dev;
+ tEventInfo sEvent;
+
+ //
+ // Save the old state to detect changes properly.
+ //
+ iOldState = g_sUSBHCD.piDeviceState[0];
+
+ //
+ // Fix up the state if any important interrupt events occurred.
+ //
+ if(g_sUSBHCD.ui32IntEvents)
+ {
+ //
+ // Disable the USB interrupt.
+ //
+ OS_INT_DISABLE(g_sUSBHCD.ui32IntNum);
+
+ if(g_sUSBHCD.ui32IntEvents & INT_EVENT_POWER_FAULT)
+ {
+ //
+ // A power fault has occurred so notify the application if there
+ // is an event handler and the event has been enabled.
+ //
+ sEvent.ui32Event = USB_EVENT_POWER_FAULT;
+ sEvent.ui32Instance = 0;
+ InternalUSBHCDSendEvent(0, &sEvent, USBHCD_EVFLAG_PWRFAULT);
+
+ g_sUSBHCD.piDeviceState[0] = eHCDPowerFault;
+ }
+ else if(g_sUSBHCD.ui32IntEvents & INT_EVENT_VBUS_ERR)
+ {
+ //
+ // A VBUS error has occurred. This event trumps connect and
+ // disconnect since it will cause a controller reset.
+ //
+ g_sUSBHCD.piDeviceState[0] = eHCDVBUSError;
+ }
+ else
+ {
+ //
+ // Has a device connected?
+ //
+ if(g_sUSBHCD.ui32IntEvents & INT_EVENT_CONNECT)
+ {
+ g_sUSBHCD.piDeviceState[0] = eHCDDevReset;
+ g_sUSBHCD.psUSBDevice[0].ui8Hub = 0;
+ g_sUSBHCD.psUSBDevice[0].ui8HubPort = 0;
+ }
+ else
+ {
+ //
+ // Has a device disconnected?
+ //
+ if(g_sUSBHCD.ui32IntEvents & INT_EVENT_DISCONNECT)
+ {
+ g_sUSBHCD.piDeviceState[0] = eHCDDevDisconnected;
+ }
+ }
+
+ //
+ // Handle the start of frame event
+ //
+ if(g_sUSBHCD.ui32IntEvents & INT_EVENT_SOF)
+ {
+ //
+ // If the connect event is enabled then send the event.
+ //
+ sEvent.ui32Event = USB_EVENT_SOF;
+ sEvent.ui32Instance = 0;
+ InternalUSBHCDSendEvent(0, &sEvent, USBHCD_EVFLAG_SOF);
+
+ USBHostCheckPipes();
+
+ //
+ // Call the hub driver to have it perform any necessary
+ // processing to handle downstream devices.
+ //
+ USBHHubMain();
+ }
+
+ //
+ // Handle LPM interrupt events.
+ //
+ if(g_sUSBHCD.ui32IntEvents & INT_EVENT_LPM)
+ {
+ //
+ // There should be a pending LPM request.
+ //
+ ASSERT((g_sUSBHCD.ui32IntEvents & INT_EVENT_LPM_PEND) != 0);
+
+ for(i32Dev = 0; i32Dev < MAX_USB_DEVICES + 1; i32Dev++)
+ {
+ //
+ // Find the device with the pending LPM request.
+ //
+ if(g_sUSBHCD.psUSBDevice[i32Dev].ui32Flags &
+ USBHDEV_FLAG_LPMPEND)
+ {
+ //
+ // Clear the pending event at the device level, this
+ // leaves the error set if it was already set.
+ //
+ g_sUSBHCD.psUSBDevice[i32Dev].ui32Flags &=
+ ~USBHDEV_FLAG_LPMPEND;
+
+ //
+ // Clear the pending request and event at the host
+ // controller level.
+ //
+ g_sUSBHCD.ui32IntEvents &= ~(INT_EVENT_LPM_PEND |
+ INT_EVENT_LPM);
+ }
+ }
+ }
+ }
+
+ //
+ // Clear the flags.
+ //
+ g_sUSBHCD.ui32IntEvents = 0;
+
+ //
+ // Enable the USB interrupt.
+ //
+ OS_INT_ENABLE(g_sUSBHCD.ui32IntNum);
+ }
+
+ //
+ // Process the state machine for each connected device. Yes, the exit
+ // condition for this loop is correct since we support (MAX_USB_DEVICES+1)
+ // devices (the hub counts as one).
+ //
+ for(i32Dev = 0; i32Dev <= MAX_USB_DEVICES; i32Dev++)
+ {
+ //
+ // If this is not the first device (i.e. the one directly connected to
+ // the host controller) then set the old state to the current state
+ // since we won't have mucked with it in any of the previous code.
+ //
+ if(i32Dev != 0)
+ {
+ iOldState = g_sUSBHCD.piDeviceState[i32Dev];
+ }
+
+ //
+ // Process the state machine for this device.
+ //
+ ProcessUSBDeviceStateMachine(iOldState, i32Dev);
+ }
+}
+
+static void
+ProcessUSBDeviceStateMachine(tUSBHDeviceState iOldState,
+ uint32_t ui32DevIndex)
+{
+ switch(g_sUSBHCD.piDeviceState[ui32DevIndex])
+ {
+ //
+ // There was a power fault condition so shut down and wait for the
+ // application to re-initialized the system.
+ //
+ case eHCDPowerFault:
+ {
+ break;
+ }
+
+ //
+ // There was a VBUS error so handle it.
+ //
+ case eHCDVBUSError:
+ {
+ //
+ // Disable USB interrupts.
+ //
+ OS_INT_DISABLE(g_sUSBHCD.ui32IntNum);
+
+ //
+ // If there was a device in any state of connection then indicate
+ // that it has been disconnected.
+ //
+ if((iOldState != eHCDIdle) && (iOldState != eHCDPowerFault))
+ {
+ //
+ // Handle device disconnect.
+ //
+ USBHCDDeviceDisconnected(0, ui32DevIndex);
+ }
+
+ //
+ // Reset the controller.
+ //
+ MAP_SysCtlPeripheralReset(SYSCTL_PERIPH_USB0);
+
+ //
+ // Wait for 100ms before trying to re-power the device.
+ //
+ OS_DELAY(g_ui32Tickms * 100);
+
+ //
+ // Re-initialize the HCD.
+ //
+ USBHCDInitInternal(0, g_sUSBHCD.pvPool, g_sUSBHCD.ui32PoolSize);
+
+ break;
+ }
+ //
+ // Trigger a reset to the connected device.
+ //
+ case eHCDDevReset:
+ {
+ if(!ui32DevIndex)
+ {
+ //
+ // Trigger a Reset. This is only ever done for devices
+ // attached directly to the controller.
+ //
+ DEBUG_OUTPUT("USB reset.\n");
+ USBHCDReset(0);
+ }
+
+ //
+ // The state moves to connected but not configured.
+ //
+ g_sUSBHCD.piDeviceState[0] = eHCDDevConnected;
+
+ //
+ // Remember that we don't have a valid configuration descriptor
+ // yet.
+ //
+ g_sUSBHCD.psUSBDevice[0].bConfigRead = false;
+
+ break;
+ }
+ //
+ // Device connection has been established now start enumerating
+ // the device.
+ //
+ case eHCDDevConnected:
+ case eHCDDevConnectedHub:
+ {
+ //
+ // First check if we have read the device descriptor at all
+ // before proceeding.
+ //
+ if(g_sUSBHCD.psUSBDevice[ui32DevIndex].sDeviceDescriptor.bLength ==
+ 0)
+ {
+ //
+ // Initialize a request for the device descriptor.
+ //
+ DEBUG_OUTPUT("Connection %d - getting device descriptor\n",
+ ui32DevIndex);
+
+ //
+ // Hub enumeration has already set the speed so do not
+ // override the setting here.
+ //
+ if(g_sUSBHCD.piDeviceState[ui32DevIndex] == eHCDDevConnected)
+ {
+ //
+ // Remember the speed of this device to ensure endpoints
+ // are properly configured.
+ //
+ switch(USBHostSpeedGet(USB0_BASE))
+ {
+ case USB_HIGH_SPEED:
+ {
+ g_sUSBHCD.psUSBDevice[ui32DevIndex].ui32Speed =
+ USB_EP_SPEED_HIGH;
+ break;
+ }
+ case USB_FULL_SPEED:
+ {
+ g_sUSBHCD.psUSBDevice[ui32DevIndex].ui32Speed =
+ USB_EP_SPEED_FULL;
+ break;
+ }
+ default:
+ {
+ g_sUSBHCD.psUSBDevice[ui32DevIndex].ui32Speed =
+ USB_EP_SPEED_LOW;
+ break;
+ }
+ }
+ }
+
+ if(USBHCDGetDeviceDescriptor(0,
+ &g_sUSBHCD.psUSBDevice[ui32DevIndex]) == 0)
+ {
+ //
+ // If the device descriptor cannot be read then the device
+ // will be treated as unknown.
+ //
+ g_sUSBHCD.piDeviceState[ui32DevIndex] = eHCDDevError;
+
+ DEBUG_OUTPUT("Connection %d - failed to get descriptor\n",
+ ui32DevIndex);
+
+ //
+ // Send an unknown connection event to let the application
+ // know that there is a device connected but return no
+ // zero for the instance.
+ //
+ SendUnknownConnect(0, 0);
+
+ //
+ // If the device is connected via a hub, tell the hub
+ // driver that we experienced an error enumerating the
+ // device.
+ //
+ if(g_sUSBHCD.psUSBDevice[ui32DevIndex].ui8Hub)
+ {
+ USBHHubEnumerationError(
+ g_sUSBHCD.psUSBDevice[ui32DevIndex].ui8Hub,
+ g_sUSBHCD.psUSBDevice[ui32DevIndex].ui8HubPort);
+ }
+ }
+ }
+ //
+ // If we have the device descriptor then move on to setting
+ // the address of the device.
+ //
+ else if(g_sUSBHCD.psUSBDevice[ui32DevIndex].ui32Address == 0)
+ {
+ DEBUG_OUTPUT("Connection %d - setting address %d\n",
+ ui32DevIndex, ui32DevIndex + 1);
+
+ //
+ // Send the set address command.
+ //
+ USBHCDSetAddress(ui32DevIndex, (ui32DevIndex + 1));
+
+ //
+ // Save the address.
+ //
+ g_sUSBHCD.psUSBDevice[ui32DevIndex].ui32Address =
+ (ui32DevIndex + 1);
+
+ //
+ // Move on to the addressed state.
+ //
+ g_sUSBHCD.piDeviceState[ui32DevIndex] = eHCDDevAddressed;
+ }
+ break;
+ }
+ case eHCDDevAddressed:
+ {
+ //
+ // First check if we have read the configuration descriptor.
+ //
+ if(!g_sUSBHCD.psUSBDevice[ui32DevIndex].bConfigRead)
+ {
+ DEBUG_OUTPUT("Connection %d - getting config descriptor\n",
+ ui32DevIndex);
+
+ //
+ // Initialize a request for the configuration descriptor.
+ //
+ if(USBHCDGetConfigDescriptor(0,
+ &g_sUSBHCD.psUSBDevice[ui32DevIndex]) == 0)
+ {
+ //
+ // If the device descriptor cannot be read then the device
+ // will be treated as unknown.
+ //
+ g_sUSBHCD.piDeviceState[ui32DevIndex] = eHCDDevError;
+
+ DEBUG_OUTPUT("Connection %d - failed to get descriptor\n",
+ ui32DevIndex);
+
+ //
+ // Send an unknown connection event to let the application
+ // know that there is a device connected but return no
+ // zero for the instance.
+ //
+ SendUnknownConnect(0, 0);
+
+ //
+ // If the device is connected via a hub, tell the hub
+ // driver that we experienced an error enumerating the
+ // device.
+ //
+ if(g_sUSBHCD.psUSBDevice[ui32DevIndex].ui8Hub)
+ {
+ USBHHubEnumerationError(
+ g_sUSBHCD.psUSBDevice[ui32DevIndex].ui8Hub,
+ g_sUSBHCD.psUSBDevice[ui32DevIndex].ui8HubPort);
+ }
+ }
+ }
+ //
+ // Now have addressed and received the device configuration,
+ // so get ready to set the device configuration.
+ //
+ else
+ {
+ DEBUG_OUTPUT("Connection %d - setting configuration.\n",
+ ui32DevIndex);
+
+ //
+ // Use the first configuration to set the device
+ // configuration.
+ //
+ USBHCDSetConfig(0,
+ (uint32_t)&g_sUSBHCD.psUSBDevice[ui32DevIndex], 1);
+
+ //
+ // Move on to the configured state.
+ //
+ g_sUSBHCD.piDeviceState[ui32DevIndex] = eHCDDevConfigured;
+
+ //
+ // Open the driver for the device.
+ //
+ g_pi32USBHActiveDriver[ui32DevIndex] = USBHCDOpenDriver(0,
+ ui32DevIndex);
+
+ //
+ // If the device is connected via a hub, tell the hub
+ // driver that enumeration is complete.
+ //
+ if(g_sUSBHCD.psUSBDevice[ui32DevIndex].ui8Hub)
+ {
+ USBHHubEnumerationComplete(
+ g_sUSBHCD.psUSBDevice[ui32DevIndex].ui8Hub,
+ g_sUSBHCD.psUSBDevice[ui32DevIndex].ui8HubPort);
+ }
+ }
+ break;
+ }
+ //
+ // The device was making a request and is now complete.
+ //
+ case eHCDDevRequest:
+ {
+ g_sUSBHCD.piDeviceState[ui32DevIndex] = eHCDDevConnected;
+ break;
+ }
+ //
+ // The strings are currently not accessed.
+ //
+ case eHCDDevGetStrings:
+ {
+ break;
+ }
+ //
+ // Basically Idle at this point.
+ //
+ case eHCDDevDisconnected:
+ {
+ DEBUG_OUTPUT("Connection %d - disconnected.\n",
+ ui32DevIndex);
+
+ //
+ // Handle device disconnect.
+ //
+ USBHCDDeviceDisconnected(0, ui32DevIndex);
+
+ //
+ // Return to the Idle state.
+ //
+ g_sUSBHCD.piDeviceState[ui32DevIndex] = eHCDIdle;
+ break;
+ }
+
+ //
+ // Connection and enumeration is complete so allow this function
+ // to exit.
+ //
+ case eHCDDevConfigured:
+ {
+ break;
+ }
+
+ //
+ // Poorly behaving device are in limbo in this state until removed.
+ //
+ case eHCDDevError:
+ {
+ DEBUG_OUTPUT("Connection %d - Error!\n", ui32DevIndex);
+
+ //
+ // If this device is connected directly to us, tidy up and ignore
+ // it until it is removed. If the device is connected to a hub,
+ // we just leave it in the error state until it is removed.
+ //
+ if(ui32DevIndex == 0)
+ {
+ g_sUSBHCD.ui32IntEvents |= INT_EVENT_DISCONNECT;
+ g_sUSBHCD.piDeviceState[ui32DevIndex] = eHCDIdle;
+ }
+ break;
+ }
+ default:
+ {
+ break;
+ }
+ }
+}
+
+//*****************************************************************************
+//
+//! This function completes a control transaction to a device.
+//!
+//! \param ui32Index is the controller index to use for this transfer.
+//! \param psSetupPacket is the setup request to be sent.
+//! \param psDevice is the device instance pointer for this request.
+//! \param pui8Data is the data to send for OUT requests or the receive buffer
+//! for IN requests.
+//! \param ui32Size is the size of the buffer in \e pui8Data.
+//! \param ui32MaxPacketSize is the maximum packet size for the device for this
+//! request.
+//!
+//! This function handles the state changes necessary to send a control
+//! transaction to a device. This function should not be called from within
+//! an interrupt callback as it is a blocking function.
+//!
+//! \return The number of bytes of data that were sent or received as a result
+//! of this request.
+//
+//*****************************************************************************
+uint32_t
+USBHCDControlTransfer(uint32_t ui32Index, tUSBRequest *psSetupPacket,
+ tUSBHostDevice *psDevice, uint8_t *pui8Data,
+ uint32_t ui32Size, uint32_t ui32MaxPacketSize)
+{
+ uint32_t ui32Remaining;
+ uint32_t ui32DataSize;
+
+ //
+ // Debug sanity check.
+ //
+ ASSERT(g_sUSBHEP0State.iState == eEP0StateIdle);
+ ASSERT(ui32Index == 0);
+
+ //
+ // Initialize the state of the data for this request.
+ //
+ g_sUSBHEP0State.pui8Data = pui8Data;
+ g_sUSBHEP0State.ui32BytesRemaining = ui32Size;
+ g_sUSBHEP0State.ui32DataSize = ui32Size;
+
+ //
+ // Set the maximum packet size.
+ //
+ g_sUSBHEP0State.ui32MaxPacketSize = ui32MaxPacketSize;
+
+ //
+ // Save the current address.
+ //
+ g_sUSBHEP0State.ui32DevAddress = psDevice->ui32Address;
+
+ //
+ // Set the address the host will used to communicate with the device.
+ //
+ MAP_USBHostAddrSet(USB0_BASE, USB_EP_0, g_sUSBHEP0State.ui32DevAddress,
+ USB_EP_HOST_OUT);
+
+ //
+ // Make sure that endpoint 0 has the proper speed setting.
+ //
+ USBHostEndpointConfig(USB0_BASE, USB_EP_0, 64, 0, 0,
+ (USB_EP_MODE_CTRL | psDevice->ui32Speed |
+ USB_EP_HOST_OUT));
+
+ //
+ // Put the data in the correct FIFO.
+ //
+ MAP_USBEndpointDataPut(USB0_BASE, USB_EP_0, (uint8_t *)psSetupPacket,
+ sizeof(tUSBRequest));
+
+ //
+ // If this is an IN request, change to that state.
+ //
+ if(psSetupPacket->bmRequestType & USB_RTYPE_DIR_IN)
+ {
+ g_sUSBHEP0State.iState = eEP0StateSetupIN;
+ }
+ else
+ {
+ //
+ // If there is no data then this is not an OUT request.
+ //
+ if(ui32Size != 0)
+ {
+ //
+ // Since there is data, this is an OUT request.
+ //
+ g_sUSBHEP0State.iState = eEP0StateSetupOUT;
+ }
+ else
+ {
+ //
+ // Otherwise this request has no data and just a status phase.
+ //
+ g_sUSBHEP0State.iState = eEP0StateStatusIN;
+ }
+ }
+
+ //
+ // Make sure we are talking to the correct device.
+ //
+ if(psDevice->ui8Hub == 0)
+ {
+ USBHostHubAddrSet(USB0_BASE, USB_EP_0, 0,
+ USB_EP_HOST_OUT | psDevice->ui32Speed);
+ }
+ else
+ {
+ USBHostHubAddrSet(USB0_BASE, USB_EP_0,
+ (psDevice->ui8Hub | (psDevice->ui8HubPort << 8)),
+ USB_EP_HOST_OUT | psDevice->ui32Speed);
+ }
+
+ //
+ // Send the Setup packet.
+ //
+ MAP_USBEndpointDataSend(USB0_BASE, USB_EP_0, USB_TRANS_SETUP);
+
+ //
+ // Block until endpoint 0 returns to the IDLE state.
+ //
+ while(g_sUSBHEP0State.iState != eEP0StateIdle)
+ {
+ OS_INT_DISABLE(g_sUSBHCD.ui32IntNum);
+
+ if((g_sUSBHCD.ui32IntEvents & (INT_EVENT_ENUM | INT_EVENT_SOF)) ==
+ (INT_EVENT_ENUM | INT_EVENT_SOF))
+ {
+ g_sUSBHCD.ui32IntEvents &= ~(INT_EVENT_ENUM | INT_EVENT_SOF);
+
+ USBHCDEnumHandler();
+ }
+
+ OS_INT_ENABLE(g_sUSBHCD.ui32IntNum);
+
+ if(g_sUSBHEP0State.iState == eEP0StateError)
+ {
+ return(0xffffffff);
+ }
+
+ //
+ // If we aborted the transfer due to an error, tell the caller
+ // that no bytes were transferred.
+ //
+ if(g_sUSBHCD.ui32IntEvents & (INT_EVENT_VBUS_ERR |
+ INT_EVENT_DISCONNECT))
+ {
+ return(0xffffffff);
+ }
+ }
+
+ //
+ // Calculate and return the number of bytes that were sent or received.
+ // The extra copy into local variables is required to prevent some
+ // compilers from warning about undefined order of volatile access.
+ //
+ ui32DataSize = g_sUSBHEP0State.ui32DataSize;
+ ui32Remaining = g_sUSBHEP0State.ui32BytesRemaining;
+
+ return(ui32DataSize - ui32Remaining);
+}
+
+//*****************************************************************************
+//
+// Starts enumerating a new device connected via the hub.
+//
+// \param ui32Index is the index of the USB controller to use.
+// \param ui32Hub is the hub address from which the connection is being made.
+// \param ui32Port is the hub port number that the new device is connected to.
+// \param pui8ConfigPool is memory to be used to store the device's
+// configuration descriptor.
+// \param ui32ConfigSize is the number of bytes available in the buffer pointed
+// to by pui8ConfigPool.
+//
+// This function is called by the hub class driver after it has detected a new
+// device connection and reset the device.
+//
+// \return Returns the index of the device allocated or 0 if no resources are
+// available. Device index 0 is the hub itself.
+//
+//*****************************************************************************
+uint32_t
+USBHCDHubDeviceConnected(uint32_t ui32Index, uint8_t ui8Hub,
+ uint8_t ui8Port, uint32_t ui32Speed)
+{
+ uint32_t ui32DevIndex;
+
+ //
+ // Debug sanity checks.
+ //
+ ASSERT(ui32Index == 0);
+ ASSERT(ui8Port);
+
+ DEBUG_OUTPUT("Connection from hub %d, port %d.\n", ui8Hub, ui8Port);
+
+ //
+ // Look for a free slot in the device table.
+ //
+ for(ui32DevIndex = 1; ui32DevIndex <= MAX_USB_DEVICES; ui32DevIndex++)
+ {
+ if((g_sUSBHCD.psUSBDevice[ui32DevIndex].ui32Flags &
+ USBHDEV_FLAG_ALLOCATED) == 0)
+ {
+ //
+ // We found one. Set the state to ensure that it gets enumerated.
+ //
+ g_sUSBHCD.psUSBDevice[ui32DevIndex].ui32Flags =
+ USBHDEV_FLAG_ALLOCATED;
+ g_sUSBHCD.psUSBDevice[ui32DevIndex].psConfigDescriptor->bLength = 0;
+ g_sUSBHCD.psUSBDevice[ui32DevIndex].ui8Hub = ui8Hub;
+ g_sUSBHCD.psUSBDevice[ui32DevIndex].ui8HubPort = ui8Port;
+ g_sUSBHCD.psUSBDevice[ui32DevIndex].ui32Speed = ui32Speed;
+ g_sUSBHCD.psUSBDevice[ui32DevIndex].sDeviceDescriptor.bLength = 0;
+
+ //
+ // Set the state to ensure enumeration begins.
+ //
+ g_sUSBHCD.piDeviceState[ui32DevIndex] = eHCDDevConnectedHub;
+
+ DEBUG_OUTPUT("Allocating device %d\n", ui32DevIndex);
+
+ //
+ // Pass the device index back to the hub driver.
+ //
+ return(ui32DevIndex);
+ }
+ }
+
+ //
+ // If we get here, there are device slots available so send back an invalid
+ // device index to tell the caller to ignore this device.
+ //
+ return(0);
+}
+
+//*****************************************************************************
+//
+// Called when a device is disconnected from a hub.
+//
+// \param ui32Index is the index of the USB controller to use.
+// \param ui32DevIndex is the device index for the USB device that was
+// disconnected.
+//
+//*****************************************************************************
+void
+USBHCDHubDeviceDisconnected(uint32_t ui32Index, uint32_t ui32DevIndex)
+{
+ //
+ // Debug sanity checks.
+ //
+ ASSERT(ui32Index == 0);
+ ASSERT(ui32DevIndex && (ui32DevIndex <= MAX_USB_DEVICES));
+
+ DEBUG_OUTPUT("Disconnection from hub %d, port %d, device %d\n",
+ g_sUSBHCD.psUSBDevice[ui32DevIndex].ui8Hub,
+ g_sUSBHCD.psUSBDevice[ui32DevIndex].ui8HubPort, ui32DevIndex);
+
+ //
+ // Set the device state to ensure that USBHCDMain cleans it up.
+ //
+ g_sUSBHCD.piDeviceState[ui32DevIndex] = eHCDDevDisconnected;
+}
+
+//*****************************************************************************
+//
+// This is the endpoint 0 interrupt handler.
+//
+// \return None.
+//
+//*****************************************************************************
+static void
+USBHCDEnumHandler(void)
+{
+ uint32_t ui32EPStatus;
+ uint32_t ui32DataSize;
+
+ //
+ // Get the end point 0 status.
+ //
+ ui32EPStatus = MAP_USBEndpointStatus(USB0_BASE, USB_EP_0);
+
+ //
+ // If there was an error then go to the error state.
+ //
+ if(ui32EPStatus == USB_HOST_EP0_ERROR)
+ {
+ //
+ // Clear this status indicating that the status packet was
+ // received.
+ //
+ MAP_USBHostEndpointStatusClear(USB0_BASE, USB_EP_0,
+ USB_HOST_EP0_ERROR);
+ MAP_USBFIFOFlush(USB0_BASE, USB_EP_0, 0);
+
+ //
+ // Just go back to the idle state.
+ //
+ g_sUSBHEP0State.iState = eEP0StateError;
+
+ return;
+ }
+
+ switch(g_sUSBHEP0State.iState)
+ {
+ //
+ // Handle the status state, this is a transitory state from
+ // USB_STATE_TX or USB_STATE_RX back to USB_STATE_IDLE.
+ //
+ case eEP0StateStatus:
+ {
+ //
+ // Handle the case of a received status packet.
+ //
+ if(ui32EPStatus & (USB_HOST_EP0_RXPKTRDY | USB_HOST_EP0_STATUS))
+ {
+ //
+ // Clear this status indicating that the status packet was
+ // received.
+ //
+ MAP_USBHostEndpointStatusClear(USB0_BASE, USB_EP_0,
+ (USB_HOST_EP0_RXPKTRDY |
+ USB_HOST_EP0_STATUS));
+ }
+
+ //
+ // Just go back to the idle state.
+ //
+ g_sUSBHEP0State.iState = eEP0StateIdle;
+
+ break;
+ }
+
+ //
+ // This state triggers a STATUS IN request from the device.
+ //
+ case eEP0StateStatusIN:
+ {
+ //
+ // Generate an IN request from the device.
+ //
+ MAP_USBHostRequestStatus(USB0_BASE);
+
+ //
+ // Change to the status phase and wait for the response.
+ //
+ g_sUSBHEP0State.iState = eEP0StateStatus;
+
+ break;
+ }
+
+ //
+ // In the IDLE state the code is waiting to receive data from the host.
+ //
+ case eEP0StateIdle:
+ {
+ break;
+ }
+
+ //
+ // Data is still being sent to the host so handle this in the
+ // EP0StateTx() function.
+ //
+ case eEP0StateSetupOUT:
+ {
+ //
+ // Send remaining data if necessary.
+ //
+ USBHCDEP0StateTx();
+
+ break;
+ }
+
+ //
+ // Handle the receive state for commands that are receiving data on
+ // endpoint 0.
+ //
+ case eEP0StateSetupIN:
+ {
+ //
+ // Generate a new IN request to the device.
+ //
+ MAP_USBHostRequestIN(USB0_BASE, USB_EP_0);
+
+ //
+ // Proceed to the RX state to receive the requested data.
+ //
+ g_sUSBHEP0State.iState = eEP0StateRx;
+
+ break;
+ }
+
+ //
+ // The endpoint remains in this state until all requested data has
+ // been received.
+ //
+ case eEP0StateRx:
+ {
+ //
+ // There was a stall on endpoint 0 so go back to the idle state
+ // as this command has been terminated.
+ //
+ if(ui32EPStatus & USB_HOST_EP0_RX_STALL)
+ {
+ g_sUSBHEP0State.iState = eEP0StateIdle;
+
+ //
+ // Clear the stalled state on endpoint 0.
+ //
+ MAP_USBHostEndpointStatusClear(USB0_BASE, USB_EP_0,
+ ui32EPStatus & USB_HOST_IN_STATUS);
+ break;
+ }
+
+ //
+ // Set the number of bytes to get out of this next packet.
+ //
+ ui32DataSize = g_sUSBHEP0State.ui32BytesRemaining;
+ if(ui32DataSize > g_sUSBHEP0State.ui32MaxPacketSize)
+ {
+ //
+ // Don't send more than EP0_MAX_PACKET_SIZE bytes.
+ //
+ ui32DataSize = MAX_PACKET_SIZE_EP0;
+ }
+
+ if(ui32DataSize != 0)
+ {
+ //
+ // Get the data from the USB controller end point 0.
+ //
+ MAP_USBEndpointDataGet(USB0_BASE, USB_EP_0,
+ g_sUSBHEP0State.pui8Data,
+ &ui32DataSize);
+ }
+
+ //
+ // Advance the pointer.
+ //
+ g_sUSBHEP0State.pui8Data += ui32DataSize;
+
+ //
+ // Decrement the number of bytes that are being waited on.
+ //
+ g_sUSBHEP0State.ui32BytesRemaining -= ui32DataSize;
+
+ //
+ // Need to ack the data on end point 0 in this case
+ // without setting data end.
+ //
+ MAP_USBHostEndpointDataAck(USB0_BASE, USB_EP_0);
+
+ //
+ // If there was not more than the maximum packet size bytes of data
+ // the this was a int16_t packet and indicates that this transfer
+ // is complete. If there were exactly
+ // g_sUSBHEP0State.ui32MaxPacketSize remaining then there still
+ // needs to be null packet sent before this transfer is complete.
+ //
+ if((ui32DataSize < g_sUSBHEP0State.ui32MaxPacketSize) ||
+ (g_sUSBHEP0State.ui32BytesRemaining == 0))
+ {
+ //
+ // Return to the idle state.
+ //
+ g_sUSBHEP0State.iState = eEP0StateStatus;
+
+ //
+ // No more data.
+ //
+ g_sUSBHEP0State.pui8Data = 0;
+
+ //
+ // Send a null packet to acknowledge that all data was
+ // received.
+ //
+ MAP_USBEndpointDataSend(USB0_BASE, USB_EP_0, USB_TRANS_STATUS);
+ }
+ else
+ {
+ //
+ // Request more data.
+ //
+ MAP_USBHostRequestIN(USB0_BASE, USB_EP_0);
+ }
+ break;
+ }
+
+ //
+ // The device stalled endpoint zero so check if the stall needs to be
+ // cleared once it has been successfully sent.
+ //
+ case eEP0StateStall:
+ {
+ //
+ // Reset the global end point 0 state to IDLE.
+ //
+ g_sUSBHEP0State.iState = eEP0StateIdle;
+
+ break;
+ }
+
+ //
+ // Halt on an unknown state, but only in DEBUG builds.
+ //
+ default:
+ {
+ ASSERT(0);
+ break;
+ }
+ }
+}
+
+//*****************************************************************************
+//
+// This internal function handles sending data on endpoint 0.
+//
+// \return None.
+//
+//*****************************************************************************
+static void
+USBHCDEP0StateTx(void)
+{
+ uint32_t ui32NumBytes;
+ uint8_t *pui8Data;
+
+ //
+ // In the TX state on endpoint 0.
+ //
+ g_sUSBHEP0State.iState = eEP0StateSetupOUT;
+
+ //
+ // Set the number of bytes to send this iteration.
+ //
+ ui32NumBytes = g_sUSBHEP0State.ui32BytesRemaining;
+
+ //
+ // Limit individual transfers to 64 bytes.
+ //
+ if(ui32NumBytes > 64)
+ {
+ ui32NumBytes = 64;
+ }
+
+ //
+ // Save the pointer so that it can be passed to the USBEndpointDataPut()
+ // function.
+ //
+ pui8Data = (uint8_t *)g_sUSBHEP0State.pui8Data;
+
+ //
+ // Advance the data pointer and counter to the next data to be sent.
+ //
+ g_sUSBHEP0State.ui32BytesRemaining -= ui32NumBytes;
+ g_sUSBHEP0State.pui8Data += ui32NumBytes;
+
+ //
+ // Put the data in the correct FIFO.
+ //
+ MAP_USBEndpointDataPut(USB0_BASE, USB_EP_0, pui8Data, ui32NumBytes);
+
+ //
+ // If this is exactly 64 then don't set the last packet yet.
+ //
+ if(ui32NumBytes == 64)
+ {
+ //
+ // There is more data to send or exactly 64 bytes were sent, this
+ // means that there is either more data coming or a null packet needs
+ // to be sent to complete the transaction.
+ //
+ MAP_USBEndpointDataSend(USB0_BASE, USB_EP_0, USB_TRANS_OUT);
+ }
+ else
+ {
+ //
+ // Send the last bit of data.
+ //
+ MAP_USBEndpointDataSend(USB0_BASE, USB_EP_0, USB_TRANS_OUT);
+
+ //
+ // Now go to the status state and wait for the transmit to complete.
+ //
+ g_sUSBHEP0State.iState = eEP0StateStatusIN;
+ }
+}
+
+//*****************************************************************************
+//
+//! This function returns the USB hub port for the requested device instance.
+//!
+//! \param ui32Instance is a unique value indicating which device to query.
+//!
+//! This function returns the USB hub port for the device that is associated
+//! with the \e ui32Instance parameter. The caller must use the value for
+//! \e ui32Instance was passed to the application when it receives a
+//! \b USB_EVENT_CONNECTED event. The function returns the USB hub port for
+//! the interface number specified by the \e ui32Interface parameter.
+//!
+//! \return The USB hub port for the requested interface.
+//
+//*****************************************************************************
+uint8_t
+USBHCDDevHubPort(uint32_t ui32Instance)
+{
+ uint32_t ui32DevIndex;
+
+ ui32DevIndex = HCDInstanceToDevIndex(ui32Instance);
+
+ if(ui32DevIndex == 0xff)
+ {
+ return(ui32DevIndex);
+ }
+
+ return(g_sUSBHCD.psUSBDevice[ui32DevIndex].ui8HubPort);
+}
+
+//*****************************************************************************
+//
+//! This function will return the USB address for the requested device
+//! instance.
+//!
+//! \param ui32Instance is a unique value indicating which device to query.
+//!
+//! This function returns the USB address for the device that is associated
+//! with the \e ui32Instance parameter. The caller must use a value for
+//! \e ui32Instance have been passed to the application when it receives a
+//! \b USB_EVENT_CONNECTED event. The function will return the USB address for
+//! the interface number specified by the \e ui32Interface parameter.
+//!
+//! \return The USB address for the requested interface.
+//
+//*****************************************************************************
+uint8_t
+USBHCDDevAddress(uint32_t ui32Instance)
+{
+ uint32_t ui32DevIndex;
+
+ ui32DevIndex = HCDInstanceToDevIndex(ui32Instance);
+
+ if(ui32DevIndex == 0xff)
+ {
+ return(ui32DevIndex);
+ }
+
+ return(g_sUSBHCD.psUSBDevice[ui32DevIndex].ui32Address);
+}
+
+//*****************************************************************************
+//
+//! This function will return the USB class for the requested device
+//! instance.
+//!
+//! \param ui32Instance is a unique value indicating which device to query.
+//! \param ui32Interface is the interface number to query for the USB class.
+//!
+//! This function returns the USB class for the device that is associated
+//! with the \e ui32Instance parameter. The caller must use a value for
+//! \e ui32Instance have been passed to the application when it receives a
+//! \b USB_EVENT_CONNECTED event. The function will return the USB class for
+//! the interface number specified by the \e ui32Interface parameter. If
+//! \e ui32Interface is set to 0xFFFFFFFF then the function will return the USB
+//! class for the first interface that is found in the device's USB
+//! descriptors.
+//!
+//! \return The USB class for the requested interface.
+//
+//*****************************************************************************
+uint8_t
+USBHCDDevClass(uint32_t ui32Instance, uint32_t ui32Interface)
+{
+ uint32_t ui32DevIndex;
+ tInterfaceDescriptor *psInterface;
+
+ ui32DevIndex = HCDInstanceToDevIndex(ui32Instance);
+
+ //
+ // If the instance was not valid return an undefined class.
+ //
+ if(ui32DevIndex == 0xff)
+ {
+ return(USB_CLASS_DEVICE);
+ }
+
+ //
+ // Get the interface descriptor.
+ //
+ psInterface = USBDescGetInterface(
+ g_sUSBHCD.psUSBDevice[ui32DevIndex].psConfigDescriptor,
+ g_sUSBHCD.psUSBDevice[ui32DevIndex].ui32Interface,
+ ui32Interface);
+
+ //
+ // Make sure that the interface requested actually exists.
+ //
+ if(psInterface)
+ {
+ //
+ // Return the interface class.
+ //
+ return(psInterface->bInterfaceClass);
+ }
+
+ //
+ // No valid interface so return an undefined class.
+ //
+ return(USB_CLASS_DEVICE);
+}
+
+//*****************************************************************************
+//
+//! This function will return the USB subclass for the requested device
+//! instance.
+//!
+//! \param ui32Instance is a unique value indicating which device to query.
+//! \param ui32Interface is the interface number to query for the USB subclass.
+//!
+//! This function returns the USB subclass for the device that is associated
+//! with the \e ui32Instance parameter. The caller must use a value for
+//! \e ui32Instance have been passed to the application when it receives a
+//! \b USB_EVENT_CONNECTED event. The function will return the USB subclass
+//! for the interface number specified by the \e ui32Interface parameter. If
+//! \e ui32Interface is set to 0xFFFFFFFF then the function will return the USB
+//! subclass for the first interface that is found in the device's USB
+//! descriptors.
+//!
+//! \return The USB subclass for the requested interface.
+//
+//*****************************************************************************
+uint8_t
+USBHCDDevSubClass(uint32_t ui32Instance, uint32_t ui32Interface)
+{
+ uint32_t ui32DevIndex;
+ tInterfaceDescriptor *psInterface;
+
+ ui32DevIndex = HCDInstanceToDevIndex(ui32Instance);
+
+ //
+ // If the instance was not valid return an undefined subclass.
+ //
+ if(ui32DevIndex == 0xff)
+ {
+ return(USB_SUBCLASS_UNDEFINED);
+ }
+
+ //
+ // Get the interface descriptor.
+ //
+ psInterface = USBDescGetInterface(
+ g_sUSBHCD.psUSBDevice[ui32DevIndex].psConfigDescriptor,
+ g_sUSBHCD.psUSBDevice[ui32DevIndex].ui32Interface,
+ ui32Interface);
+
+ //
+ // Make sure that the interface requested actually exists.
+ //
+ if(psInterface)
+ {
+ //
+ // Return the interface subclass.
+ //
+ return(psInterface->bInterfaceSubClass);
+ }
+
+ //
+ // No valid interface so return an undefined subclass.
+ //
+ return(USB_SUBCLASS_UNDEFINED);
+}
+
+//*****************************************************************************
+//
+//! This function returns the USB protocol for the requested device instance.
+//!
+//! \param ui32Instance is a unique value indicating which device to query.
+//! \param ui32Interface is the interface number to query for the USB protocol.
+//!
+//! This function returns the USB protocol for the device that is associated
+//! with the \e ui32Instance parameter. The caller must use a value for
+//! \e ui32Instance have been passed to the application when it receives a
+//! \b USB_EVENT_CONNECTED event. The function will return the USB protocol
+//! for the interface number specified by the \e ui32Interface parameter. If
+//! \e ui32Interface is set to 0xFFFFFFFF then the function will return the USB
+//! protocol for the first interface that is found in the device's USB
+//! descriptors.
+//!
+//! \return The USB protocol for the requested interface.
+//
+//*****************************************************************************
+uint8_t
+USBHCDDevProtocol(uint32_t ui32Instance, uint32_t ui32Interface)
+{
+ uint32_t ui32DevIndex;
+ tInterfaceDescriptor *psInterface;
+
+ ui32DevIndex = HCDInstanceToDevIndex(ui32Instance);
+
+ //
+ // If the instance was not valid return an undefined protocol.
+ //
+ if(ui32DevIndex == 0xff)
+ {
+ return(USB_PROTOCOL_UNDEFINED);
+ }
+
+ //
+ // Get the interface descriptor.
+ //
+ psInterface = USBDescGetInterface(
+ g_sUSBHCD.psUSBDevice[ui32DevIndex].psConfigDescriptor,
+ g_sUSBHCD.psUSBDevice[ui32DevIndex].ui32Interface,
+ ui32Interface);
+
+ //
+ // Make sure that the interface requested actually exists.
+ //
+ if(psInterface)
+ {
+ //
+ // Return the interface protocol.
+ //
+ return(psInterface->bInterfaceProtocol);
+ }
+
+ //
+ // No valid interface so return an undefined protocol.
+ //
+ return(USB_PROTOCOL_UNDEFINED);
+}
+
+//*****************************************************************************
+//
+//! This function sets one of the \b USBLIB_FEATURE_ requests.
+//!
+//! \param ui32Index is the index of the USB controller to access.
+//! \param ui32Feature is one of the \b USBLIB_FEATURE_ defines.
+//! \param pvFeature is a pointer to the data for the \b USBLIB_FEATURE
+//! request.
+//!
+//! This function sends the requested feature request to the USB library.
+//! Not all features are supported by all devices so see the documentation
+//! for the \b USBLIB_FEATURE_ to determine if the feature is supported.
+//!
+//! \return Returns \b true if the feature was set and \b false if the feature
+//! is not supported or could not be changed to the requested value.
+//
+//*****************************************************************************
+bool
+USBHCDFeatureSet(uint32_t ui32Index, uint32_t ui32Feature,
+ void *pvFeature)
+{
+ bool bRetCode;
+ tLPMFeature *psLPMFeature;
+
+ bRetCode = true;
+
+ switch(ui32Feature)
+ {
+ case USBLIB_FEATURE_CPUCLK:
+ {
+ //
+ // Set the ticks per millisecond.
+ //
+ g_ui32Tickms = (*(uint32_t *)pvFeature / 3000);
+ break;
+ }
+ case USBLIB_FEATURE_LPM:
+ {
+ psLPMFeature = (tLPMFeature *)pvFeature;
+
+ if(psLPMFeature->ui32Features & USBLIB_FEATURE_LPM_EN)
+ {
+ g_sUSBHCD.ui32Features |= USBLIB_FEATURE_LPM_EN;
+
+ if(psLPMFeature->ui32Features & USBLIB_FEATURE_LPM_RMT_WAKE)
+ {
+ g_sUSBHCD.ui32Features |= USBLIB_FEATURE_LPM_RMT_WAKE;
+ }
+ g_sUSBHCD.ui32LPMHIRD = psLPMFeature->ui32HIRD;
+ }
+ else
+ {
+ psLPMFeature->ui32Features &= ~USBLIB_FEATURE_LPM_EN;
+ }
+ break;
+ }
+ case USBLIB_FEATURE_USBPLL:
+ {
+ //
+ // If the PLL rate is not evenly divisible by 60MHz then
+ // do not set it.
+ //
+ if((*(uint32_t *)pvFeature % 60000000) != 0)
+ {
+ bRetCode = false;
+ }
+ else
+ {
+ //
+ // Save the new PLL rate.
+ //
+ g_ui32PLLDiv = (*(uint32_t *)pvFeature / 60000000);
+ }
+ break;
+ }
+ case USBLIB_FEATURE_USBULPI:
+ {
+ //
+ // Save the ULPI support level.
+ //
+ g_ui32ULPISupport = *(uint32_t *)pvFeature;
+
+ break;
+ }
+ default:
+ {
+ bRetCode = false;
+ break;
+ }
+ }
+ return(bRetCode);
+}
+
+//*****************************************************************************
+//
+//! This function returns the current status of an LPM request.
+//!
+//! \param psDevice is the device to query.
+//!
+//! This function returns the current status of LPM requests for a given
+//! device. This is called to determine if a previous request completed
+//! successfully or if there was an error.
+//!
+//! \return This function returns the following values:
+//! - \b USBHCD_LPM_AVAIL - There are no pending LPM requests on this specific
+//! device or the last request completed successfully.
+//! - \b USBHCD_LPM_ERROR - The last LPM request for this device did not
+//! complete successfully.
+//! - \b USBHCD_LPM_PENDING - The last LPM request has not completed.
+//
+//*****************************************************************************
+uint32_t
+USBHCDLPMStatus(tUSBHostDevice *psDevice)
+{
+ uint32_t ui32Ret;
+
+ ASSERT(psDevice != 0);
+
+ //
+ // Should never have both USBHDEV_FLAG_LPMERROR and USBHDEV_FLAG_LPMPEND
+ // set at the same time.
+ //
+ ASSERT((psDevice->ui32Flags &
+ (USBHDEV_FLAG_LPMERROR | USBHDEV_FLAG_LPMPEND)) !=
+ (USBHDEV_FLAG_LPMERROR | USBHDEV_FLAG_LPMPEND));
+
+ //
+ // Default to no pending transfers or errors.
+ //
+ ui32Ret = USBHCD_LPM_AVAIL;
+
+ if(psDevice->ui32Flags & USBHDEV_FLAG_LPMERROR)
+ {
+ //
+ // An error occurred after the last call to send an LPM command.
+ //
+ ui32Ret = USBHCD_LPM_ERROR;
+ }
+ else if(psDevice->ui32Flags & USBHDEV_FLAG_LPMPEND)
+ {
+ //
+ // Still have a pending transfer.
+ //
+ ui32Ret = USBHCD_LPM_PENDING;
+ }
+
+ return(ui32Ret);
+}
+
+//*****************************************************************************
+//
+//! This function generates an LPM request for a device to enter L1 sleep
+//! state.
+//!
+//! \param psDevice is the device to query.
+//!
+//! This function sends a request to a device to enter the LPM L1 sleep state.
+//! The caller must check the return value to see if the request can be
+//! attempted at this time. If another LPM transaction is busy on another
+//! device this function will return \b USBHCD_LPM_PENDING or
+//! \b USBHCD_LPM_AVAIL if the LPM request was scheduled to be sent. The
+//! caller should check the USBHCDLPMStatus() function to determine if the
+//! request has completed.
+//!
+//! \return This function returns the following values:
+//! - USBHCD_LPM_AVAIL - The transition to L1 state is scheduled to be sent.
+//! - USBHCD_LPM_PENDING - There is already an LPM request pending.
+//
+//*****************************************************************************
+uint32_t
+USBHCDLPMSleep(tUSBHostDevice *psDevice)
+{
+ uint32_t ui32Ret;
+
+ ASSERT(psDevice != 0);
+
+ //
+ // Disable the USB interrupt.
+ //
+ OS_INT_DISABLE(g_sUSBHCD.ui32IntNum);
+
+ //
+ // If there is no current LPM pending then send the request.
+ //
+ if((g_sUSBHCD.ui32IntEvents & INT_EVENT_LPM_PEND) ||
+ (psDevice->ui32Flags & USBHDEV_FLAG_LPMPEND))
+ {
+ ui32Ret = USBHCD_LPM_PENDING;
+ }
+ else
+ {
+ //
+ // New pending LPM transfer at the host controller level.
+ //
+ g_sUSBHCD.ui32IntEvents |= INT_EVENT_LPM_PEND;
+
+ //
+ // New pending request and clear any previous error for this
+ // device in case it was already set.
+ //
+ psDevice->ui32Flags |= USBHDEV_FLAG_LPMPEND;
+ psDevice->ui32Flags &= ~USBHDEV_FLAG_LPMERROR;
+
+ USBHostLPMSend(USB0_BASE, psDevice->ui32Address, USB_EP_0);
+
+ ui32Ret = USBHCD_LPM_AVAIL;
+ }
+
+ //
+ // Disable the USB interrupt.
+ //
+ OS_INT_ENABLE(g_sUSBHCD.ui32IntNum);
+
+ return(ui32Ret);
+}
+
+//*****************************************************************************
+//
+//! This function generates an LPM request for a device to exit L1 sleep state.
+//!
+//! \param ui32Index specifies which USB controller to use.
+//!
+//! This function will start LPM resume signaling on the USB bus. This wakes
+//! all devices and is similar to USBHCDResume() call but is triggered by an
+//! LPM request.
+//!
+//! \return None.
+//
+//*****************************************************************************
+void
+USBHCDLPMResume(uint32_t ui32Index)
+{
+ ASSERT(ui32Index == 0);
+
+ USBHostLPMResume(USB0_BASE);
+}
+
+//*****************************************************************************
+//
+// Close the Doxygen group.
+//! @}
+//
+//*****************************************************************************
diff --git a/usblib/host/usbhostpriv.h b/usblib/host/usbhostpriv.h
new file mode 100644
index 0000000..1128749
--- /dev/null
+++ b/usblib/host/usbhostpriv.h
@@ -0,0 +1,201 @@
+//*****************************************************************************
+//
+// usbhostpriv.h - Internal header file for USB host functions.
+//
+// Copyright (c) 2011-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 Tiva USB Library.
+//
+//*****************************************************************************
+
+#ifndef __USBHOSTPRIV_H__
+#define __USBHOSTPRIV_H__
+
+//*****************************************************************************
+//
+// If building with a C++ compiler, make all of the definitions in this header
+// have a C binding.
+//
+//*****************************************************************************
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+//*****************************************************************************
+//
+// The states a hub port can be in during device connection.
+//
+//*****************************************************************************
+typedef enum
+{
+ //
+ // The port has no device connected.
+ //
+ ePortIdle,
+
+ //
+ // The port has a device present and is waiting for the enumeration
+ // sequence to begin.
+ //
+ ePortConnected,
+
+ //
+ // A device connection notification has been received and we have initiated
+ // a reset to the port. We are waiting for the reset to complete.
+ //
+ ePortResetActive,
+
+ //
+ // The Port reset has completed but now the hub is waiting the required
+ // 10ms before accessing the device.
+ //
+ ePortResetWait,
+
+ //
+ // A device is connected and the port has been reset. Control has been
+ // passed to the main host handling portion of USBLib to enumerate the
+ // device.
+ //
+ ePortActive,
+
+ //
+ // A device has completed enumeration.
+ //
+ ePortEnumerated,
+
+ //
+ // A device is attached to the port but enumeration failed.
+ //
+ ePortError
+}
+tHubPortState;
+
+//*****************************************************************************
+//
+// The list of valid event flags in the g_sUSBHCD.ui32EventEnables member
+// variable.
+//
+//*****************************************************************************
+#define USBHCD_EVFLAG_SOF 0x00000001
+#define USBHCD_EVFLAG_CONNECT 0x00000002
+#define USBHCD_EVFLAG_UNKCNCT 0x00000004
+#define USBHCD_EVFLAG_DISCNCT 0x00000008
+#define USBHCD_EVFLAG_PWRFAULT 0x00000010
+#define USBHCD_EVFLAG_PWRDIS 0x00000020
+#define USBHCD_EVFLAG_PWREN 0x00000040
+
+//*****************************************************************************
+//
+// This is the structure that holds all of the information for devices
+// that are enumerated in the system. It is passed in to Open function of
+// USB host class drivers so that they can allocate any endpoints and parse
+// out other information that the device class needs to complete enumeration.
+//
+//*****************************************************************************
+struct tUSBHostDevice
+{
+ //
+ // The current device address for this device.
+ //
+ uint32_t ui32Address;
+
+ //
+ // The current interface for this device.
+ //
+ uint32_t ui32Interface;
+
+ //
+ // A flag used to record whether this is a low-speed or a full-speed
+ // device.
+ //
+ bool bLowSpeed;
+
+ //
+ // The USB connection speed for this device.
+ //
+ uint32_t ui32Speed;
+
+ //
+ // A flag indicating whether or not we have read the device's
+ // configuration descriptor yet.
+ //
+ bool bConfigRead;
+
+ //
+ // The hub number to which this device is attached.
+ //
+ uint8_t ui8Hub;
+
+ //
+ // The hub port number to which the device is attached.
+ //
+ uint8_t ui8HubPort;
+
+ //
+ // The device descriptor for this device.
+ //
+ tDeviceDescriptor sDeviceDescriptor;
+
+ //
+ // A pointer to the configuration descriptor for this device.
+ //
+ tConfigDescriptor *psConfigDescriptor;
+
+ //
+ // The size of the buffer allocated to psConfigDescriptor.
+ //
+ uint32_t ui32ConfigDescriptorSize;
+
+ //
+ // Internal flags used by the host controller driver.
+ //
+ uint32_t ui32Flags;
+};
+
+//*****************************************************************************
+//
+// Functions within the host controller that are called by the hub class driver
+//
+//*****************************************************************************
+extern uint32_t USBHCDHubDeviceConnected(uint32_t ui32Index, uint8_t ui8Hub,
+ uint8_t ui8Port, uint32_t ui32Speed);
+extern void USBHCDHubDeviceDisconnected(uint32_t ui32Index,
+ uint32_t ui32DevIndex);
+
+//*****************************************************************************
+//
+// Functions in the hub class driver that are called by the host controller.
+//
+//*****************************************************************************
+extern void USBHHubMain(void);
+extern void USBHHubInit(void);
+extern void USBHHubEnumerationComplete(uint8_t ui8Hub, uint8_t ui8Port);
+extern void USBHHubEnumerationError(uint8_t ui8Hub, uint8_t ui8Port);
+extern uint32_t USBHCDLPMSleep(tUSBHostDevice *psDevice);
+extern uint32_t USBHCDLPMStatus(tUSBHostDevice *psDevice);
+
+//*****************************************************************************
+//
+// Mark the end of the C bindings section for C++ compilers.
+//
+//*****************************************************************************
+#ifdef __cplusplus
+}
+#endif
+
+#endif // __USBHOSTPRIV_H__
diff --git a/usblib/host/usbhscsi.c b/usblib/host/usbhscsi.c
new file mode 100644
index 0000000..407dc2d
--- /dev/null
+++ b/usblib/host/usbhscsi.c
@@ -0,0 +1,777 @@
+//*****************************************************************************
+//
+// usbhscsi.c - USB host SCSI layer used by the USB host MSC driver.
+//
+// Copyright (c) 2008-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 Tiva USB Library.
+//
+//*****************************************************************************
+
+#include <stdbool.h>
+#include <stdint.h>
+#include "inc/hw_types.h"
+#include "usblib/usblib.h"
+#include "usblib/usbmsc.h"
+#include "usblib/host/usbhost.h"
+#include "usblib/host/usbhmsc.h"
+#include "usblib/host/usbhscsi.h"
+
+//*****************************************************************************
+//
+//! \addtogroup usblib_host_class
+//! @{
+//
+//*****************************************************************************
+
+//*****************************************************************************
+//
+// This is the data verify tag passed between requests.
+//
+//*****************************************************************************
+#define CBW_TAG_VALUE 0x54231990
+
+//*****************************************************************************
+//
+//! This function is used to issue SCSI commands via USB.
+//!
+//! \param ui32InPipe is the USB IN pipe to use for this command.
+//! \param ui32OutPipe is the USB OUT pipe to use for this command.
+//! \param psSCSICmd is the SCSI command structure to send.
+//! \param pui8Data is pointer to the command data to be sent.
+//! \param pui32Size is the number of bytes is the number of bytes expected or
+//! sent by the command.
+//!
+//! This internal function is used to handle SCSI commands sent by other
+//! functions. It serves as a layer between the SCSI command and the USB
+//! interface being used to send the command. The \e pSCSI parameter contains
+//! the SCSI command to send. For commands that expect data back, the
+//! \e pui8Data is the buffer to store the data into and \e pui32Size is used
+//! to store the amount of data to request as well as used to indicate how many
+//! bytes were filled into the \e pui8Data buffer on return. For commands that
+//! are sending data, \e pui8Data is the data to be sent and \e pui32Size is
+//! the number of bytes to send.
+//!
+//! \return This function returns the SCSI status from the command. The value
+//! will be either \b SCSI_CMD_STATUS_PASS or \b SCSI_CMD_STATUS_FAIL.
+//
+//*****************************************************************************
+static uint32_t
+USBHSCSISendCommand(uint32_t ui32InPipe, uint32_t ui32OutPipe,
+ tMSCCBW *psSCSICmd, uint8_t *pui8Data, uint32_t *pui32Size)
+{
+ tMSCCSW sCmdStatus;
+ uint32_t ui32Bytes;
+
+ //
+ // Initialize the command status.
+ //
+ sCmdStatus.dCSWSignature = 0;
+ sCmdStatus.dCSWTag = 0;
+ sCmdStatus.bCSWStatus = SCSI_CMD_STATUS_FAIL;
+
+ //
+ // Set the CBW signature and tag.
+ //
+ psSCSICmd->dCBWSignature = CBW_SIGNATURE;
+ psSCSICmd->dCBWTag = CBW_TAG_VALUE;
+
+ //
+ // Set the size of the data to be returned by the device.
+ //
+ psSCSICmd->dCBWDataTransferLength = *pui32Size;
+
+ //
+ // Send the command.
+ //
+ ui32Bytes = USBHCDPipeWrite(ui32OutPipe, (uint8_t*)psSCSICmd,
+ sizeof(tMSCCBW));
+
+ //
+ // If no bytes went out then the command failed.
+ //
+ if(ui32Bytes == 0)
+ {
+ return(SCSI_CMD_STATUS_FAIL);
+ }
+
+ //
+ // Only request data if there is data to request.
+ //
+ if(psSCSICmd->dCBWDataTransferLength != 0)
+ {
+ //
+ // See if this is a read or a write.
+ //
+ if(psSCSICmd->bmCBWFlags & CBWFLAGS_DIR_IN)
+ {
+ //
+ // Read the data back.
+ //
+ *pui32Size = USBHCDPipeRead(ui32InPipe, pui8Data, *pui32Size);
+ }
+ else
+ {
+ //
+ // Write the data out.
+ //
+ *pui32Size = USBHCDPipeWrite(ui32OutPipe, pui8Data, *pui32Size);
+ }
+ }
+
+ //
+ // Get the status of the command.
+ //
+ ui32Bytes = USBHCDPipeRead(ui32InPipe, (uint8_t *)&sCmdStatus,
+ sizeof(tMSCCSW));
+
+
+ //
+ // If the status was invalid or did not have the correct signature then
+ // indicate a failure.
+ //
+ if((ui32Bytes == 0) || (sCmdStatus.dCSWSignature != CSW_SIGNATURE) ||
+ (sCmdStatus.dCSWTag != CBW_TAG_VALUE))
+ {
+ return(SCSI_CMD_STATUS_FAIL);
+ }
+
+ //
+ // Return the status.
+ //
+ return((uint32_t)sCmdStatus.bCSWStatus);
+}
+
+//*****************************************************************************
+//
+//! This will issue the SCSI inquiry command to a device.
+//!
+//! \param ui32InPipe is the USB IN pipe to use for this command.
+//! \param ui32OutPipe is the USB OUT pipe to use for this command.
+//! \param pui8Data is the data buffer to return the results into.
+//! \param pui32Size is the size of buffer that was passed in on entry and the
+//! number of bytes returned.
+//!
+//! This function should be used to issue a SCSI Inquiry command to a mass
+//! storage device. To allow for multiple devices, the \e ui32InPipe and
+//! \e ui32OutPipe parameters indicate which USB pipes to use for this call.
+//!
+//! \note The \e pui8Data buffer pointer should have at least
+//! \b SCSI_INQUIRY_DATA_SZ bytes of data or this function will overflow the
+//! buffer.
+//!
+//! \return This function returns the SCSI status from the command. The value
+//! will be either \b SCSI_CMD_STATUS_PASS or \b SCSI_CMD_STATUS_FAIL.
+//
+//*****************************************************************************
+uint32_t
+USBHSCSIInquiry(uint32_t ui32InPipe, uint32_t ui32OutPipe,
+ uint8_t *pui8Data, uint32_t *pui32Size)
+{
+ tMSCCBW sSCSICmd;
+ uint32_t *pui32Data;
+
+ //
+ // Create a local 32-bit pointer to the command.
+ //
+ pui32Data = (uint32_t *)sSCSICmd.CBWCB;
+
+ //
+ // The number of bytes of data that the host expects to transfer on the
+ // Bulk-In or Bulk-Out endpoint (as indicated by the Direction bit) during
+ // the execution of this command. If this field is zero, the device and
+ // the host shall transfer no data between the CBW and the associated CSW,
+ // and the device shall ignore the value of the Direction bit in
+ // bmCBWFlags.
+ //
+ *pui32Size = SCSI_INQUIRY_DATA_SZ;
+
+ //
+ // This is an IN request.
+ //
+ sSCSICmd.bmCBWFlags = CBWFLAGS_DIR_IN;
+
+ //
+ // Only handle LUN 0.
+ //
+ sSCSICmd.bCBWLUN = 0;
+
+ //
+ // This is the length of the command itself.
+ //
+ sSCSICmd.bCBWCBLength = 6;
+
+ //
+ // Send Inquiry command with no request for vital product data.
+ //
+ pui32Data[0] = SCSI_INQUIRY_CMD;
+
+ //
+ // Allocation length.
+ //
+ pui32Data[1] = SCSI_INQUIRY_DATA_SZ;
+ pui32Data[2] = 0;
+ pui32Data[3] = 0;
+
+ //
+ // Send the command and get the results.
+ //
+ return(USBHSCSISendCommand(ui32InPipe, ui32OutPipe, &sSCSICmd, pui8Data,
+ pui32Size));
+}
+
+//*****************************************************************************
+//
+//! This will issue the SCSI read capacity command to a device.
+//!
+//! \param ui32InPipe is the USB IN pipe to use for this command.
+//! \param ui32OutPipe is the USB OUT pipe to use for this command.
+//! \param pui8Data is the data buffer to return the results into.
+//! \param pui32Size is the size of buffer that was passed in on entry and the
+//! number of bytes returned.
+//!
+//! This function should be used to issue a SCSI Read Capacity command
+//! to a mass storage device that is connected. To allow for multiple devices,
+//! the \e ui32InPipe and \e ui32OutPipe parameters indicate which USB pipes to
+//! use for this call.
+//!
+//! \note The \e pui8Data buffer pointer should have at least
+//! \b SCSI_READ_CAPACITY_SZ bytes of data or this function will overflow the
+//! buffer.
+//!
+//! \return This function returns the SCSI status from the command. The value
+//! will be either \b SCSI_CMD_STATUS_PASS or \b SCSI_CMD_STATUS_FAIL.
+//
+//*****************************************************************************
+uint32_t
+USBHSCSIReadCapacity(uint32_t ui32InPipe, uint32_t ui32OutPipe,
+ uint8_t *pui8Data, uint32_t *pui32Size)
+{
+ tMSCCBW sSCSICmd;
+ uint32_t *pui32Data;
+
+ //
+ // Create a local 32-bit pointer to the command.
+ //
+ pui32Data = (uint32_t *)sSCSICmd.CBWCB;
+
+ //
+ // Set the size of the command data.
+ //
+ *pui32Size = SCSI_READ_CAPACITY_SZ;
+
+ //
+ // This is an IN request.
+ //
+ sSCSICmd.bmCBWFlags = CBWFLAGS_DIR_IN;
+
+ //
+ // Only handle LUN 0.
+ //
+ sSCSICmd.bCBWLUN = 0;
+
+ //
+ // Set the length of the command itself.
+ //
+ sSCSICmd.bCBWCBLength = 12;
+
+ //
+ // Only use the first byte and set it to the Read Capacity command. The
+ // rest are set to 0.
+ //
+ pui32Data[0] = SCSI_READ_CAPACITY;
+ pui32Data[1] = 0;
+ pui32Data[2] = 0;
+ pui32Data[3] = 0;
+
+ //
+ // Send the command and get the results.
+ //
+ return(USBHSCSISendCommand(ui32InPipe, ui32OutPipe, &sSCSICmd, pui8Data,
+ pui32Size));
+}
+
+//*****************************************************************************
+//
+//! This will issue the SCSI read capacities command to a device.
+//!
+//! \param ui32InPipe is the USB IN pipe to use for this command.
+//! \param ui32OutPipe is the USB OUT pipe to use for this command.
+//! \param pui8Data is the data buffer to return the results into.
+//! \param pui32Size is the size of buffer that was passed in on entry and the
+//! number of bytes returned.
+//!
+//! This function should be used to issue a SCSI Read Capacities command
+//! to a mass storage device that is connected. To allow for multiple devices,
+//! the \e ui32InPipe and \e ui32OutPipe parameters indicate which USB pipes to
+//! use for this call.
+//!
+//! \return This function returns the SCSI status from the command. The value
+//! will be either \b SCSI_CMD_STATUS_PASS or \b SCSI_CMD_STATUS_FAIL.
+//
+//*****************************************************************************
+uint32_t
+USBHSCSIReadCapacities(uint32_t ui32InPipe, uint32_t ui32OutPipe,
+ uint8_t *pui8Data, uint32_t *pui32Size)
+{
+ tMSCCBW sSCSICmd;
+ uint32_t *pui32Data;
+
+ //
+ // Create a local 32-bit pointer to the command.
+ //
+ pui32Data = (uint32_t *)sSCSICmd.CBWCB;
+
+ //
+ // This is an IN request.
+ //
+ sSCSICmd.bmCBWFlags = CBWFLAGS_DIR_IN;
+
+ //
+ // Only handle LUN 0.
+ //
+ sSCSICmd.bCBWLUN = 0;
+
+ //
+ // Set the length of the command itself.
+ //
+ sSCSICmd.bCBWCBLength = 12;
+
+ //
+ // Only use the first byte and set it to the Read Capacity command. The
+ // rest are set to 0.
+ //
+ pui32Data[0] = SCSI_READ_CAPACITIES;
+ pui32Data[1] = 0;
+ pui32Data[2] = 0;
+ pui32Data[3] = 0;
+
+ //
+ // Send the command and get the results.
+ //
+ return(USBHSCSISendCommand(ui32InPipe, ui32OutPipe, &sSCSICmd, pui8Data,
+ pui32Size));
+}
+
+//*****************************************************************************
+//
+//! This will issue the SCSI Mode Sense(6) command to a device.
+//!
+//! \param ui32InPipe is the USB IN pipe to use for this command.
+//! \param ui32OutPipe is the USB OUT pipe to use for this command.
+//! \param ui32Flags is a combination of flags defining the exact query that is
+//! to be made.
+//! \param pui8Data is the data buffer to return the results into.
+//! \param pui32Size is the size of the buffer on entry and number of bytes
+//! read on exit.
+//!
+//! This function should be used to issue a SCSI Mode Sense(6) command
+//! to a mass storage device. To allow for multiple devices,the \e ui32InPipe
+//! and \e ui32OutPipe parameters indicate which USB pipes to use for this
+//! call. The call will return at most the number of bytes in the \e pui32Size
+//! parameter, however it can return less and change the \e pui32Size parameter
+//! to the number of valid bytes in the \e *pui32Size buffer.
+//!
+//! The \e ui32Flags parameter is a combination of the following three sets of
+//! definitions:
+//!
+//! One of the following values must be specified:
+//!
+//! - \b SCSI_MS_PC_CURRENT request for current settings.
+//! - \b SCSI_MS_PC_CHANGEABLE request for changeable settings.
+//! - \b SCSI_MS_PC_DEFAULT request for default settings.
+//! - \b SCSI_MS_PC_SAVED request for the saved values.
+//!
+//! One of these following values must also be specified to determine the page
+//! code for the request:
+//!
+//! - \b SCSI_MS_PC_VENDOR is the vendor specific page code.
+//! - \b SCSI_MS_PC_DISCO is the disconnect/reconnect page code.
+//! - \b SCSI_MS_PC_CONTROL is the control page code.
+//! - \b SCSI_MS_PC_LUN is the protocol specific LUN page code.
+//! - \b SCSI_MS_PC_PORT is the protocol specific port page code.
+//! - \b SCSI_MS_PC_POWER is the power condition page code.
+//! - \b SCSI_MS_PC_INFORM is the informational exceptions page code.
+//! - \b SCSI_MS_PC_ALL will request all pages codes supported by the device.
+//!
+//! The last value is optional and supports the following global flag:
+//! - \b SCSI_MS_DBD disables returning block descriptors.
+//!
+//! Example: Request for all current settings.
+//!
+//! \verbatim
+//! SCSIModeSense6(ui32InPipe, ui32OutPipe,
+//! SCSI_MS_PC_CURRENT | SCSI_MS_PC_ALL,
+//! pui8Data, pui32Size);
+//! \endverbatim
+//!
+//! \return This function returns the SCSI status from the command. The value
+//! will be either \b SCSI_CMD_STATUS_PASS or \b SCSI_CMD_STATUS_FAIL.
+//
+//*****************************************************************************
+uint32_t
+USBHSCSIModeSense6(uint32_t ui32InPipe, uint32_t ui32OutPipe,
+ uint32_t ui32Flags, uint8_t *pui8Data,
+ uint32_t *pui32Size)
+{
+ tMSCCBW sSCSICmd;
+ uint32_t *pui32Data;
+
+ //
+ // Create a local 32-bit pointer to the command.
+ //
+ pui32Data = (uint32_t *)sSCSICmd.CBWCB;
+
+ //
+ // This is an IN request.
+ //
+ sSCSICmd.bmCBWFlags = CBWFLAGS_DIR_IN;
+
+ //
+ // Only handle LUN 0.
+ //
+ sSCSICmd.bCBWLUN = 0;
+
+ //
+ // Set the size of the command data.
+ //
+ sSCSICmd.bCBWCBLength = 6;
+
+ //
+ // Set the options for the Mode Sense Command (6).
+ //
+ pui32Data[0] = (SCSI_MODE_SENSE_6 | ui32Flags);
+ pui32Data[1] = (uint8_t)*pui32Size;
+ pui32Data[2] = 0;
+ pui32Data[3] = 0;
+
+ //
+ // Send the command and get the results.
+ //
+ return(USBHSCSISendCommand(ui32InPipe, ui32OutPipe, &sSCSICmd, pui8Data,
+ pui32Size));
+}
+
+//*****************************************************************************
+//
+//! This function issues a SCSI Test Unit Ready command to a device.
+//!
+//! \param ui32InPipe is the USB IN pipe to use for this command.
+//! \param ui32OutPipe is the USB OUT pipe to use for this command.
+//!
+//! This function is used to issue a SCSI Test Unit Ready command to a device.
+//! This call will simply return the results of issuing this command.
+//!
+//! \return This function returns the results of the SCSI Test Unit Ready
+//! command. The value will be either \b SCSI_CMD_STATUS_PASS or
+//! \b SCSI_CMD_STATUS_FAIL.
+//
+//*****************************************************************************
+uint32_t
+USBHSCSITestUnitReady(uint32_t ui32InPipe, uint32_t ui32OutPipe)
+{
+ tMSCCBW sSCSICmd;
+ uint32_t ui32Size;
+ uint32_t *pui32Data;
+
+ //
+ // Create a local 32-bit pointer to the command.
+ //
+ pui32Data = (uint32_t *)sSCSICmd.CBWCB;
+
+ //
+ // No data in this command.
+ //
+ ui32Size = 0;
+
+ //
+ // This is an IN request.
+ //
+ sSCSICmd.bmCBWFlags = CBWFLAGS_DIR_IN;
+
+ //
+ // Only handle LUN 0.
+ //
+ sSCSICmd.bCBWLUN = 0;
+
+ //
+ // Set the size of the command data.
+ //
+ sSCSICmd.bCBWCBLength = 6;
+
+ //
+ // Set the parameter options.
+ //
+ pui32Data[0] = SCSI_TEST_UNIT_READY;
+ pui32Data[1] = 0;
+ pui32Data[2] = 0;
+ pui32Data[3] = 0;
+
+ //
+ // Send the command and get the results.
+ //
+ return(USBHSCSISendCommand(ui32InPipe, ui32OutPipe, &sSCSICmd, 0,
+ &ui32Size));
+}
+
+//*****************************************************************************
+//
+//! This function issues a SCSI Request Sense command to a device.
+//!
+//! \param ui32InPipe is the USB IN pipe to use for this command.
+//! \param ui32OutPipe is the USB OUT pipe to use for this command.
+//! \param pui8Data is the data buffer to return the results into.
+//! \param pui32Size is the size of the buffer on entry and number of bytes
+//! read on exit.
+//!
+//! This function is used to issue a SCSI Request Sense command to a device.
+//! It will return the data in the buffer pointed to by \e pui8Data. The
+//! parameter \e pui32Size should have the allocation size in bytes of the
+//! buffer pointed to by \e pui8Data.
+//!
+//! \return This function returns the results of the SCSI Request Sense
+//! command. The value will be either \b SCSI_CMD_STATUS_PASS or
+//! \b SCSI_CMD_STATUS_FAIL.
+//
+//*****************************************************************************
+uint32_t
+USBHSCSIRequestSense(uint32_t ui32InPipe, uint32_t ui32OutPipe,
+ uint8_t *pui8Data, uint32_t *pui32Size)
+{
+ tMSCCBW sSCSICmd;
+ uint32_t *pui32Data;
+
+ //
+ // Create a local 32-bit pointer to the command.
+ //
+ pui32Data = (uint32_t *)sSCSICmd.CBWCB;
+
+ //
+ // This is an IN request.
+ //
+ sSCSICmd.bmCBWFlags = CBWFLAGS_DIR_IN;
+
+ //
+ // Only handle LUN 0.
+ //
+ sSCSICmd.bCBWLUN = 0;
+
+ //
+ // Set the size of the command data.
+ //
+ sSCSICmd.bCBWCBLength = 12;
+
+ //
+ // Set the parameter options.
+ //
+ pui32Data[0] = SCSI_REQUEST_SENSE;
+ pui32Data[1] = 18;
+ pui32Data[2] = 0;
+ pui32Data[3] = 0;
+
+ //
+ // Send the command and get the results.
+ //
+ return(USBHSCSISendCommand(ui32InPipe, ui32OutPipe, &sSCSICmd, pui8Data,
+ pui32Size));
+}
+
+//*****************************************************************************
+//
+//! This function issues a SCSI Read(10) command to a device.
+//!
+//! \param ui32InPipe is the USB IN pipe to use for this command.
+//! \param ui32OutPipe is the USB OUT pipe to use for this command.
+//! \param ui32LBA is the logical block address to read.
+//! \param pui8Data is the data buffer to return the data.
+//! \param pui32Size is the size of the buffer on entry and number of bytes
+//! read on exit.
+//! \param ui32NumBlocks is the number of contiguous blocks to read from the
+//! device.
+//!
+//! This function is used to issue a SCSI Read(10) command to a device. The
+//! \e ui32LBA parameter specifies the logical block address to read from the
+//! device. The data from this block will be returned in the buffer pointed to
+//! by \e pui8Data. The parameter \e pui32Size should indicate enough space to
+//! hold a full block size, or only the first \e pui32Size bytes of the LBA are
+//! returned.
+//!
+//! \return This function returns the results of the SCSI Read(10) command.
+//! The value will be either \b SCSI_CMD_STATUS_PASS or
+//! \b SCSI_CMD_STATUS_FAIL.
+//
+//*****************************************************************************
+uint32_t
+USBHSCSIRead10(uint32_t ui32InPipe, uint32_t ui32OutPipe,
+ uint32_t ui32LBA, uint8_t *pui8Data,
+ uint32_t *pui32Size, uint32_t ui32NumBlocks)
+{
+ tMSCCBW sSCSICmd;
+ int32_t i32Idx;
+
+ //
+ // Zero out the response data.
+ //
+ for(i32Idx = 0; i32Idx < sizeof(sSCSICmd.CBWCB); i32Idx++)
+ {
+ sSCSICmd.CBWCB[i32Idx] = 0;
+ }
+
+ //
+ // This is an IN request.
+ //
+ sSCSICmd.bmCBWFlags = CBWFLAGS_DIR_IN;
+
+ //
+ // Only handle LUN 0.
+ //
+ sSCSICmd.bCBWLUN = 0;
+
+ //
+ // Set the size of the command data.
+ //
+ sSCSICmd.bCBWCBLength = 10;
+
+ //
+ // Set the parameter options.
+ //
+ sSCSICmd.CBWCB[0] = SCSI_READ_10;
+
+ //
+ // LBA starts at offset 2.
+ //
+ sSCSICmd.CBWCB[2] = (uint8_t)(ui32LBA >> 24);
+ sSCSICmd.CBWCB[3] = (uint8_t)(ui32LBA >> 16);
+ sSCSICmd.CBWCB[4] = (uint8_t)(ui32LBA >> 8);
+ sSCSICmd.CBWCB[5] = (uint8_t)ui32LBA;
+
+ //
+ // Transfer length in blocks starts at offset 7.
+ //
+ sSCSICmd.CBWCB[7] = (uint8_t)(ui32NumBlocks >> 8);
+ sSCSICmd.CBWCB[8] = (uint8_t)ui32NumBlocks;
+
+ //
+ // Send the command and get the results.
+ //
+ return(USBHSCSISendCommand(ui32InPipe, ui32OutPipe, &sSCSICmd, pui8Data,
+ pui32Size));
+}
+
+//*****************************************************************************
+//
+//! This function issues a SCSI Write(10) command to a device.
+//!
+//! This function is used to issue a SCSI Write(10) command to a device. The
+//! \e ui32LBA parameter specifies the logical block address on the device.
+//! The data to write to this block should be in the buffer pointed to by
+//! \e pui8Data parameter. The parameter \e pui32Size should indicate the
+//! amount of data to write to the specified LBA.
+//!
+//! \param ui32InPipe is the USB IN pipe to use for this command.
+//! \param ui32OutPipe is the USB OUT pipe to use for this command.
+//! \param ui32LBA is the logical block address to read.
+//! \param pui8Data is the data buffer to write out.
+//! \param pui32Size is the size of the buffer.
+//! \param ui32NumBlocks is the number of contiguous blocks to write to the
+//! device.
+//!
+//! \return This function returns the results of the SCSI Write(10) command.
+//! The value will be either \b SCSI_CMD_STATUS_PASS or
+//! \b SCSI_CMD_STATUS_FAIL.
+//
+//*****************************************************************************
+uint32_t
+USBHSCSIWrite10(uint32_t ui32InPipe, uint32_t ui32OutPipe,
+ uint32_t ui32LBA, uint8_t *pui8Data,
+ uint32_t *pui32Size, uint32_t ui32NumBlocks)
+{
+ tMSCCBW sSCSICmd;
+ uint32_t *pui32Data;
+
+ //
+ // Create a local 32-bit pointer to the command.
+ //
+ pui32Data = (uint32_t *)sSCSICmd.CBWCB;
+
+ //
+ // This is an IN request.
+ //
+ sSCSICmd.bmCBWFlags = CBWFLAGS_DIR_OUT;
+
+ //
+ // Only handle LUN 0.
+ //
+ sSCSICmd.bCBWLUN = 0;
+
+ //
+ // Set the size of the command data.
+ //
+ sSCSICmd.bCBWCBLength = 10;
+
+ //
+ // Set the parameter options.
+ //
+ sSCSICmd.CBWCB[0] = SCSI_WRITE_10;
+
+ //
+ // Clear the reserved field.
+ //
+ sSCSICmd.CBWCB[1] = 0;
+
+ //
+ // LBA starts at offset 2.
+ //
+ sSCSICmd.CBWCB[2] = (uint8_t)(ui32LBA >> 24);
+ sSCSICmd.CBWCB[3] = (uint8_t)(ui32LBA >> 16);
+ sSCSICmd.CBWCB[4] = (uint8_t)(ui32LBA >> 8);
+ sSCSICmd.CBWCB[5] = (uint8_t)ui32LBA;
+
+ //
+ // Clear the reserved field.
+ //
+ sSCSICmd.CBWCB[6] = 0;
+
+ //
+ // Set the transfer length in blocks.
+ // This also sets the Control value to 0 at offset 9.
+ //
+ sSCSICmd.CBWCB[7] = (ui32NumBlocks & 0xFF00) >> 8;
+
+ //
+ // The blocks go into is byte offset 8 or word address 2.
+ //
+ pui32Data[2] = (ui32NumBlocks & 0xFF);
+
+ //
+ // The blocks go into is byte offset 12 or word address 3.
+ //
+ pui32Data[3] = 0;
+
+ //
+ // Send the command and get the results.
+ //
+ return(USBHSCSISendCommand(ui32InPipe, ui32OutPipe, &sSCSICmd, pui8Data,
+ pui32Size));
+}
+
+//*****************************************************************************
+//
+// Close the Doxygen group.
+//! @}
+//
+//*****************************************************************************
diff --git a/usblib/host/usbhscsi.h b/usblib/host/usbhscsi.h
new file mode 100644
index 0000000..29291e1
--- /dev/null
+++ b/usblib/host/usbhscsi.h
@@ -0,0 +1,87 @@
+//*****************************************************************************
+//
+// usbhscsi.h - Definitions for the USB host SCSI layer.
+//
+// Copyright (c) 2008-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 Tiva USB Library.
+//
+//*****************************************************************************
+
+#ifndef __USBHSCSI_H__
+#define __USBHSCSI_H__
+
+//*****************************************************************************
+//
+// If building with a C++ compiler, make all of the definitions in this header
+// have a C binding.
+//
+//*****************************************************************************
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+//*****************************************************************************
+//
+//! \addtogroup usblib_host_class
+//! @{
+//
+//*****************************************************************************
+
+//*****************************************************************************
+//
+// Prototypes for the APIs exported by the USB SCSI layer.
+//
+//*****************************************************************************
+extern uint32_t USBHSCSIInquiry(uint32_t ui32InPipe, uint32_t ui32OutPipe,
+ uint8_t *pui8Buffer, uint32_t *pui32Size);
+extern uint32_t USBHSCSIReadCapacity(uint32_t ui32InPipe, uint32_t ui32OutPipe,
+ uint8_t *pui8Data, uint32_t *pui32Size);
+extern uint32_t USBHSCSIReadCapacities(uint32_t ui32InPipe,
+ uint32_t ui32OutPipe, uint8_t *pui8Data,
+ uint32_t *pui32Size);
+extern uint32_t USBHSCSIModeSense6(uint32_t ui32InPipe, uint32_t ui32OutPipe,
+ uint32_t ui32Flags, uint8_t *pui8Data,
+ uint32_t *pui32Size);
+extern uint32_t USBHSCSITestUnitReady(uint32_t ui32InPipe,
+ uint32_t ui32OutPipe);
+extern uint32_t USBHSCSIRequestSense(uint32_t ui32InPipe, uint32_t ui32OutPipe,
+ uint8_t *pui8Data, uint32_t *pui32Size);
+extern uint32_t USBHSCSIRead10(uint32_t ui32InPipe, uint32_t ui32OutPipe,
+ uint32_t ui32LBA, uint8_t *pui8Data,
+ uint32_t *pui32Size, uint32_t ui32NumBlocks);
+extern uint32_t USBHSCSIWrite10(uint32_t ui32InPipe, uint32_t ui32OutPipe,
+ uint32_t ui32LBA, uint8_t *pui8Data,
+ uint32_t *pui32Size, uint32_t ui32NumBlocks);
+
+//*****************************************************************************
+//
+//! @}
+//
+//*****************************************************************************
+
+//*****************************************************************************
+//
+// Mark the end of the C bindings section for C++ compilers.
+//
+//*****************************************************************************
+#ifdef __cplusplus
+}
+#endif
+
+#endif // __USBHSCSI_H__