1、 USB CDC介绍
USB的CDC类是USB通信设备类(Communication Device Class)的简称。CDC类是USB组织定义的一类专门给各种通信设备(电信通信设备和中速网络通信设备)使用的USB子类。
USB CDC具备两个类接口:通信接口类(Communication Interface Class)和数据接口类(Data Interface Class)。
协议原文:Two classes of interfaces are described in this specification:Communication Class interfaces and Data Class interfaces.The CommunicationClass interface is a management interface and is required of all communicationdevices. The Data Class interface can be used to transport data whose structureand usage is not defined by any other class, such as Audio.The format of thedata moving over this interface can be identified using the associatedCommunication Class interface.
个人见解:通常一个CDC类又由两个接口子类组成通信接口类(Communication Interface Class)和数据接口类(Data Interface Class)。通信接口类是一个管理接口,是所有通信设备的都需要具备的接口。数据接口类和用于数据的传输,它的结构和用途与其他(USB)定义的类不一样,如音频接口类。数据接口类传输的数据格式可以由通信接口类确定。
USB CDC类结构如图1所示:
图1 USB CDC类结构
通信接口类是一个主要通过通信接口类对设备进行管理和控制,而通过数据接口类传送数据。这两个接口子类占有不同数量和类型的终端点(Endpoints),如图1所示。
通信接口类需要一个控制终端点(Control Endpoint)和一个可选的中断(Interrupt)型终端点。数据接口子类需要一个方向为输入(IN)的周期性(Isochronous)型终端点和一个方向为输出(OUT)的周期性型终端点。其中控制终端点主要用于USB设备的枚举和虚拟串口的波特率和数据类型(数据位数、停止位和起始位)设置的通信。输出方向的非同步终端点用于主机(Host)向从设备(Slave)发送数据,相当于传统物理串口中的TXD线(如果从单片机的角度看),输入方向的非同步终端点用于从设备向主机发送数据,相当于传统物理串口中的RXD线。
2、相关资料推荐
(1) USB CDC标准协议网址:http://www.usb.org/developers/devclass_docs
(2) USB CDC标准协议:“usbcdc11.pdf”(Universal Serial Bus Class Definitions for Communication Devices)
CSDN下载网址:http://download.csdn.net/detail/xhoufei2010/7434447
(3) USB书籍资料推荐(PDF版):《计算机USB系统原理及其主从机设计》
CSDN下载网址:http://download.csdn.net/detail/xhoufei2010/7434465
(4) 程序开发环境:CCS5.5
(5) 硬件芯片:TM4C1236D5PM
(6) 驱动软件包(TI cortex-M4芯片驱动包):SW-TM4C-2.0.1.11577
(7) 工程源代码链接:
PUDN网站下载:http://www.pudn.com/downloads630/sourcecode/embedded/detail2557336.html
CSDN网站下载:http://download.csdn.net/detail/xhoufei2010/7434425
3、USB驱动结构
USB驱动结构图如图2所示。
图2 USB主机系统结构
对于TI的Cortex-M4芯片,第1层“USB总线接口层”、第2层“USB系统层”的“USB主控制驱动程序”已经由驱动库“SW-TM4C-2.0.1.11577.exe”完成,用户安装之后,“usblib”文件夹有相应的驱动。
用户需要完成主要为“USB核心驱动程序”和“管理接口”。
图3 USB核心驱动程序USB的结构
对于USB CDC类传输,依靠为管道传输。TI cortex-M4系列芯片共有14个管道:7个IN管道、7个OUT管道(详细介绍可查看datasheet的USB章节)。
USB的管道机制完全支持USB的4种管道类型(也就是数据传输的类型),即批量传输、同步传输、中断传输和控制传输。对于USB CDC的数据传输接口类,采用的为批量传输:BULK IN、BULK OUT。通信接口类采用的是中断传输。
(1) 修改TI USB驱动库"usbhostenum.c"文件
对于TI的驱动库含有USB CDC主机的枚举驱动已经提供(如图2“USB主控制驱动程序”)。对于驱动库中的”usbhostenum.c”文件,有一地方个人觉得是明显的错误。
//
// Use the first configuration to set the device
// configuration.
//
USBHCDSetConfig(0,
(uint32_t)&g_sUSBHCD.psUSBDevice[ui32DevIndex], 1);
对于从机在主机端的端口号,不应该为固定数值1,应该根据从机自身的描述符确定。
本人修改如下:
// 修改人:sky
// 修改内容:设备采用的配置的配置值,由原来的固定数值1修改为,根据从机的信息而定
// 实现步骤:1、先获取从机的配置值,保存在一个全局变量g_sUSBHCD
// 2、然后将从机获取的配置值,由主机进行设置配置值,不再沿用TI驱动库的固定数值1
USBHCDSetConfig(0,
(uint32_t)&g_sUSBHCD.psUSBDevice[ui32DevIndex],
g_sUSBHCD.psUSBDevice[ui32DevIndex].psConfigDescriptor->bConfigurationValue);
另外,对于USB HOST CDC的接收回调函数,应该提供接收数据的长度,故增加的一个接口函数,用于提供接收的数据长度(参数为全局静态变量)。
uint32_t USBHCD_GetReceiveSize(void)
{
return s_recvByte;
}
函数的相关操作见TI驱动库“usblib\host”文件夹内的“usbhostenum.c”文件,该文件修改之后,代码如下:
//*****************************************************************************
//
// usbhostenum.c - Device enumeration code for the USB host library.
//
// Copyright (c) 2008-2013 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.0.1.11577 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);
// 接收数据统计
static uint32_t s_recvByte = 0;
//*****************************************************************************
//
// 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 number of bytes of read data to copy.
//
uint32_t ui32ReadSize;
//
// 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 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 = ui32Size;
}
//
// 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 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_BLIZZARD;
//
// These devices have a different USB interrupt number.
//
if(CLASS_IS_SNOWFLAKE)
{
g_sUSBHCD.ui32IntNum = INT_USB0_SNOWFLAKE;
}
//
// 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 USBHCD_VBUS_MANUAL is used then the application must provide an
//! event driver to receive the USB_EVENT_POWER_ENABLE and
//! 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_SNOWFLAKE)
{
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)
{
//
// Enable the DMA channel and wait for it to complete.
//
g_sUSBHCD.psUSBINPipes[ui32Idx].iState = ePipeReadDMAWait;
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)
{
USBEndpointDataGet(USB0_BASE, IndexToUSBEP(ui32Idx + 1),
g_sUSBHCD.psUSBINPipes[ui32Idx].pui8ReadPtr,
&g_sUSBHCD.psUSBINPipes[ui32Idx].ui32ReadSize);
// 添加部分
s_recvByte = g_sUSBHCD.psUSBINPipes[ui32Idx].ui32ReadSize;
}
//
// 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.
//
// 修改人:sky
// 修改内容:设备采用的配置的配置值,由原来的固定数值1修改为,根据从机的信息而定
// 实现步骤:1、先获取从机的配置值,保存在一个全局变量g_sUSBHCD
// 2、然后将从机获取的配置值,由主机进行设置配置值,不再沿用TI驱动库的固定数值1
USBHCDSetConfig(0,
(uint32_t)&g_sUSBHCD.psUSBDevice[ui32DevIndex],
g_sUSBHCD.psUSBDevice[ui32DevIndex].psConfigDescriptor->bConfigurationValue);
//
// 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 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
//! 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
//! 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
//! 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);
}
uint32_t USBHCD_GetReceiveSize(void)
{
return s_recvByte;
}
//*****************************************************************************
//
// Close the Doxygen group.
//! @}
//
//*****************************************************************************
(2)修改“usblib.h”文件
添加接口函数“uint32_t USBHCD_GetReceiveSize(void)”的声明,该函数用户告知用户USB Host CDC端口接收到的从机的数据长度。该文件只需要在“usblib.h”文件的1941行添加如下代码:
// 添加部分
extern uint32_t USBHCD_GetReceiveSize(void);
修改之后代码如下:
//*****************************************************************************
//
// usblib.h - Main header file for the USB Library.
//
// Copyright (c) 2008-2013 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.0.1.11577 of the Tiva USB Library.
//
//*****************************************************************************
#ifndef __USBLIB_H__
#define __USBLIB_H__
//*****************************************************************************
//
// If building with a C++ compiler, make all of the definitions in this header
// have a C binding.
//
//*****************************************************************************
#ifdef __cplusplus
extern "C"
{
#endif
//*****************************************************************************
//
// This is the maximum number of devices we can support when in host mode and
// using a hub. By default, we support up to 4 devices (plus 1 internally for
// the hub itself).
//
//*****************************************************************************
#ifndef MAX_USB_DEVICES
#define MAX_USB_DEVICES 5
#endif
//*****************************************************************************
//
// This is the maximum number of endpoints supported by the usblib.
//
//*****************************************************************************
#ifndef USBLIB_NUM_EP
#define USBLIB_NUM_EP 8 // Number of supported endpoints.
#endif
//*****************************************************************************
//
// The following macro allows compiler-independent syntax to be used to
// define packed structures. A typical structure definition using these
// macros will look similar to the following example:
//
// #ifdef ewarm
// #pragma pack(1)
// #endif
//
// typedef struct _PackedStructName
// {
// uint32_t ui32FirstField;
// int8_t i8CharMember;
// uint16_t ui16Short;
// }
// PACKED tPackedStructName;
//
// #ifdef ewarm
// #pragma pack()
// #endif
//
// The conditional blocks related to ewarm include the #pragma pack() lines
// only if the IAR Embedded Workbench compiler is being used. Unfortunately,
// it is not possible to emit a #pragma from within a macro definition so this
// must be done explicitly.
//
//*****************************************************************************
#if defined(ccs) || \
defined(codered) || \
defined(gcc) || \
defined(rvmdk) || \
defined(__ARMCC_VERSION) || \
defined(sourcerygxx)
#define PACKED __attribute__ ((packed))
#elif defined(ewarm)
#define PACKED
#else
#error Unrecognized COMPILER!
#endif
//*****************************************************************************
//
// Assorted language IDs from the document "USB_LANGIDs.pdf" provided by the
// USB Implementers' Forum (Version 1.0).
//
//*****************************************************************************
#define USB_LANG_CHINESE_PRC 0x0804 // Chinese (PRC)
#define USB_LANG_CHINESE_TAIWAN 0x0404 // Chinese (Taiwan)
#define USB_LANG_EN_US 0x0409 // English (United States)
#define USB_LANG_EN_UK 0x0809 // English (United Kingdom)
#define USB_LANG_EN_AUS 0x0C09 // English (Australia)
#define USB_LANG_EN_CA 0x1009 // English (Canada)
#define USB_LANG_EN_NZ 0x1409 // English (New Zealand)
#define USB_LANG_FRENCH 0x040C // French (Standard)
#define USB_LANG_GERMAN 0x0407 // German (Standard)
#define USB_LANG_HINDI 0x0439 // Hindi
#define USB_LANG_ITALIAN 0x0410 // Italian (Standard)
#define USB_LANG_JAPANESE 0x0411 // Japanese
#define USB_LANG_KOREAN 0x0412 // Korean
#define USB_LANG_ES_TRAD 0x040A // Spanish (Traditional)
#define USB_LANG_ES_MODERN 0x0C0A // Spanish (Modern)
#define USB_LANG_SWAHILI 0x0441 // Swahili (Kenya)
#define USB_LANG_URDU_IN 0x0820 // Urdu (India)
#define USB_LANG_URDU_PK 0x0420 // Urdu (Pakistan)
//*****************************************************************************
//
//! \addtogroup usbchap9_src
//! @{
//
//*****************************************************************************
//*****************************************************************************
//
// Note:
//
// Structure definitions which are derived directly from the USB specification
// use field names from the specification. Since a somewhat different version
// of Hungarian prefix notation is used from the standard, beware of making
// assumptions about field sizes based on the field prefix when using
// these structures. Of particular note is the difference in the meaning of
// the 'i' prefix. In USB structures, this indicates a single byte index
// whereas in other code, this is an integer or enumeration variable.
//
//*****************************************************************************
//*****************************************************************************
//
// All structures defined in this section of the header require byte packing of
// fields. This is usually accomplished using the PACKED macro but, for IAR
// Embedded Workbench, this requires a pragma.
//
//*****************************************************************************
#ifdef ewarm
#pragma pack(1)
#endif
//*****************************************************************************
//
// Definitions related to standard USB device requests (sections 9.3 & 9.4)
//
//*****************************************************************************
//*****************************************************************************
//
//! The standard USB request header as defined in section 9.3 of the USB 2.0
//! specification.
//
//*****************************************************************************
typedef struct
{
//
//! Determines the type and direction of the request.
//
uint8_t bmRequestType;
//
//! Identifies the specific request being made.
//
uint8_t bRequest;
//
//! Word-sized field that varies according to the request.
//
uint16_t wValue;
//
//! Word-sized field that varies according to the request; typically used
//! to pass an index or offset.
//
uint16_t wIndex;
//
//! The number of bytes to transfer if there is a data stage to the
//! request.
//
uint16_t wLength;
}
PACKED tUSBRequest;
//*****************************************************************************
//
// The following defines are used with the bmRequestType member of tUSBRequest.
//
// Request types have 3 bit fields:
// 4:0 - Is the recipient type.
// 6:5 - Is the request type.
// 7 - Is the direction of the request.
//
//*****************************************************************************
#define USB_RTYPE_DIR_IN 0x80
#define USB_RTYPE_DIR_OUT 0x00
#define USB_RTYPE_TYPE_M 0x60
#define USB_RTYPE_VENDOR 0x40
#define USB_RTYPE_CLASS 0x20
#define USB_RTYPE_STANDARD 0x00
#define USB_RTYPE_RECIPIENT_M 0x1f
#define USB_RTYPE_OTHER 0x03
#define USB_RTYPE_ENDPOINT 0x02
#define USB_RTYPE_INTERFACE 0x01
#define USB_RTYPE_DEVICE 0x00
//*****************************************************************************
//
// Standard USB requests IDs used in the bRequest field of tUSBRequest.
//
//*****************************************************************************
#define USBREQ_GET_STATUS 0x00
#define USBREQ_CLEAR_FEATURE 0x01
#define USBREQ_SET_FEATURE 0x03
#define USBREQ_SET_ADDRESS 0x05
#define USBREQ_GET_DESCRIPTOR 0x06
#define USBREQ_SET_DESCRIPTOR 0x07
#define USBREQ_GET_CONFIG 0x08
#define USBREQ_SET_CONFIG 0x09
#define USBREQ_GET_INTERFACE 0x0a
#define USBREQ_SET_INTERFACE 0x0b
#define USBREQ_SYNC_FRAME 0x0c
//*****************************************************************************
//
// Data returned from a USBREQ_GET_STATUS request to a device.
//
//*****************************************************************************
#define USB_STATUS_SELF_PWR 0x0001 // Currently self powered.
#define USB_STATUS_BUS_PWR 0x0000 // Currently bus-powered.
#define USB_STATUS_PWR_M 0x0001 // Mask for power mode.
#define USB_STATUS_REMOTE_WAKE 0x0002 // Remote wake-up is currently enabled.
//*****************************************************************************
//
// Feature Selectors (tUSBRequest.wValue) passed on USBREQ_CLEAR_FEATURE and
// USBREQ_SET_FEATURE.
//
//*****************************************************************************
#define USB_FEATURE_EP_HALT 0x0000 // Endpoint halt feature.
#define USB_FEATURE_REMOTE_WAKE 0x0001 // Remote wake feature, device only.
#define USB_FEATURE_TEST_MODE 0x0002 // Test mode
//*****************************************************************************
//
// Endpoint Selectors (tUSBRequest.wIndex) passed on USBREQ_CLEAR_FEATURE,
// USBREQ_SET_FEATURE and USBREQ_GET_STATUS.
//
//*****************************************************************************
#define USB_REQ_EP_NUM_M 0x007F
#define USB_REQ_EP_DIR_M 0x0080
#define USB_REQ_EP_DIR_IN 0x0080
#define USB_REQ_EP_DIR_OUT 0x0000
//*****************************************************************************
//
// Standard USB descriptor types. These values are passed in the upper bytes
// of tUSBRequest.wValue on USBREQ_GET_DESCRIPTOR and also appear in the
// bDescriptorType field of standard USB descriptors.
//
//*****************************************************************************
#define USB_DTYPE_DEVICE 1
#define USB_DTYPE_CONFIGURATION 2
#define USB_DTYPE_STRING 3
#define USB_DTYPE_INTERFACE 4
#define USB_DTYPE_ENDPOINT 5
#define USB_DTYPE_DEVICE_QUAL 6
#define USB_DTYPE_OSPEED_CONF 7
#define USB_DTYPE_INTERFACE_PWR 8
#define USB_DTYPE_OTG 9
#define USB_DTYPE_INTERFACE_ASC 11
#define USB_DTYPE_CS_INTERFACE 36
#define USB_DTYPE_HUB 41
//*****************************************************************************
//
// Definitions related to USB descriptors (sections 9.5 & 9.6)
//
//*****************************************************************************
//*****************************************************************************
//
//! This structure describes a generic descriptor header. These fields are to
//! be found at the beginning of all valid USB descriptors.
//
//*****************************************************************************
typedef struct
{
//
//! The length of this descriptor (including this length byte) expressed
//! in bytes.
//
uint8_t bLength;
//
//! The type identifier of the descriptor whose information follows. For
//! standard descriptors, this field could contain, for example,
//! USB_DTYPE_DEVICE to identify a device descriptor or USB_DTYPE_ENDPOINT
//! to identify an endpoint descriptor.
//
uint8_t bDescriptorType;
}
PACKED tDescriptorHeader;
//*****************************************************************************
//
//! This structure describes the USB device descriptor as defined in USB
//! 2.0 specification section 9.6.1.
//
//*****************************************************************************
typedef struct
{
//
//! The length of this descriptor in bytes. All device descriptors are
//! 18 bytes long.
//
uint8_t bLength;
//
//! The type of the descriptor. For a device descriptor, this will be
//! USB_DTYPE_DEVICE (1).
//
uint8_t bDescriptorType;
//
//! The USB Specification Release Number in BCD format. For USB 2.0, this
//! will be 0x0200.
//
uint16_t bcdUSB;
//
//! The device class code.
//
uint8_t bDeviceClass;
//
//! The device subclass code. This value qualifies the value found in the
//! bDeviceClass field.
//
uint8_t bDeviceSubClass;
//
//! The device protocol code. This value is qualified by the values of
//! bDeviceClass and bDeviceSubClass.
//
uint8_t bDeviceProtocol;
//
//! The maximum packet size for endpoint zero. Valid values are 8, 16, 32
//! and 64.
//
uint8_t bMaxPacketSize0;
//
//! The device Vendor ID (VID) as assigned by the USB-IF.
//
uint16_t idVendor;
//
//! The device Product ID (PID) as assigned by the manufacturer.
//
uint16_t idProduct;
//
//! The device release number in BCD format.
//
uint16_t bcdDevice;
//
//! The index of a string descriptor describing the manufacturer.
//
uint8_t iManufacturer;
//
//! The index of a string descriptor describing the product.
//
uint8_t iProduct;
//
//! The index of a string descriptor describing the device's serial
//! number.
//
uint8_t iSerialNumber;
//
//! The number of possible configurations offered by the device. This
//! field indicates the number of distinct configuration descriptors that
//! the device offers.
//
uint8_t bNumConfigurations;
}
PACKED tDeviceDescriptor;
//*****************************************************************************
//
// USB Device Class codes used in the tDeviceDescriptor.bDeviceClass field.
// Definitions for the bDeviceSubClass and bDeviceProtocol fields are device
// specific and can be found in the appropriate device class header files.
//
//*****************************************************************************
#define USB_CLASS_DEVICE 0x00
#define USB_CLASS_AUDIO 0x01
#define USB_CLASS_CDC 0x02
#define USB_CLASS_HID 0x03
#define USB_CLASS_PHYSICAL 0x05
#define USB_CLASS_IMAGE 0x06
#define USB_CLASS_PRINTER 0x07
#define USB_CLASS_MASS_STORAGE 0x08
#define USB_CLASS_HUB 0x09
#define USB_CLASS_CDC_DATA 0x0a
#define USB_CLASS_SMART_CARD 0x0b
#define USB_CLASS_SECURITY 0x0d
#define USB_CLASS_VIDEO 0x0e
#define USB_CLASS_HEALTHCARE 0x0f
#define USB_CLASS_DIAG_DEVICE 0xdc
#define USB_CLASS_WIRELESS 0xe0
#define USB_CLASS_MISC 0xef
#define USB_CLASS_APP_SPECIFIC 0xfe
#define USB_CLASS_VEND_SPECIFIC 0xff
#define USB_CLASS_EVENTS 0xffffffff
//*****************************************************************************
//
// Generic values for undefined subclass and protocol.
//
//*****************************************************************************
#define USB_SUBCLASS_UNDEFINED 0x00
#define USB_PROTOCOL_UNDEFINED 0x00
//*****************************************************************************
//
// The following are the miscellaneous subclass values.
//
//*****************************************************************************
#define USB_MISC_SUBCLASS_SYNC 0x01
#define USB_MISC_SUBCLASS_COMMON \
0x02
//*****************************************************************************
//
// These following are miscellaneous protocol values.
//
//*****************************************************************************
#define USB_MISC_PROTOCOL_IAD 0x01
//*****************************************************************************
//
// These following are hub protocol values.
//
//*****************************************************************************
#define USB_HUB_PROTOCOL_FS 0x00
#define USB_HUB_PROTOCOL_SINGLE 0x01
#define USB_HUB_PROTOCOL_MULTI 0x02
//*****************************************************************************
//
//! This structure describes the USB device qualifier descriptor as defined in
//! the USB 2.0 specification, section 9.6.2.
//
//*****************************************************************************
typedef struct
{
//
//! The length of this descriptor in bytes. All device qualifier
//! descriptors are 10 bytes long.
//
uint8_t bLength;
//
//! The type of the descriptor. For a device descriptor, this will be
//! USB_DTYPE_DEVICE_QUAL (6).
//
uint8_t bDescriptorType;
//
//! The USB Specification Release Number in BCD format. For USB 2.0, this
//! will be 0x0200.
//
uint16_t bcdUSB;
//
//! The device class code.
//
uint8_t bDeviceClass;
//
//! The device subclass code. This value qualifies the value found in the
//! bDeviceClass field.
//
uint8_t bDeviceSubClass;
//
//! The device protocol code. This value is qualified by the values of
//! bDeviceClass and bDeviceSubClass.
//
uint8_t bDeviceProtocol;
//
//! The maximum packet size for endpoint zero when operating at a speed
//! other than high speed.
//
uint8_t bMaxPacketSize0;
//
//! The number of other-speed configurations supported.
//
uint8_t bNumConfigurations;
//
//! Reserved for future use. Must be set to zero.
//
uint8_t bReserved;
}
PACKED tDeviceQualifierDescriptor;
//*****************************************************************************
//
//! This structure describes the USB configuration descriptor as defined in
//! USB 2.0 specification section 9.6.3. This structure also applies to the
//! USB other speed configuration descriptor defined in section 9.6.4.
//
//*****************************************************************************
typedef struct
{
//
//! The length of this descriptor in bytes. All configuration descriptors
//! are 9 bytes long.
//
uint8_t bLength;
//
//! The type of the descriptor. For a configuration descriptor, this will
//! be USB_DTYPE_CONFIGURATION (2).
//
uint8_t bDescriptorType;
//
//! The total length of data returned for this configuration. This
//! includes the combined length of all descriptors (configuration,
//! interface, endpoint and class- or vendor-specific) returned for this
//! configuration.
//
uint16_t wTotalLength;
//
//! The number of interface supported by this configuration.
//
uint8_t bNumInterfaces;
//
//! The value used as an argument to the SetConfiguration standard request
//! to select this configuration.
//
uint8_t bConfigurationValue;
//
//! The index of a string descriptor describing this configuration.
//
uint8_t iConfiguration;
//
//! Attributes of this configuration.
//
uint8_t bmAttributes;
//
//! The maximum power consumption of the USB device from the bus in this
//! configuration when the device is fully operational. This is expressed
//! in units of 2mA so, for example, 100 represents 200mA.
//
uint8_t bMaxPower;
}
PACKED tConfigDescriptor;
//*****************************************************************************
//
// Flags used in constructing the value assigned to the field
// tConfigDescriptor.bmAttributes. Note that bit 7 is reserved and must be set
// to 1.
//
//*****************************************************************************
#define USB_CONF_ATTR_PWR_M 0xC0
#define USB_CONF_ATTR_SELF_PWR 0xC0
#define USB_CONF_ATTR_BUS_PWR 0x80
#define USB_CONF_ATTR_RWAKE 0xA0
//*****************************************************************************
//
//! This structure describes the USB interface descriptor as defined in USB
//! 2.0 specification section 9.6.5.
//
//*****************************************************************************
typedef struct
{
//
//! The length of this descriptor in bytes. All interface descriptors
//! are 9 bytes long.
//
uint8_t bLength;
//
//! The type of the descriptor. For an interface descriptor, this will
//! be USB_DTYPE_INTERFACE (4).
//
uint8_t bDescriptorType;
//
//! The number of this interface. This is a zero based index into the
//! array of concurrent interfaces supported by this configuration.
//
uint8_t bInterfaceNumber;
//
//! The value used to select this alternate setting for the interface
//! defined in bInterfaceNumber.
//
uint8_t bAlternateSetting;
//
//! The number of endpoints used by this interface (excluding endpoint
//! zero).
//
uint8_t bNumEndpoints;
//
//! The interface class code as assigned by the USB-IF.
//
uint8_t bInterfaceClass;
//
//! The interface subclass code as assigned by the USB-IF.
//
uint8_t bInterfaceSubClass;
//
//! The interface protocol code as assigned by the USB-IF.
//
uint8_t bInterfaceProtocol;
//
//! The index of a string descriptor describing this interface.
//
uint8_t iInterface;
}
PACKED tInterfaceDescriptor;
//*****************************************************************************
//
//! This structure describes the USB endpoint descriptor as defined in USB
//! 2.0 specification section 9.6.6.
//
//*****************************************************************************
typedef struct
{
//
//! The length of this descriptor in bytes. All endpoint descriptors
//! are 7 bytes long.
//
uint8_t bLength;
//
//! The type of the descriptor. For an endpoint descriptor, this will
//! be USB_DTYPE_ENDPOINT (5).
//
uint8_t bDescriptorType;
//
//! The address of the endpoint. This field contains the endpoint number
//! ORed with flag USB_EP_DESC_OUT or USB_EP_DESC_IN to indicate the
//! endpoint direction.
//
uint8_t bEndpointAddress;
//
//! The endpoint transfer type, USB_EP_ATTR_CONTROL, USB_EP_ATTR_ISOC,
//! USB_EP_ATTR_BULK or USB_EP_ATTR_INT and, if isochronous, additional
//! flags indicating usage type and synchronization method.
//
uint8_t bmAttributes;
//
//! The maximum packet size this endpoint is capable of sending or
//! receiving when this configuration is selected. For high speed
//! isochronous or interrupt endpoints, bits 11 and 12 are used to
//! pass additional information.
//
uint16_t wMaxPacketSize;
//
//! The polling interval for data transfers expressed in frames or
//! micro frames depending upon the operating speed.
//
uint8_t bInterval;
}
PACKED tEndpointDescriptor;
//*****************************************************************************
//
// Flags used in constructing the value assigned to the field
// tEndpointDescriptor.bEndpointAddress.
//
//*****************************************************************************
#define USB_EP_DESC_OUT 0x00
#define USB_EP_DESC_IN 0x80
#define USB_EP_DESC_NUM_M 0x0f
//*****************************************************************************
//
// Mask used to extract the maximum packet size (in bytes) from the
// wMaxPacketSize field of the endpoint descriptor.
//
//*****************************************************************************
#define USB_EP_MAX_PACKET_COUNT_M \
0x07FF
//*****************************************************************************
//
// Endpoint attributes used in tEndpointDescriptor.bmAttributes.
//
//*****************************************************************************
#define USB_EP_ATTR_CONTROL 0x00
#define USB_EP_ATTR_ISOC 0x01
#define USB_EP_ATTR_BULK 0x02
#define USB_EP_ATTR_INT 0x03
#define USB_EP_ATTR_TYPE_M 0x03
#define USB_EP_ATTR_ISOC_M 0x0c
#define USB_EP_ATTR_ISOC_NOSYNC 0x00
#define USB_EP_ATTR_ISOC_ASYNC 0x04
#define USB_EP_ATTR_ISOC_ADAPT 0x08
#define USB_EP_ATTR_ISOC_SYNC 0x0c
#define USB_EP_ATTR_USAGE_M 0x30
#define USB_EP_ATTR_USAGE_DATA 0x00
#define USB_EP_ATTR_USAGE_FEEDBACK \
0x10
#define USB_EP_ATTR_USAGE_IMPFEEDBACK \
0x20
//*****************************************************************************
//
//! This structure describes the USB string descriptor for index 0 as defined
//! in USB 2.0 specification section 9.6.7. Note that the number of language
//! IDs is variable and can be determined by examining bLength. The number of
//! language IDs present in the descriptor is given by ((bLength - 2) / 2).
//
//*****************************************************************************
typedef struct
{
//
//! The length of this descriptor in bytes. This value will vary
//! depending upon the number of language codes provided in the descriptor.
//
uint8_t bLength;
//
//! The type of the descriptor. For a string descriptor, this will be
//! USB_DTYPE_STRING (3).
//
uint8_t bDescriptorType;
//
//! The language code (LANGID) for the first supported language. Note that
//! this descriptor may support multiple languages, in which case, the
//! number of elements in the wLANGID array will increase and bLength will
//! be updated accordingly.
//
uint16_t wLANGID[1];
}
PACKED tString0Descriptor;
//*****************************************************************************
//
//! This structure describes the USB string descriptor for all string indexes
//! other than 0 as defined in USB 2.0 specification section 9.6.7.
//
//*****************************************************************************
typedef struct
{
//
//! The length of this descriptor in bytes. This value will be 2 greater
//! than the number of bytes comprising the UNICODE string that the
//! descriptor contains.
//
uint8_t bLength;
//
//! The type of the descriptor. For a string descriptor, this will be
//! USB_DTYPE_STRING (3).
//
uint8_t bDescriptorType;
//
//! The first byte of the UNICODE string. This string is not NULL
//! terminated. Its length (in bytes) can be computed by subtracting 2
//! from the value in the bLength field.
//
uint8_t bString;
}
PACKED tStringDescriptor;
//*****************************************************************************
//
//! Write a 16-bit value to a USB descriptor block.
//!
//! \param ui16Value is the 16-bit value to write to the descriptor.
//!
//! This helper macro is used in descriptor definitions to write two-byte
//! values. Since the configuration descriptor contains all interface and
//! endpoint descriptors in a contiguous block of memory, these descriptors are
//! typically defined using an array of bytes rather than as packed structures.
//!
//! \return Not a function.
//
//*****************************************************************************
#define USBShort(ui16Value) (ui16Value & 0xff), (ui16Value >> 8)
//*****************************************************************************
//
//! Write a 24-bit value to a USB descriptor block.
//!
//! \param ui32Value is the 24-bit value that to write to the descriptor.
//!
//! This helper macro is used in descriptor definitions to write three-byte
//! values. Since the configuration descriptor contains all interface and
//! endpoint descriptors in a contiguous block of memory, these descriptors are
//! typically defined using an array of bytes rather than as packed structures.
//!
//! \return Not a function.
//
//*****************************************************************************
#define USB3Byte(ui32Value) (ui32Value & 0xff), \
((ui32Value >> 8) & 0xff), \
((ui32Value >> 16) & 0xff)
//*****************************************************************************
//
//! Write a 32-bit value to a USB descriptor block.
//!
//! \param ui32Value is the 32-bit value that to write to the descriptor.
//!
//! This helper macro is used in descriptor definitions to write four-byte
//! values. Since the configuration descriptor contains all interface and
//! endpoint descriptors in a contiguous block of memory, these descriptors are
//! typically defined using an array of bytes rather than as packed structures.
//!
//! \return Not a function.
//
//*****************************************************************************
#define USBLong(ui32Value) (ui32Value & 0xff), \
((ui32Value >> 8) & 0xff), \
((ui32Value >> 16) & 0xff), \
((ui32Value >> 24) & 0xff)
//*****************************************************************************
//
//! Traverse to the next USB descriptor in a block.
//!
//! \param ptr points to the first byte of a descriptor in a block of
//! USB descriptors.
//!
//! This macro aids in traversing lists of descriptors by returning a pointer
//! to the next descriptor in the list given a pointer to the current one.
//!
//! \return Returns a pointer to the next descriptor in the block following
//! \e ptr.
//!
//*****************************************************************************
#define NEXT_USB_DESCRIPTOR(ptr) \
(tDescriptorHeader *)(((uint8_t *)(ptr)) + \
*((uint8_t *)(ptr)))
//*****************************************************************************
//
// Return to default packing when using the IAR Embedded Workbench compiler.
//
//*****************************************************************************
#ifdef ewarm
#pragma pack()
#endif
//*****************************************************************************
//
// Close the usbchap9_src Doxygen group.
//! @}
//
//*****************************************************************************
//*****************************************************************************
//
//! \addtogroup device_api
//! @{
//
//*****************************************************************************
//*****************************************************************************
//
// Function prototype for any standard USB request.
//
//*****************************************************************************
typedef void (* tStdRequest)(void *pvInstance, tUSBRequest *pUSBRequest);
//*****************************************************************************
//
// Data callback for receiving data from an endpoint.
//
//*****************************************************************************
typedef void (* tInfoCallback)(void *pvInstance, uint32_t ui32Info);
//*****************************************************************************
//
// Callback made to indicate that an interface alternate setting change has
// occurred.
//
//*****************************************************************************
typedef void (* tInterfaceCallback)(void *pvInstance, uint8_t ui8InterfaceNum,
uint8_t ui8AlternateSetting);
//*****************************************************************************
//
// Generic interrupt handler callbacks.
//
//*****************************************************************************
typedef void (* tUSBIntHandler)(void *pvInstance);
//*****************************************************************************
//
// Interrupt handler callbacks that have status information.
//
//*****************************************************************************
typedef void (* tUSBEPIntHandler)(void *pvInstance, uint32_t ui32Status);
//*****************************************************************************
//
// Generic handler callbacks that are used when the callers needs to call into
// an instance of class.
//
//*****************************************************************************
typedef void (* tUSBDeviceHandler)(void *pvInstance, uint32_t ui32Request,
void *pvRequestData);
//*****************************************************************************
//
//! USB event handler functions used during enumeration and operation of the
//! device stack.
//
//*****************************************************************************
typedef struct
{
//
//! This callback is made whenever the USB host requests a non-standard
//! descriptor from the device.
//
tStdRequest pfnGetDescriptor;
//
//! This callback is made whenever the USB host makes a non-standard
//! request.
//
tStdRequest pfnRequestHandler;
//
//! This callback is made in response to a SetInterface request from the
//! host.
//
tInterfaceCallback pfnInterfaceChange;
//
//! This callback is made in response to a SetConfiguration request from
//! the host.
//
tInfoCallback pfnConfigChange;
//
//! This callback is made when data has been received following to a call
//! to USBDCDRequestDataEP0.
//
tInfoCallback pfnDataReceived;
//
//! This callback is made when data has been transmitted following a call
//! to USBDCDSendDataEP0.
//
tInfoCallback pfnDataSent;
//
//! This callback is made when a USB reset is detected.
//
tUSBIntHandler pfnResetHandler;
//
//! This callback is made when the bus has been inactive long enough to
//! trigger a suspend condition.
//
tUSBIntHandler pfnSuspendHandler;
//
//! This is called when resume signaling is detected.
//
tUSBIntHandler pfnResumeHandler;
//
//! This callback is made when the device is disconnected from the USB bus.
//
tUSBIntHandler pfnDisconnectHandler;
//
//! This callback is made to inform the device of activity on all endpoints
//! other than endpoint zero.
//
tUSBEPIntHandler pfnEndpointHandler;
//
//! This generic handler is provided to allow requests based on
//! a given instance to be passed into a device. This is commonly used
//! by a top level composite device that is using multiple instances of
//! a class.
//
tUSBDeviceHandler pfnDeviceHandler;
}
tCustomHandlers;
//*****************************************************************************
//
//! This structure defines a contiguous block of data which contains a group
//! of descriptors that form part of a configuration descriptor for a device.
//! It is assumed that a config section contains only whole descriptors. It is
//! not valid to split a single descriptor across multiple sections.
//!
//*****************************************************************************
typedef struct
{
//
//! The number of bytes of descriptor data pointed to by pui8Data.
//
uint16_t ui16Size;
//
//! A pointer to a block of data containing an integral number of
//! USB descriptors which form part of a larger configuration descriptor.
//
const uint8_t *pui8Data;
}
tConfigSection;
//*****************************************************************************
//
//! This is the top level structure defining a USB device configuration
//! descriptor. A configuration descriptor contains a collection of device-
//! specific descriptors in addition to the basic config, interface and
//! endpoint descriptors. To allow flexibility in constructing the
//! configuration, the descriptor is described in terms of a list of data
//! blocks. The first block must contain the configuration descriptor itself
//! and the following blocks are appended to this in order to produce the
//! full descriptor sent to the host in response to a GetDescriptor request
//! for the configuration descriptor.
//!
//*****************************************************************************
typedef struct
{
//
//! The number of sections comprising the full descriptor for this
//! configuration.
//
uint8_t ui8NumSections;
//
//! A pointer to an array of ui8NumSections section pointers which must
//! be concatenated to form the configuration descriptor.
//
const tConfigSection * const *psSections;
}
tConfigHeader;
//*****************************************************************************
//
// Close the Doxygen group.
//! @}
//
//*****************************************************************************
//*****************************************************************************
//
//! \addtogroup general_usblib_api
//! @{
//
//*****************************************************************************
//*****************************************************************************
//
// Predeclare of the DMA instance structure.
//
//*****************************************************************************
typedef struct tUSBDMAInstance tUSBDMAInstance;
//*****************************************************************************
//
// USB descriptor parsing functions found in usbdesc.c
//
//*****************************************************************************
//*****************************************************************************
//
//! The USB_DESC_ANY label is used as a wild card in several of the descriptor
//! parsing APIs to determine whether or not particular search criteria should
//! be ignored.
//
//*****************************************************************************
#define USB_DESC_ANY 0xFFFFFFFF
extern uint32_t USBDescGetNum(tDescriptorHeader *psDesc, uint32_t ui32Size,
uint32_t ui32Type);
extern tDescriptorHeader *USBDescGet(tDescriptorHeader *psDesc,
uint32_t ui32Size, uint32_t ui32Type,
uint32_t ui32Index);
extern uint32_t
USBDescGetNumAlternateInterfaces(tConfigDescriptor *psConfig,
uint8_t ui8InterfaceNumber);
extern tInterfaceDescriptor *USBDescGetInterface(tConfigDescriptor *psConfig,
uint32_t ui32Index,
uint32_t ui32AltCfg);
extern tEndpointDescriptor *
USBDescGetInterfaceEndpoint(tInterfaceDescriptor *psInterface,
uint32_t ui32Index, uint32_t ui32Size);
//*****************************************************************************
//
//! The operating mode required by the USB library client. This type is used
//! by applications which wish to be able to switch between host and device
//! modes by calling the USBStackModeSet() API.
//
//*****************************************************************************
typedef enum
{
//
//! Operate in USB device mode with active monitoring of VBUS and the
//! ID pin must be pulled to a logic high value.
//
eUSBModeDevice = 0,
//
//! Operate in USB host mode with active monitoring of VBUS and the ID pin
//! must be pulled to a logic low value.
//
eUSBModeHost,
//
//! Operate as an On-The-Go device which requires both VBUS and ID to be
//! connected directly to the USB controller from the USB connector.
//
eUSBModeOTG,
//
//! A marker indicating that no USB mode has yet been set by the
//! application.
//
eUSBModeNone,
//
//! Force host mode so that the VBUS and ID pins are not used or monitored
//! by the USB controller.
//
eUSBModeForceHost,
//
//! Forcing device mode so that the VBUS and ID pins are not used or
//! monitored by the USB controller.
//
eUSBModeForceDevice,
}
tUSBMode;
//*****************************************************************************
//
// A pointer to a USB mode callback function. This function is called by the
// USB library to indicate to the application which operating mode it should
// use, host or device.
//
//*****************************************************************************
typedef void (*tUSBModeCallback)(uint32_t ui32Index, tUSBMode iMode);
//*****************************************************************************
//
//! USB callback function.
//!
//! \param pvCBData is the callback pointer associated with the instance
//! generating the callback. This is a value provided by the client during
//! initialization of the instance making the callback.
//! \param ui32Event is the identifier of the asynchronous event which is being
//! notified to the client.
//! \param ui32MsgParam is an event-specific parameter.
//! \param pvMsgData is an event-specific data pointer.
//!
//! A function pointer provided to the USB layer by the application
//! which will be called to notify it of all asynchronous events relating to
//! data transmission or reception. This callback is used by device class
//! drivers and host pipe functions.
//!
//! \return Returns an event-dependent value.
//
//*****************************************************************************
typedef uint32_t (* tUSBCallback)(void *pvCBData, uint32_t ui32Event,
uint32_t ui32MsgParam, void *pvMsgData);
//*****************************************************************************
//
// Error sources reported via USB_EVENT_ERROR.
//
//*****************************************************************************
//
//! The host received an invalid PID in a transaction.
//
#define USBERR_HOST_IN_PID_ERROR \
0x01000000
//
//! The host did not receive a response from a device.
//
#define USBERR_HOST_IN_NOT_COMP 0x00100000
//
//! The host received a stall on an IN endpoint.
//
#define USBERR_HOST_IN_STALL 0x00400000
//
//! The host detected a CRC or bit-stuffing error (isochronous mode).
//
#define USBERR_HOST_IN_DATA_ERROR \
0x00080000
//
//! The host received NAK on an IN endpoint for longer than the specified
//! timeout period (interrupt, bulk and control modes).
//
#define USBERR_HOST_IN_NAK_TO 0x00080000
//
//! The host failed to communicate with a device via an IN endpoint.
//
#define USBERR_HOST_IN_ERROR 0x00040000
//
//! The host receive FIFO is full.
//
#define USBERR_HOST_IN_FIFO_FULL \
0x00020000
//
//! The host received NAK on an OUT endpoint for longer than the specified
//! timeout period (bulk, interrupt and control modes).
//
#define USBERR_HOST_OUT_NAK_TO 0x00000080
//
//! The host did not receive a response from a device (isochronous mode).
//
#define USBERR_HOST_OUT_NOT_COMP \
0x00000080
//
//! The host received a stall on an OUT endpoint.
//
#define USBERR_HOST_OUT_STALL 0x00000020
//
//! The host failed to communicate with a device via an OUT endpoint.
//
#define USBERR_HOST_OUT_ERROR 0x00000004
//
//! The host received NAK on endpoint 0 for longer than the configured
//! timeout.
//
#define USBERR_HOST_EP0_NAK_TO 0x00000080
//
//! The host failed to communicate with a device via an endpoint zero.
//
#define USBERR_HOST_EP0_ERROR 0x00000010
//
//! The device detected a CRC error in received data.
//
#define USBERR_DEV_RX_DATA_ERROR \
0x00080000
//
//! The device was unable to receive a packet from the host since the receive
//! FIFO is full.
//
#define USBERR_DEV_RX_OVERRUN 0x00040000
//
//! The device receive FIFO is full.
//
#define USBERR_DEV_RX_FIFO_FULL 0x00020000
//*****************************************************************************
//
// Close the general_usblib_api Doxygen group.
//! @}
//
//*****************************************************************************
//*****************************************************************************
//
//! \addtogroup usblib_events
//! @{
//
//*****************************************************************************
//*****************************************************************************
//
//! This structure is used to return generic event based information to an
//! application. The following events are currently supported:
//! USB_EVENT_CONNECTED, USB_EVENT_DISCONNECTED, USB_EVENT_POWER_FAULT,
//! USB_EVENT_POWER_FAULT, USB_EVENT_POWER_ENABLE,
//! USB_EVENT_POWER_DISABLE and USB_EVENT_SOF.
//
//*****************************************************************************
typedef struct
{
//
//! One of the USB_EVENT_ values.
//
uint32_t ui32Event;
//
//! The caller supplied instance value that is passed to event handlers.
//
uint32_t ui32Instance;
}
tEventInfo;
//*****************************************************************************
//
// Base identifiers for groups of USB events. These are used by both the
// device class drivers and host layer.
//
// USB_CLASS_EVENT_BASE is the lowest identifier that should be used for
// a class-specific event. Individual event bases are defined for each
// of the supported device class drivers. Events with IDs between
// USB_EVENT_BASE and USB_CLASS_EVENT_BASE are reserved for stack use.
//
//*****************************************************************************
#define USB_EVENT_BASE 0x0000
#define USB_CLASS_EVENT_BASE 0x8000
//*****************************************************************************
//
// Event base identifiers for the various device classes supported in host
// and device modes.
// The first 0x800 values of a range are reserved for the device specific
// messages and the second 0x800 values of a range are used for the host
// specific messages for a given class.
//
//*****************************************************************************
#define USBD_CDC_EVENT_BASE (USB_CLASS_EVENT_BASE + 0)
#define USBD_HID_EVENT_BASE (USB_CLASS_EVENT_BASE + 0x1000)
#define USBD_HID_KEYB_EVENT_BASE \
(USBD_HID_EVENT_BASE + 0x100)
#define USBD_BULK_EVENT_BASE (USB_CLASS_EVENT_BASE + 0x2000)
#define USBD_MSC_EVENT_BASE (USB_CLASS_EVENT_BASE + 0x3000)
#define USBD_AUDIO_EVENT_BASE (USB_CLASS_EVENT_BASE + 0x4000)
#define USBD_DFU_EVENT_BASE (USB_CLASS_EVENT_BASE + 0x5000)
#define USBH_CDC_EVENT_BASE (USBD_CDC_EVENT_BASE + 0x800)
#define USBH_HID_EVENT_BASE (USBD_HID_EVENT_BASE + 0x800)
#define USBH_BULK_EVENT_BASE (USBD_BULK_EVENT_BASE + 0x800)
#define USBH_MSC_EVENT_BASE (USBD_MSC_EVENT_BASE + 0x800)
#define USBH_AUDIO_EVENT_BASE (USBD_AUDIO_EVENT_BASE + 0x800)
//*****************************************************************************
//
// General events supported by device classes and host pipes.
//
//*****************************************************************************
//
//! The device is now attached to a USB host and ready to begin sending
//! and receiving data (used by device classes only).
//
#define USB_EVENT_CONNECTED (USB_EVENT_BASE + 0)
//
//! The device has been disconnected from the USB host (used by device classes
//! only).
//!
//! \note In device mode, the USB_EVENT_DISCONNECTED will not be reported if
//! the MCU's PB1/USB0VBUS pin is connected to a fixed +5 Volts rather than
//! directly to the VBUS pin on the USB connector.
//
#define USB_EVENT_DISCONNECTED (USB_EVENT_BASE + 1)
//
//! Data has been received and is in the buffer provided or is ready to be
//! read from the FIFO.
//
#define USB_EVENT_RX_AVAILABLE (USB_EVENT_BASE + 2)
//
//! This event is sent by a lower layer to inquire about the amount of
//! unprocessed data buffered in the layers above. It is used in cases
//! where a low level driver needs to ensure that all preceding data has
//! been processed prior to performing some action or making some notification.
//! Clients receiving this event should return the number of bytes of data
//! that are unprocessed or 0 if no outstanding data remains.
//
#define USB_EVENT_DATA_REMAINING \
(USB_EVENT_BASE + 3)
//
//! This event is sent by a lower layer supporting DMA to request a buffer in
//! which the next received packet may be stored. The \e ui32MsgValue
//! parameter indicates the maximum size of packet that can be received in this
//! channel and \e pvMsgData points to storage which should be written with the
//! returned buffer pointer. The return value from the callback should be the
//! size of the buffer allocated (which may be less than the maximum size
//! passed in \e ui32MsgValue if the client knows that fewer bytes are expected
//! to be received) or 0 if no buffer is being returned.
//
#define USB_EVENT_REQUEST_BUFFER \
(USB_EVENT_BASE + 4)
//
//! Data has been sent and acknowledged. If this event is received via the
//! USB buffer callback, the \e ui32MsgValue parameter indicates the number of
//! bytes from the transmit buffer that have been successfully transmitted
//! and acknowledged.
//
#define USB_EVENT_TX_COMPLETE (USB_EVENT_BASE + 5)
//
//! An error has been reported on the channel or pipe. The \e ui32MsgValue
//! parameter indicates the source(s) of the error and is the logical OR
//! combination of "USBERR_" flags defined below.
//
#define USB_EVENT_ERROR (USB_EVENT_BASE + 6)
//
//! The bus has entered suspend state.
//
#define USB_EVENT_SUSPEND (USB_EVENT_BASE + 7)
//
//! The bus has left suspend state.
//
#define USB_EVENT_RESUME (USB_EVENT_BASE + 8)
//
//! A scheduler event has occurred.
//
#define USB_EVENT_SCHEDULER (USB_EVENT_BASE + 9)
//
//! A device or host has detected a stall condition.
//
#define USB_EVENT_STALL (USB_EVENT_BASE + 10)
//
//! The host detected a power fault condition.
//
#define USB_EVENT_POWER_FAULT (USB_EVENT_BASE + 11)
//
//! The controller has detected a A-Side cable and needs power applied This is
//! only generated on OTG parts if automatic power control is disabled.
//
#define USB_EVENT_POWER_ENABLE (USB_EVENT_BASE + 12)
//
//! The controller needs power removed, This is only generated on OTG parts
//! if automatic power control is disabled.
//
#define USB_EVENT_POWER_DISABLE (USB_EVENT_BASE + 13)
//
//! This define is used with a device class's pfnDeviceHandler handler function
//! to indicate that the USB library has changed the interface number. This
//! event is typically due to the class being included in a composite device.
//!
//! The \e pvInstance is a pointer to an instance of the device being accessed.
//!
//! The \e ui32Request is USB_EVENT_COMP_IFACE_CHANGE.
//!
//! The \e pvRequestData is a pointer to a two byte array where the first value
//! is the old interface number and the second is the new interface number.
//
#define USB_EVENT_COMP_IFACE_CHANGE \
(USB_EVENT_BASE + 14)
//
//! This define is used with a device class's pfnDeviceHandler handler function
//! to indicate that the USB library has changed the endpoint number. This
//! event is typically due to the class being included in a composite device.
//!
//! The \e pvInstance is a pointer to an instance of the device being accessed.
//!
//! The \e ui32Request is USB_EVENT_COMP_EP_CHANGE.
//!
//! The \e pvRequestData is a pointer to a two byte array where the first value
//! is the old endpoint number and the second is the new endpoint number. The
//! endpoint numbers should be exactly as USB specification defines them and
//! bit 7 set indicates an IN endpoint and bit 7 clear indicates an OUT
//! endpoint.
//
#define USB_EVENT_COMP_EP_CHANGE \
(USB_EVENT_BASE + 15)
//
//! This define is used with a device class's pfnDeviceHandler handler function
//! to indicate that the USB library has changed the string index number for a
//! string. This event is typically due to the class being included in a
//! composite device.
//!
//! The \e pvInstance is a pointer to an instance of the device being accessed.
//!
//! The \e ui32Request is USB_EVENT_COMP_STR_CHANGE.
//!
//! The \e pvRequestData is a pointer to a two byte array where the first value
//! is the old string index and the second is the new string index.
//
#define USB_EVENT_COMP_STR_CHANGE \
(USB_EVENT_BASE + 16)
//
//! This define is used with a device class's pfnDeviceHandler handler function
//! to indicate that the USB library has changed the configuration descriptor.
//! This allows the class to make final adjustments to the configuration
//! descriptor. This event is typically due to the class being included in a
//! composite device.
//!
//! The \e pvInstance is a pointer to an instance of the device being accessed.
//!
//! The \e ui32Request is USB_EVENT_COMP_CONFIG.
//!
//! The \e pvRequestData is a pointer to the beginning of the configuration
//! descriptor for the device instance.
//
#define USB_EVENT_COMP_CONFIG (USB_EVENT_BASE + 17)
//
//! An unknown device is now attached to a USB host. This value is only valid
//! for the generic event handler and not other device handlers. It is
//! useful for applications that want to know when an unknown device is
//! connected and what the class is of the unknown device.
//!
//! The \e ui32Instance is the device instance for the unknown device.
//
#define USB_EVENT_UNKNOWN_CONNECTED \
(USB_EVENT_BASE + 18)
//
//! A start of frame event has occurred. This event is disabled by default
//! and must be enabled via a call from the application to USBHCDEventEnable().
//
#define USB_EVENT_SOF (USB_EVENT_BASE + 19)
//
//! This event occurs when a device enters LPM sleep mode.
//
#define USB_EVENT_LPM_SLEEP (USB_EVENT_BASE + 20)
//
//! This event occurs when a device is resumed from LPM sleep mode.
//
#define USB_EVENT_LPM_RESUME (USB_EVENT_BASE + 21)
//
//! This event occurs when a device has responded with a NYET to an LPM request
//! because LPM responses were disabled.
//
#define USB_EVENT_LPM_ERROR (USB_EVENT_BASE + 22)
//*****************************************************************************
//
// Close the usblib_events Doxygen group.
//! @}
//
//*****************************************************************************
//*****************************************************************************
//
//! \addtogroup usblib_buffer_api
//! @{
//
//*****************************************************************************
//*****************************************************************************
//
// A function pointer type which describes either a class driver packet read
// or packet write function (both have the same prototype) to the USB
// buffer object.
//
//*****************************************************************************
typedef uint32_t (* tUSBPacketTransfer)(void *pvHandle, uint8_t *pi8Data,
uint32_t ui32Length, bool bLast);
//*****************************************************************************
//
// A function pointer type which describes either a class driver transmit
// or receive packet available function (both have the same prototype) to the
// USB buffer object.
//
//*****************************************************************************
typedef uint32_t (* tUSBPacketAvailable)(void *pvHandle);
//*****************************************************************************
//
//! The number of bytes of workspace that each USB buffer object requires.
//! This workspace memory is provided to the buffer on USBBufferInit() in
//! the \e pvWorkspace field of the \e tUSBBuffer structure.
//
//*****************************************************************************
#define USB_BUFFER_WORKSPACE_SIZE \
24
//*****************************************************************************
//
// The defines used with the USBDCDFeatureSet() or USBHCDFeatureSet() calls.
//
//*****************************************************************************
//*****************************************************************************
//
// Enable or disable support for LPM for devices in the USB library.
//
// \param ui32Index is the index of the USB controller to access.
// \param ui32Feature is USBLIB_FEATURE_LPM
// \param pvFeature is a pointer to an 32-bit value that holds the settings.
//
// This feature setting enables or disables LPM support in the USB library in
// either host or device mode depending on if the USBHCDFeatureSet() or
// USBDCDFeatureSet() is called. If no action is taken the default behavior of
// USB library is to not support LPM transactions.
//
// The following are the settings for the \b USBLIB_FEATURE_LPM feature
// request.
//
// - USBLIB_FEATURE_LPM_EN is used to enable LPM support in host or device
// mode.
// - USBLIB_FEATURE_LPM_DIS(default) is used to disable LPM support in host or
// device mode.
//
// \return Returns \b true if the setting was accepted and \b false if this
// setting is not supported.
//
//*****************************************************************************
#define USBLIB_FEATURE_LPM 0x00000001
//*****************************************************************************
//
// Method to inform the USB library of the current processor speed in Hz.
//
// \param ui32Index is the index of the USB controller to access.
// \param ui32Feature is USBLIB_FEATURE_CPUCLK
// \param pvFeature is a pointer to an 32-bit value that holds the processor
// speed in Hz.
//
// This feature setting allows an application to inform the USB library of the
// current processor speed that is can use for internal timing when the frame
// counter is not yet running. The \e pvFeature is a pointer to an 32-bit
// value that holds the processor speed in Hz.
//
// \return Returns \b true if the setting was accepted and \b false if this
// setting is not supported.
//
//*****************************************************************************
#define USBLIB_FEATURE_CPUCLK 0x00000002
//*****************************************************************************
//
// Method to inform the USB library of the PLL speed in Hz.
//
// \param ui32Index is the index of the USB controller to access.
// \param ui32Feature is USBLIB_FEATURE_USBPLL
// \param pvFeature is a pointer to an 32-bit value that holds the USB PLL
// speed in Hz.
//
// This feature setting allows an application to inform the USB library of the
// current USB PLL rate in case the USB library needs this information for
// internal configuration. If this feature is not set, then default rate
// for the USB PLL is 480MHz. The \e pvFeature is a pointer to an 32-bit value
// that holds the USB PLL speed in Hz. If the application needs to use an
// external USB clock the PLL value should be set to zero. This is used when
// connecting to an external USB phy which is providing the 60-MHz clock.
//
// \return Returns \b true if the setting was accepted and \b false if this
// setting is not supported.
//
//*****************************************************************************
#define USBLIB_FEATURE_USBPLL 0x00000003
//*****************************************************************************
//
// Method to inform the USB library of the PLL speed in Hz.
//
// \param ui32Index is the index of the USB controller to access.
// \param ui32Feature is USBLIB_FEATURE_USBULPI
// \param pvFeature is a pointer to an 32-bit value that holds the USB ULPI
// settings
//
// This feature setting allows an application to disable or configure and
// enable the ULPI features in the USB library. If this feature is not set,
// the default behavior is to not support ULPI operation. The \e pvFeature is
// a pointer to an 32-bit value that holds the USB ULPI configuration. The
// following are the valid settings for this feature:
//
// - USBLIB_FEATURE_ULPI_NONE disables all ULPI support.
// - USBLIB_FEATURE_ULPI_HS enable ULPI with high speed support.
// - USBLIB_FEATURE_ULPI_FS enable ULPI with full speed support.
//
// \return Returns \b true if the setting was accepted and \b false if this
// setting is not supported.
//
//*****************************************************************************
#define USBLIB_FEATURE_USBULPI 0x00000004
//*****************************************************************************
//
// The defines used with the USBDCDFeatureSet() or USBHCDFeatureSet() calls
// for \b USBLIB_FEATURE_LPM feature requests.
//
//*****************************************************************************
#define USBLIB_FEATURE_LPM_RMT_WAKE \
0x00000002
#define USBLIB_FEATURE_LPM_EN 0x00000001
#define USBLIB_FEATURE_LPM_DIS 0x00000000
//*****************************************************************************
//
// The structure used with the USBDCDFeatureSet() or USBHCDFeatureSet() calls
// to set feature enables and resume timing parameter.
//
//*****************************************************************************
typedef struct
{
uint32_t ui32HIRD;
uint32_t ui32Features;
}
tLPMFeature;
//*****************************************************************************
//
// The defines used with the USBDCDFeatureSet() or USBHCDFeatureSet() calls
// for \b USBLIB_FEATURE_USBULPI feature requests.
//
//*****************************************************************************
#define USBLIB_FEATURE_ULPI_NONE \
0x00000000
#define USBLIB_FEATURE_ULPI_HS 0x00000010
#define USBLIB_FEATURE_ULPI_LS 0x00000020
//*****************************************************************************
//
//! The structure used by the application to initialize a buffer object that
//! will provide buffered access to either a transmit or receive channel.
//
//*****************************************************************************
typedef struct
{
//
//! This field sets the mode of the buffer. If true, the buffer
//! operates as a transmit buffer and supports calls to USBBufferWrite
//! by the client. If false, the buffer operates as a receive buffer
//! and supports calls to USBBufferRead.
//
bool bTransmitBuffer;
//
//! A pointer to the callback function which will be called to notify
//! the application of all asynchronous events related to the operation
//! of the buffer.
//
tUSBCallback pfnCallback;
//
//! A pointer that the buffer will pass back to the client in the
//! first parameter of all callbacks related to this instance.
//
void *pvCBData;
//
//! The function which should be called to transmit a packet of data
//! in transmit mode or receive a packet in receive mode.
//
tUSBPacketTransfer pfnTransfer;
//
//! The function which should be called to determine if the endpoint is
//! ready to accept a new packet for transmission in transmit mode or
//! to determine the size of the buffer required to read a packet in
//! receive mode.
//
tUSBPacketAvailable pfnAvailable;
//
//! The handle to pass to the low level function pointers
//! provided in the pfnTransfer and pfnAvailable members. For USB device
//! use, this is the psDevice parameter required by the relevant device
//! class driver APIs. For USB host use, this is the pipe identifier
//! returned by USBHCDPipeAlloc.
//
void *pvHandle;
//
//! A pointer to memory to be used as the ring buffer for this
//! instance.
//
uint8_t *pui8Buffer;
//
//! The size, in bytes, of the buffer pointed to by pi8Buffer.
//
uint32_t ui32BufferSize;
//
//! A pointer to USB_BUFFER_WORKSPACE_SIZE bytes of RAM that the buffer
//! object can use for workspace.
//
void *pvWorkspace;
}
tUSBBuffer;
//*****************************************************************************
//
//! The structure used for encapsulating all the items associated with a
//! ring buffer.
//
//*****************************************************************************
typedef struct
{
//
//! The ring buffer size.
//
uint32_t ui32Size;
//
//! The ring buffer write index.
//
volatile uint32_t ui32WriteIndex;
//
//! The ring buffer read index.
//
volatile uint32_t ui32ReadIndex;
//
//! The ring buffer.
//
uint8_t *pui8Buf;
}
tUSBRingBufObject;
//*****************************************************************************
//
// Close the Doxygen group.
//! @}
//
//*****************************************************************************
//*****************************************************************************
//
// USB buffer API function prototypes.
//
//*****************************************************************************
extern const tUSBBuffer *USBBufferInit(const tUSBBuffer *psBuffer);
extern void USBBufferZeroLengthPacketInsert(const tUSBBuffer *psBuffer,
bool bSendZLP);
extern void USBBufferInfoGet(const tUSBBuffer *psBuffer,
tUSBRingBufObject *psRingBuf);
extern void *USBBufferCallbackDataSet(tUSBBuffer *psBuffer, void *pvCBData);
extern uint32_t USBBufferWrite(const tUSBBuffer *psBuffer,
const uint8_t *pui8Data, uint32_t ui32Length);
extern void USBBufferDataWritten(const tUSBBuffer *psBuffer,
uint32_t ui32Length);
extern void USBBufferDataRemoved(const tUSBBuffer *psBuffer,
uint32_t ui32Length);
extern void USBBufferFlush(const tUSBBuffer *psBuffer);
extern uint32_t USBBufferRead(const tUSBBuffer *psBuffer, uint8_t *pui8Data,
uint32_t ui32Length);
extern uint32_t USBBufferDataAvailable(const tUSBBuffer *psBuffer);
extern uint32_t USBBufferSpaceAvailable(const tUSBBuffer *psBuffer);
extern uint32_t USBBufferEventCallback(void *pvCBData, uint32_t ui32Event,
uint32_t ui32MsgValue, void *pvMsgData);
extern bool USBRingBufFull(tUSBRingBufObject *psUSBRingBuf);
extern bool USBRingBufEmpty(tUSBRingBufObject *psUSBRingBuf);
extern void USBRingBufFlush(tUSBRingBufObject *psUSBRingBuf);
extern uint32_t USBRingBufUsed(tUSBRingBufObject *psUSBRingBuf);
extern uint32_t USBRingBufFree(tUSBRingBufObject *psUSBRingBuf);
extern uint32_t USBRingBufContigUsed(tUSBRingBufObject *psUSBRingBuf);
extern uint32_t USBRingBufContigFree(tUSBRingBufObject *psUSBRingBuf);
extern uint32_t USBRingBufSize(tUSBRingBufObject *psUSBRingBuf);
extern uint8_t USBRingBufReadOne(tUSBRingBufObject *psUSBRingBuf);
extern void USBRingBufRead(tUSBRingBufObject *psUSBRingBuf,
uint8_t *pui8Data, uint32_t ui32Length);
extern void USBRingBufWriteOne(tUSBRingBufObject *psUSBRingBuf,
uint8_t ui8Data);
extern void USBRingBufWrite(tUSBRingBufObject *psUSBRingBuf,
const uint8_t *pui8Data, uint32_t ui32Length);
extern void USBRingBufAdvanceWrite(tUSBRingBufObject *psUSBRingBuf,
uint32_t ui32NumBytes);
extern void USBRingBufAdvanceRead(tUSBRingBufObject *psUSBRingBuf,
uint32_t ui32NumBytes);
extern void USBRingBufInit(tUSBRingBufObject *psUSBRingBuf,
uint8_t *pui8Buf, uint32_t ui32Size);
//*****************************************************************************
//
// Mode selection and dual mode interrupt steering functions.
//
//*****************************************************************************
extern void USBStackModeSet(uint32_t ui32Index, tUSBMode iUSBMode,
tUSBModeCallback pfnCallback);
extern void USBDualModeInit(uint32_t ui32Index);
extern void USBDualModeTerm(uint32_t ui32Index);
extern void USBOTGMain(uint32_t ui32MsTicks);
extern void USBOTGPollRate(uint32_t ui32Index, uint32_t ui32PollRate);
extern void USBOTGModeInit(uint32_t ui32Index, uint32_t ui32PollRate,
void *pHostData, uint32_t ui32HostDataSize);
extern void USBOTGModeTerm(uint32_t ui32Index);
extern void USB0OTGModeIntHandler(void);
extern bool USBOTGFeatureSet(uint32_t ui32Index, uint32_t ui32Feature,
void *pvFeature);
extern void USB0DualModeIntHandler(void);
// 添加部分
extern uint32_t USBHCD_GetReceiveSize(void);
//*****************************************************************************
//
// Mark the end of the C bindings section for C++ compilers.
//
//*****************************************************************************
#ifdef __cplusplus
}
#endif
#endif // __USBLIB_H__
(3)USB HOST CDC驱动文件“usbhcdc.h”
/**
* @addtogroup module_USBHCDC
* @{
*/
/**
* @file
* @brief USB CDC类主机端驱动
* @details
* @version 1.0.0
* @author sky.houfei
* @date 2014-1-9
*/
//*****************************************************************************
//
// usbhcdc.h - Definitions for the USB cdc host driver.
//
//
//*****************************************************************************
#ifndef __USBHCDC_H__
#define __USBHCDC_H__
#include "usblib/host/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_host_class
//! @{
//
//*****************************************************************************
//*****************************************************************************
//
// These defines are the the events that will be passed in the \e ulEvent
// parameter of the callback from the driver.
//
//*****************************************************************************
#define CDC_EVENT_OPEN 1
#define CDC_EVENT_CLOSE 2
#define CDC_EVENT_RX_AVAILABLE 3
#define CDC_EVENT_INTERRUPT 4
#define CDC_EVENT_TX_COMPLETE 5
//*****************************************************************************
//
// The prototype for the USB CDC host driver callback function.
//
//*****************************************************************************
typedef void (*tUSBHCDCCallback)(unsigned long ulInstance,
unsigned long ulEvent,
void *pvEventData,
unsigned long ulSize);
//*****************************************************************************
//
// Prototypes for the USB CDC host driver APIs.
//
//*****************************************************************************
extern unsigned long USBHCDCDriverOpen(unsigned long ulDrive,
tUSBHCDCCallback pfnCallback);
extern long USBHCDCReady(unsigned long ulInstance);
extern void USBHCDCSend(unsigned char *pcData, unsigned long Size);
extern bool USBHCDC_IsSendable(void);
//*****************************************************************************
//
// This is the structure for an instance of a USB CDC host driver.
//
//*****************************************************************************
typedef struct
{
//
// Save the device instance.
//
tUSBHostDevice *pDevice;
//
// Used to save the callback.
//
tUSBHCDCCallback pfnCallback;
//
// Interrupt pipe.
//
unsigned long ulBulkInterruptPipe;
//
// Bulk IN pipe.
//
unsigned long ulBulkInPipe;
//
// Bulk OUT pipe.
//
unsigned long ulBulkOutPipe;
}
tUSBHCDCInstance;
extern const tUSBHostClassDriver g_USBHostCDCClassDriver;
//*****************************************************************************
//
//! @}
//
//*****************************************************************************
//*****************************************************************************
//
// Mark the end of the C bindings section for C++ compilers.
//
//*****************************************************************************
#ifdef __cplusplus
}
#endif
#endif // __USBHCDC_H__
(4)USB Host CDC驱动文件"usbhcdc.c"
/**
* @addtogroup module_USBHCDC
* @{
*/
/**
* @file
* @brief USB CDC类主机端驱动
* @details
* @version 1.0.0
* @author sky.houfei
* @date 2014-1-9
*/
//*****************************************************************************
//
// usbhcdc.c - USB Communications Device Class host driver.
//
//
//
//*****************************************************************************
#include <string.h>
#include <stdint.h>
#include <stdbool.h>
#include "inc/hw_types.h"
#include "inc/hw_memmap.h"
#include "driverlib/sysctl.h"
#include "driverlib/usb.h"
#include "usblib/usblib.h"
#include "usblib/host/usbhost.h"
#include "usblib/host/usbhscsi.h"
#include "usblib/host/usbhostpriv.h"
#include "USBHCDC/usbhcdc.h"
//*****************************************************************************
//
//! \addtogroup usblib_host_class
//! @{
//
//*****************************************************************************
//*****************************************************************************
//
// Forward declarations for the driver open and close calls.
//
//*****************************************************************************
static void *USBHCDCOpen(tUSBHostDevice *pDevice);
static void USBHCDCClose(void *pvInstance);
//*****************************************************************************
//
// The array of USB CDC host drivers.
//
//*****************************************************************************
static tUSBHCDCInstance g_USBHCDCDevice =
{
0
};
//*****************************************************************************
//
//! This constant global structure defines the CDC Driver that
//! is provided with the USB library.
//
//*****************************************************************************
const tUSBHostClassDriver g_USBHostCDCClassDriver =
{
USB_CLASS_CDC,
USBHCDCOpen,
USBHCDCClose,
0
};
//*****************************************************************************
//
// This function handles callbacks for the Interrupt IN endpoint.
//
//*****************************************************************************
unsigned char SchedulePipeInterruptBuffer[64];
void USBHCDCInterruptCallback(uint32_t ulPipe, uint32_t ulEvent)
{
unsigned long ulSize;
//
// Handles a request to schedule a new request on the interrupt IN
// pipe.
//
if(ulEvent == USB_EVENT_SCHEDULER)
{
USBHCDPipeSchedule(ulPipe, SchedulePipeInterruptBuffer, 64);
}
//
// Called when new data is available on the interrupt IN pipe.
//
if(ulEvent == USB_EVENT_RX_AVAILABLE)
{
//
// If the callback exists then call it.
//
if(g_USBHCDCDevice.pfnCallback != 0)
{
//
// Read the Data out.
//
ulSize = USBHCDPipeReadNonBlocking(ulPipe, SchedulePipeInterruptBuffer,
64);
//
// Call
//
g_USBHCDCDevice.pfnCallback((unsigned long)&g_USBHCDCDevice,
CDC_EVENT_INTERRUPT,
(void*)SchedulePipeInterruptBuffer,
ulSize);
//
// Schedule another read
//
USBHCDPipeSchedule(ulPipe, SchedulePipeInterruptBuffer, 64);
}
}
}
//*****************************************************************************
//
// This function handles callbacks for the bulk in endpoint.
//
//*****************************************************************************
unsigned char SchedulePipeInBuffer[64];
void USBHCDCINCallback(uint32_t ulPipe, uint32_t ulEvent)
{
unsigned long ulSize;
//
// Handles a request to schedule a new request on the BULK IN
// pipe.
//
if(ulEvent == USB_EVENT_SCHEDULER)
{
USBHCDPipeSchedule(ulPipe, SchedulePipeInBuffer, 64);
}
//
// Called when new data is available on the BULK IN pipe.
//
if(ulEvent == USB_EVENT_RX_AVAILABLE)
{
//
// If the callback exists then call it.
//
if(g_USBHCDCDevice.pfnCallback != 0)
{
//
// Get the bulk in data size.
//
ulSize = USBHCD_GetReceiveSize();
//
// Call
//
g_USBHCDCDevice.pfnCallback((unsigned long)&g_USBHCDCDevice,
CDC_EVENT_RX_AVAILABLE,
(void*)SchedulePipeInBuffer,
ulSize);
//
// Schedule another read
//
USBHCDPipeSchedule(ulPipe, SchedulePipeInBuffer, 64);
}
}
}
//*****************************************************************************
//
// This function handles callbacks for the BULK OUT endpoint.
//
//*****************************************************************************
unsigned char SchedulePipeOutBuffer[64];
void USBHCDCOUTCallback(uint32_t ulPipe, uint32_t ulEvent)
{
unsigned long ulSize = 64;
//
// Handles a request to schedule a new request on the BULK OUT pipe.
//
if(ulEvent == USB_EVENT_SCHEDULER)
{
USBHCDPipeSchedule(ulPipe, SchedulePipeOutBuffer, 64);
}
//
// Called when new data is available on the BULK OUT pipe.
//
if(ulEvent == USB_EVENT_TX_COMPLETE)
{
//
// If the callback exists then call it.
//
if(g_USBHCDCDevice.pfnCallback != 0)
{
//
// Call
//
g_USBHCDCDevice.pfnCallback((unsigned long)&g_USBHCDCDevice,
CDC_EVENT_TX_COMPLETE,
(void*)SchedulePipeOutBuffer,
ulSize);
}
}
}
//*****************************************************************************
//
//! This function is used to open an instance of the CDC driver.
//!
//! \param pDevice is a pointer to the device information structure.
//!
//! This function will attempt to open an instance of the CDC driver based on
//! the information contained in the pDevice 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 USBCDCClose() when the
//! driver is no longer needed.
//!
//! \return The function will return a pointer to a CDC driver instance.
//
//*****************************************************************************
static void *
USBHCDCOpen(tUSBHostDevice *pDevice)
{
int iIdx;
tEndpointDescriptor *pEndpointDescriptor;
tInterfaceDescriptor *pInterface;
tInterfaceDescriptor *pInterfaceCommunication;
//
// Don't allow the device to be opened without closing first.
//
if(g_USBHCDCDevice.pDevice)
{
return(0);
}
//
// Save the device pointer.
//
g_USBHCDCDevice.pDevice = pDevice;
//
// Get the interface descriptor.
//
// USB CDC 含有:通信接口类(Communication Interface Class)和数据接口类
// 注意USBDescGetInterface()函数的第2个参数ui32Index
// idx为0时的接口为通信接口类(中断控制传输)
// idx为1时的接口为数据接口类 (管道传输)
// communication class interface
pInterfaceCommunication = USBDescGetInterface(pDevice->psConfigDescriptor, 0, 0);
//
// Loop through the endpoints of the device.
//
for(iIdx = 0; iIdx < pInterfaceCommunication->bNumEndpoints; iIdx++)
{
//
// Get the first endpoint descriptor.
//
pEndpointDescriptor =
USBDescGetInterfaceEndpoint(pInterfaceCommunication, iIdx,
pDevice->ui32ConfigDescriptorSize);
//
// If no more endpoints then break out.
//
if(pEndpointDescriptor == 0)
{
break;
}
//
// See if this is a interrupt endpoint.
//
if((pEndpointDescriptor->bmAttributes & USB_EP_ATTR_INT) ==
USB_EP_ATTR_INT)
{
//
// Allocate the USB Pipe for this Bulk IN Interrupt endpoint.
//
g_USBHCDCDevice.ulBulkInterruptPipe =
USBHCDPipeAllocSize(0, USBHCD_PIPE_BULK_IN,
pDevice,
pEndpointDescriptor->wMaxPacketSize,
USBHCDCInterruptCallback);
//
// Configure the USB pipe as a interrupt endpoint.
//
USBHCDPipeConfig(g_USBHCDCDevice.ulBulkInterruptPipe,
pEndpointDescriptor->wMaxPacketSize,
pEndpointDescriptor->bInterval,
(pEndpointDescriptor->bEndpointAddress &
USB_EP_DESC_NUM_M));
}
}
// data class interface
pInterface = USBDescGetInterface(pDevice->psConfigDescriptor, 1, 0);
//
// Loop through the endpoints of the device.
//
for(iIdx = 0; iIdx < pInterface->bNumEndpoints; iIdx++)
{
//
// Get the first endpoint descriptor.
//
pEndpointDescriptor =
USBDescGetInterfaceEndpoint(pInterface, iIdx,
pDevice->ui32ConfigDescriptorSize);
//
// If no more endpoints then break out.
//
if(pEndpointDescriptor == 0)
{
break;
}
//
// See if this is a bulk endpoint.
//
if((pEndpointDescriptor->bmAttributes & USB_EP_ATTR_BULK) ==
USB_EP_ATTR_BULK)
{
//
// See if this is bulk IN or bulk OUT.
//
if(pEndpointDescriptor->bEndpointAddress & USB_EP_DESC_IN)
{
//
// Allocate the USB Pipe for this Bulk IN endpoint.
//
g_USBHCDCDevice.ulBulkInPipe =
USBHCDPipeAllocSize(0,//(pEndpointDescriptor->bEndpointAddress & 0x0f),
USBHCD_PIPE_BULK_IN,
pDevice,
pEndpointDescriptor->wMaxPacketSize,
USBHCDCINCallback);
//
// Configure the USB pipe as a Bulk IN endpoint.
//
USBHCDPipeConfig(g_USBHCDCDevice.ulBulkInPipe,
pEndpointDescriptor->wMaxPacketSize,
pEndpointDescriptor->bInterval,
(pEndpointDescriptor->bEndpointAddress &
USB_EP_DESC_NUM_M));
}
else
{
//
// Allocate the USB Pipe for this Bulk OUT endpoint.
//
g_USBHCDCDevice.ulBulkOutPipe =
USBHCDPipeAllocSize(0,//(pEndpointDescriptor->bEndpointAddress & 0x0f),
USBHCD_PIPE_BULK_OUT,
pDevice,
pEndpointDescriptor->wMaxPacketSize,
USBHCDCOUTCallback);
//
// Configure the USB pipe as a Bulk OUT endpoint.
//
USBHCDPipeConfig(g_USBHCDCDevice.ulBulkOutPipe,
pEndpointDescriptor->wMaxPacketSize,
pEndpointDescriptor->bInterval,
(pEndpointDescriptor->bEndpointAddress &
USB_EP_DESC_NUM_M));
}
}
}
//
// If the callback exists, call it with an Open event.
//
if(g_USBHCDCDevice.pfnCallback != 0)
{
g_USBHCDCDevice.pfnCallback((unsigned long)&g_USBHCDCDevice,
CDC_EVENT_OPEN, 0, 0);
}
//
// Return the only instance of this device.
//
return(&g_USBHCDCDevice);
}
//*****************************************************************************
//
//! This function is used to release an instance of the CDC driver.
//!
//! \param pvInstance is an instance pointer that needs to be released.
//!
//! This function will free up any resources in use by the CDC driver instance
//! that is passed in. The \e pvInstance pointer should be a valid value that
//! was returned from a call to USBCDCOpen().
//!
//! \return None.
//
//*****************************************************************************
static void
USBHCDCClose(void *pvInstance)
{
//
// Do nothing if there is not a driver open.
//
if(g_USBHCDCDevice.pDevice == 0)
{
return;
}
//
// Reset the device pointer.
//
g_USBHCDCDevice.pDevice = 0;
//
// Free the interrupt pipe.
//
if(g_USBHCDCDevice.ulBulkInterruptPipe != 0)
{
USBHCDPipeFree(g_USBHCDCDevice.ulBulkInterruptPipe);
}
//
// Free the Bulk IN pipe.
//
if(g_USBHCDCDevice.ulBulkInPipe != 0)
{
USBHCDPipeFree(g_USBHCDCDevice.ulBulkInPipe);
}
//
// Free the Bulk OUT pipe.
//
if(g_USBHCDCDevice.ulBulkOutPipe != 0)
{
USBHCDPipeFree(g_USBHCDCDevice.ulBulkOutPipe);
}
//
// If the callback exists then call it.
//
if(g_USBHCDCDevice.pfnCallback != 0)
{
g_USBHCDCDevice.pfnCallback((unsigned long)&g_USBHCDCDevice,
CDC_EVENT_CLOSE, 0, 0);
}
}
//*****************************************************************************
//
//! This function checks if a drive is ready to be accessed.
//!
//! \param ulInstance 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 ulInstance parameter to determine which device to check and
//! will return zero when the device is ready. Any non-zero return code
//! indicates that the device was not ready.
//!
//! \return This function will return zero if the device is ready and it will
//! return a other value if the device is not ready or if an error occurred.
//
//*****************************************************************************
long
USBHCDCReady(unsigned long ulInstance)
{
tUSBHCDCInstance *pCDCDevice;
//
// Get the instance pointer in a more usable form.
//
pCDCDevice = (tUSBHCDCInstance *)ulInstance;
//
// If there is no device present then return an error.
//
if(pCDCDevice->pDevice == 0)
{
return(-1);
}
// 创建一个输入管道,用于接收从机的数据
USBHCDPipeSchedule(g_USBHCDCDevice.ulBulkInPipe,
SchedulePipeInBuffer,
sizeof(SchedulePipeInBuffer));
//
// Success.
//
return(0);
}
//*****************************************************************************
//
//! This function is used to send string to Bulk Out Pipe
//!
//! \param *pcData is pointer to data
//! \param Size is number of bytes
//!
//!
//! \return None.
//
//*****************************************************************************
void USBHCDCSend(unsigned char *pcData, unsigned long Size)
{
USBHCDPipeSchedule(g_USBHCDCDevice.ulBulkOutPipe,
pcData,
Size);
}
//*****************************************************************************
//
//! This function should be called before any devices are present to enable
//! the CDC class driver.
//!
//! \param ulDrive is the drive number to open.
//! \param pfnCallback is the driver callback for any CDC events.
//!
//! This function is called to open an instance of a CDC device. It
//! should be called before any devices are connected to allow for proper
//! notification of drive connection and disconnection. The \e ulDrive
//! 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
//! CDC functions. If there is no driver available at the time of
//! this call, this function will return zero.
//
//*****************************************************************************
unsigned long
USBHCDCDriverOpen(unsigned long ulDrive, tUSBHCDCCallback pfnCallback)
{
//
// Only the first drive is supported and only one callback is supported.
//
if((ulDrive != 0) || (g_USBHCDCDevice.pfnCallback))
{
return(0);
}
//
// Save the callback.
//
g_USBHCDCDevice.pfnCallback = pfnCallback;
//
// Return the requested device instance.
//
return((unsigned long)&g_USBHCDCDevice);
}
//*****************************************************************************
//
// Close the Doxygen group.
//! @}
//
//*****************************************************************************
(5)USB 客户应用层驱动"USB.h"
/**
* @addtogroup module_Driver
* @{
*/
/**
* @file
* @brief USB驱动,USB配置为CDC类的HOST端
* @details
* @version 1.0.0
* @author sky.houfei
* @date 2014-1-9
*/
#ifndef DRIVER_USB_H_
#define DRIVER_USB_H_
#include "stdbool.h"
#ifdef __cplusplus
extern "C" {
#endif
void USB_Init(void);
void USB_Monitor(void);
void USB_SendTest(void);
bool USB_IsConnected(void);
#ifdef __cplusplus
}
#endif
#endif /* DRIVER_USB_H_ */
/** @} */
(6) USB 客户应用层驱动"USB.c"
/**
* @addtogroup module_Driver
* @{
*/
/**
* @file
* @brief USB驱动,USB配置为CDC类的HOST端
* @details
* @version 1.0.0
* @author sky.houfei
* @date 2014-1-9
*/
#include <string.h>
#include <stdint.h>
#include <stdbool.h>
#include "inc/hw_types.h"
#include "inc/hw_memmap.h"
#include "inc/hw_ints.h"
#include "inc/hw_gpio.h"
#include "inc/hw_sysctl.h"
#include "inc/hw_usb.h"
#include "inc/hw_nvic.h"
#include "driverlib/rom.h"
#include "driverlib/gpio.h"
#include "driverlib/pin_map.h"
#include "driverlib/interrupt.h"
#include "driverlib/sysctl.h"
#include "driverlib/usb.h"
#include "usblib/usblib.h"
#include "usblib/usb-ids.h"
#include "usblib/host/usbhost.h"
#include "Driver/System.h"
#include "Driver/USB.h"
#include "USBHCDC/usbhcdc.h"
//*******************************************************************
// USB_HCD 端口和引脚定义
#define USB_HCD_PERIPH_USB SYSCTL_PERIPH_USB0
#define USB_HCD_PERIPH_GPIO SYSCTL_PERIPH_GPIOD
#define USB_HCD_GPIO_BASE GPIO_PORTD_BASE
#define USB_HCD_GPIO_PINS (GPIO_PIN_4 | GPIO_PIN_5)
// USB 控制引脚,用于控制USB端口的主从机模式
#define USB_CONTROL_PERIPH SYSCTL_PERIPH_GPIOA
#define USB_CONTROL_PORT GPIO_PORTA_BASE
#define USB_CONTROL_PIN GPIO_PIN_7
static bool s_isUSBConnected = false; // USB连接是否连接定义
//*****************************************************************************
//
// Hold the current state for the application.
//
//*****************************************************************************
volatile enum
{
//
// No device is present.
//
STATE_NO_DEVICE,
//
// Mass storage device is being enumerated.
//
STATE_DEVICE_ENUM,
//
// Mass storage device is ready.
//
STATE_DEVICE_READY,
//
// An unsupported device has been attached.
//
STATE_UNKNOWN_DEVICE,
//
// A power fault has occurred.
//
STATE_POWER_FAULT
}
g_eState;
//*****************************************************************************
//
// The size of the host controller's memory pool in bytes.
//
//*****************************************************************************
#define HCD_MEMORY_SIZE 128
//*****************************************************************************
//
// The memory pool to provide to the Host controller driver.
//
//*****************************************************************************
uint8_t g_pui8HCDPool[HCD_MEMORY_SIZE];
//*****************************************************************************
//
// The instance data for the CDC driver.
//
//*****************************************************************************
unsigned long g_ulCDCInstance = 0;
//*****************************************************************************
//
// Declare the USB Events driver interface.
//
//*****************************************************************************
DECLARE_EVENT_DRIVER(g_sUSBEventDriver, 0, 0, USBHCDEvents);
//*****************************************************************************
//
// The global that holds all of the host drivers in use in the application.
// In this case, only the CDC class is loaded.
//
//*****************************************************************************
static tUSBHostClassDriver const * const g_ppHostClassDrivers[] =
{
&g_USBHostCDCClassDriver,
&g_sUSBEventDriver
};
//*****************************************************************************
//
// This global holds the number of class drivers in the g_ppHostClassDrivers
// list.
//
//*****************************************************************************
static const unsigned long g_ulNumHostClassDrivers =
sizeof(g_ppHostClassDrivers) / sizeof(tUSBHostClassDriver *);
//*****************************************************************************
//
// This is the callback from the CDC driver.
//
// \param ulInstance is the driver instance which is needed when communicating
// with the driver.
// \param ulEvent is one of the events defined by the driver.
// \param pvData is a pointer to data passed into the initial call to register
// the callback.
//
// This function handles callback events from the CDC driver. The only events
// currently handled are the CDC_EVENT_OPEN, CDC_EVENT_CLOSE and
// CDC_EVENT_RX_AVAILABLE. This allows
// the main routine to know when an CDC device has been detected and
// enumerated and when an CDC device has been removed from the system.
// When CDC_EVENT_RX_AVAILABLE is received the pipe is filled with new data.
//
// \return None
//
//*****************************************************************************
void
CDCCallback(unsigned long ulInstance, unsigned long ulEvent, void *pvData,
unsigned long ulSize)
{
//
// Determine the event.
//
switch(ulEvent)
{
//
// Called when the device driver has successfully enumerated an CDC
// device.
//
case CDC_EVENT_OPEN:
{
//
// Proceed to the enumeration state.
//
g_eState = STATE_DEVICE_ENUM;
// printf("\nUSB CDC Open");
break;
}
//
// Called when the device driver has been unloaded due to error or
// the device is no longer present.
//
case CDC_EVENT_CLOSE:
{
//
// Go back to the "no device" state and wait for a new connection.
//
g_eState = STATE_NO_DEVICE;
s_isUSBConnected = false;
// printf("\nUSB CDC Close");
break;
}
case CDC_EVENT_RX_AVAILABLE:
{
// 如果USB主机接收到USB从机的数据,则ulSize为接收到的数据长度, *pvData为数据内容
// 此处代码为调试使用,将数据保存到buf之中,USB CDC类的管道传输为先传输一个字节,然后再传出其余字节
// 故从机发送一包数据给主机,则主机将会分多次接收到数据内容。
uint8_t i = 0;
uint8_t buf[64] = {0};
for (i = 0; i < ulSize; i++)
{
// 调试使用,将数据缓存到buf[]数组之中,开发者可通过debug调试查看
// 也可以通过串口将字符打印
buf[i] = *((uint8_t*)pvData + i);
// printf(" %02x", buf[i]);
}
break;
}
case CDC_EVENT_TX_COMPLETE:
{
// printf("\nUSB CDC TX");
break;
}
default:
{
// printf("\nUSB CDC default[%d]", ulEvent);
break;
}
}
}
//*****************************************************************************
//
// This is the generic callback from host stack.
//
// \param pvData is actually a pointer to a tEventInfo structure.
//
// This function will be called to inform the application when a USB event has
// occurred that is outside those related to the mass storage device. At this
// point this is used to detect unsupported devices being inserted and removed.
// It is also used to inform the application when a power fault has occurred.
// This function is required when the g_USBGenericEventDriver is included in
// the host controller driver array that is passed in to the
// USBHCDRegisterDrivers() function.
//
// \return None.
//
//*****************************************************************************
void
USBHCDEvents(void *pvData)
{
tEventInfo *pEventInfo;
//
// Cast this pointer to its actual type.
//
pEventInfo = (tEventInfo *)pvData;
switch(pEventInfo->ui32Event)
{
//
// An unknown device has been connected.
//
case USB_EVENT_CONNECTED:
{
//
// An unknown device was detected.
//
// printf("\nUSB has been connected");
break;
}
case USB_EVENT_UNKNOWN_CONNECTED:
g_eState = STATE_UNKNOWN_DEVICE;
// printf("\nUknown USB connected");
break;
//
// The unknown device has been been unplugged.
//
case USB_EVENT_DISCONNECTED:
{
//
// Unknown device has been removed.
//
g_eState = STATE_NO_DEVICE;
// printf("\nUSB Disconnected");
break;
}
//
// A bus power fault was detected.
//
case USB_EVENT_POWER_FAULT:
{
//
// No power means no device is present.
//
g_eState = STATE_POWER_FAULT;
// printf("\nPower fault");
break;
}
default:
{
// printf("\nEVENT default[%d]", pEventInfo->ui32Event);
break;
}
}
}
/**
* @brief USB初始化。
* @details USB初始化设置为CDC类的主机端(HOST)。
* @param[in] 无。
* @return 无。
*/
void USB_Init(void)
{
// USB 控制端口,用于控制USB主从机模式,默认设为主机模式,需要置为高电平(低电平为从模式)
ROM_SysCtlPeripheralEnable(USB_CONTROL_PERIPH);
ROM_GPIOPinTypeGPIOOutput(USB_CONTROL_PORT, USB_CONTROL_PIN);
// 设置为高电平
HWREG(USB_CONTROL_PORT + (GPIO_O_DATA + ((USB_CONTROL_PIN) << 2))) = 0xFF;
// USB 模块和 D+/D- 引脚配置
ROM_SysCtlPeripheralEnable(USB_HCD_PERIPH_GPIO);
GPIOPinTypeUSBAnalog(USB_HCD_GPIO_BASE, USB_HCD_GPIO_PINS); // 配置为USB模拟
// USB设置为主机模式
USBStackModeSet(0, eUSBModeHost, 0);
// 默认没有连接设备
g_eState = STATE_NO_DEVICE;
//
// Register the host class drivers.
//
USBHCDRegisterDrivers(0, g_ppHostClassDrivers, g_ulNumHostClassDrivers);
//
// Open an instance of the CDC class driver.
//
g_ulCDCInstance = USBHCDCDriverOpen(0, CDCCallback);
//
// Initialize the USB controller for host operation.
//
USBHCDInit(0, g_pui8HCDPool, HCD_MEMORY_SIZE);
ROM_IntEnable(INT_USB0);
}
/**
* @brief USB检测函数,用于检测主机USB状态。
* @details 如果从机正常连接,则创建一个USB接收管道。如果有状态变化,则记录相应的状态。
* 注意该函数需要定时的调用,用于随时监听主机的状态,关在在于USBHCDMain()函数,需要定时调用。
* 经过测试,主机每隔10ms定时监听一次,可以正常工作。
*/
void USB_Monitor(void)
{
static bool isReady = false;
USBHCDMain();
switch(g_eState)
{
case STATE_DEVICE_ENUM:
{
isReady = false;
// printf("\nUSB enum device ");
//
// Take it easy on the USB CDC device if it is slow to
// start up after connecting.
//
if(USBHCDCReady(g_ulCDCInstance) != 0)
{
//
// Wait about 100ms before attempting to check if the
// device is ready again.
//
SysCtlDelay(SysCtlClockGet()/30);
// printf("\nWait for USB device reset");
break;
}
g_eState = STATE_DEVICE_READY;
break;
}
//
// Ready
//
case STATE_DEVICE_READY:
{
if (isReady == false)
{
isReady = true;
// printf("\nUSB ready");
s_isUSBConnected = true; // USB连接完成
}
break;
}
//
// Something has caused a power fault.
//
case STATE_POWER_FAULT:
{
// printf("\nUSB Power Fault");
break;
}
default:
{
break;
}
}
}
/**
* @brief USB是否已经连接。
* @return 如果USB CDC从机正常工作,则返回true;否则返回false。
*/
bool USB_IsConnected(void)
{
return s_isUSBConnected;
}
/**
* @brief USB发送测试。
* @details USB发送数据包至从机。
*/
void USB_SendTest(void)
{
uint8_t data[] =
{
0x7e, 0x01, 0x02, 0x03, 0x04,
0x06, 0x07, 0x08, 0x09, 0x7e
};
// USB发送数据
USBHCDCSend(data, sizeof(data));
}
/** @} */
说明:
a. 在主主函数main.c需要反复调用void USB_Monitor(void);函数,用于监听USB Host端的状态,本人测试每隔10毫秒监听一次主机状态,可以正确进行USB CDC状态。该函数的关键在于调用USBHCDMain();,此函数为主机监听的入口函数。
b. CDCCallback为CDC类的回调函数,提供给用户使用。用户需要查看结构到的数据内容,本人提供的函数已经给予相关的说明:ulSize为接收到的数据长度, *pvData为数据内容。
(7)主函数简单示例:
/**
* @file
* @brief 主程序。
* @details 程序入口函数。
* @version 1.0.0
* @author sky.houfei
* @date 2014-1-9
*/
//*****************************************************************************
#include <stdint.h>
#include "driverlib/rom.h"
#include "Driver/System.h"
#include "Driver/USB.h"
//*****************************************************************************
void main(void)
{
uint8_t testCount = 0; // 测试次数
// 驱动初始化
System_Init(); // 系统时钟初始化,时钟配置为80MHz
USB_Init(); // USB驱动初始化,配置为USB Host CDC类
// 主循环
while (1)
{
USB_Monitor(); // 监听USB,需要定时监听USB,查看USB状态
if (USB_IsConnected())
{
// 如果USB从机已经连接成功,则测试通信:主机端每隔10毫秒发送一包数据
// 共发送5次数据包
if (testCount < 5)
{
USB_SendTest(); // USB发送测试,发送一包数据至从机
testCount++;
System_DelayMs(10); // 延时10毫秒
}
}
}
}