text: //*****************************************************************************
  //
  // usbbuffer.c - USB buffer object.
  //
  // Copyright (c) 2008-2016 Texas Instruments Incorporated.  All rights reserved.
  // Software License Agreement
  // 
  // Texas Instruments (TI) is supplying this software for use solely and
  // exclusively on TI's microcontroller products. The software is owned by
  // TI and/or its suppliers, and is protected under applicable copyright
  // laws. You may not combine this software with "viral" open-source
  // software in order to form a larger program.
  // 
  // THIS SOFTWARE IS PROVIDED "AS IS" AND WITH ALL FAULTS.
  // NO WARRANTIES, WHETHER EXPRESS, IMPLIED OR STATUTORY, INCLUDING, BUT
  // NOT LIMITED TO, IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
  // A PARTICULAR PURPOSE APPLY TO THIS SOFTWARE. TI SHALL NOT, UNDER ANY
  // CIRCUMSTANCES, BE LIABLE FOR SPECIAL, INCIDENTAL, OR CONSEQUENTIAL
  // DAMAGES, FOR ANY REASON WHATSOEVER.
  // 
  // This is part of revision 2.1.3.156 of the Tiva USB Library.
  //
  //*****************************************************************************
  
  #include <stdbool.h>
  #include <stdint.h>
  #include "inc/hw_types.h"
  #include "driverlib/debug.h"
  #include "usblib/usblib.h"
  #include "usblib/usblibpriv.h"
  
  //*****************************************************************************
  //
  //! \addtogroup usblib_buffer_api
  //! @{
  //
  //*****************************************************************************
  
  //*****************************************************************************
  //
  // Flags which may be set in the tUSBBufferVars ui32Flags 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(tUSBBuffer *psBuffer)
  {
      uint32_t ui32Packet, ui32Space, ui32Total, ui32Sent;
  
      //
      // Ask the lower layer if it has space to accept another packet of data.
      //
      ui32Packet = psBuffer->pfnAvailable(psBuffer->pvHandle);
  
      //
      // If we were returned something other than zero, we can write that number
      // of bytes to the lower layer.
      //
      if(ui32Packet)
      {
          //
          // How much contiguous data do we have in the buffer?
          //
          ui32Space = USBRingBufContigUsed(&psBuffer->sPrivateData.sRingBuf);
  
          //
          // How much total data do we have in the buffer?
          //
          ui32Total = USBRingBufUsed(&psBuffer->sPrivateData.sRingBuf);
  
          //
          // How much data will we be sending as a result of this call?
          //
          ui32Sent = (ui32Packet < ui32Total) ? ui32Packet : ui32Total;
  
          //
          // Write the contiguous bytes to the lower layer assuming there is
          // something to send.
          //
          if(ui32Space)
          {
              //
              // There is data available to send.  Update our state to indicate
              // the amount we will be sending in this packet.
              //
              psBuffer->sPrivateData.ui32LastSent = ui32Sent;
  
              //
              // Determine the maximum sized block we can send in this transfer.
              //
              ui32Space = (ui32Space < ui32Packet) ? ui32Space : ui32Packet;
              //
              // 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,
                                (psBuffer->sPrivateData.sRingBuf.pui8Buf +
                                 psBuffer->sPrivateData.sRingBuf.ui32ReadIndex),
                                 ui32Space,
                                (((ui32Space < ui32Packet) &&
                                  (ui32Space < ui32Total)) ? 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((ui32Space < ui32Packet) && (ui32Space < ui32Total))
              {
                  //
                  // The packet straddled the wrap.  How much space remains in
                  // the packet?
                  //
                  ui32Packet -= ui32Space;
  
                  //
                  // How much data can we actually send?
                  //
                  ui32Space = ui32Total - ui32Space;
                  ui32Space = (ui32Space > ui32Packet) ? ui32Packet : ui32Space;
  
                  psBuffer->pfnTransfer(psBuffer->pvHandle,
                                        psBuffer->sPrivateData.sRingBuf.pui8Buf,
                                        ui32Space, true);
              }
          }
          else
          {
              //
              // There is no data to send.  Did we last send a full packet?
              //
              if(psBuffer->sPrivateData.ui32LastSent == ui32Packet)
              {
                  //
                  // Yes - if necessary, send a zero-length packet back to the
                  // host to complete the last transaction.
                  //
                  if(psBuffer->sPrivateData.ui32Flags & USB_BUFFER_FLAG_SEND_ZLP)
                  {
                      psBuffer->sPrivateData.ui32LastSent = 0;
                      psBuffer->pfnTransfer(psBuffer->pvHandle,
                                        psBuffer->sPrivateData.sRingBuf.pui8Buf,
                                        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 ui32Size is the size reported in the event.
  // \param pui8Data 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 uint32_t
  HandleRxAvailable(tUSBBuffer *psBuffer, uint32_t ui32Size, uint8_t *pui8Data)
  {
      uint32_t ui32Avail, ui32Read, ui32Packet, ui32RetCount;
  
      //
      // Has the data already been read into memory?
      //
      if(pui8Data)
      {
          //
          // Yes - is it already in our ring buffer?
          //
          if((pui8Data >= psBuffer->pui8Buffer) &&
             (pui8Data < psBuffer->pui8Buffer + psBuffer->ui32BufferSize))
          {
              //
              // The data is already in our ring buffer so merely update the
              // write pointer to add the new data.
              //
              USBRingBufAdvanceWrite(&psBuffer->sPrivateData.sRingBuf, ui32Size);
  
              //
              // In this case, we pass back 0 to indicate that the lower layer
              // doesn't need to make any buffer pointer updates.
              //
              ui32RetCount = 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?
              //
              ui32Avail = USBRingBufFree(&psBuffer->sPrivateData.sRingBuf);
  
              //
              // How much should we copy?
              //
              ui32Read = (ui32Avail < ui32Size) ? ui32Avail : ui32Size;
  
              //
              // Copy the data into the buffer.
              //
              USBRingBufWrite(&psBuffer->sPrivateData.sRingBuf, pui8Data,
                              ui32Read);
  
              //
              // 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.
              //
              ui32RetCount = ui32Read;
          }
      }
      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?
          //
          ui32Packet = psBuffer->pfnAvailable(psBuffer->pvHandle);
  
          //
          // How much contiguous space do we have in the buffer?
          //
          ui32Avail = USBRingBufContigFree(&psBuffer->sPrivateData.sRingBuf);
  
          //
          // Get as much of the packet as we can in the available space.
          //
          ui32Read = psBuffer->pfnTransfer(psBuffer->pvHandle,
                                (psBuffer->sPrivateData.sRingBuf.pui8Buf +
                                 psBuffer->sPrivateData.sRingBuf.ui32WriteIndex),
                                ui32Avail, true);
  
          //
          // Advance the ring buffer write pointer to add our new data.
          //
          if(ui32Read)
          {
              USBRingBufAdvanceWrite(&psBuffer->sPrivateData.sRingBuf, ui32Read);
          }
  
          //
          // Did we get the whole packet?
          //
          if(ui32Read < ui32Packet)
          {
              //
              // No - how much space do we have in the buffer?
              //
              ui32Avail = USBRingBufContigFree(&psBuffer->sPrivateData.sRingBuf);
  
              //
              // If there is any space left, read as much of the remainder of
              // the packet as we can.
              //
              if(ui32Avail)
              {
                  ui32Packet =
                      psBuffer->pfnTransfer(psBuffer->pvHandle,
                                (psBuffer->sPrivateData.sRingBuf.pui8Buf +
                                 psBuffer->sPrivateData.sRingBuf.ui32WriteIndex),
                                 ui32Avail, true);
  
                  //
                  // Update the write pointer after we read more data into the
                  // buffer.
                  //
                  if(ui32Packet)
                  {
                      USBRingBufAdvanceWrite(&psBuffer->sPrivateData.sRingBuf,
                                             ui32Packet);
                  }
              }
          }
  
          //
          // 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.
          //
          ui32RetCount = 0;
      }
  
      //
      // How much data do we have in the buffer?
      //
      ui32Avail = USBRingBufUsed(&psBuffer->sPrivateData.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.
      //
      ui32Read = psBuffer->pfnCallback(psBuffer->pvCBData,
                               USB_EVENT_RX_AVAILABLE, ui32Avail,
                               (psBuffer->sPrivateData.sRingBuf.pui8Buf +
                                psBuffer->sPrivateData.sRingBuf.ui32ReadIndex));
  
      //
      // If the client read anything from the buffer, update the read pointer.
      //
      USBRingBufAdvanceRead(&psBuffer->sPrivateData.sRingBuf, ui32Read);
  
      //
      // Return the correct value to the low level driver.
      //
      return(ui32RetCount);
  }
  
  //*****************************************************************************
  //
  // 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 uint32_t
  HandleDataRemaining(tUSBBuffer *psBuffer)
  {
      uint32_t ui32BufData, ui32ClientData;
  
      //
      // How much data does the client currently have buffered?
      //
      ui32ClientData = psBuffer->pfnCallback(psBuffer->pvCBData,
                                             USB_EVENT_DATA_REMAINING, 0,
                                             (void *)0);
  
      //
      // How much data do we have in the buffer?
      //
      ui32BufData = USBRingBufUsed(&psBuffer->sPrivateData.sRingBuf);
  
      //
      // Return the total number of bytes of unprocessed data to the lower layer.
      //
      return(ui32BufData + ui32ClientData);
  }
  
  //*****************************************************************************
  //
  // Handles USB_EVENT_TX_COMPLETE for a transmit buffer.
  //
  // \param psBuffer points to the buffer which is receiving the event.
  // \param ui32Size 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 uint32_t
  HandleTxComplete(tUSBBuffer *psBuffer, uint32_t ui32Size)
  {
      //
      // Update the transmit buffer read pointer to remove the data that has
      // now been transmitted.
      //
      USBRingBufAdvanceRead(&psBuffer->sPrivateData.sRingBuf, ui32Size);
  
      //
      // 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 ui32Size is the size of the buffer requested.
  // \param ppui8Buffer 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 ui32Size
  // 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 ui32Size 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 uint32_t
  HandleRequestBuffer(tUSBBuffer *psBuffer, uint32_t ui32Size,
                      uint8_t **ppui8Buffer)
  {
      uint32_t ui32Space;
  
      //
      // How much contiguous space do we have available?
      //
      ui32Space = USBRingBufContigFree(&psBuffer->sPrivateData.sRingBuf);
  
      //
      // Is there enough space available to satisfy the request?
      //
      if(ui32Space >= ui32Size)
      {
          //
          // Yes - return the current write pointer
          //
          *ppui8Buffer = psBuffer->sPrivateData.sRingBuf.pui8Buf +
                         psBuffer->sPrivateData.sRingBuf.ui32WriteIndex;
          return(ui32Size);
      }
      else
      {
          //
          // We do not have enough contiguous space following the current write
          // pointer to satisfy the request so do not provide a buffer.
          //
          *ppui8Buffer = (uint8_t *)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(tUSBBuffer *psBuffer)
  {
      //
      // Check parameter validity.
      //
      ASSERT(psBuffer && psBuffer->pui8Buffer &&
             psBuffer->ui32BufferSize && psBuffer->pfnAvailable &&
             psBuffer->pfnTransfer && psBuffer->pfnCallback);
  
      //
      // Get a pointer to the buffer workspace and initialize the variables it
      // contains.
      //
      psBuffer->sPrivateData.ui32Flags = 0;
      USBRingBufInit(&psBuffer->sPrivateData.sRingBuf, psBuffer->pui8Buffer,
                     psBuffer->ui32BufferSize);
  
      //
      // 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, bool bSendZLP)
  {
      tUSBBufferVars *psPrivate;
  
      //
      // Check parameter validity.
      //
      ASSERT(psBuffer);
  
      //
      // Create a writable pointer to the private data.
      //
      psPrivate = &((tUSBBuffer *)psBuffer)->sPrivateData;
  
      //
      // Set the flag telling us whether or not to send a zero-length packet
      // after sending a full packet (64 bytes and 512 bytes for HS) and 
      // finding no more data to send.
      //
      if(bSendZLP)
      {
          //
          // Enable ZLP transmission.
          //
          psPrivate->ui32Flags |= USB_BUFFER_FLAG_SEND_ZLP;
      }
      else
      {
          //
          // Disable ZLP transmission.
          //
          psPrivate->ui32Flags &= ~ 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)
  {
      //
      // Check parameter validity.
      //
      ASSERT(psBuffer && psRingBuf);
  
      //
      // Copy the current ring buffer settings to the clients storage.
      //
      psRingBuf->pui8Buf = psBuffer->sPrivateData.sRingBuf.pui8Buf;
      psRingBuf->ui32ReadIndex = psBuffer->sPrivateData.sRingBuf.ui32ReadIndex;
      psRingBuf->ui32Size = psBuffer->sPrivateData.sRingBuf.ui32ReadIndex;
      psRingBuf->ui32WriteIndex = psBuffer->sPrivateData.sRingBuf.ui32WriteIndex;
  }
  
  //*****************************************************************************
  //
  //! 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 ui32Length 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, uint32_t ui32Length)
  {
      tUSBBufferVars *psPrivate;
  
      //
      // Check parameter validity.
      //
      ASSERT(psBuffer);
  
      //
      // Create a writable pointer to the private data.
      //
      psPrivate = &((tUSBBuffer *)psBuffer)->sPrivateData;
  
      //
      // Advance the ring buffer write pointer to include the newly written
      // data.
      //
      if(ui32Length)
      {
          USBRingBufAdvanceWrite(&psPrivate->sRingBuf, ui32Length);
      }
  
      //
      // Try to schedule a new packet transmission.
      //
      ScheduleNextTransmission((tUSBBuffer *)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 ui32Length 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 inpsBufVarsdices.  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, uint32_t ui32Length)
  {
      tUSBBufferVars *psPrivate;
  
      //
      // Check parameter validity.
      //
      ASSERT(psBuffer);
  
      //
      // Create a writable pointer to the private data.
      //
      psPrivate = &((tUSBBuffer *)psBuffer)->sPrivateData;
  
      //
      // Advance the ring buffer write pointer to include the newly written
      // data.
      //
      if(ui32Length)
      {
          USBRingBufAdvanceRead(&psPrivate->sRingBuf, ui32Length);
      }
  }
  
  //*****************************************************************************
  //
  //! 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 pui8Data points to the first byte of data which is to be written.
  //! \param ui32Length 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.
  //
  //*****************************************************************************
  uint32_t
  USBBufferWrite(const tUSBBuffer *psBuffer, const uint8_t *pui8Data,
                 uint32_t ui32Length)
  {
      uint32_t ui32Space;
      tUSBBufferVars *psPrivate;
  
      //
      // Check parameter validity.
      //
      ASSERT(psBuffer && pui8Data);
      ASSERT(psBuffer->bTransmitBuffer == true);
  
      //
      // Create a writable pointer to the private data.
      //
      psPrivate = &((tUSBBuffer *)psBuffer)->sPrivateData;
  
      //
      // How much space is left in the buffer?
      //
      ui32Space = USBRingBufFree(&psPrivate->sRingBuf);
  
      //
      // How many bytes will we write?
      //
      ui32Length = (ui32Length > ui32Space) ? ui32Space : ui32Length;
  
      //
      // Write the data to the buffer.
      //
      if(ui32Length)
      {
          USBRingBufWrite(&psPrivate->sRingBuf, pui8Data, ui32Length);
      }
  
      //
      // Try to transmit the next packet to the host.
      //
      ScheduleNextTransmission((tUSBBuffer *)psBuffer);
  
      //
      // Tell the caller how many bytes we wrote to the buffer.
      //
      return(ui32Length);
  }
  
  //*****************************************************************************
  //
  //! 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 *psPrivate;
  
      //
      // Check parameter validity.
      //
      ASSERT(psBuffer);
  
      //
      // Create a writable pointer to the private data.
      //
      psPrivate = &((tUSBBuffer *)psBuffer)->sPrivateData;
  
      //
      // Flush the ring buffer.
      //
      USBRingBufFlush(&psPrivate->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 pui8Data points to a buffer into which the received data will be
  //! written.
  //! \param ui32Length is the size of the buffer pointed to by pui8Data.
  //!
  //! This function reads up to \e ui32Length bytes of data received from the USB
  //! host into the supplied application buffer.  If the receive buffer
  //! contains fewer than \e ui32Length 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 pui8Data.
  //!
  //! \return Returns the number of bytes of data read.
  //
  //*****************************************************************************
  uint32_t
  USBBufferRead(const tUSBBuffer *psBuffer, uint8_t *pui8Data,
                uint32_t ui32Length)
  {
      uint32_t ui32Avail, ui32Read;
      tUSBBufferVars *psPrivate;
      //
      // Check parameter validity.
      //
      ASSERT(psBuffer && pui8Data && ui32Length);
  
      //
      // Create a writable pointer to the private data.
      //
      psPrivate = &((tUSBBuffer *)psBuffer)->sPrivateData;
  
      //
      // How much data is in the buffer?
      //
      ui32Avail = USBRingBufUsed(&psPrivate->sRingBuf);
  
      //
      // Determine how many bytes we can actually read.
      //
      ui32Read = (ui32Avail < ui32Length) ? ui32Avail : ui32Length;
  
      //
      // Read the data from the buffer assuming there is some to read.
      //
      if(ui32Read)
      {
          USBRingBufRead(&psPrivate->sRingBuf, pui8Data, ui32Read);
      }
  
      //
      // Tell the caller how many bytes we wrote to their buffer.
      //
      return(ui32Read);
  }
  
  //*****************************************************************************
  //
  //! 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.
  //
  //*****************************************************************************
  uint32_t
  USBBufferDataAvailable(const tUSBBuffer *psBuffer)
  {
      tUSBBufferVars *psPrivate;
  
      //
      // Check parameter validity.
      //
      ASSERT(psBuffer);
  
      //
      // Create a writable pointer to the private data.
      //
      psPrivate = &((tUSBBuffer *)psBuffer)->sPrivateData;
  
      //
      // Return the amount of data in the buffer.
      //
      return(USBRingBufUsed(&psPrivate->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.
  //
  //*****************************************************************************
  uint32_t
  USBBufferSpaceAvailable(const tUSBBuffer *psBuffer)
  {
      tUSBBufferVars *psPrivate;
  
      //
      // Check parameter validity.
      //
      ASSERT(psBuffer);
  
      //
      // Create a writable pointer to the private data.
      //
      psPrivate = &((tUSBBuffer *)psBuffer)->sPrivateData;
  
      //
      // Return the amount of space available in the buffer.
      //
      return(USBRingBufFree(&psPrivate->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 ui32Event is the identifier of the event being sent.  This will be
  //! a general event identifier of the form \b USBD_EVENT_xxxx or a device
  //! class-dependent event of the form \b USBD_CDC_EVENT_xxx or
  //! \b USBD_HID_EVENT_xxx.
  //! \param ui32MsgValue 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.
  //
  //*****************************************************************************
  uint32_t
  USBBufferEventCallback(void *pvCBData, uint32_t ui32Event,
                         uint32_t ui32MsgValue, 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(ui32Event)
      {
          //
          // 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, ui32MsgValue, 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, ui32MsgValue);
              }
              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, ui32MsgValue, 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, ui32Event, ui32MsgValue,
                                   pvMsgData));
  }
  
  //*****************************************************************************
  //
  // Close the Doxygen group.
  //! @}
  //
  //*****************************************************************************
  