From c241dbd7e78c50327781a35d88d9f2db7ff2b271 Mon Sep 17 00:00:00 2001 From: Yuval Adam Date: Mon, 29 Oct 2012 23:08:53 +0200 Subject: Added usblib --- usblib/usbbuffer.c | 1184 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 1184 insertions(+) create mode 100644 usblib/usbbuffer.c (limited to 'usblib/usbbuffer.c') diff --git a/usblib/usbbuffer.c b/usblib/usbbuffer.c new file mode 100644 index 0000000..a2617fc --- /dev/null +++ b/usblib/usbbuffer.c @@ -0,0 +1,1184 @@ +//***************************************************************************** +// +// usbbuffer.c - USB buffer object. +// +// Copyright (c) 2008-2012 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 9453 of the Stellaris USB Library. +// +//***************************************************************************** + +#include "inc/hw_types.h" +#include "driverlib/debug.h" +#include "usblib/usblib.h" +#include "usblib/usblibpriv.h" + +//***************************************************************************** +// +//! \addtogroup usblib_buffer_api +//! @{ +// +//***************************************************************************** + +//***************************************************************************** +// +// Workspace variables required by each buffer instance. This structure is +// overlaid on the pvWorkspace memory provided in the tUSBBuffer structure +// passed to USBBufferInit(). +// +//***************************************************************************** +typedef struct +{ + tUSBRingBufObject sRingBuf; + unsigned long ulLastSent; + unsigned long ulFlags; +} +tUSBBufferVars; + +//***************************************************************************** +// +// Flags which may be set in the tUSBBufferVars ulFlags field. +// +//***************************************************************************** +#define USB_BUFFER_FLAG_SEND_ZLP 0x00000001 + +//***************************************************************************** +// +// Schedule the next packet transmission to the host if data remains to be +// sent. +// +// \param psBuffer points to the buffer from which a packet transmission is +// to be scheduled. +// +// This function checks to determine whether the lower layer is capable of +// accepting a new packet for transmission and, if so, schedules the next +// packet transmission if data remains in the buffer. +// +// \return None. +// +//***************************************************************************** +static void +ScheduleNextTransmission(const tUSBBuffer *psBuffer) +{ + tUSBBufferVars *psVars; + unsigned long ulPacket, ulSpace, ulTotal, ulSent; + + // + // Get a pointer to our workspace variables. + // + psVars = psBuffer->pvWorkspace; + + // + // Ask the lower layer if it has space to accept another packet of data. + // + ulPacket = psBuffer->pfnAvailable(psBuffer->pvHandle); + + // + // If we were returned something other than zero, we can write that number + // of bytes to the lower layer. + // + if(ulPacket) + { + // + // How much contiguous data do we have in the buffer? + // + ulSpace = USBRingBufContigUsed(&psVars->sRingBuf); + + // + // How much total data do we have in the buffer? + // + ulTotal = USBRingBufUsed(&psVars->sRingBuf); + + // + // How much data will we be sending as a result of this call? + // + ulSent = (ulPacket < ulTotal) ? ulPacket : ulTotal; + + // + // Write the contiguous bytes to the lower layer assuming there is + // something to send. + // + if(ulSpace) + { + // + // There is data available to send. Update our state to indicate + // the amount we will be sending in this packet. + // + psVars->ulLastSent = ulSent; + + // + // Determine the maximum sized block we can send in this transfer. + // + ulSpace = (ulSpace < ulPacket) ? ulSpace : ulPacket; + // + // Call the lower layer to send the new packet. If the current + // data spans the buffer wrap, tell the lower layer that it can + // expect a second call to fill the whole packet before it + // transmits it. + // + psBuffer->pfnTransfer(psBuffer->pvHandle, + (psVars->sRingBuf.pucBuf + + psVars->sRingBuf.ulReadIndex), ulSpace, + (((ulSpace < ulPacket) && + (ulSpace < ulTotal)) ? false : true)); + + // + // Do we need to send a second part to fill out the packet? This + // will occur if the current packet spans the buffer wrap. + // + if((ulSpace < ulPacket) && (ulSpace < ulTotal)) + { + // + // The packet straddled the wrap. How much space remains in + // the packet? + // + ulPacket -= ulSpace; + + // + // How much data can we actually send? + // + ulSpace = ulTotal - ulSpace; + ulSpace = (ulSpace > ulPacket) ? ulPacket : ulSpace; + + psBuffer->pfnTransfer(psBuffer->pvHandle, + psVars->sRingBuf.pucBuf, ulSpace, true); + } + } + else + { + // + // There is no data to send. Did we last send a full packet? + // + if(psVars->ulLastSent == ulPacket) + { + // + // Yes - if necessary, send a zero-length packet back to the + // host to complete the last transaction. + // + if(psVars->ulFlags & USB_BUFFER_FLAG_SEND_ZLP) + { + psVars->ulLastSent = 0; + psBuffer->pfnTransfer(psBuffer->pvHandle, + psVars->sRingBuf.pucBuf, 0, true); + } + } + } + + // + // Don't update the ring buffer read index yet. We do this once we are + // sure the packet was correctly transmitted. + // + } +} + +//***************************************************************************** +// +// Handles USB_EVENT_RX_AVAILABLE for a receive buffer. +// +// \param psBuffer points to the buffer which is receiving the event. +// \param ulSize is the size reported in the event. +// \param pucData is the pointer provided in the event. +// +// This function is responsible for reading data from the lower layer into +// the buffer or, if we had previously passed a section of the buffer to the +// lower layer for it to write into directly, updating the buffer write pointer +// to add the new data to the buffer. +// +// If the pointer provided is NULL, we call the low level pfnTransfer function +// to get the new data. If the pointer is not NULL and not within the existing +// ring buffer, we copy the data directly from the pointer to the buffer and +// return the number of bytes read. +// +// \return Returns the number of bytes read from the lower layer. +// +//***************************************************************************** +static unsigned long +HandleRxAvailable(tUSBBuffer *psBuffer, unsigned long ulSize, + unsigned char *pucData) +{ + tUSBBufferVars *psVars; + unsigned long ulAvail, ulRead, ulPacket, ulRetCount; + + // + // Get a pointer to our workspace variables. + // + psVars = psBuffer->pvWorkspace; + + // + // Has the data already been read into memory? + // + if(pucData) + { + // + // Yes - is it already in our ring buffer? + // + if((pucData >= psBuffer->pcBuffer) && + (pucData < psBuffer->pcBuffer + psBuffer->ulBufferSize)) + { + // + // The data is already in our ring buffer so merely update the + // write pointer to add the new data. + // + USBRingBufAdvanceWrite(&psVars->sRingBuf, ulSize); + + // + // In this case, we pass back 0 to indicate that the lower layer + // doesn't need to make any buffer pointer updates. + // + ulRetCount = 0; + } + else + { + // + // The data is not within our buffer so we need to copy it into + // the buffer. + // + // How much space does the buffer have available? + // + ulAvail = USBRingBufFree(&psVars->sRingBuf); + + // + // How much should we copy? + // + ulRead = (ulAvail < ulSize) ? ulAvail : ulSize; + + // + // Copy the data into the buffer. + // + USBRingBufWrite(&psVars->sRingBuf, pucData, ulRead); + + // + // We need to return the number of bytes we read in this case + // since the buffer supplied to us was owned by the lower layer and + // it may need to update its read pointer. + // + ulRetCount = ulRead; + } + } + else + { + // + // We were passed a NULL pointer so the low level driver has not read + // the data into memory yet. We need to call the transfer function to + // get the packet. + // + // How big is the packet that we need to receive? + // + ulPacket = psBuffer->pfnAvailable(psBuffer->pvHandle); + + // + // How much contiguous space do we have in the buffer? + // + ulAvail = USBRingBufContigFree(&psVars->sRingBuf); + + // + // Get as much of the packet as we can in the available space. + // + ulRead = psBuffer->pfnTransfer(psBuffer->pvHandle, + (psVars->sRingBuf.pucBuf + + psVars->sRingBuf.ulWriteIndex), + ulAvail, true); + + // + // Advance the ring buffer write pointer to add our new data. + // + if(ulRead) + { + USBRingBufAdvanceWrite(&psVars->sRingBuf, ulRead); + } + + // + // Did we get the whole packet? + // + if(ulRead < ulPacket) + { + // + // No - how much space do we have in the buffer? + // + ulAvail = USBRingBufContigFree(&psVars->sRingBuf); + + // + // If there is any space left, read as much of the remainder of + // the packet as we can. + // + if(ulAvail) + { + ulPacket = + psBuffer->pfnTransfer(psBuffer->pvHandle, + (psVars->sRingBuf.pucBuf + + psVars->sRingBuf.ulWriteIndex), + ulAvail, true); + + // + // Update the write pointer after we read more data into the + // buffer. + // + if(ulPacket) + { + USBRingBufAdvanceWrite(&psVars->sRingBuf, ulPacket); + } + } + } + + // + // We need to return 0 in this case to indicate that the lower layer + // need not perform any buffer maintenance as a result of the callback. + // + ulRetCount = 0; + } + + // + // How much data do we have in the buffer? + // + ulAvail = USBRingBufUsed(&psVars->sRingBuf); + + // + // Pass the event on to the client with the current read pointer and + // available data size. The client is expected to understand the ring + // structure and be able to deal with wrap if it wants to read the data + // directly from the buffer. + // + ulRead = psBuffer->pfnCallback(psBuffer->pvCBData, + USB_EVENT_RX_AVAILABLE, + ulAvail, + (psVars->sRingBuf.pucBuf + + psVars->sRingBuf.ulReadIndex)); + + // + // If the client read anything from the buffer, update the read pointer. + // + USBRingBufAdvanceRead(&psVars->sRingBuf, ulRead); + + // + // Return the correct value to the low level driver. + // + return(ulRetCount); +} + +//***************************************************************************** +// +// Handles USB_EVENT_DATA_REMAINING for a receive buffer. +// +// \param psBuffer points to the buffer which is receiving the event. +// +// This function determines the total number of bytes of data that remain +// unprocessed in the client and buffer and reports this back to the caller. +// +// \return Returns the number of bytes remaining to be processed. +// +//***************************************************************************** +static unsigned long +HandleDataRemaining(tUSBBuffer *psBuffer) +{ + unsigned long ulBufData, ulClientData; + tUSBBufferVars *psVars; + + // + // Get a pointer to our workspace variables. + // + psVars = psBuffer->pvWorkspace; + + // + // How much data does the client currently have buffered? + // + ulClientData = psBuffer->pfnCallback(psBuffer->pvCBData, + USB_EVENT_DATA_REMAINING, 0, + (void *)0); + + // + // How much data do we have in the buffer? + // + ulBufData = USBRingBufUsed(&psVars->sRingBuf); + + // + // Return the total number of bytes of unprocessed data to the lower layer. + // + return(ulBufData + ulClientData); +} + +//***************************************************************************** +// +// Handles USB_EVENT_TX_COMPLETE for a transmit buffer. +// +// \param psBuffer points to the buffer which is receiving the event. +// \param ulSize is the number of bytes that have been transmitted and +// acknowledged. +// +// This function informs us that data written to the lower layer from a +// transmit buffer has been successfully transmitted. We use this to update +// the buffer read pointer and attempt to schedule the next transmission if +// data remains in the buffer. +// +// \return Returns the number of bytes remaining to be processed. +// +//***************************************************************************** +static unsigned long +HandleTxComplete(tUSBBuffer *psBuffer, unsigned long ulSize) +{ + tUSBBufferVars *psVars; + + // + // Get a pointer to our workspace variables. + // + psVars = psBuffer->pvWorkspace; + + // + // Update the transmit buffer read pointer to remove the data that has + // now been transmitted. + // + USBRingBufAdvanceRead(&psVars->sRingBuf, ulSize); + + // + // Try to schedule the next packet transmission if data remains to be + // sent. + // + ScheduleNextTransmission(psBuffer); + + // + // The return code from this event is ignored. + // + return(0); +} + +//***************************************************************************** +// +// Handles USB_EVENT_REQUEST_BUFFER for a receive buffer. +// +// \param psBuffer points to the buffer which is receiving the event. +// \param ulSize is the size of the buffer requested. +// \param ppucBuffer is a pointer which is to be written with a pointer to +// the returned buffer. +// +// This function is called by a low level driver that wishes to receive data +// automatically and write it directly to a memory buffer, either using +// software or DMA prior to issuing USB_EVENT_RX_AVAILABLE. The event is sent +// in advance of receiving data to provide storage for whatever is received +// next. +// +// If we have a contiguous block of space in the buffer of at least ulSize +// bytes immediately in front of the current write pointer, we pass this back +// otherwise we send NULL indicating that the next packet should be notified +// using a standard USB_EVENT_RX_AVAILABLE event without being received +// automatically. Note that the USB_EVENT_REQUEST_BUFFER protocol allows us to +// return less than \e ulSize bytes if we know how much data is expected next +// but this is not possible here since the USBBuffer knows nothing about the +// protocol whose data it is handling. +// +// \return Returns the number of bytes remaining to be processed. +// +//***************************************************************************** +static unsigned long +HandleRequestBuffer(tUSBBuffer *psBuffer, unsigned long ulSize, + unsigned char **ppucBuffer) +{ + tUSBBufferVars *psVars; + unsigned long ulSpace; + + // + // Get a pointer to our workspace variables. + // + psVars = psBuffer->pvWorkspace; + + // + // How much contiguous space do we have available? + // + ulSpace = USBRingBufContigFree(&psVars->sRingBuf); + + // + // Is there enough space available to satisfy the request? + // + if(ulSpace >= ulSize) + { + // + // Yes - return the current write pointer + // + *ppucBuffer = psVars->sRingBuf.pucBuf + psVars->sRingBuf.ulWriteIndex; + return(ulSize); + } + else + { + // + // We do not have enough contiguous space following the current write + // pointer to satisfy the request so do not provide a buffer. + // + *ppucBuffer = (unsigned char *)0; + return(0); + } +} + +//***************************************************************************** +// +//! Initializes a USB buffer object to be used with a given USB controller and +//! device or host class driver. +//! +//! \param psBuffer points to a structure containing information on the buffer +//! memory to be used and the underlying device or host class driver whose data +//! is to be buffered. This structure must remain accessible for as long as +//! the buffer is in use. +//! +//! This function is used to initialize a USB buffer object and insert it +//! into the function and callback interfaces between an underlying driver +//! and the application. The caller supplies information on both the RAM +//! to be used to buffer data, the type of buffer to be created (transmit or +//! receive) and the functions to be called in the lower layer to transfer +//! data to or from the USB controller. +//! +//! \return Returns the original buffer structure pointer if successful or +//! NULL if an error is detected. +// +//***************************************************************************** +const tUSBBuffer * +USBBufferInit(const tUSBBuffer *psBuffer) +{ + tUSBBufferVars *psVars; + + // + // Check parameter validity. + // + ASSERT(psBuffer && psBuffer->pvWorkspace && psBuffer->pcBuffer && + psBuffer->ulBufferSize && psBuffer->pfnAvailable && + psBuffer->pfnTransfer && psBuffer->pfnCallback); + + // + // Get a pointer to the buffer workspace and initialize the variables it + // contains. + // + psVars = psBuffer->pvWorkspace; + psVars->ulFlags = 0; + USBRingBufInit(&psVars->sRingBuf, psBuffer->pcBuffer, + psBuffer->ulBufferSize); + + // + // If all is well, return the same pointer we were originally passed. + // + return(psBuffer); +} + +//***************************************************************************** +// +//! Enables or disables zero-length packet insertion. +//! +//! \param psBuffer is the pointer to the buffer instance whose information +//! is being queried. +//! \param bSendZLP is \b true to send zero-length packets or \b false to +//! prevent them from being sent. +//! +//! This function allows the use of zero-length packets to be controlled by +//! an application. In cases where the USB buffer has sent a full (64 byte) +//! packet and then discovers that the transmit buffer is empty, the default +//! behavior is to do nothing. Some protocols, however, require that a zero- +//! length packet be inserted to signal the end of the data. When using such +//! a protocol, this function should be called with \e bSendZLP set to \b true +//! to enable the desired behavior. +//! +//! \return None. +// +//***************************************************************************** +void +USBBufferZeroLengthPacketInsert(const tUSBBuffer *psBuffer, tBoolean bSendZLP) +{ + tUSBBufferVars *psVars; + + // + // Check parameter validity. + // + ASSERT(psBuffer); + + // + // Get our workspace variables. + // + psVars = psBuffer->pvWorkspace; + + // + // Set the flag telling us whether or not to send a zero-length packet + // after sending a 64 bytes packet and finding no more data to send. + // + if(bSendZLP) + { + // + // Enable ZLP transmission. + // + psVars->ulFlags |= USB_BUFFER_FLAG_SEND_ZLP; + } + else + { + // + // Disable ZLP transmission. + // + psVars->ulFlags &= ~ USB_BUFFER_FLAG_SEND_ZLP; + } +} + +//***************************************************************************** +// +//! Returns the current ring buffer indices for this USB buffer. +//! +//! \param psBuffer is the pointer to the buffer instance whose information +//! is being queried. +//! \param psRingBuf is a pointer to storage that will be written with the +//! current ring buffer control structure for this USB buffer. +//! +//! This function is provided to aid a client wishing to write data directly +//! into the USB buffer rather than using the USBBufferWrite() function. This +//! may be necessary to control when the USBBuffer starts transmission of a +//! large block of data, for example. +//! +//! A transmit buffer will immediately send a new packet on any call to +//! USBBufferWrite() if the underlying layer indicates that a transmission can +//! be started. In some cases this is not desirable and a client may wish to +//! wishes to write more data to the buffer in advance of starting transmission +//! to the lower layer. In such cases, this function may be called to retrieve +//! the current ring buffer indices and the buffer accessed directly. Once the +//! client has written all data it wishes to send, it should call function +//! USBBufferDataWritten() to indicate that transmission may begin. +//! +//! \return None. +// +//***************************************************************************** +void +USBBufferInfoGet(const tUSBBuffer *psBuffer, tUSBRingBufObject *psRingBuf) +{ + tUSBBufferVars *psVars; + + // + // Check parameter validity. + // + ASSERT(psBuffer && psRingBuf); + + // + // Get our workspace variables. + // + psVars = psBuffer->pvWorkspace; + + // + // Copy the current ring buffer settings to the clients storage. + // + *psRingBuf = psVars->sRingBuf; +} + +//***************************************************************************** +// +//! Indicates that a client has written data directly into the buffer and +//! wishes to start transmission. +//! +//! \param psBuffer is the pointer to the buffer instance into which data has +//! been written. +//! \param ulLength is the number of bytes of data that the client has written. +//! +//! This function updates the USB buffer write pointer and starts transmission +//! of the data in the buffer assuming the lower layer is ready to receive a +//! new packet. The function is provided to aid a client wishing to write +//! data directly into the USB buffer rather than using the USBBufferWrite() +//! function. This may be necessary to control when the USB buffer starts +//! transmission of a large block of data, for example. +//! +//! A transmit buffer will immediately send a new packet on any call to +//! USBBufferWrite() if the underlying layer indicates that a transmission can +//! be started. In some cases this is not desirable and a client may wish to +//! write more data to the buffer in advance of starting transmission +//! to the lower layer. In such cases, USBBufferInfoGet() may be called to +//! retrieve the current ring buffer indices and the buffer accessed directly. +//! Once the client has written all data it wishes to send (taking care to +//! handle the ring buffer wrap), it should call this function to indicate that +//! transmission may begin. +//! +//! \return None. +// +//***************************************************************************** +void +USBBufferDataWritten(const tUSBBuffer *psBuffer, unsigned long ulLength) +{ + tUSBBufferVars *psVars; + + // + // Check parameter validity. + // + ASSERT(psBuffer); + + // + // Get our workspace variables. + // + psVars = psBuffer->pvWorkspace; + + // + // Advance the ring buffer write pointer to include the newly written + // data. + // + if(ulLength) + { + USBRingBufAdvanceWrite(&psVars->sRingBuf, ulLength); + } + + // + // Try to schedule a new packet transmission. + // + ScheduleNextTransmission(psBuffer); +} + +//***************************************************************************** +// +//! Indicates that a client has read data directly out of the buffer. +//! +//! \param psBuffer is the pointer to the buffer instance from which data has +//! been read. +//! \param ulLength is the number of bytes of data that the client has read. +//! +//! This function updates the USB buffer read pointer to remove data that +//! the client has read directly rather than via a call to USBBufferRead(). +//! The function is provided to aid a client wishing to minimize data copying. +//! To read directly from the buffer, a client must call USBBufferInfoGet() to +//! retrieve the current buffer indices. With this information, the data +//! following the current read index can be read. Once the client has +//! processed much data as it needs, USBBufferDataRemoved() must be called to +//! advance the read pointer past the data that has been read and free up that +//! section of the buffer. The client must take care to correctly handle the +//! wrap point if accessing the buffer directly. +//! +//! \return None. +// +//***************************************************************************** +void +USBBufferDataRemoved(const tUSBBuffer *psBuffer, unsigned long ulLength) +{ + tUSBBufferVars *psVars; + + // + // Check parameter validity. + // + ASSERT(psBuffer); + + // + // Get our workspace variables. + // + psVars = psBuffer->pvWorkspace; + + // + // Advance the ring buffer write pointer to include the newly written + // data. + // + if(ulLength) + { + USBRingBufAdvanceRead(&psVars->sRingBuf, ulLength); + } +} + +//***************************************************************************** +// +//! Sets the callback pointer supplied to clients of this buffer. +//! +//! \param psBuffer is the pointer to the buffer instance whose callback data +//! is to be changed. +//! \param pvCBData is the pointer the client wishes to receive on all future +//! callbacks from this buffer. +//! +//! This function sets the callback pointer which this buffer will supply +//! to clients as the \e pvCBData parameter in all future calls to the +//! event callback. +//! +//! \note If this function is to be used, the application must ensure that the +//! tUSBBuffer structure used to describe this buffer is held in RAM rather +//! than flash. The \e pvCBData value passed is written directly into this +//! structure. +//! +//! \return Returns the previous callback pointer set for the buffer. +// +//***************************************************************************** +void * +USBBufferCallbackDataSet(tUSBBuffer *psBuffer, void *pvCBData) +{ + void *pvOldData; + + // + // Keep a copy of the old callback data. + // + pvOldData = psBuffer->pvCBData; + + // + // Replace the callback data with the new value. + // + psBuffer->pvCBData = pvCBData; + + // + // Give the caller the old value back. + // + return(pvOldData); +} + +//***************************************************************************** +// +//! Writes a block of data to the transmit buffer and queues it for +//! transmission to the USB controller. +//! +//! \param psBuffer points to the pointer instance into which data is to be +//! written. +//! \param pucData points to the first byte of data which is to be written. +//! \param ulLength is the number of bytes of data to write to the buffer. +//! +//! This function copies the supplied data into the transmit buffer. The +//! transmit buffer data will be packetized according to the constraints +//! imposed by the lower layer in use and sent to the USB controller as soon as +//! possible. Once a packet is transmitted and acknowledged, a +//! \b USB_EVENT_TX_COMPLETE event will be sent to the application callback +//! indicating the number of bytes that have been sent from the buffer. +//! +//! Attempts to send more data than there is space for in the transmit buffer +//! will result in fewer bytes than expected being written. The value returned +//! by the function indicates the actual number of bytes copied to the buffer. +//! +//! \return Returns the number of bytes actually written. +// +//***************************************************************************** +unsigned long +USBBufferWrite(const tUSBBuffer *psBuffer, const unsigned char *pucData, + unsigned long ulLength) +{ + unsigned long ulSpace; + tUSBBufferVars *psVars; + + // + // Check parameter validity. + // + ASSERT(psBuffer && pucData); + ASSERT(psBuffer->bTransmitBuffer == true); + + // + // Get our workspace variables. + // + psVars = psBuffer->pvWorkspace; + + // + // How much space is left in the buffer? + // + ulSpace = USBRingBufFree(&psVars->sRingBuf); + + // + // How many bytes will we write? + // + ulLength = (ulLength > ulSpace) ? ulSpace : ulLength; + + // + // Write the data to the buffer. + // + if(ulLength) + { + USBRingBufWrite(&psVars->sRingBuf, pucData, ulLength); + } + + // + // Try to transmit the next packet to the host. + // + ScheduleNextTransmission(psBuffer); + + // + // Tell the caller how many bytes we wrote to the buffer. + // + return(ulLength); +} + +//***************************************************************************** +// +//! Flushes a USB buffer, discarding any data that it contains. +//! +//! \param psBuffer is the pointer to the buffer instance which is to be +//! flushed. +//! +//! This function discards all data currently in the supplied buffer without +//! processing (transmitting it via the USB controller or passing it to the +//! client depending upon the buffer mode). +//! +//! \return None. +// +//***************************************************************************** +void +USBBufferFlush(const tUSBBuffer *psBuffer) +{ + tUSBBufferVars *psVars; + + // + // Check parameter validity. + // + ASSERT(psBuffer); + + // + // Get our workspace variables. + // + psVars = psBuffer->pvWorkspace; + + // + // Flush the ring buffer. + // + USBRingBufFlush(&psVars->sRingBuf); +} + +//***************************************************************************** +// +//! Reads a block of data from a USB receive buffer into storage supplied by +//! the caller. +//! +//! \param psBuffer is the pointer to the buffer instance from which data is +//! to be read. +//! \param pucData points to a buffer into which the received data will be +//! written. +//! \param ulLength is the size of the buffer pointed to by pucData. +//! +//! This function reads up to ulLength bytes of data received from the USB +//! host into the supplied application buffer. If the receive buffer +//! contains fewer than \e ulLength bytes of data, the data that is present +//! will be copied and the return code will indicate the actual number of bytes +//! copied to \e pucData. +//! +//! \return Returns the number of bytes of data read. +// +//***************************************************************************** +unsigned long +USBBufferRead(const tUSBBuffer *psBuffer, unsigned char *pucData, + unsigned long ulLength) +{ + tUSBBufferVars *psVars; + unsigned long ulAvail, ulRead; + + // + // Check parameter validity. + // + ASSERT(psBuffer && pucData && ulLength); + + // + // Get our workspace variables. + // + psVars = psBuffer->pvWorkspace; + + // + // How much data is in the buffer? + // + ulAvail = USBRingBufUsed(&psVars->sRingBuf); + + // + // Determine how many bytes we can actually read. + // + ulRead = (ulAvail < ulLength) ? ulAvail : ulLength; + + // + // Read the data from the buffer assuming there is some to read. + // + if(ulRead) + { + USBRingBufRead(&psVars->sRingBuf, pucData, ulRead); + } + + // + // Tell the caller how many bytes we wrote to their buffer. + // + return(ulRead); +} + +//***************************************************************************** +// +//! Returns the number of bytes of data available in the buffer. +//! +//! \param psBuffer is the pointer to the buffer instance which is to be +//! queried. +//! +//! This function may be used to determine the number of bytes of data in a +//! buffer. For a receive buffer, this indicates the number of bytes that the +//! client can read from the buffer using USBBufferRead(). For a transmit +//! buffer, this indicates the amount of data that remains to be sent to the +//! USB controller. +//! +//! \return Returns the number of bytes of data in the buffer. +// +//***************************************************************************** +unsigned long +USBBufferDataAvailable(const tUSBBuffer *psBuffer) +{ + tUSBBufferVars *psVars; + + // + // Check parameter validity. + // + ASSERT(psBuffer); + + // + // Get our workspace variables. + // + psVars = psBuffer->pvWorkspace; + + // + // Return the amount of data in the buffer. + // + return(USBRingBufUsed(&psVars->sRingBuf)); +} + +//***************************************************************************** +// +//! Returns the number of free bytes in the buffer. +//! +//! \param psBuffer is the pointer to the buffer instance which is to be +//! queried. +//! +//! This function returns the number of free bytes in the buffer. For a +//! transmit buffer, this indicates the maximum number of bytes that can be +//! passed on a call to USBBufferWrite() and accepted for transmission. For a +//! receive buffer, it indicates the number of bytes that can be read from the +//! USB controller before the buffer will be full. +//! +//! \return Returns the number of free bytes in the buffer. +// +//***************************************************************************** +unsigned long +USBBufferSpaceAvailable(const tUSBBuffer *psBuffer) +{ + tUSBBufferVars *psVars; + + // + // Check parameter validity. + // + ASSERT(psBuffer); + + // + // Get our workspace variables. + // + psVars = psBuffer->pvWorkspace; + + // + // Return the amount of space available in the buffer. + // + return(USBRingBufFree(&psVars->sRingBuf)); +} + +//***************************************************************************** +// +//! Called by the USB buffer to notify the client of asynchronous events. +//! +//! \param pvCBData is the client-supplied callback pointer associated with +//! this buffer instance. +//! \param ulEvent is the identifier of the event being sent. This will be +//! a general event identifier of the form USBD_EVENT_xxxx or a device +//! class-dependent event of the form USBD_CDC_EVENT_xxx or +//! USBD_HID_EVENT_xxx. +//! \param ulMsgValue is an event-specific parameter value. +//! \param pvMsgData is an event-specific data pointer. +//! +//! This function is the USB buffer event handler that applications should +//! register with the USB device class driver as the callback for the channel +//! which is to be buffered using this buffer. +//! +//! \note This function will never be called by an application. It is the +//! handler that allows the USB buffer to be inserted above the device class +//! driver or host pipe driver and below the application to offer buffering +//! support. +//! +//! \return The return value is dependent upon the event being processed. +// +//***************************************************************************** +unsigned long +USBBufferEventCallback(void *pvCBData, unsigned long ulEvent, + unsigned long ulMsgValue, void *pvMsgData) +{ + tUSBBuffer *psBuffer; + + // + // Get our instance data pointers from the callback data. + // + psBuffer = (tUSBBuffer *)pvCBData; + ASSERT(psBuffer); + + // + // Which event have we been sent? + // + switch(ulEvent) + { + // + // Data is available from the lower layer. + // + case USB_EVENT_RX_AVAILABLE: + { + // + // This event is only relevant to us if we are a receive buffer. + // + if(!psBuffer->bTransmitBuffer) + { + return(HandleRxAvailable(psBuffer, ulMsgValue, pvMsgData)); + } + break; + } + + // + // We are being asked how much data remains to be processed. + // + case USB_EVENT_DATA_REMAINING: + { + return(HandleDataRemaining(psBuffer)); + } + + // + // A previous transmission has completed. + // + case USB_EVENT_TX_COMPLETE: + { + // + // This event is only relevant to us if we are a transmit buffer. + // + if(psBuffer->bTransmitBuffer) + { + // + // Handle the message then drop out of the switch so that the + // event is echoed to the layer above. + // + HandleTxComplete(psBuffer, ulMsgValue); + } + break; + } + + // + // We are being asked to provide a buffer into which the next packet + // can be received. + // + case USB_EVENT_REQUEST_BUFFER: + { + // + // This event is only relevant to us if we are a receive buffer. + // + if(!psBuffer->bTransmitBuffer) + { + return(HandleRequestBuffer(psBuffer, ulMsgValue, pvMsgData)); + } + break; + } + + // + // All other events are merely passed through to the client. + // + default: + { + break; + } + } + + // + // If we drop out of the switch, we need to pass the event on to the client + // unmodified and return the relevant return code back to the lower layer. + // + return(psBuffer->pfnCallback(psBuffer->pvCBData, ulEvent, ulMsgValue, + pvMsgData)); +} + +//***************************************************************************** +// +// Close the Doxygen group. +//! @} +// +//***************************************************************************** -- cgit v1.3.1