| 12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445 |
- //*****************************************************************************
- //
- // usbdbulk.c - USB bulk device class driver.
- //
- // Copyright (c) 2008-2010 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 6288 of the Stellaris USB Library.
- //
- //*****************************************************************************
- #include "hw_usb.h"
- #include "hw_types.h"
- #include "debug.h"
- #include "interrupt.h"
- #include "usb.h"
- #include "usblib.h"
- #include "usbdevice.h"
- #include "usbdcomp.h"
- #include "usbdbulk.h"
- #include "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 usDeferredOpFlags 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->usDeferredOpFlags to indicate that the operation is pending.
- //
- //*****************************************************************************
- #define BULK_DO_PACKET_RX 5
- //*****************************************************************************
- //
- // Macros to convert between USB controller base address and an index. These
- // are currently trivial but are included to allow for the possibility of
- // supporting more than one controller in the future.
- //
- //*****************************************************************************
- #if (USB_NUM_INSTANCE == 2)
- #define USB_BASE_TO_INDEX(BaseAddr, index) do{ \
- if(USB0_BASE==BaseAddr) \
- index = 0; \
- else if(USB1_BASE==BaseAddr) \
- index = 1; \
- else \
- index = -1; \
- }while(0)
- #define USB_INDEX_TO_BASE(Index, BaseAddr) ( \
- if(0==Index) \
- BaseAddr = USB0_BASE; \
- else if(1==Index) \
- BaseAddr = USB1_BASE; \
- else \
- BaseAddr = -1; \
- )
- #else
- #define USB_BASE_TO_INDEX(BaseAddr, index) do{ \
- if(USB0_BASE==BaseAddr) \
- index = 0; \
- else \
- index = -1; \
- }while(0)
- #define USB_INDEX_TO_BASE(Index, BaseAddr) ( \
- if(0==Index) \
- BaseAddr = USB0_BASE; \
- else \
- BaseAddr = -1; \
- )
- #endif
- //*****************************************************************************
- //
- // 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 serial 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 USB_FIFO_SZ_TO_BYTES(DATA_IN_EP_FIFO_SIZE)
- #define DATA_OUT_EP_MAX_SIZE USB_FIFO_SZ_TO_BYTES(DATA_IN_EP_FIFO_SIZE)
- //*****************************************************************************
- //
- // USB instance Object
- //
- //*****************************************************************************
- extern tUSBInstanceObject g_USBInstance[];
- //*****************************************************************************
- //
- // Device Descriptor. This is stored in RAM to allow several fields to be
- // changed at runtime based on the client's requirements.
- //
- //*****************************************************************************
- unsigned char g_pBulkDeviceDescriptor[] =
- {
- 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.
- //
- //*****************************************************************************
- unsigned char g_pBulkDescriptor[] =
- {
- //
- // 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 unsigned char g_pBulkInterface[] =
- {
- //
- // 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 | USB_EP_TO_INDEX(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 | USB_EP_TO_INDEX(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 serial config 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_pBulkDescriptor),
- g_pBulkDescriptor
- };
- const tConfigSection g_sBulkInterfaceSection =
- {
- sizeof(g_pBulkInterface),
- g_pBulkInterface
- };
- //*****************************************************************************
- //
- // 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(tConfigSection *))
- //*****************************************************************************
- //
- // 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_pBulkConfigDescriptors[] =
- {
- &g_sBulkConfigHeader
- };
- //*****************************************************************************
- //
- // Forward references for device handler callbacks
- //
- //*****************************************************************************
- static void HandleConfigChange(void *pvInstance, unsigned int ulInfo,
- unsigned int ulIndex);
- static void HandleDisconnect(void *pvInstance);
- static void HandleEndpoints(void *pvInstance, unsigned int ulStatus,
- unsigned int ulIndex);
- static void HandleSuspend(void *pvInstance);
- static void HandleResume(void *pvInstance);
- static void HandleDevice(void *pvInstance, unsigned int ulRequest,
- void *pvRequestData);
- //*****************************************************************************
- //
- // The device information structure for the USB serial device.
- //
- //*****************************************************************************
- tDeviceInfo g_sBulkDeviceInfo =
- {
- //
- // Device event handler callbacks.
- //
- {
- 0, // GetDescriptor
- 0, // RequestHandler
- 0, // InterfaceChange
- HandleConfigChange, // ConfigChange
- 0, // DataReceived
- 0, // DataSentCallback
- 0, // ResetHandler
- HandleSuspend, // SuspendHandler
- HandleResume, // ResumeHandler
- HandleDisconnect, // DisconnectHandler
- HandleEndpoints, // EndpointHandler
- HandleDevice // Device handler.
- },
- g_pBulkDeviceDescriptor,
- g_pBulkConfigDescriptors,
- 0, // Will be completed during USBDBulkInit().
- 0, // Will be completed during USBDBulkInit().
- &g_sUSBDefaultFIFOConfig
- };
- //*****************************************************************************
- //
- // Set or clear deferred operation flags in an "atomic" manner.
- //
- // \param pusDeferredOp points to the flags variable which is to be modified.
- // \param usBit 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 unsigned short *pusDeferredOp, unsigned short usBit,
- tBoolean bSet)
- {
- //
- // Set the flag bit to 1 or 0 using a bitband access.
- //
- HWREGBITH(pusDeferredOp, usBit) = bSet ? 1 : 0;
- }
- //*****************************************************************************
- //
- // Receives notifications related to data received from the host.
- //
- // \param psDevice is the device instance whose endpoint is to be processed.
- // \param ulStatus 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 tBoolean
- ProcessDataFromHost(const tUSBDBulkDevice *psDevice, unsigned int ulStatus,
- unsigned int ulIndex)
- {
- unsigned int ulEPStatus;
- unsigned int ulSize;
- tBulkInstance *psInst;
- //
- // Get a pointer to our instance data.
- //
- psInst = psDevice->psPrivateBulkData;
- //
- // Get the endpoint status to see why we were called.
- //
- ulEPStatus = USBEndpointStatus(g_USBInstance[ulIndex].uiBaseAddr, psInst->ucOUTEndpoint);
- //
- // Clear the status bits.
- //
- USBDevEndpointStatusClear(g_USBInstance[ulIndex].uiBaseAddr, psInst->ucOUTEndpoint, ulEPStatus);
- //
- // Has a packet been received?
- //
- if(ulEPStatus & 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 doesn't read
- // the packet in the context of the USB_EVENT_RX_AVAILABLE callback,
- // the event will be signaled later during tick processing.
- //
- SetDeferredOpFlag(&psInst->usDeferredOpFlags, BULK_DO_PACKET_RX, true);
- //
- // How big is the packet we've just been sent?
- //
- ulSize = USBEndpointDataAvail(psInst->ulUSBBase, psInst->ucOUTEndpoint);
- //
- // 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.
- //
- psDevice->pfnRxCallback(psDevice->pvRxCBData,
- USB_EVENT_RX_AVAILABLE, ulSize,
- (void *)0);
- }
- else
- {
- //
- // No packet was received. Some error must have been reported. Check
- // and pass this on to the client if necessary.
- //
- if(ulEPStatus & USB_RX_ERROR_FLAGS)
- {
- //
- // This is an error we report to the client so...
- //
- psDevice->pfnRxCallback(psDevice->pvRxCBData,
- USB_EVENT_ERROR,
- (ulEPStatus & USB_RX_ERROR_FLAGS),
- (void *)0);
- }
- return (false);
- }
- return (true);
- }
- //*****************************************************************************
- //
- // Receives notifications related to data sent to the host.
- //
- // \param psDevice is the device instance whose endpoint is to be processed.
- // \param ulStatus 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 tBoolean
- ProcessDataToHost(const tUSBDBulkDevice *psDevice, unsigned int ulStatus,
- unsigned int ulIndex)
- {
- tBulkInstance *psInst;
- unsigned int ulEPStatus;
- unsigned int ulSize;
- //
- // Get a pointer to our instance data.
- //
- psInst = psDevice->psPrivateBulkData;
- //
- // Get the endpoint status to see why we were called.
- //
- ulEPStatus = USBEndpointStatus(psInst->ulUSBBase, psInst->ucINEndpoint);
- //
- // Clear the status bits.
- //
- USBDevEndpointStatusClear(psInst->ulUSBBase, psInst->ucINEndpoint,
- ulEPStatus);
- //
- // Our last transmission completed. Clear our state back to idle and
- // see if we need to send any more data.
- //
- psInst->eBulkTxState = BULK_STATE_IDLE;
- //
- // Notify the client that the last transmission completed.
- //
- ulSize = psInst->usLastTxSize;
- psInst->usLastTxSize = 0;
- psDevice->pfnTxCallback(psDevice->pvTxCBData, USB_EVENT_TX_COMPLETE,
- ulSize, (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 ulStatus.
- //
- //*****************************************************************************
- static void
- HandleEndpoints(void *pvInstance, unsigned int ulStatus, unsigned int ulIndex)
- {
- const tUSBDBulkDevice *psBulkInst;
- tBulkInstance *psInst;
- ASSERT(pvInstance != 0);
- //
- // Determine if the serial device is in single or composite mode because
- // the meaning of ulIndex is different in both cases.
- //
- psBulkInst = (const tUSBDBulkDevice *)pvInstance;
- psInst = psBulkInst->psPrivateBulkData;
- //
- // Handler for the bulk OUT data endpoint.
- //
- if(ulStatus & (0x10000 << USB_EP_TO_INDEX(psInst->ucOUTEndpoint)))
- {
- //
- // Data is being sent to us from the host.
- //
- ProcessDataFromHost(pvInstance, ulStatus, ulIndex);
- }
- //
- // Handler for the bulk IN data endpoint.
- //
- if(ulStatus & (1 << USB_EP_TO_INDEX(psInst->ucINEndpoint)))
- {
- ProcessDataToHost(pvInstance, ulStatus, ulIndex);
- }
- }
- //*****************************************************************************
- //
- // Called by the USB stack whenever a configuration change occurs.
- //
- //*****************************************************************************
- static void
- HandleConfigChange(void *pvInstance, unsigned int ulInfo,
- unsigned int ulIndex)
- {
- tBulkInstance *psInst;
- const tUSBDBulkDevice *psDevice;
- ASSERT(pvInstance != 0);
- //
- // Create a device instance pointer.
- //
- psDevice = (const tUSBDBulkDevice *)pvInstance;
- //
- // Get a pointer to our instance data.
- //
- psInst = psDevice->psPrivateBulkData;
- //
- // Set all our endpoints to idle state.
- //
- psInst->eBulkRxState = BULK_STATE_IDLE;
- psInst->eBulkTxState = BULK_STATE_IDLE;
- //
- // If we have a control callback, let the client know we are open for
- // business.
- //
- if(psDevice->pfnRxCallback)
- {
- //
- // Pass the connected event to the client.
- //
- psDevice->pfnRxCallback(psDevice->pvRxCBData, USB_EVENT_CONNECTED, 0,
- (void *)0);
- }
- //
- // Remember that we are connected.
- //
- psInst->bConnected = true;
- }
- //*****************************************************************************
- //
- // Device instance specific handler.
- //
- //*****************************************************************************
- static void
- HandleDevice(void *pvInstance, unsigned int ulRequest, void *pvRequestData)
- {
- tBulkInstance *psInst;
- unsigned char *pucData;
- //
- // Create the serial instance data.
- //
- psInst = ((tUSBDBulkDevice *)pvInstance)->psPrivateBulkData;
- //
- // Create the char array used by the events supported by the USB CDC
- // serial class.
- //
- pucData = (unsigned char *)pvRequestData;
- switch(ulRequest)
- {
- //
- // This was an interface change event.
- //
- case USB_EVENT_COMP_IFACE_CHANGE:
- {
- psInst->ucInterface = pucData[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(pucData[0] & USB_EP_DESC_IN)
- {
- psInst->ucINEndpoint = INDEX_TO_USB_EP((pucData[1] & 0x7f));
- }
- else
- {
- //
- // Extract the new endpoint number.
- //
- psInst->ucOUTEndpoint = INDEX_TO_USB_EP(pucData[1] & 0x7f);
- }
- break;
- }
- default:
- {
- break;
- }
- }
- }
- //*****************************************************************************
- //
- // This function is called by the USB device stack whenever the device is
- // disconnected from the host.
- //
- //*****************************************************************************
- static void
- HandleDisconnect(void *pvInstance)
- {
- const tUSBDBulkDevice *psBulkDevice;
- tBulkInstance *psInst;
- ASSERT(pvInstance != 0);
- //
- // Create the instance pointer.
- //
- psBulkDevice = (const tUSBDBulkDevice *)pvInstance;
- //
- // Get a pointer to our instance data.
- //
- psInst = psBulkDevice->psPrivateBulkData;
- //
- // 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 *pvInstance)
- {
- const tUSBDBulkDevice *psBulkDevice;
- ASSERT(pvInstance != 0);
- //
- // Create the instance pointer.
- //
- psBulkDevice = (const tUSBDBulkDevice *)pvInstance;
- //
- // 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 *pvInstance)
- {
- const tUSBDBulkDevice *psBulkDevice;
- ASSERT(pvInstance != 0);
- //
- // Create the instance pointer.
- //
- psBulkDevice = (const tUSBDBulkDevice *)pvInstance;
- //
- // Pass the event on to the client.
- //
- psBulkDevice->pfnRxCallback(psBulkDevice->pvRxCBData, USB_EVENT_RESUME, 0,
- (void *)0);
- }
- //*****************************************************************************
- //
- //! Initializes bulk device operation for a given USB controller.
- //!
- //! \param ulIndex is the index of the USB controller which is to be
- //! initialized for bulk device operation.
- //! \param psDevice 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 psDevice 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
- //! 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 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 the psDevice pointer on success.
- //
- //*****************************************************************************
- void *
- USBDBulkInit(unsigned int ulIndex, const tUSBDBulkDevice *psDevice)
- {
- void *pvInstance;
- //
- // Check parameter validity.
- //
- ASSERT(ulIndex == 0);
- ASSERT(psDevice);
- pvInstance = USBDBulkCompositeInit(ulIndex, psDevice);
- if(pvInstance)
- {
- //
- // All is well so now pass the descriptors to the lower layer and put
- // the bulk device on the bus.
- //
- USBDCDInit(ulIndex, psDevice->psPrivateBulkData->psDevInfo);
- }
- //
- // Return the pointer to the instance indicating that everything went well.
- //
- return(pvInstance);
- }
- //*****************************************************************************
- //
- //! Initializes bulk device operation for a given USB controller.
- //!
- //! \param ulIndex is the index of the USB controller which is to be
- //! initialized for bulk device operation.
- //! \param psDevice points to a structure containing parameters customizing
- //! the operation of the bulk device.
- //!
- //! An application wishing to make use of a composite
- //! USB bulk communication channel needs to call this function.
- //! This function is used for initializing an instance related information of the
- //! bulk device.
- //!
- //! \return Returns zero on failure or a non-zero value that should be
- //! used with the remaining USB HID Bulk APIs.
- //
- //*****************************************************************************
- void *
- USBDBulkCompositeInit(unsigned int ulIndex, const tUSBDBulkDevice *psDevice)
- {
- tBulkInstance *psInst;
- tDeviceDescriptor *psDevDesc;
- //
- // Check parameter validity.
- //
- ASSERT(ulIndex == 0);
- ASSERT(psDevice);
- ASSERT(psDevice->ppStringDescriptors);
- ASSERT(psDevice->psPrivateBulkData);
- ASSERT(psDevice->pfnRxCallback);
- ASSERT(psDevice->pfnTxCallback);
- if(ulIndex == 0)
- {
- g_USBInstance[ulIndex].uiUSBInstance = ulIndex;
- g_USBInstance[ulIndex].uiBaseAddr = USB0_BASE;
- g_USBInstance[ulIndex].uiSubBaseAddr = USB_0_OTGBASE;
- g_USBInstance[ulIndex].uiInterruptNum = SYS_INT_USB0;
- g_USBInstance[ulIndex].uiSubInterruptNum = SYS_INT_USBSSINT;
- g_USBInstance[ulIndex].uiPHYConfigRegAddr = CFGCHIP2_USBPHYCTRL;
- }
- #if (USB_NUM_INSTANCE == 2)
- else if(ulIndex == 1)
- {
- g_USBInstance[ulIndex].uiUSBInstance = ulIndex;
- g_USBInstance[ulIndex].uiBaseAddr = USB1_BASE;
- g_USBInstance[ulIndex].uiSubBaseAddr = USB_1_OTGBASE;
- g_USBInstance[ulIndex].uiInterruptNum = SYS_INT_USB1;
- g_USBInstance[ulIndex].uiSubInterruptNum = SYS_INT_USBSSINT;
- g_USBInstance[ulIndex].uiPHYConfigRegAddr = CFGCHIP2_USB1PHYCTRL;
- }
- #endif
- //
- // Initialize the workspace in the passed instance structure.
- //
- psInst = psDevice->psPrivateBulkData;
- psInst->psConfDescriptor = (tConfigDescriptor *)g_pBulkDescriptor;
- psInst->psDevInfo = &g_sBulkDeviceInfo;
- psInst->ulUSBBase = g_USBInstance[ulIndex].uiBaseAddr;
- psInst->eBulkRxState = BULK_STATE_UNCONFIGURED;
- psInst->eBulkTxState = BULK_STATE_UNCONFIGURED;
- psInst->usDeferredOpFlags = 0;
- psInst->bConnected = false;
- //
- // Set the default endpoint and interface assignments.
- //
- psInst->ucINEndpoint = DATA_IN_ENDPOINT;
- psInst->ucOUTEndpoint = DATA_OUT_ENDPOINT;
- psInst->ucInterface = 0;
- //
- // Fix up the device descriptor with the client-supplied values.
- //
- psDevDesc = (tDeviceDescriptor *)psInst->psDevInfo->pDeviceDescriptor;
- psDevDesc->idVendor = psDevice->usVID;
- psDevDesc->idProduct = psDevice->usPID;
- //
- // Fix up the configuration descriptor with client-supplied values.
- //
- psInst->psConfDescriptor->bmAttributes = psDevice->ucPwrAttributes;
- psInst->psConfDescriptor->bMaxPower =
- (unsigned char)(psDevice->usMaxPowermA / 2);
- //
- // Plug in the client's string stable to the device information
- // structure.
- //
- psInst->psDevInfo->ppStringDescriptors = psDevice->ppStringDescriptors;
- psInst->psDevInfo->ulNumStringDescriptors
- = psDevice->ulNumStringDescriptors;
- //
- // Set the device instance.
- //
- psInst->psDevInfo->pvInstance = (void *)psDevice;
- //
- // Return the pointer to the instance indicating that everything went well.
- //
- return((void *)psDevice);
- }
- //*****************************************************************************
- //
- //! Shut down the bulk device.
- //!
- //! \param pvInstance 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 pvInstance instance should not me used in any
- //! other calls.
- //!
- //! \return None.
- //
- //*****************************************************************************
- void
- USBDBulkTerm(void *pvInstance)
- {
- tBulkInstance *psInst;
- int index;
- ASSERT(pvInstance);
- //
- // Get a pointer to our instance data.
- //
- psInst = ((tUSBDBulkDevice *)pvInstance)->psPrivateBulkData;
- //
- // Terminate the requested instance.
- //
- USB_BASE_TO_INDEX(psInst->ulUSBBase, index);
- USBDCDTerm(index);
- psInst->ulUSBBase = 0;
- psInst->psDevInfo = (tDeviceInfo *)0;
- psInst->psConfDescriptor = (tConfigDescriptor *)0;
- return;
- }
- //*****************************************************************************
- //
- //! Sets the client-specific pointer parameter for the receive channel
- //! callback.
- //!
- //! \param pvInstance 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 pvInstance structure passed to USBDBulkInit() resides in
- //! RAM. If this structure is in flash, callback pointer changes will not be
- //! possible.
- //!
- //! \return Returns the previous callback pointer that was being used for
- //! this instance's receive callback.
- //
- //*****************************************************************************
- void *
- USBDBulkSetRxCBData(void *pvInstance, void *pvCBData)
- {
- void *pvOldValue;
- ASSERT(pvInstance);
- //
- // Set the callback data for the receive channel after remembering the
- // previous value.
- //
- pvOldValue = ((tUSBDBulkDevice *)pvInstance)->pvRxCBData;
- ((tUSBDBulkDevice *)pvInstance)->pvRxCBData = pvCBData;
- //
- // Return the previous callback pointer.
- //
- return (pvOldValue);
- }
- //*****************************************************************************
- //
- //! Sets the client-specific pointer parameter for the transmit callback.
- //!
- //! \param pvInstance 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 pvInstance structure passed to USBDBulkInit() resides in
- //! RAM. If this structure is in flash, callback pointer changes will not be
- //! possible.
- //!
- //! \return Returns the previous callback pointer that was being used for
- //! this instance's transmit callback.
- //
- //*****************************************************************************
- void *
- USBDBulkSetTxCBData(void *pvInstance, void *pvCBData)
- {
- void *pvOldValue;
- ASSERT(pvInstance);
- //
- // Set the callback pointer for the transmit channel after remembering the
- // previous value.
- //
- pvOldValue = ((tUSBDBulkDevice *)pvInstance)->pvTxCBData;
- ((tUSBDBulkDevice *)pvInstance)->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 pvInstance is the pointer to the device instance structure as
- //! returned by USBDBulkInit().
- //! \param pcData points to the first byte of data which is to be transmitted.
- //! \param ulLength 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
- //! 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 ulLength 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.
- //
- //*****************************************************************************
- unsigned int
- USBDBulkPacketWrite(void *pvInstance, unsigned char *pcData,
- unsigned int ulLength, tBoolean bLast)
- {
- tBulkInstance *psInst;
- int iRetcode;
- ASSERT(pvInstance);
- //
- // Get our instance data pointer
- //
- psInst = ((tUSBDBulkDevice *)pvInstance)->psPrivateBulkData;
- //
- // Can we send the data provided?
- //
- if((ulLength > DATA_IN_EP_MAX_SIZE) ||
- (psInst->eBulkTxState != BULK_STATE_IDLE))
- {
- //
- // 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.
- //
- iRetcode = USBEndpointDataPut(psInst->ulUSBBase, psInst->ucINEndpoint,
- pcData, ulLength);
- //
- // Did we copy the data successfully?
- //
- if(iRetcode != -1)
- {
- //
- // Remember how many bytes we sent.
- //
- psInst->usLastTxSize += (unsigned short)ulLength;
- //
- // 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->eBulkTxState = BULK_STATE_WAIT_DATA;
- iRetcode = USBEndpointDataSend(psInst->ulUSBBase,
- psInst->ucINEndpoint, USB_TRANS_IN);
- }
- }
- //
- // Did an error occur while trying to send the data?
- //
- if(iRetcode != -1)
- {
- //
- // No - tell the caller we sent all the bytes provided.
- //
- return (ulLength);
- }
- else
- {
- //
- // Yes - tell the caller we couldn't send the data.
- //
- return (0);
- }
- }
- //*****************************************************************************
- //
- //! Reads a packet of data received from the USB host via the bulk data
- //! interface.
- //!
- //! \param pvInstance is the pointer to the device instance structure as
- //! returned by USBDBulkInit().
- //! \param pcData points to a buffer into which the received data will be
- //! written.
- //! \param ulLength is the size of the buffer pointed to by pcData.
- //! \param bLast indicates whether the client will make a further call to
- //! read additional data from the packet.
- //!
- //! This function reads up to \e ulLength 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.
- //
- //*****************************************************************************
- unsigned int
- USBDBulkPacketRead(void *pvInstance, unsigned char *pcData,
- unsigned int ulLength, tBoolean bLast)
- {
- unsigned int ulEPStatus, ulPkt;
- unsigned int ulCount;
- tBulkInstance *psInst;
- int iRetcode;
- ASSERT(pvInstance);
- //
- // Get our instance data pointer
- //
- psInst = ((tUSBDBulkDevice *)pvInstance)->psPrivateBulkData;
- //
- // Does the relevant endpoint FIFO have a packet waiting for us?
- //
- ulEPStatus = USBEndpointStatus(psInst->ulUSBBase, psInst->ucOUTEndpoint);
- if(ulEPStatus & USB_DEV_RX_PKT_RDY)
- {
- //
- // How many bytes are available for us to receive?
- //
- ulPkt = USBEndpointDataAvail(psInst->ulUSBBase, psInst->ucOUTEndpoint);
- //
- // Get as much data as we can.
- //
- ulCount = ulLength;
- iRetcode = USBEndpointDataGet(psInst->ulUSBBase, psInst->ucOUTEndpoint,
- pcData, &ulCount);
- //
- // Did we read the last of the packet data?
- //
- if(ulCount == ulPkt)
- {
- //
- // Clear the endpoint status so that we know no packet is
- // waiting.
- //
- USBDevEndpointStatusClear(psInst->ulUSBBase, psInst->ucOUTEndpoint,
- ulEPStatus);
- //
- // Acknowledge the data, thus freeing the host to send the
- // next packet.
- //
- USBDevEndpointDataAck(psInst->ulUSBBase, psInst->ucOUTEndpoint,
- true);
- //
- // Clear the flag we set to indicate that a packet read is
- // pending.
- //
- SetDeferredOpFlag(&psInst->usDeferredOpFlags, BULK_DO_PACKET_RX,
- false);
- }
- //
- // If all went well, tell the caller how many bytes they got.
- //
- if(iRetcode != -1)
- {
- return (ulCount);
- }
- }
- //
- // 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 pvInstance 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.
- //
- //*****************************************************************************
- unsigned int
- USBDBulkTxPacketAvailable(void *pvInstance)
- {
- tBulkInstance *psInst;
- ASSERT(pvInstance);
- //
- // Get our instance data pointer.
- //
- psInst = ((tUSBDBulkDevice *)pvInstance)->psPrivateBulkData;
- //
- // Do we have a packet transmission currently ongoing?
- //
- if(psInst->eBulkTxState != BULK_STATE_IDLE)
- {
- //
- // 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 pvInstance 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.
- //
- //*****************************************************************************
- unsigned int
- USBDBulkRxPacketAvailable(void *pvInstance)
- {
- unsigned int ulEPStatus;
- unsigned int ulSize;
- tBulkInstance *psInst;
- ASSERT(pvInstance);
- //
- // Get our instance data pointer
- //
- psInst = ((tUSBDBulkDevice *)pvInstance)->psPrivateBulkData;
- //
- // Does the relevant endpoint FIFO have a packet waiting for us?
- //
- ulEPStatus = USBEndpointStatus(psInst->ulUSBBase, psInst->ucOUTEndpoint);
- if(ulEPStatus & USB_DEV_RX_PKT_RDY)
- {
- //
- // Yes - a packet is waiting. How big is it?
- //
- ulSize = USBEndpointDataAvail(psInst->ulUSBBase, psInst->ucOUTEndpoint);
- return (ulSize);
- }
- else
- {
- //
- // There is no packet waiting to be received.
- //
- return (0);
- }
- }
- //*****************************************************************************
- //
- //! Reports the device power status (bus- or self-powered) to the USB library.
- //!
- //! \param pvInstance is the pointer to the bulk device instance structure.
- //! \param ucPower 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 *pvInstance, unsigned char ucPower)
- {
- ASSERT(pvInstance);
- //
- // Pass the request through to the lower layer.
- //
- USBDCDPowerStatusSet(0, ucPower);
- }
- //*****************************************************************************
- //
- //! Requests a remote wake up to resume communication when in suspended state.
- //!
- //! \param pvInstance 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.
- //
- //*****************************************************************************
- tBoolean
- USBDBulkRemoteWakeupRequest(void *pvInstance)
- {
- ASSERT(pvInstance);
- //
- // Pass the request through to the lower layer.
- //
- return(USBDCDRemoteWakeupRequest(0));
- }
- //*****************************************************************************
- //
- // Close the Doxygen group.
- //! @}
- //
- //*****************************************************************************
|