897 lines
31 KiB
C
897 lines
31 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, uint8_t *dat, uint8_t fifoNum);
|
|
static void USB_WriteFIFO_Generic(uint8_t numBytes, uint8_t *dat);
|
|
|
|
#endif // #ifdef SI_GPTR
|
|
|
|
// -----------------------------------------------------------------------------
|
|
// 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, uint8_t *dat)
|
|
{
|
|
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, uint8_t *dat)
|
|
{
|
|
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.
|
|
******************************************************************************/
|
|
void handleUsbOut3Int(void)
|
|
{
|
|
#if (SLAB_USB_EP3OUT_TRANSFER_TYPE == USB_EPTYPE_ISOC)
|
|
uint16_t nextIdx;
|
|
#if (SLAB_USB_EP3OUT_MAX_PACKET_SIZE > 255)
|
|
uint16_t count;
|
|
#else
|
|
uint8_t count;
|
|
#endif // ( SLAB_USB_EP3OUT_MAX_PACKET_SIZE > 255 )
|
|
#else
|
|
uint8_t count;
|
|
#endif // ( SLAB_USB_EP3OUT_TRANSFER_TYPE == USB_EPTYPE_ISOC )
|
|
|
|
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;
|
|
}
|
|
#if ((SLAB_USB_EP3OUT_TRANSFER_TYPE == USB_EPTYPE_BULK) || (SLAB_USB_EP3OUT_TRANSFER_TYPE == USB_EPTYPE_INTR))
|
|
// 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;
|
|
}
|
|
#endif
|
|
else
|
|
{
|
|
#if ((SLAB_USB_EP3OUT_TRANSFER_TYPE == USB_EPTYPE_BULK) || (SLAB_USB_EP3OUT_TRANSFER_TYPE == USB_EPTYPE_INTR))
|
|
USB_ReadFIFO(3, count, myUsbDevice.ep3out.buf);
|
|
|
|
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;
|
|
}
|
|
#elif (SLAB_USB_EP3OUT_TRANSFER_TYPE == USB_EPTYPE_ISOC)
|
|
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;
|
|
}
|
|
#endif // ( ( SLAB_USB_EP3OUT_TRANSFER_TYPE == USB_EPTYPE_BULK ) || ( SLAB_USB_EP3OUT_TRANSFER_TYPE == USB_EPTYPE_INTR ) )
|
|
|
|
myUsbDevice.ep3out.misc.bits.outPacketPending = false;
|
|
status = USB_STATUS_OK;
|
|
USB_EpnClearOutPacketReady();
|
|
}
|
|
if (myUsbDevice.ep3out.misc.bits.callback == true)
|
|
{
|
|
if (xferComplete == true)
|
|
{
|
|
myUsbDevice.ep3out.misc.bits.callback = false;
|
|
}
|
|
|
|
#if ((SLAB_USB_EP3OUT_TRANSFER_TYPE == USB_EPTYPE_BULK) || (SLAB_USB_EP3OUT_TRANSFER_TYPE == USB_EPTYPE_INTR))
|
|
USBD_XferCompleteCb(EP3OUT, status, count, myUsbDevice.ep3out.remaining);
|
|
#elif (SLAB_USB_EP3OUT_TRANSFER_TYPE == USB_EPTYPE_ISOC)
|
|
|
|
// 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
|
|
USBD_XferCompleteCb(EP3OUT, status, count, myUsbDevice.ep3outIsoIdx);
|
|
#endif
|
|
}
|
|
}
|
|
}
|
|
#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, uint8_t *dat)
|
|
{
|
|
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, 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, 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, uint8_t *dat, 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, 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, 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, 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, uint8_t *dat, 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, uint8_t *dat)
|
|
{
|
|
while (numBytes--)
|
|
{
|
|
USB_SetFIFOByte(*dat);
|
|
dat++;
|
|
}
|
|
}
|
|
|
|
#endif // #ifdef SI_GPTR
|