From 990090a4cc9070837d31e66b58d40f0c3d038741 Mon Sep 17 00:00:00 2001 From: Yuval Adam Date: Sun, 16 Mar 2014 14:41:11 +0200 Subject: Add usblib and utils --- usblib/device/usbdbulk.c | 1562 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 1562 insertions(+) create mode 100644 usblib/device/usbdbulk.c (limited to 'usblib/device/usbdbulk.c') diff --git a/usblib/device/usbdbulk.c b/usblib/device/usbdbulk.c new file mode 100644 index 0000000..1e4cf0b --- /dev/null +++ b/usblib/device/usbdbulk.c @@ -0,0 +1,1562 @@ +//***************************************************************************** +// +// usbdbulk.c - USB bulk device class driver. +// +// Copyright (c) 2008-2014 Texas Instruments Incorporated. All rights reserved. +// Software License Agreement +// +// Texas Instruments (TI) is supplying this software for use solely and +// exclusively on TI's microcontroller products. The software is owned by +// TI and/or its suppliers, and is protected under applicable copyright +// laws. You may not combine this software with "viral" open-source +// software in order to form a larger program. +// +// THIS SOFTWARE IS PROVIDED "AS IS" AND WITH ALL FAULTS. +// NO WARRANTIES, WHETHER EXPRESS, IMPLIED OR STATUTORY, INCLUDING, BUT +// NOT LIMITED TO, IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE APPLY TO THIS SOFTWARE. TI SHALL NOT, UNDER ANY +// CIRCUMSTANCES, BE LIABLE FOR SPECIAL, INCIDENTAL, OR CONSEQUENTIAL +// DAMAGES, FOR ANY REASON WHATSOEVER. +// +// This is part of revision 2.1.0.12573 of the Tiva USB Library. +// +//***************************************************************************** + +#include +#include +#include "inc/hw_memmap.h" +#include "inc/hw_types.h" +#include "driverlib/debug.h" +#include "driverlib/rom.h" +#include "driverlib/rom_map.h" +#include "driverlib/usb.h" +#include "usblib/usblib.h" +#include "usblib/usblibpriv.h" +#include "usblib/device/usbdevice.h" +#include "usblib/device/usbdbulk.h" +#include "usblib/device/usbdcomp.h" +#include "usblib/usblibpriv.h" + +//***************************************************************************** +// +//! \addtogroup bulk_device_class_api +//! @{ +// +//***************************************************************************** + +//***************************************************************************** +// +// The subset of endpoint status flags that we consider to be reception +// errors. These are passed to the client via USB_EVENT_ERROR if seen. +// +//***************************************************************************** +#define USB_RX_ERROR_FLAGS (USBERR_DEV_RX_DATA_ERROR | \ + USBERR_DEV_RX_OVERRUN | \ + USBERR_DEV_RX_FIFO_FULL) + +//***************************************************************************** +// +// Flags that may appear in ui16DeferredOpFlags to indicate some operation that +// has been requested but could not be processed at the time it was received. +// Each deferred operation is defined as the bit number that should be set in +// tBulkInstance->ui16DeferredOpFlags to indicate that the operation is +// pending. +// +//***************************************************************************** +#define BULK_DO_PACKET_RX 5 + +//***************************************************************************** +// +// Endpoints to use for each of the required endpoints in the driver.' +// +//***************************************************************************** +#define DATA_IN_ENDPOINT USB_EP_1 +#define DATA_OUT_ENDPOINT USB_EP_1 + +//***************************************************************************** +// +// Maximum packet size for the bulk endpoints used for bulk data +// transmission and reception and the associated FIFO sizes to set aside +// for each endpoint. +// +//***************************************************************************** +#define DATA_IN_EP_FIFO_SIZE USB_FIFO_SZ_64 +#define DATA_OUT_EP_FIFO_SIZE USB_FIFO_SZ_64 + +#define DATA_IN_EP_MAX_SIZE USBFIFOSizeToBytes(DATA_IN_EP_FIFO_SIZE) +#define DATA_OUT_EP_MAX_SIZE USBFIFOSizeToBytes(DATA_OUT_EP_FIFO_SIZE) + +//***************************************************************************** +// +// Device Descriptor. This is stored in RAM to allow several fields to be +// changed at runtime based on the client's requirements. +// +//***************************************************************************** +uint8_t g_pui8BulkDeviceDescriptor[] = +{ + 18, // Size of this structure. + USB_DTYPE_DEVICE, // Type of this structure. + USBShort(0x110), // USB version 1.1 (if we say 2.0, hosts assume + // high-speed - see USB 2.0 spec 9.2.6.6) + USB_CLASS_VEND_SPECIFIC, // USB Device Class + 0, // USB Device Sub-class + 0, // USB Device protocol + 64, // Maximum packet size for default pipe. + USBShort(0), // Vendor ID (VID). + USBShort(0), // Product ID (PID). + USBShort(0x100), // Device Version BCD. + 1, // Manufacturer string identifier. + 2, // Product string identifier. + 3, // Product serial number. + 1 // Number of configurations. +}; + +//***************************************************************************** +// +// Bulk device configuration descriptor. +// +// It is vital that the configuration descriptor bConfigurationValue field +// (byte 6) is 1 for the first configuration and increments by 1 for each +// additional configuration defined here. This relationship is assumed in the +// device stack for simplicity even though the USB 2.0 specification imposes +// no such restriction on the bConfigurationValue values. +// +// Note that this structure is deliberately located in RAM since we need to +// be able to patch some values in it based on client requirements. +// +//***************************************************************************** +uint8_t g_pui8BulkDescriptor[] = +{ + // + // Configuration descriptor header. + // + 9, // Size of the configuration descriptor. + USB_DTYPE_CONFIGURATION, // Type of this descriptor. + USBShort(32), // The total size of this full structure. + 1, // The number of interfaces in this + // configuration. + 1, // The unique value for this configuration. + 5, // The string identifier that describes this + // configuration. + USB_CONF_ATTR_SELF_PWR, // Bus Powered, Self Powered, remote wake up. + 250, // The maximum power in 2mA increments. +}; + +//***************************************************************************** +// +// The remainder of the configuration descriptor is stored in flash since we +// don't need to modify anything in it at runtime. +// +//***************************************************************************** +const uint8_t g_pui8BulkInterface[BULKINTERFACE_SIZE] = +{ + // + // Vendor-specific Interface Descriptor. + // + 9, // Size of the interface descriptor. + USB_DTYPE_INTERFACE, // Type of this descriptor. + 0, // The index for this interface. + 0, // The alternate setting for this + // interface. + 2, // The number of endpoints used by this + // interface. + USB_CLASS_VEND_SPECIFIC, // The interface class + 0, // The interface sub-class. + 0, // The interface protocol for the sub-class + // specified above. + 4, // The string index for this interface. + + // + // Endpoint Descriptor + // + 7, // The size of the endpoint descriptor. + USB_DTYPE_ENDPOINT, // Descriptor type is an endpoint. + USB_EP_DESC_IN | USBEPToIndex(DATA_IN_ENDPOINT), + USB_EP_ATTR_BULK, // Endpoint is a bulk endpoint. + USBShort(DATA_IN_EP_MAX_SIZE), // The maximum packet size. + 0, // The polling interval for this endpoint. + + // + // Endpoint Descriptor + // + 7, // The size of the endpoint descriptor. + USB_DTYPE_ENDPOINT, // Descriptor type is an endpoint. + USB_EP_DESC_OUT | USBEPToIndex(DATA_OUT_ENDPOINT), + USB_EP_ATTR_BULK, // Endpoint is a bulk endpoint. + USBShort(DATA_OUT_EP_MAX_SIZE), // The maximum packet size. + 0, // The polling interval for this endpoint. +}; + +//***************************************************************************** +// +// The bulk configuration descriptor is defined as two sections, one +// containing just the 9 byte USB configuration descriptor and the other +// containing everything else that is sent to the host along with it. +// +//***************************************************************************** +const tConfigSection g_sBulkConfigSection = +{ + sizeof(g_pui8BulkDescriptor), + g_pui8BulkDescriptor +}; + +const tConfigSection g_sBulkInterfaceSection = +{ + sizeof(g_pui8BulkInterface), + g_pui8BulkInterface +}; + +//***************************************************************************** +// +// This array lists all the sections that must be concatenated to make a +// single, complete bulk device configuration descriptor. +// +//***************************************************************************** +const tConfigSection *g_psBulkSections[] = +{ + &g_sBulkConfigSection, + &g_sBulkInterfaceSection +}; + +#define NUM_BULK_SECTIONS (sizeof(g_psBulkSections) / \ + sizeof(g_psBulkSections[0])) + +//***************************************************************************** +// +// The header for the single configuration we support. This is the root of +// the data structure that defines all the bits and pieces that are pulled +// together to generate the configuration descriptor. +// +//***************************************************************************** +const tConfigHeader g_sBulkConfigHeader = +{ + NUM_BULK_SECTIONS, + g_psBulkSections +}; + +//***************************************************************************** +// +// Configuration Descriptor. +// +//***************************************************************************** +const tConfigHeader * const g_ppBulkConfigDescriptors[] = +{ + &g_sBulkConfigHeader +}; + +//***************************************************************************** +// +// Forward references for device handler callbacks +// +//***************************************************************************** +static void HandleConfigChange(void *pvBulkDevice, uint32_t ui32Info); +static void HandleDisconnect(void *pvBulkDevice); +static void HandleEndpoints(void *pvBulkDevice, uint32_t ui32Status); +static void HandleSuspend(void *pvBulkDevice); +static void HandleResume(void *pvBulkDevice); +static void HandleDevice(void *pvBulkDevice, uint32_t ui32Request, + void *pvRequestData); + +//***************************************************************************** +// +// Device event handler callbacks. +// +//***************************************************************************** +const tCustomHandlers g_sBulkHandlers = +{ + // + // GetDescriptor + // + 0, + + // + // RequestHandler + // + 0, + + // + // InterfaceChange + // + 0, + + // + // ConfigChange + // + HandleConfigChange, + + // + // DataReceived + // + 0, + + // + // DataSentCallback + // + 0, + + // + // ResetHandler + // + 0, + + // + // SuspendHandler + // + HandleSuspend, + + // + // ResumeHandler + // + HandleResume, + + // + // DisconnectHandler + // + HandleDisconnect, + + // + // EndpointHandler + // + HandleEndpoints, + + // + // Device handler + // + HandleDevice +}; + +//***************************************************************************** +// +// Set or clear deferred operation flags in an "atomic" manner. +// +// \param pui16DeferredOp points to the flags variable which is to be modified. +// \param ui16Bit indicates which bit number is to be set or cleared. +// \param bSet indicates the state that the flag must be set to. If \b true, +// the flag is set, if \b false, the flag is cleared. +// +// This function safely sets or clears a bit in a flag variable. The operation +// makes use of bitbanding to ensure that the operation is atomic (no read- +// modify-write is required). +// +// \return None. +// +//***************************************************************************** +static void +SetDeferredOpFlag(volatile uint16_t *pui16DeferredOp, uint16_t ui16Bit, + bool bSet) +{ + // + // Set the flag bit to 1 or 0 using a bitband access. + // + HWREGBITH(pui16DeferredOp, ui16Bit) = bSet ? 1 : 0; +} + +//***************************************************************************** +// +// Receives notifications related to data received from the host. +// +// \param psBulkDevice is the device instance whose endpoint is to be +// processed. +// \param ui32Status is the USB interrupt status that caused this function to +// be called. +// +// This function is called from HandleEndpoints for all interrupts signaling +// the arrival of data on the bulk OUT endpoint (in other words, whenever the +// host has sent us a packet of data). We inform the client that a packet +// is available and, on return, check to see if the packet has been read. If +// not, we schedule another notification to the client for a later time. +// +// \return Returns \b true on success or \b false on failure. +// +//***************************************************************************** +static bool +ProcessDataFromHost(tUSBDBulkDevice *psBulkDevice, uint32_t ui32Status) +{ + uint32_t ui32EPStatus; + uint32_t ui32Size; + tBulkInstance *psInst; + + // + // Get a pointer to the bulk device instance data pointer + // + psInst = &psBulkDevice->sPrivateData; + + // + // Get the endpoint status to see why we were called. + // + ui32EPStatus = MAP_USBEndpointStatus(USB0_BASE, psInst->ui8OUTEndpoint); + + // + // Clear the status bits. + // + MAP_USBDevEndpointStatusClear(USB0_BASE, psInst->ui8OUTEndpoint, + ui32EPStatus); + + // + // Has a packet been received? + // + if(ui32EPStatus & USB_DEV_RX_PKT_RDY) + { + // + // Set the flag we use to indicate that a packet read is pending. This + // will be cleared if the packet is read. If the client does not read + // the packet in the context of the USB_EVENT_RX_AVAILABLE callback, + // the event will be signaled later during tick processing. + // + SetDeferredOpFlag(&psInst->ui16DeferredOpFlags, BULK_DO_PACKET_RX, + true); + + // + // How big is the packet we have just received? + // + ui32Size = MAP_USBEndpointDataAvail(psInst->ui32USBBase, + psInst->ui8OUTEndpoint); + + // + // The receive channel is not blocked so let the caller know + // that a packet is waiting. The parameters are set to indicate + // that the packet has not been read from the hardware FIFO yet. + // + psBulkDevice->pfnRxCallback(psBulkDevice->pvRxCBData, + USB_EVENT_RX_AVAILABLE, + ui32Size, (void *)0); + } + else + { + // + // No packet was received. Some error must have been reported. Check + // and pass this on to the client if necessary. + // + if(ui32EPStatus & USB_RX_ERROR_FLAGS) + { + // + // This is an error we report to the client so allow the callback + // to handle it. + // + psBulkDevice->pfnRxCallback(psBulkDevice->pvRxCBData, + USB_EVENT_ERROR, + (ui32EPStatus & USB_RX_ERROR_FLAGS), + (void *)0); + } + return(false); + } + + return(true); +} + +//***************************************************************************** +// +// Receives notifications related to data sent to the host. +// +// \param psBulkDevice is the device instance whose endpoint is to be +// processed. +// \param ui32Status is the USB interrupt status that caused this function to +// be called. +// +// This function is called from HandleEndpoints for all interrupts originating +// from the bulk IN endpoint (in other words, whenever data has been +// transmitted to the USB host). We examine the cause of the interrupt and, +// if due to completion of a transmission, notify the client. +// +// \return Returns \b true on success or \b false on failure. +// +//***************************************************************************** +static bool +ProcessDataToHost(tUSBDBulkDevice *psBulkDevice, uint32_t ui32Status) +{ + tBulkInstance *psInst; + uint32_t ui32EPStatus, ui32Size; + + // + // Get a pointer to the bulk device instance data pointer + // + psInst = &psBulkDevice->sPrivateData; + + // + // Get the endpoint status to see why we were called. + // + ui32EPStatus = MAP_USBEndpointStatus(psInst->ui32USBBase, + psInst->ui8INEndpoint); + + // + // Clear the status bits. + // + MAP_USBDevEndpointStatusClear(psInst->ui32USBBase, psInst->ui8INEndpoint, + ui32EPStatus); + + // + // Our last transmission completed. Clear our state back to idle and + // see if we need to send any more data. + // + psInst->iBulkTxState = eBulkStateIdle; + + // + // Notify the client that the last transmission completed. + // + ui32Size = psInst->ui16LastTxSize; + psInst->ui16LastTxSize = 0; + psBulkDevice->pfnTxCallback(psBulkDevice->pvTxCBData, + USB_EVENT_TX_COMPLETE, ui32Size, (void *)0); + + return(true); +} + +//***************************************************************************** +// +// Called by the USB stack for any activity involving one of our endpoints +// other than EP0. This function is a fan out that merely directs the call to +// the correct handler depending upon the endpoint and transaction direction +// signaled in ui32Status. +// +//***************************************************************************** +static void +HandleEndpoints(void *pvBulkDevice, uint32_t ui32Status) +{ + tUSBDBulkDevice *psBulkDevice; + tBulkInstance *psInst; + + ASSERT(pvBulkDevice != 0); + + // + // The bulk device structure pointer. + // + psBulkDevice = (tUSBDBulkDevice *)pvBulkDevice; + + // + // Get a pointer to the bulk device instance data pointer + // + psInst = &psBulkDevice->sPrivateData; + + // + // Handler for the bulk OUT data endpoint. + // + if(ui32Status & (0x10000 << USBEPToIndex(psInst->ui8OUTEndpoint))) + { + // + // Data is being sent to us from the host. + // + ProcessDataFromHost(psBulkDevice, ui32Status); + } + + // + // Handler for the bulk IN data endpoint. + // + if(ui32Status & (1 << USBEPToIndex(psInst->ui8INEndpoint))) + { + ProcessDataToHost(psBulkDevice, ui32Status); + } +} + +//***************************************************************************** +// +// Called by the USB stack whenever a configuration change occurs. +// +//***************************************************************************** +static void +HandleConfigChange(void *pvBulkDevice, uint32_t ui32Info) +{ + tBulkInstance *psInst; + tUSBDBulkDevice *psBulkDevice; + + ASSERT(pvBulkDevice != 0); + + // + // The bulk device structure pointer. + // + psBulkDevice = (tUSBDBulkDevice *)pvBulkDevice; + + // + // Get a pointer to the bulk device instance data pointer + // + psInst = &psBulkDevice->sPrivateData; + + // + // Set all our endpoints to idle state. + // + psInst->iBulkRxState = eBulkStateIdle; + psInst->iBulkTxState = eBulkStateIdle; + + // + // If we have a control callback, let the client know we are open for + // business. + // + if(psBulkDevice->pfnRxCallback) + { + // + // Pass the connected event to the client. + // + psBulkDevice->pfnRxCallback(psBulkDevice->pvRxCBData, + USB_EVENT_CONNECTED, 0, (void *)0); + } + + // + // Remember that we are connected. + // + psInst->bConnected = true; +} + +//***************************************************************************** +// +// Device instance specific handler. +// +//***************************************************************************** +static void +HandleDevice(void *pvBulkDevice, uint32_t ui32Request, void *pvRequestData) +{ + tBulkInstance *psInst; + uint8_t *pui8Data; + tUSBDBulkDevice *psBulkDevice; + + // + // The bulk device structure pointer. + // + psBulkDevice = (tUSBDBulkDevice *)pvBulkDevice; + + // + // Get a pointer to the bulk device instance data pointer + // + psInst = &psBulkDevice->sPrivateData; + + // + // Create the 8-bit array used by the events supported by the USB Bulk + // class. + // + pui8Data = (uint8_t *)pvRequestData; + + switch(ui32Request) + { + // + // This was an interface change event. + // + case USB_EVENT_COMP_IFACE_CHANGE: + { + psInst->ui8Interface = pui8Data[1]; + break; + } + + // + // This was an endpoint change event. + // + case USB_EVENT_COMP_EP_CHANGE: + { + // + // Determine if this is an IN or OUT endpoint that has changed. + // + if(pui8Data[0] & USB_EP_DESC_IN) + { + psInst->ui8INEndpoint = IndexToUSBEP((pui8Data[1] & 0x7f)); + } + else + { + // + // Extract the new endpoint number. + // + psInst->ui8OUTEndpoint = IndexToUSBEP(pui8Data[1] & 0x7f); + } + break; + } + case USB_EVENT_LPM_RESUME: + { + if(psBulkDevice->pfnRxCallback) + { + // + // Pass the LPM resume event to the client. + // + psBulkDevice->pfnRxCallback(psBulkDevice->pvRxCBData, + USB_EVENT_LPM_RESUME, 0, + (void *)0); + } + break; + } + case USB_EVENT_LPM_SLEEP: + { + if(psBulkDevice->pfnRxCallback) + { + // + // Pass the LPM sleep event to the client. + // + psBulkDevice->pfnRxCallback(psBulkDevice->pvRxCBData, + USB_EVENT_LPM_SLEEP, 0, (void *)0); + } + break; + } + case USB_EVENT_LPM_ERROR: + { + if(psBulkDevice->pfnRxCallback) + { + // + // Pass the LPM error event to the client. + // + psBulkDevice->pfnRxCallback(psBulkDevice->pvRxCBData, + USB_EVENT_LPM_ERROR, 0, (void *)0); + } + break; + } + default: + { + break; + } + } +} + +//***************************************************************************** +// +// This function is called by the USB device stack whenever the device is +// disconnected from the host. +// +//***************************************************************************** +static void +HandleDisconnect(void *pvBulkDevice) +{ + tUSBDBulkDevice *psBulkDevice; + tBulkInstance *psInst; + + ASSERT(pvBulkDevice != 0); + + // + // The bulk device structure pointer. + // + psBulkDevice = (tUSBDBulkDevice *)pvBulkDevice; + + // + // Get a pointer to the bulk device instance data pointer + // + psInst = &psBulkDevice->sPrivateData; + + // + // If we are not currently connected so let the client know we are open + // for business. + // + if(psInst->bConnected) + { + // + // Pass the disconnected event to the client. + // + psBulkDevice->pfnRxCallback(psBulkDevice->pvRxCBData, + USB_EVENT_DISCONNECTED, 0, (void *)0); + } + + // + // Remember that we are no longer connected. + // + psInst->bConnected = false; +} + +//***************************************************************************** +// +// This function is called by the USB device stack whenever the bus is put into +// suspend state. +// +//***************************************************************************** +static void +HandleSuspend(void *pvBulkDevice) +{ + const tUSBDBulkDevice *psBulkDevice; + + ASSERT(pvBulkDevice != 0); + + // + // The bulk device structure pointer. + // + psBulkDevice = (const tUSBDBulkDevice *)pvBulkDevice; + + // + // Pass the event on to the client. + // + psBulkDevice->pfnRxCallback(psBulkDevice->pvRxCBData, USB_EVENT_SUSPEND, 0, + (void *)0); +} + +//***************************************************************************** +// +// This function is called by the USB device stack whenever the bus is taken +// out of suspend state. +// +//***************************************************************************** +static void +HandleResume(void *pvBulkDevice) +{ + const tUSBDBulkDevice *psBulkDevice; + + ASSERT(pvBulkDevice != 0); + + // + // The bulk device structure pointer. + // + psBulkDevice = (const tUSBDBulkDevice *)pvBulkDevice; + + // + // Pass the event on to the client. + // + psBulkDevice->pfnRxCallback(psBulkDevice->pvRxCBData, USB_EVENT_RESUME, 0, + (void *)0); +} + +//***************************************************************************** +// +// This function is called periodically and provides us with a time reference +// and method of implementing delayed or time-dependent operations. +// +// \param ui32Index is the index of the USB controller for which this tick +// is being generated. +// \param ui32TimemS is the elapsed time in milliseconds since the last call +// to this function. +// +// \return None. +// +//***************************************************************************** +static void +BulkTickHandler(void *pvBulkDevice, uint32_t ui32TimemS) +{ + tBulkInstance *psInst; + uint32_t ui32Size; + tUSBDBulkDevice *psBulkDevice; + + ASSERT(pvBulkDevice != 0); + + // + // The bulk device structure pointer. + // + psBulkDevice = (tUSBDBulkDevice *)pvBulkDevice; + + // + // Get a pointer to the bulk device instance data pointer + // + psInst = &psBulkDevice->sPrivateData; + + // + // Do we have a deferred receive waiting + // + if(psInst->ui16DeferredOpFlags & (1 << BULK_DO_PACKET_RX)) + { + // + // Yes - how big is the waiting packet? + // + ui32Size = MAP_USBEndpointDataAvail(psInst->ui32USBBase, + psInst->ui8OUTEndpoint); + + // + // Tell the client that there is a packet waiting for it. + // + psBulkDevice->pfnRxCallback(psBulkDevice->pvRxCBData, + USB_EVENT_RX_AVAILABLE, ui32Size, + (void *)0); + } + + return; +} + +//***************************************************************************** +// +//! Initializes bulk device operation for a given USB controller. +//! +//! \param ui32Index is the index of the USB controller which is to be +//! initialized for bulk device operation. +//! \param psBulkDevice points to a structure containing parameters customizing +//! the operation of the bulk device. +//! +//! An application wishing to make use of a USB bulk communication channel +//! must call this function to initialize the USB controller and attach the +//! device to the USB bus. This function performs all required USB +//! initialization. +//! +//! On successful completion, this function will return the \e psBulkDevice +//! pointer passed to it. This must be passed on all future calls to the +//! device driver related to this device. +//! +//! The USBDBulk interface offers packet-based transmit and receive operation. +//! If the application would rather use block based communication with +//! transmit and receive buffers, USB buffers may be used above the bulk +//! transmit and receive channels to offer this functionality. +//! +//! Transmit Operation: +//! +//! Calls to USBDBulkPacketWrite() must send no more than 64 bytes of data at a +//! time and may only be made when no other transmission is currently +//! outstanding. +//! +//! Once a packet of data has been acknowledged by the USB host, a +//! \b USB_EVENT_TX_COMPLETE event is sent to the application callback to +//! inform it that another packet may be transmitted. +//! +//! Receive Operation: +//! +//! An incoming USB data packet will result in a call to the application +//! callback with event \b USBD_EVENT_RX_AVAILABLE. The application must then +//! call USBDBulkPacketRead(), passing a buffer capable of holding 64 bytes, to +//! retrieve the data and acknowledge reception to the USB host. +//! +//! \note The application must not make any calls to the low level USB Device +//! API if interacting with USB via the USB bulk device class API. Doing so +//! will cause unpredictable (though almost certainly unpleasant) behavior. +//! +//! \return Returns NULL on failure or void pointer that should be used with +//! the remaining USB bulk class APSs. +// +//***************************************************************************** +void * +USBDBulkInit(uint32_t ui32Index, tUSBDBulkDevice *psBulkDevice) +{ + void *pvBulkDevice; + tDeviceDescriptor *psDevDesc; + tConfigDescriptor *psConfigDesc; + + // + // Check parameter validity. + // + ASSERT(ui32Index == 0); + ASSERT(psBulkDevice); + + pvBulkDevice = USBDBulkCompositeInit(ui32Index, psBulkDevice, 0); + + if(pvBulkDevice) + { + // + // Fix up the device descriptor with the client-supplied values. + // + psDevDesc = (tDeviceDescriptor *)g_pui8BulkDeviceDescriptor; + psDevDesc->idVendor = psBulkDevice->ui16VID; + psDevDesc->idProduct = psBulkDevice->ui16PID; + + // + // Fix up the configuration descriptor with client-supplied values. + // + psConfigDesc = (tConfigDescriptor *)g_pui8BulkDescriptor; + psConfigDesc->bmAttributes = psBulkDevice->ui8PwrAttributes; + psConfigDesc->bMaxPower = (uint8_t)(psBulkDevice->ui16MaxPowermA / 2); + + // + // All is well so now pass the descriptors to the lower layer and put + // the bulk device on the bus. + // + USBDCDInit(ui32Index, &psBulkDevice->sPrivateData.sDevInfo, + (void *)psBulkDevice); + } + + // + // Return the pointer to the instance indicating that everything went well. + // + return(pvBulkDevice); +} + +//***************************************************************************** +// +//! Initializes bulk device operation for a given USB controller. +//! +//! \param ui32Index is the index of the USB controller which is to be +//! initialized for bulk device operation. +//! \param psBulkDevice points to a structure containing parameters customizing +//! the operation of the bulk device. +//! \param psCompEntry is the composite device entry to initialize when +//! creating a composite device. +//! +//! This call is very similar to USBDBulkInit() except that it is used for +//! initializing an instance of the bulk device for use in a composite device. +//! When this bulk device is part of a composite device, then the +//! \e psCompEntry should point to the composite device entry to initialize. +//! This is part of the array that is passed to the USBDCompositeInit() +//! function. +//! +//! \return Returns zero on failure or a non-zero value that should be +//! used with the remaining USB Bulk APIs. +// +//***************************************************************************** +void * +USBDBulkCompositeInit(uint32_t ui32Index, tUSBDBulkDevice *psBulkDevice, + tCompositeEntry *psCompEntry) +{ + tBulkInstance *psInst; + + // + // Check parameter validity. + // + ASSERT(ui32Index == 0); + ASSERT(psBulkDevice); + ASSERT(psBulkDevice->ppui8StringDescriptors); + ASSERT(psBulkDevice->pfnRxCallback); + ASSERT(psBulkDevice->pfnTxCallback); + + // + // Initialize the workspace in the passed instance structure. + // + psInst = &psBulkDevice->sPrivateData; + + // + // Initialize the composite entry that is used by the composite device + // class. + // + if(psCompEntry != 0) + { + psCompEntry->psDevInfo = &psInst->sDevInfo; + psCompEntry->pvInstance = (void *)psBulkDevice; + } + + // + // Initialize the device information structure. + // + psInst->sDevInfo.psCallbacks = &g_sBulkHandlers; + psInst->sDevInfo.pui8DeviceDescriptor = g_pui8BulkDeviceDescriptor; + psInst->sDevInfo.ppsConfigDescriptors = g_ppBulkConfigDescriptors; + psInst->sDevInfo.ppui8StringDescriptors = 0; + psInst->sDevInfo.ui32NumStringDescriptors = 0; + + // + // Set the basic state information for the class. + // + psInst->ui32USBBase = USB0_BASE; + psInst->iBulkRxState = eBulkStateUnconfigured; + psInst->iBulkTxState = eBulkStateUnconfigured; + psInst->ui16DeferredOpFlags = 0; + psInst->bConnected = false; + + // + // Initialize the device info structure for the Bulk device. + // + USBDCDDeviceInfoInit(0, &psInst->sDevInfo); + + // + // Set the default endpoint and interface assignments. + // + psInst->ui8INEndpoint = DATA_IN_ENDPOINT; + psInst->ui8OUTEndpoint = DATA_OUT_ENDPOINT; + psInst->ui8Interface = 0; + + // + // Plug in the client's string stable to the device information + // structure. + // + psInst->sDevInfo.ppui8StringDescriptors = + psBulkDevice->ppui8StringDescriptors; + psInst->sDevInfo.ui32NumStringDescriptors = + psBulkDevice->ui32NumStringDescriptors; + + // + // Initialize the USB tick module, this will prevent it from being + // initialized later in the call to USBDCDInit(); + // + InternalUSBTickInit(); + + // + // Register our tick handler (this must be done after USBDCDInit). + // + InternalUSBRegisterTickHandler(BulkTickHandler, (void *)psBulkDevice); + + // + // Return the pointer to the instance indicating that everything went well. + // + return((void *)psBulkDevice); +} + +//***************************************************************************** +// +//! Shut down the bulk device. +//! +//! \param pvBulkDevice is the pointer to the device instance structure as +//! returned by USBDBulkInit(). +//! +//! This function terminates device operation for the instance supplied and +//! removes the device from the USB bus. This function should not be called +//! if the bulk device is part of a composite device and instead the +//! USBDCompositeTerm() function should be called for the full composite +//! device. +//! +//! Following this call, the \e pvBulkDevice instance should not me used in any +//! other calls. +//! +//! \return None. +// +//***************************************************************************** +void +USBDBulkTerm(void *pvBulkDevice) +{ + tBulkInstance *psInst; + + ASSERT(pvBulkDevice); + + // + // Get a pointer to the bulk device instance data pointer + // + psInst = &((tUSBDBulkDevice *)pvBulkDevice)->sPrivateData; + + // + // Terminate the requested instance. + // + USBDCDTerm(USBBaseToIndex(psInst->ui32USBBase)); + + psInst->ui32USBBase = 0; + + return; +} + +//***************************************************************************** +// +//! Sets the client-specific pointer parameter for the receive channel +//! callback. +//! +//! \param pvBulkDevice is the pointer to the device instance structure as +//! returned by USBDBulkInit(). +//! \param pvCBData is the pointer that client wishes to be provided on each +//! event sent to the receive channel callback function. +//! +//! The client uses this function to change the callback pointer passed in +//! the first parameter on all callbacks to the \e pfnRxCallback function +//! passed on USBDBulkInit(). +//! +//! If a client wants to make runtime changes in the callback pointer, it must +//! ensure that the \e pvBulkDevice structure passed to USBDBulkInit() resides +//! in RAM. If this structure is in flash, callback pointer changes are not +//! possible. +//! +//! \return Returns the previous callback pointer that was being used for +//! this instance's receive callback. +// +//***************************************************************************** +void * +USBDBulkSetRxCBData(void *pvBulkDevice, void *pvCBData) +{ + void *pvOldValue; + + ASSERT(pvBulkDevice); + + // + // Set the callback data for the receive channel after remembering the + // previous value. + // + pvOldValue = ((tUSBDBulkDevice *)pvBulkDevice)->pvRxCBData; + ((tUSBDBulkDevice *)pvBulkDevice)->pvRxCBData = pvCBData; + + // + // Return the previous callback pointer. + // + return(pvOldValue); +} + +//***************************************************************************** +// +//! Sets the client-specific pointer parameter for the transmit callback. +//! +//! \param pvBulkDevice is the pointer to the device instance structure as +//! returned by USBDBulkInit(). +//! \param pvCBData is the pointer that client wishes to be provided on each +//! event sent to the transmit channel callback function. +//! +//! The client uses this function to change the callback pointer passed in +//! the first parameter on all callbacks to the \e pfnTxCallback function +//! passed on USBDBulkInit(). +//! +//! If a client wants to make runtime changes in the callback pointer, it must +//! ensure that the \e pvBulkDevice structure passed to USBDBulkInit() resides +//! in RAM. If this structure is in flash, callback pointer changes are not +//! possible. +//! +//! \return Returns the previous callback pointer that was being used for +//! this instance's transmit callback. +// +//***************************************************************************** +void * +USBDBulkSetTxCBData(void *pvBulkDevice, void *pvCBData) +{ + void *pvOldValue; + + ASSERT(pvBulkDevice); + + // + // Set the callback pointer for the transmit channel after remembering the + // previous value. + // + pvOldValue = ((tUSBDBulkDevice *)pvBulkDevice)->pvTxCBData; + ((tUSBDBulkDevice *)pvBulkDevice)->pvTxCBData = pvCBData; + + // + // Return the previous callback pointer value. + // + return(pvOldValue); +} + +//***************************************************************************** +// +//! Transmits a packet of data to the USB host via the bulk data interface. +//! +//! \param pvBulkDevice is the pointer to the device instance structure as +//! returned by USBDBulkInit(). +//! \param pi8Data points to the first byte of data which is to be transmitted. +//! \param ui32Length is the number of bytes of data to transmit. +//! \param bLast indicates whether more data is to be written before a packet +//! should be scheduled for transmission. If \b true, the client will make +//! a further call to this function. If \b false, no further call will be +//! made and the driver should schedule transmission of a short packet. +//! +//! This function schedules the supplied data for transmission to the USB +//! host in a single USB packet. If no transmission is currently ongoing, +//! the data is immediately copied to the relevant USB endpoint FIFO for +//! transmission. Whenever a USB packet is acknowledged by the host, a +//! \b USB_EVENT_TX_COMPLETE event will be sent to the transmit channel +//! callback indicating that more data can now be transmitted. +//! +//! The maximum value for \e ui32Length is 64 bytes (the maximum USB packet +//! size for the bulk endpoints in use by the device). Attempts to send more +//! data than this will result in a return code of 0 indicating that the data +//! cannot be sent. +//! +//! The \e bLast parameter allows a client to make multiple calls to this +//! function before scheduling transmission of the packet to the host. This +//! can be helpful if, for example, constructing a packet on the fly or +//! writing a packet which spans the wrap point in a ring buffer. +//! +//! \return Returns the number of bytes actually sent. At this level, this +//! will either be the number of bytes passed (if less than or equal to the +//! maximum packet size for the USB endpoint in use and no outstanding +//! transmission ongoing) or 0 to indicate a failure. +// +//***************************************************************************** +uint32_t +USBDBulkPacketWrite(void *pvBulkDevice, uint8_t *pi8Data, uint32_t ui32Length, + bool bLast) +{ + tBulkInstance *psInst; + int32_t i32Retcode; + + ASSERT(pvBulkDevice); + + // + // Get a pointer to the bulk device instance data pointer + // + psInst = &((tUSBDBulkDevice *)pvBulkDevice)->sPrivateData; + + // + // Can we send the data provided? + // + if((ui32Length > DATA_IN_EP_MAX_SIZE) || + (psInst->iBulkTxState != eBulkStateIdle)) + { + // + // Either the packet was too big or we are in the middle of sending + // another packet. Return 0 to indicate that we can't send this data. + // + return(0); + } + + // + // Copy the data into the USB endpoint FIFO. + // + i32Retcode = MAP_USBEndpointDataPut(psInst->ui32USBBase, + psInst->ui8INEndpoint, + pi8Data, ui32Length); + + // + // Did we copy the data successfully? + // + if(i32Retcode != -1) + { + // + // Remember how many bytes we sent. + // + psInst->ui16LastTxSize += (uint16_t)ui32Length; + + // + // If this is the last call for this packet, schedule transmission. + // + if(bLast) + { + // + // Send the packet to the host if we have received all the data we + // can expect for this packet. + // + psInst->iBulkTxState = eBulkStateWaitData; + i32Retcode = MAP_USBEndpointDataSend(psInst->ui32USBBase, + psInst->ui8INEndpoint, + USB_TRANS_IN); + } + } + + // + // Did an error occur while trying to send the data? + // + if(i32Retcode != -1) + { + // + // No - tell the caller we sent all the bytes provided. + // + return(ui32Length); + } + else + { + // + // Yes - tell the caller we could not send the data. + // + return(0); + } +} + +//***************************************************************************** +// +//! Reads a packet of data received from the USB host via the bulk data +//! interface. +//! +//! \param pvBulkDevice is the pointer to the device instance structure as +//! returned by USBDBulkInit(). +//! \param pi8Data points to a buffer into which the received data will be +//! written. +//! \param ui32Length is the size of the buffer pointed to by pi8Data. +//! \param bLast indicates whether the client will make a further call to +//! read additional data from the packet. +//! +//! This function reads up to \e ui32Length bytes of data received from the USB +//! host into the supplied application buffer. If the driver detects that the +//! entire packet has been read, it is acknowledged to the host. +//! +//! The \e bLast parameter is ignored in this implementation since the end of +//! a packet can be determined without relying upon the client to provide +//! this information. +//! +//! \return Returns the number of bytes of data read. +// +//***************************************************************************** +uint32_t +USBDBulkPacketRead(void *pvBulkDevice, uint8_t *pi8Data, uint32_t ui32Length, + bool bLast) +{ + uint32_t ui32EPStatus, ui32Count, ui32Pkt; + tBulkInstance *psInst; + int32_t i32Retcode; + + ASSERT(pvBulkDevice); + + // + // Get our instance data pointer + // + psInst = &((tUSBDBulkDevice *)pvBulkDevice)->sPrivateData; + + // + // Does the relevant endpoint FIFO have a packet waiting for us? + // + ui32EPStatus = MAP_USBEndpointStatus(psInst->ui32USBBase, + psInst->ui8OUTEndpoint); + + if(ui32EPStatus & USB_DEV_RX_PKT_RDY) + { + // + // How many bytes are available for us to receive? + // + ui32Pkt = MAP_USBEndpointDataAvail(psInst->ui32USBBase, + psInst->ui8OUTEndpoint); + + // + // Get as much data as we can. + // + ui32Count = ui32Length; + i32Retcode = MAP_USBEndpointDataGet(psInst->ui32USBBase, + psInst->ui8OUTEndpoint, + pi8Data, &ui32Count); + + // + // Did we read the last of the packet data? + // + if(ui32Count == ui32Pkt) + { + // + // Clear the endpoint status so that we know no packet is + // waiting. + // + MAP_USBDevEndpointStatusClear(psInst->ui32USBBase, + psInst->ui8OUTEndpoint, + ui32EPStatus); + + // + // Acknowledge the data, thus freeing the host to send the + // next packet. + // + MAP_USBDevEndpointDataAck(psInst->ui32USBBase, + psInst->ui8OUTEndpoint, true); + + // + // Clear the flag we set to indicate that a packet read is + // pending. + // + SetDeferredOpFlag(&psInst->ui16DeferredOpFlags, BULK_DO_PACKET_RX, + false); + } + + // + // If all went well, tell the caller how many bytes they got. + // + if(i32Retcode != -1) + { + return(ui32Count); + } + } + + // + // No packet was available or an error occurred while reading so tell + // the caller no bytes were returned. + // + return(0); +} + +//***************************************************************************** +// +//! Returns the number of free bytes in the transmit buffer. +//! +//! \param pvBulkDevice is the pointer to the device instance structure as +//! returned by USBDBulkInit(). +//! +//! This function returns the maximum number of bytes that can be passed on a +//! call to USBDBulkPacketWrite() and accepted for transmission. The value +//! returned will be the maximum USB packet size (64) if no transmission is +//! currently outstanding or 0 if a transmission is in progress. +//! +//! \return Returns the number of bytes available in the transmit buffer. +// +//***************************************************************************** +uint32_t +USBDBulkTxPacketAvailable(void *pvBulkDevice) +{ + tBulkInstance *psInst; + + ASSERT(pvBulkDevice); + + // + // Get our instance data pointer. + // + psInst = &((tUSBDBulkDevice *)pvBulkDevice)->sPrivateData; + + // + // Do we have a packet transmission currently ongoing? + // + if(psInst->iBulkTxState != eBulkStateIdle) + { + // + // We are not ready to receive a new packet so return 0. + // + return(0); + } + else + { + // + // We can receive a packet so return the max packet size for the + // relevant endpoint. + // + return(DATA_IN_EP_MAX_SIZE); + } +} + +//***************************************************************************** +// +//! Determines whether a packet is available and, if so, the size of the +//! buffer required to read it. +//! +//! \param pvBulkDevice is the pointer to the device instance structure as +//! returned by USBDBulkInit(). +//! +//! This function may be used to determine if a received packet remains to be +//! read and allows the application to determine the buffer size needed to +//! read the data. +//! +//! \return Returns 0 if no received packet remains unprocessed or the +//! size of the packet if a packet is waiting to be read. +// +//***************************************************************************** +uint32_t +USBDBulkRxPacketAvailable(void *pvBulkDevice) +{ + uint32_t ui32EPStatus, ui32Size; + tBulkInstance *psInst; + + ASSERT(pvBulkDevice); + + // + // Get a pointer to the bulk device instance data pointer + // + psInst = &((tUSBDBulkDevice *)pvBulkDevice)->sPrivateData; + + // + // Does the relevant endpoint FIFO have a packet waiting for us? + // + ui32EPStatus = MAP_USBEndpointStatus(psInst->ui32USBBase, + psInst->ui8OUTEndpoint); + + if(ui32EPStatus & USB_DEV_RX_PKT_RDY) + { + // + // Yes - a packet is waiting. How big is it? + // + ui32Size = MAP_USBEndpointDataAvail(psInst->ui32USBBase, + psInst->ui8OUTEndpoint); + + return(ui32Size); + } + else + { + // + // There is no packet waiting to be received. + // + return(0); + } +} +#ifndef DEPRECATED + +//***************************************************************************** +// +//! Reports the device power status (bus- or self-powered) to the USB library. +//! +//! \param pvBulkDevice is the pointer to the bulk device instance structure. +//! \param ui8Power indicates the current power status, either +//! \b USB_STATUS_SELF_PWR or \b USB_STATUS_BUS_PWR. +//! +//! Applications which support switching between bus- or self-powered +//! operation should call this function whenever the power source changes +//! to indicate the current power status to the USB library. This information +//! is required by the USB library to allow correct responses to be provided +//! when the host requests status from the device. +//! +//! \return None. +// +//***************************************************************************** +void +USBDBulkPowerStatusSet(void *pvBulkDevice, uint8_t ui8Power) +{ + ASSERT(pvBulkDevice); + + // + // Pass the request through to the lower layer. + // + USBDCDPowerStatusSet(0, ui8Power); +} +#endif + +//***************************************************************************** +// +//! Requests a remote wake up to resume communication when in suspended state. +//! +//! \param pvBulkDevice is the pointer to the bulk device instance structure. +//! +//! When the bus is suspended, an application which supports remote wake up +//! (advertised to the host via the configuration descriptor) may call this +//! function to initiate remote wake up signaling to the host. If the remote +//! wake up feature has not been disabled by the host, this will cause the bus +//! to resume operation within 20mS. If the host has disabled remote wake up, +//! \b false will be returned to indicate that the wake up request was not +//! successful. +//! +//! \return Returns \b true if the remote wake up is not disabled and the +//! signaling was started or \b false if remote wake up is disabled or if +//! signaling is currently ongoing following a previous call to this function. +// +//***************************************************************************** +bool +USBDBulkRemoteWakeupRequest(void *pvBulkDevice) +{ + ASSERT(pvBulkDevice); + + // + // Pass the request through to the lower layer. + // + return(USBDCDRemoteWakeupRequest(0)); +} + +//***************************************************************************** +// +// Close the Doxygen group. +//! @} +// +//***************************************************************************** -- cgit v1.3.1