solo/efm8/lib/c8051f380/efm8_usb/src/efm8_usbdep.c
2018-07-04 12:48:18 -04:00

1029 lines
35 KiB
C

/**************************************************************************//**
* Copyright (c) 2015 by Silicon Laboratories Inc. All rights reserved.
*
* http://developer.silabs.com/legal/version/v11/Silicon_Labs_Software_License_Agreement.txt
*****************************************************************************/
#include "si_toolchain.h"
#include "efm8_usb.h"
#include <stdint.h>
#include <endian.h>
extern SI_SEGMENT_VARIABLE(myUsbDevice, USBD_Device_TypeDef, MEM_MODEL_SEG);
// -----------------------------------------------------------------------------
// Function Prototypes
// -------------------------------
// Memory-specific FIFO access functions
#ifdef SI_GPTR
static void USB_ReadFIFO_Idata(uint8_t numBytes, SI_VARIABLE_SEGMENT_POINTER(dat, uint8_t, SI_SEG_IDATA), uint8_t fifoNum);
static void USB_WriteFIFO_Idata(uint8_t numBytes, SI_VARIABLE_SEGMENT_POINTER(dat, uint8_t, SI_SEG_IDATA));
static void USB_ReadFIFO_Xdata(uint8_t numBytes, SI_VARIABLE_SEGMENT_POINTER(dat, uint8_t, SI_SEG_XDATA), uint8_t fifoNum);
static void USB_WriteFIFO_Xdata(uint8_t numBytes, SI_VARIABLE_SEGMENT_POINTER(dat, uint8_t, SI_SEG_XDATA));
#if SI_GPTR_MTYPE_PDATA != SI_GPTR_MTYPE_XDATA
static void USB_ReadFIFO_Pdata(uint8_t numBytes, SI_VARIABLE_SEGMENT_POINTER(dat, uint8_t, SI_SEG_PDATA), uint8_t fifoNum);
static void USB_WriteFIFO_Pdata(uint8_t numBytes, SI_VARIABLE_SEGMENT_POINTER(dat, uint8_t, SI_SEG_PDATA));
#endif
#if SI_GPTR_MTYPE_DATA != SI_GPTR_MTYPE_IDATA
static void USB_ReadFIFO_Data(uint8_t numBytes, SI_VARIABLE_SEGMENT_POINTER(dat, uint8_t, SI_SEG_DATA), uint8_t fifoNum);
static void USB_WriteFIFO_Data(uint8_t numBytes, uint8_t SI_VARIABLE_SEGMENT_POINTER(dat, uint8_t, SI_SEG_DATA));
#endif
static void USB_WriteFIFO_Code(uint8_t numBytes, SI_VARIABLE_SEGMENT_POINTER(dat, uint8_t, SI_SEG_CODE));
#else
// -------------------------------
// Generic FIFO access functions
static void USB_ReadFIFO_Generic(uint8_t numBytes, SI_VARIABLE_SEGMENT_POINTER(dat, uint8_t, SI_SEG_GENERIC), uint8_t fifoNum);
static void USB_WriteFIFO_Generic(uint8_t numBytes, SI_VARIABLE_SEGMENT_POINTER(dat, uint8_t, SI_SEG_GENERIC));
#endif // #ifdef SI_GPTR
#if (SLAB_USB_EP3OUT_USED && (SLAB_USB_EP3OUT_TRANSFER_TYPE == USB_EPTYPE_ISOC))
static void memclearXdata(SI_VARIABLE_SEGMENT_POINTER(s, uint8_t, SI_SEG_XDATA),
uint16_t n);
#endif
// -----------------------------------------------------------------------------
// Functions
/***************************************************************************//**
* @brief Reads Isochronous data from the Endpoint FIFO
* @param fifoNum
* USB Endpoint FIFO to read
* @param numBytes
* Number of bytes to read from the FIFO
* @param dat
* Pointer to buffer to hold data read from the FIFO
******************************************************************************/
#if (SLAB_USB_EP3OUT_USED && (SLAB_USB_EP3OUT_TRANSFER_TYPE == USB_EPTYPE_ISOC) && (SLAB_USB_EP3OUT_MAX_PACKET_SIZE > 255))
// ----------------------------------------------------------------------------
// If Isochronous mode is enabled and the max packet size is greater than 255,
// break the FIFO reads up into multiple reads of 255 or less bytes.
// ----------------------------------------------------------------------------
void USB_ReadFIFOIso(uint8_t fifoNum, uint16_t numBytes, SI_VARIABLE_SEGMENT_POINTER(dat, uint8_t, SI_SEG_GENERIC))
{
uint8_t numBytesRead;
// USB_ReadFIFO() accepts a maximum of 255 bytes. If the number of bytes to
// send is greated than 255, call USB_ReadFIFO() multiple times.
while (numBytes > 0)
{
numBytesRead = (numBytes > 255) ? 255 : numBytes;
USB_ReadFIFO(fifoNum, numBytesRead, dat);
numBytes -= numBytesRead;
dat += numBytesRead;
}
}
#else
#define USB_ReadFIFOIso(a, b, c) USB_ReadFIFO(a, b, c)
#endif
/***************************************************************************//**
* @brief Writes Isochronous data to the Endpoint FIFO
* @param fifoNum
* USB Endpoint FIFO to write
* @param numBytes
* Number of bytes to write to the FIFO
* @param dat
* Pointer to buffer hoding data to write to the FIFO
******************************************************************************/
#if (SLAB_USB_EP3IN_USED && (SLAB_USB_EP3IN_TRANSFER_TYPE == USB_EPTYPE_ISOC) && (SLAB_USB_EP3IN_MAX_PACKET_SIZE > 255))
// ----------------------------------------------------------------------------
// If Isochronous mode is enabled and the max packet size is greater than 255,
// break the FIFO writes up into multiple writes of 255 or less bytes.
// ----------------------------------------------------------------------------
void USB_WriteFIFOIso(uint8_t fifoNum, uint16_t numBytes, SI_VARIABLE_SEGMENT_POINTER(dat, uint8_t, SI_SEG_GENERIC))
{
uint8_t numBytesWrite;
// USB_WriteFIFO() accepts a maximum of 255 bytes. If the number of bytes to
// send is greated than 255, call USB_WriteFIFO() multiple times.
while (numBytes > 0)
{
numBytesWrite = (numBytes > 255) ? 255 : numBytes;
numBytes -= numBytesWrite;
USB_WriteFIFO(fifoNum, numBytesWrite, dat, (numBytes == 0));
dat += numBytesWrite;
}
}
#else
#define USB_WriteFIFOIso(a, b, c) USB_WriteFIFO(a, b, c, true)
#endif
#if SLAB_USB_EP1IN_USED
/***************************************************************************//**
* @brief Handle Endpoint 1 IN transfer interrupt
* @note This function takes no parameters, but it uses the EP1IN status
* variables stored in @ref myUsbDevice.ep1in.
******************************************************************************/
void handleUsbIn1Int(void)
{
uint8_t xferred;
bool callback;
USB_SetIndex(1);
if (USB_EpnInGetSentStall())
{
USB_EpnInClearSentStall();
}
else if (myUsbDevice.ep1in.state == D_EP_TRANSMITTING)
{
xferred = (myUsbDevice.ep1in.remaining > SLAB_USB_EP1IN_MAX_PACKET_SIZE)
? SLAB_USB_EP1IN_MAX_PACKET_SIZE : myUsbDevice.ep1in.remaining;
myUsbDevice.ep1in.remaining -= xferred;
myUsbDevice.ep1in.buf += xferred;
callback = myUsbDevice.ep1in.misc.bits.callback;
// Load more data
if (myUsbDevice.ep1in.remaining > 0)
{
USB_WriteFIFO(1,
(myUsbDevice.ep1in.remaining > SLAB_USB_EP1IN_MAX_PACKET_SIZE)
? SLAB_USB_EP1IN_MAX_PACKET_SIZE
: myUsbDevice.ep1in.remaining,
myUsbDevice.ep1in.buf,
true);
}
else
{
myUsbDevice.ep1in.misc.bits.callback = false;
myUsbDevice.ep1in.state = D_EP_IDLE;
}
if (callback == true)
{
USBD_XferCompleteCb(EP1IN, USB_STATUS_OK, xferred, myUsbDevice.ep1in.remaining);
}
}
}
#endif // SLAB_USB_EP1IN_USED
#if SLAB_USB_EP2IN_USED
/***************************************************************************//**
* @brief Handle Endpoint 2 IN transfer interrupt
* @note This function takes no parameters, but it uses the EP2IN status
* variables stored in @ref myUsbDevice.ep2in.
******************************************************************************/
void handleUsbIn2Int(void)
{
uint8_t xferred;
bool callback;
USB_SetIndex(2);
if (USB_EpnInGetSentStall())
{
USB_EpnInClearSentStall();
}
else if (myUsbDevice.ep2in.state == D_EP_TRANSMITTING)
{
xferred = (myUsbDevice.ep2in.remaining > SLAB_USB_EP2IN_MAX_PACKET_SIZE)
? SLAB_USB_EP2IN_MAX_PACKET_SIZE : myUsbDevice.ep2in.remaining;
myUsbDevice.ep2in.remaining -= xferred;
myUsbDevice.ep2in.buf += xferred;
callback = myUsbDevice.ep2in.misc.bits.callback;
// Load more data
if (myUsbDevice.ep2in.remaining > 0)
{
USB_WriteFIFO(2,
(myUsbDevice.ep2in.remaining > SLAB_USB_EP2IN_MAX_PACKET_SIZE)
? SLAB_USB_EP2IN_MAX_PACKET_SIZE
: myUsbDevice.ep2in.remaining,
myUsbDevice.ep2in.buf,
true);
}
else
{
myUsbDevice.ep2in.misc.bits.callback = false;
myUsbDevice.ep2in.state = D_EP_IDLE;
}
if (callback == true)
{
USBD_XferCompleteCb(EP2IN, USB_STATUS_OK, xferred, myUsbDevice.ep2in.remaining);
}
}
}
#endif // SLAB_USB_EP2IN_USED
#if SLAB_USB_EP3IN_USED
/***************************************************************************//**
* @brief Handle Endpoint 3 IN transfer interrupt
* @details Endpoint 3 IN is the only IN endpoint that supports isochronous
* transfers.
* @note This function takes no parameters, but it uses the EP3IN status
* variables stored in @ref myUsbDevice.ep3in.
******************************************************************************/
void handleUsbIn3Int(void)
{
#if SLAB_USB_EP3IN_TRANSFER_TYPE == USB_EPTYPE_ISOC
uint16_t xferred, nextIdx;
#else
uint8_t xferred;
bool callback;
#endif
USB_SetIndex(3);
if (USB_EpnInGetSentStall())
{
USB_EpnInClearSentStall();
}
else if (myUsbDevice.ep3in.state == D_EP_TRANSMITTING)
{
#if ((SLAB_USB_EP3IN_TRANSFER_TYPE == USB_EPTYPE_BULK) || (SLAB_USB_EP3IN_TRANSFER_TYPE == USB_EPTYPE_INTR))
xferred = (myUsbDevice.ep3in.remaining > SLAB_USB_EP3IN_MAX_PACKET_SIZE)
? SLAB_USB_EP3IN_MAX_PACKET_SIZE : myUsbDevice.ep3in.remaining;
myUsbDevice.ep3in.remaining -= xferred;
myUsbDevice.ep3in.buf += xferred;
#endif
#if ((SLAB_USB_EP3IN_TRANSFER_TYPE == USB_EPTYPE_BULK) || (SLAB_USB_EP3IN_TRANSFER_TYPE == USB_EPTYPE_INTR))
callback = myUsbDevice.ep3in.misc.bits.callback;
#elif (SLAB_USB_EP3IN_TRANSFER_TYPE == USB_EPTYPE_ISOC)
if (myUsbDevice.ep3in.misc.bits.callback == true)
{
// In Isochronous mode, the meaning of the USBD_XferCompleteCb parameters changes:
// xferred is ignored
// remaining is the current index into the circular buffer
// the return value is the number of bytes to transmit in the next packet
xferred = USBD_XferCompleteCb(EP3IN, USB_STATUS_OK, 0, myUsbDevice.ep3inIsoIdx);
if (xferred == 0)
{
myUsbDevice.ep3in.misc.bits.inPacketPending = true;
return;
}
}
#endif
// Load more data
#if ((SLAB_USB_EP3IN_TRANSFER_TYPE == USB_EPTYPE_BULK) || (SLAB_USB_EP3IN_TRANSFER_TYPE == USB_EPTYPE_INTR))
if (myUsbDevice.ep3in.remaining > 0)
{
USB_WriteFIFO(3,
(myUsbDevice.ep3in.remaining > SLAB_USB_EP3IN_MAX_PACKET_SIZE)
? SLAB_USB_EP3IN_MAX_PACKET_SIZE
: myUsbDevice.ep3in.remaining,
myUsbDevice.ep3in.buf,
true);
}
else
{
myUsbDevice.ep3in.misc.bits.callback = false;
myUsbDevice.ep3in.state = D_EP_IDLE;
}
if (callback == true)
{
USBD_XferCompleteCb(EP3IN, USB_STATUS_OK, xferred, myUsbDevice.ep3in.remaining);
}
#elif (SLAB_USB_EP3IN_TRANSFER_TYPE == USB_EPTYPE_ISOC)
nextIdx = xferred + myUsbDevice.ep3inIsoIdx;
myUsbDevice.ep3in.misc.bits.inPacketPending = false;
// Check if the next index is past the end of the circular buffer.
// If so, break the write up into two calls to USB_WriteFIFOIso()
if (nextIdx > myUsbDevice.ep3in.remaining)
{
USB_WriteFIFOIso(3, myUsbDevice.ep3in.remaining - myUsbDevice.ep3inIsoIdx, &myUsbDevice.ep3in.buf[myUsbDevice.ep3inIsoIdx]);
myUsbDevice.ep3inIsoIdx = nextIdx - myUsbDevice.ep3in.remaining;
USB_WriteFIFOIso(3, myUsbDevice.ep3inIsoIdx, myUsbDevice.ep3in.buf);
}
else
{
USB_WriteFIFOIso(3, xferred, &myUsbDevice.ep3in.buf[myUsbDevice.ep3inIsoIdx]);
myUsbDevice.ep3inIsoIdx = nextIdx;
}
#endif // ( ( SLAB_USB_EP3IN_TRANSFER_TYPE == USB_EPTYPE_BULK ) || ( SLAB_USB_EP3IN_TRANSFER_TYPE == USB_EPTYPE_INTR ) )
}
}
#endif // SLAB_USB_EP3IN_USED
#if SLAB_USB_EP1OUT_USED
/***************************************************************************//**
* @brief Handle Endpoint 1 OUT transfer interrupt
* @note This function takes no parameters, but it uses the EP1OUT status
* variables stored in @ref myUsbDevice.ep1out.
******************************************************************************/
void handleUsbOut1Int(void)
{
uint8_t count;
USB_Status_TypeDef status;
bool xferComplete = false;
USB_SetIndex(1);
if (USB_EpnOutGetSentStall())
{
USB_EpnOutClearSentStall();
}
else if (USB_EpnGetOutPacketReady())
{
count = USB_EpOutGetCount();
// If USBD_Read() has not been called, return an error
if (myUsbDevice.ep1out.state != D_EP_RECEIVING)
{
myUsbDevice.ep1out.misc.bits.outPacketPending = true;
status = USB_STATUS_EP_ERROR;
}
// Check for overrun of user buffer
else if (myUsbDevice.ep1out.remaining < count)
{
myUsbDevice.ep1out.state = D_EP_IDLE;
myUsbDevice.ep1out.misc.bits.outPacketPending = true;
status = USB_STATUS_EP_RX_BUFFER_OVERRUN;
}
else
{
USB_ReadFIFO(1, count, myUsbDevice.ep1out.buf);
myUsbDevice.ep1out.misc.bits.outPacketPending = false;
myUsbDevice.ep1out.remaining -= count;
myUsbDevice.ep1out.buf += count;
if ((myUsbDevice.ep1out.remaining == 0) || (count != SLAB_USB_EP1OUT_MAX_PACKET_SIZE))
{
myUsbDevice.ep1out.state = D_EP_IDLE;
xferComplete = true;
}
status = USB_STATUS_OK;
USB_EpnClearOutPacketReady();
}
if (myUsbDevice.ep1out.misc.bits.callback == true)
{
if (xferComplete == true)
{
myUsbDevice.ep1out.misc.bits.callback = false;
}
USBD_XferCompleteCb(EP1OUT, status, count, myUsbDevice.ep1out.remaining);
}
}
}
#endif // EP1OUT_USED
#if SLAB_USB_EP2OUT_USED
/***************************************************************************//**
* @brief Handle Endpoint 2 OUT transfer interrupt
* @note This function takes no parameters, but it uses the EP2OUT status
* variables stored in @ref myUsbDevice.ep2out.
******************************************************************************/
void handleUsbOut2Int(void)
{
uint8_t count;
USB_Status_TypeDef status;
bool xferComplete = false;
USB_SetIndex(2);
if (USB_EpnOutGetSentStall())
{
USB_EpnOutClearSentStall();
}
else if (USB_EpnGetOutPacketReady())
{
count = USB_EpOutGetCount();
// If USBD_Read() has not been called, return an error
if (myUsbDevice.ep2out.state != D_EP_RECEIVING)
{
myUsbDevice.ep2out.misc.bits.outPacketPending = true;
status = USB_STATUS_EP_ERROR;
}
// Check for overrun of user buffer
else if (myUsbDevice.ep2out.remaining < count)
{
myUsbDevice.ep2out.state = D_EP_IDLE;
myUsbDevice.ep2out.misc.bits.outPacketPending = true;
status = USB_STATUS_EP_RX_BUFFER_OVERRUN;
}
else
{
USB_ReadFIFO(2, count, myUsbDevice.ep2out.buf);
myUsbDevice.ep2out.misc.bits.outPacketPending = false;
myUsbDevice.ep2out.remaining -= count;
myUsbDevice.ep2out.buf += count;
if ((myUsbDevice.ep2out.remaining == 0) || (count != SLAB_USB_EP2OUT_MAX_PACKET_SIZE))
{
myUsbDevice.ep2out.state = D_EP_IDLE;
xferComplete = true;
}
status = USB_STATUS_OK;
USB_EpnClearOutPacketReady();
}
if (myUsbDevice.ep2out.misc.bits.callback == true)
{
if (xferComplete == true)
{
myUsbDevice.ep2out.misc.bits.callback = false;
}
USBD_XferCompleteCb(EP2OUT, status, count, myUsbDevice.ep2out.remaining);
}
}
}
#endif // EP2OUT_USED
#if SLAB_USB_EP3OUT_USED
/***************************************************************************//**
* @brief Handle Endpoint 3 OUT transfer interrupt
* @details Endpoint 3 OUT is the only OUT endpoint that supports
* isochronous transfers.
* @note This function takes no parameters, but it uses the EP3OUT status
* variables stored in @ref myUsbDevice.ep3out.
******************************************************************************/
#if ((SLAB_USB_EP3OUT_TRANSFER_TYPE == USB_EPTYPE_BULK) || (SLAB_USB_EP3OUT_TRANSFER_TYPE == USB_EPTYPE_INTR))
void handleUsbOut3Int(void)
{
uint8_t count;
USB_Status_TypeDef status;
bool xferComplete = false;
USB_SetIndex(3);
if (USB_EpnOutGetSentStall())
{
USB_EpnOutClearSentStall();
}
else if (USB_EpnGetOutPacketReady())
{
count = USB_EpOutGetCount();
// If USBD_Read() has not been called, return an error
if (myUsbDevice.ep3out.state != D_EP_RECEIVING)
{
myUsbDevice.ep3out.misc.bits.outPacketPending = true;
status = USB_STATUS_EP_ERROR;
}
// Check for overrun of user buffer
else if (myUsbDevice.ep3out.remaining < count)
{
myUsbDevice.ep3out.state = D_EP_IDLE;
myUsbDevice.ep3out.misc.bits.outPacketPending = true;
status = USB_STATUS_EP_RX_BUFFER_OVERRUN;
}
else
{
USB_ReadFIFO(3, count, myUsbDevice.ep3out.buf);
myUsbDevice.ep3out.misc.bits.outPacketPending = false;
myUsbDevice.ep3out.remaining -= count;
myUsbDevice.ep3out.buf += count;
if ((myUsbDevice.ep3out.remaining == 0) || (count != SLAB_USB_EP3OUT_MAX_PACKET_SIZE))
{
myUsbDevice.ep3out.state = D_EP_IDLE;
xferComplete = true;
}
status = USB_STATUS_OK;
USB_EpnClearOutPacketReady();
}
if (myUsbDevice.ep3out.misc.bits.callback == true)
{
if (xferComplete == true)
{
myUsbDevice.ep3out.misc.bits.callback = false;
}
USBD_XferCompleteCb(EP3OUT, status, count, myUsbDevice.ep3out.remaining);
}
}
}
#elif (SLAB_USB_EP3OUT_TRANSFER_TYPE == USB_EPTYPE_ISOC)
void handleUsbOut3Int(void)
{
uint16_t nextIdx;
uint16_t numZeroBytesFromCb;
#if (SLAB_USB_EP3OUT_MAX_PACKET_SIZE > 255)
uint16_t count;
#else
uint8_t count;
#endif
USB_Status_TypeDef status = USB_STATUS_OK;
bool xferComplete = false;
USB_SetIndex(3);
if (USB_EpnOutGetSentStall())
{
USB_EpnOutClearSentStall();
}
else if (USB_EpnGetOutPacketReady())
{
count = USB_EpOutGetCount();
// If USBD_Read() has not been called, return an error
if (myUsbDevice.ep3out.state != D_EP_RECEIVING)
{
myUsbDevice.ep3out.misc.bits.outPacketPending = true;
status = USB_STATUS_EP_ERROR;
}
else
{
// DATERR bit set (i.e. CRC/bit-stuffing error)
if (USB_EpnGetDataError()
#ifdef SLAB_USB_ISOC_OUT_MIN_PACKET_SIZE
|| (count < SLAB_USB_ISOC_OUT_MIN_PACKET_SIZE)
#endif
#ifdef SLAB_USB_ISOC_OUT_MAX_PACKET_SIZE
|| (count > SLAB_USB_ISOC_OUT_MAX_PACKET_SIZE)
#endif
)
{
status = USB_STATUS_DATA_ERROR;
}
#ifdef SLAB_USB_ISOC_OUT_PACKETSIZE_MOD2
if ((count % 2) != 0)
{
status = USB_STATUS_DATA_ERROR;
}
#elif defined SLAB_USB_ISOC_OUT_PACKETSIZE_MOD4
if (( count % 4) != 0)
{
status = USB_STATUS_DATA_ERROR;
}
#elif defined SLAB_USB_ISOC_OUT_PACKETSIZE_MOD6
if (count % 6) != 0)
{
status = USB_STATUS_DATA_ERROR;
}
#endif
if (status == USB_STATUS_DATA_ERROR)
{
count = 0;
// Flush FIFO to get rid of bad packet
USB_EpnOutFlush();
myUsbDevice.ep3out.misc.bits.outPacketPending = false;
// Flush clears OPRDY, so no need to call USB_EpnClearOutPacketReady() now
}
else // No data error
{
nextIdx = count + myUsbDevice.ep3outIsoIdx;
// In isochronous mode, a circular buffer is used to hold the data
// If the next index into the circular buffer passes the end of the
// buffer, make two calls to USB_ReadFIFOIso()
if (nextIdx > myUsbDevice.ep3out.remaining)
{
USB_ReadFIFOIso(3, myUsbDevice.ep3out.remaining - myUsbDevice.ep3outIsoIdx, &myUsbDevice.ep3out.buf[myUsbDevice.ep3outIsoIdx]);
myUsbDevice.ep3outIsoIdx = nextIdx - myUsbDevice.ep3out.remaining;
USB_ReadFIFOIso(3, myUsbDevice.ep3outIsoIdx, myUsbDevice.ep3out.buf);
}
else
{
USB_ReadFIFOIso(3, count, &myUsbDevice.ep3out.buf[myUsbDevice.ep3outIsoIdx]);
myUsbDevice.ep3outIsoIdx = nextIdx;
}
myUsbDevice.ep3out.misc.bits.outPacketPending = false;
USB_EpnClearOutPacketReady();
}
}
if (myUsbDevice.ep3out.misc.bits.callback == true)
{
if (xferComplete == true)
{
myUsbDevice.ep3out.misc.bits.callback = false;
}
// In Isochronous mode, the meaning of the USBD_XferCompleteCb parameters changes:
// xferred is the number of bytes received in the last packet
// remaining is the current index into the circular buffer
numZeroBytesFromCb = USBD_XferCompleteCb(EP3OUT, status, count, myUsbDevice.ep3outIsoIdx);
// If data error occurred, the callback return value specifies how many zero-valued bytes to queue
if (numZeroBytesFromCb && (status == USB_STATUS_DATA_ERROR))
{
uint16_t numZeroBytesToWrite;
SI_SEGMENT_VARIABLE_SEGMENT_POINTER(bufPtr,
uint8_t,
SI_SEG_XDATA,
SI_SEG_DATA);
// Clear status after calling USBD_XferCompleteCb()
status = USB_STATUS_OK;
// Add the specified number of zero-value bytes
nextIdx = numZeroBytesFromCb + myUsbDevice.ep3outIsoIdx;
// Next index is past the end of the buffer (requires two writes)
if (nextIdx > myUsbDevice.ep3out.remaining)
{
// Write up to the end of the buffer
numZeroBytesToWrite = myUsbDevice.ep3out.remaining - myUsbDevice.ep3outIsoIdx;
bufPtr = &myUsbDevice.ep3out.buf[myUsbDevice.ep3outIsoIdx];
memclearXdata(bufPtr, numZeroBytesToWrite);
// Write the rest, starting at beginning of buffer
myUsbDevice.ep3outIsoIdx = nextIdx - myUsbDevice.ep3out.remaining;
numZeroBytesToWrite = myUsbDevice.ep3outIsoIdx;
bufPtr = &myUsbDevice.ep3out.buf[0];
memclearXdata(bufPtr, numZeroBytesToWrite);
}
// Next index is not past the end of the buffer
else
{
bufPtr = &myUsbDevice.ep3out.buf[myUsbDevice.ep3outIsoIdx];
memclearXdata(bufPtr, numZeroBytesFromCb);
myUsbDevice.ep3outIsoIdx = nextIdx;
}
}
}
}
}
/***************************************************************************//**
* @brief Sets all elements in a contiguous array of XDATA to zero
* @param s
* Pointer to the block of memory to fill
* @param n
* Number of bytes to be set to the value
******************************************************************************/
static void memclearXdata(SI_VARIABLE_SEGMENT_POINTER(s, uint8_t, SI_SEG_XDATA),
uint16_t n)
{
while (n)
{
*s++ = 0;
n--;
}
}
#endif // #if ((SLAB_USB_EP3OUT_TRANSFER_TYPE == USB_EPTYPE_BULK) || (SLAB_USB_EP3OUT_TRANSFER_TYPE == USB_EPTYPE_INTR))
#endif // EP3OUT_USED
/***************************************************************************//**
* @brief Reads data from the USB FIFO
* @param fifoNum
* USB Endpoint FIFO to read
* @param numBytes
* Number of bytes to read from the FIFO
* @param dat
* Pointer to buffer to hold data read from the FIFO
******************************************************************************/
void USB_ReadFIFO(uint8_t fifoNum, uint8_t numBytes, SI_VARIABLE_SEGMENT_POINTER(dat, uint8_t, SI_SEG_GENERIC))
{
if (numBytes > 0)
{
USB_EnableReadFIFO(fifoNum);
// Convert generic pointer to memory-specific pointer and call the
// the corresponding memory-specific function, if possible.
// The memory-specific functions are much faster than the generic functions.
#ifdef SI_GPTR
switch (((SI_GEN_PTR_t *)&dat)->gptr.memtype)
{
case SI_GPTR_MTYPE_IDATA:
USB_ReadFIFO_Idata(numBytes, (SI_VARIABLE_SEGMENT_POINTER(, uint8_t, SI_SEG_IDATA))dat, fifoNum);
break;
// For some compilers, IDATA and DATA are treated the same.
// Only call the USB_ReadFIFO_Data() if the compiler differentiates
// between DATA and IDATA.
#if (SI_GPTR_MTYPE_DATA != SI_GPTR_MTYPE_IDATA)
case SI_GPTR_MTYPE_DATA:
USB_ReadFIFO_Data(numBytes, dat, fifoNum);
break;
#endif
case SI_GPTR_MTYPE_XDATA:
USB_ReadFIFO_Xdata(numBytes, (SI_VARIABLE_SEGMENT_POINTER(, uint8_t, SI_SEG_XDATA))dat, fifoNum);
break;
// For some compilers, XDATA and PDATA are treated the same.
// Only call the USB_ReadFIFO_Pdata() if the compiler differentiates
// between XDATA and PDATA.
#if (SI_GPTR_MTYPE_PDATA != SI_GPTR_MTYPE_XDATA)
case SI_GPTR_MTYPE_PDATA:
USB_ReadFIFO_Pdata(numBytes, dat, fifoNum);
break;
#endif
default:
break;
}
#else
USB_ReadFIFO_Generic(numBytes, dat, fifoNum);
#endif // #ifdef SI_GPTR
USB_DisableReadFIFO(fifoNum);
}
}
/***************************************************************************//**
* @brief Writes data to the USB FIFO
* @param fifoNum
* USB Endpoint FIFO to write
* @param numBytes
* Number of bytes to write to the FIFO
* @param dat
* Pointer to buffer hoding data to write to the FIFO
* @param txPacket
* If TRUE, the packet will be sent immediately after loading the
* FIFO
* If FALSE, the packet will be stored in the FIFO and the
* transmission must be started at a later time
******************************************************************************/
void USB_WriteFIFO(uint8_t fifoNum, uint8_t numBytes, SI_VARIABLE_SEGMENT_POINTER(dat, uint8_t, SI_SEG_GENERIC), bool txPacket)
{
USB_EnableWriteFIFO(fifoNum);
// Convert generic pointer to memory-specific pointer and call the
// the corresponding memory-specific function, if possible.
// The memory-specific functions are much faster than the generic functions.
#ifdef SI_GPTR
switch (((SI_GEN_PTR_t *)&dat)->gptr.memtype)
{
case SI_GPTR_MTYPE_IDATA:
USB_WriteFIFO_Idata(numBytes, (SI_VARIABLE_SEGMENT_POINTER(, uint8_t, SI_SEG_IDATA))dat);
break;
// For some compilers, IDATA and DATA are treated the same.
// Only call the USB_WriteFIFO_Data() if the compiler differentiates between
// DATA and IDATA.
#if (SI_GPTR_MTYPE_DATA != SI_GPTR_MTYPE_IDATA)
case SI_GPTR_MTYPE_DATA:
USB_WriteFIFO_Data(numBytes, dat);
break;
#endif
case SI_GPTR_MTYPE_XDATA:
USB_WriteFIFO_Xdata(numBytes, (SI_VARIABLE_SEGMENT_POINTER(, uint8_t, SI_SEG_XDATA))dat);
break;
// For some compilers, XDATA and PDATA are treated the same.
// Only call the USB_WriteFIFO_Pdata() if the compiler differentiates
// between XDATA and PDATA.
#if (SI_GPTR_MTYPE_PDATA != SI_GPTR_MTYPE_XDATA)
case SI_GPTR_MTYPE_PDATA:
USB_WriteFIFO_Pdata(numBytes, dat);
break;
#endif
case SI_GPTR_MTYPE_CODE:
USB_WriteFIFO_Code(numBytes, (SI_VARIABLE_SEGMENT_POINTER(, uint8_t, SI_SEG_CODE))dat);
break;
default:
break;
}
#else
USB_WriteFIFO_Generic(numBytes, dat);
#endif // #ifdef SI_GPTR
USB_DisableWriteFIFO(fifoNum);
if ((txPacket == true) && (fifoNum > 0))
{
USB_SetIndex(fifoNum);
USB_EpnSetInPacketReady();
}
}
// -----------------------------------------------------------------------------
// Memory-Specific FIFO Access Functions
//
// Memory-specific functions are much faster (more than 2x) than generic
// generic functions, so we will use memory-specific functions if possible.
// -----------------------------------------------------------------------------
#ifdef SI_GPTR
/***************************************************************************//**
* @brief Reads data from the USB FIFO to a buffer in IRAM
* @param numBytes
* Number of bytes to read from the FIFO
* @param dat
* Pointer to IDATA buffer to hold data read from the FIFO
* @param fifoNum
* USB FIFO to read
******************************************************************************/
static void USB_ReadFIFO_Idata(uint8_t numBytes, SI_VARIABLE_SEGMENT_POINTER(dat, uint8_t, SI_SEG_IDATA), uint8_t fifoNum)
{
while (--numBytes)
{
USB_GetFIFOByte(dat);
dat++;
}
USB_GetLastFIFOByte(dat, fifoNum);
}
/***************************************************************************//**
* @brief Writes data held in IRAM to the USB FIFO
* @details The FIFO to write must be set before calling the function with
* @ref USB_EnableWriteFIFO().
* @param numBytes
* Number of bytes to write to the FIFO
* @param dat
* Pointer to IDATA buffer holding data to write to the FIFO
******************************************************************************/
static void USB_WriteFIFO_Idata(uint8_t numBytes, SI_VARIABLE_SEGMENT_POINTER(dat, uint8_t, SI_SEG_IDATA))
{
while (numBytes--)
{
USB_SetFIFOByte(*dat);
dat++;
}
}
/***************************************************************************//**
* @brief Reads data from the USB FIFO to a buffer in XRAM
* @param numBytes
* Number of bytes to read from the FIFO
* @param dat
* Pointer to XDATA buffer to hold data read from the FIFO
* @param fifoNum
* USB FIFO to read
******************************************************************************/
static void USB_ReadFIFO_Xdata(uint8_t numBytes, SI_VARIABLE_SEGMENT_POINTER(dat, uint8_t, SI_SEG_XDATA), uint8_t fifoNum)
{
while (--numBytes)
{
USB_GetFIFOByte(dat);
dat++;
}
USB_GetLastFIFOByte(dat, fifoNum);
}
/***************************************************************************//**
* @brief Writes data held in XRAM to the USB FIFO
* @details The FIFO to write must be set before calling the function with
* @ref USB_EnableWriteFIFO().
* @param numBytes
* Number of bytes to write to the FIFO
* @param dat
* Pointer to XDATA buffer holding data to write to the FIFO
******************************************************************************/
static void USB_WriteFIFO_Xdata(uint8_t numBytes, SI_VARIABLE_SEGMENT_POINTER(dat, uint8_t, SI_SEG_XDATA))
{
while (numBytes--)
{
USB_SetFIFOByte(*dat);
dat++;
}
}
#if SI_GPTR_MTYPE_PDATA != SI_GPTR_MTYPE_XDATA
/***************************************************************************//**
* @brief Reads data from the USB FIFO to a buffer in paged XRAM
* @param numBytes
* Number of bytes to read from the FIFO
* @param dat
* Pointer to PDATA buffer to hold data read from the FIFO
* @param fifoNum
* USB FIFO to read
******************************************************************************/
static void USB_ReadFIFO_Pdata(uint8_t numBytes, SI_VARIABLE_SEGMENT_POINTER(dat, uint8_t, SI_SEG_PDATA), uint8_t fifoNum)
{
while (--numBytes)
{
USB_GetFIFOByte(dat);
dat++;
}
USB_GetLastFIFOByte(dat, fifoNum);
}
/***************************************************************************//**
* @brief Writes data held in paged XRAM to the USB FIFO
* @details The FIFO to write must be set before calling the function with
* @ref USB_EnableWriteFIFO().
* @param numBytes
* Number of bytes to write to the FIFO
* @param dat
* Pointer to PDATA buffer holding data to write to the FIFO
******************************************************************************/
static void USB_WriteFIFO_Pdata(uint8_t numBytes, SI_VARIABLE_SEGMENT_POINTER(dat, uint8_t, SI_SEG_PDATA))
{
while (numBytes--)
{
USB_SetFIFOByte(*dat);
dat++;
}
}
#endif
#if SI_GPTR_MTYPE_DATA != SI_GPTR_MTYPE_IDATA
/***************************************************************************//**
* @brief Reads data from the USB FIFO to a buffer in DRAM
* @param numBytes
* Number of bytes to read from the FIFO
* @param dat
* Pointer to DATA buffer to hold data read from the FIFO
* @param fifoNum
* USB FIFO to read
******************************************************************************/
static void USB_ReadFIFO_Data(uint8_t numBytes, SI_VARIABLE_SEGMENT_POINTER(dat, uint8_t, SI_SEG_DATA), uint8_t fifoNum)
{
while (--numBytes)
{
USB_GetFIFOByte(dat);
dat++;
}
USB_GetLastFIFOByte(dat, fifoNum);
}
/***************************************************************************//**
* @brief Writes data held in DRAM to the USB FIFO
* @details The FIFO to write must be set before calling the function with
* @ref USB_EnableWriteFIFO().
* @param numBytes
* Number of bytes to write to the FIFO
* @param dat
* Pointer to DATA buffer to hold data read from the FIFO
******************************************************************************/
static void USB_WriteFIFO_Data(uint8_t numBytes, SI_VARIABLE_SEGMENT_POINTER(dat, uint8_t, SI_SEG_DATA))
{
while (numBytes--)
{
USB_SetFIFOByte(*dat);
dat++;
}
}
#endif
/***************************************************************************//**
* @brief Writes data held in code space to the USB FIFO
* @details The FIFO to write must be set before calling the function with
* @ref USB_EnableWriteFIFO().
* @param numBytes
* Number of bytes to write to the FIFO
* @param dat
* Pointer to CODE buffer holding data to write to the FIFO
******************************************************************************/
static void USB_WriteFIFO_Code(uint8_t numBytes, SI_VARIABLE_SEGMENT_POINTER(dat, uint8_t, SI_SEG_CODE))
{
while (numBytes--)
{
USB_SetFIFOByte(*dat);
dat++;
}
}
#else
/***************************************************************************//**
* @brief Reads data from the USB FIFO to a buffer in generic memory space
* @param numBytes
* Number of bytes to read from the FIFO
* @param dat
* Pointer to generic buffer to hold data read from the FIFO
* @param fifoNum
* USB FIFO to read
******************************************************************************/
static void USB_ReadFIFO_Generic(uint8_t numBytes, SI_VARIABLE_SEGMENT_POINTER(dat, uint8_t, SI_SEG_GENERIC), uint8_t fifoNum)
{
while (--numBytes)
{
USB_GetFIFOByte(dat);
dat++;
}
USB_GetLastFIFOByte(dat, fifoNum);
}
/***************************************************************************//**
* @brief Writes data held in generic memory space to the USB FIFO
* @details The FIFO to write must be set before calling the function with
* @ref USB_EnableWriteFIFO().
* @param numBytes
* Number of bytes to write to the FIFO
* @param dat
* Pointer to generic buffer holding data to write to the FIFO
******************************************************************************/
static void USB_WriteFIFO_Generic(uint8_t numBytes, SI_VARIABLE_SEGMENT_POINTER(dat, uint8_t, SI_SEG_GENERIC))
{
while (numBytes--)
{
USB_SetFIFOByte(*dat);
dat++;
}
}
#endif // #ifdef SI_GPTR