summaryrefslogtreecommitdiff
path: root/usblib/usbbuffer.c
diff options
context:
space:
mode:
Diffstat (limited to 'usblib/usbbuffer.c')
-rw-r--r--usblib/usbbuffer.c1184
1 files changed, 1184 insertions, 0 deletions
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.
+//! @}
+//
+//*****************************************************************************