git-svn-id: svn://svn.code.sf.net/p/chibios/svn/trunk@4063 35acf78f-673a-0410-8e92-d51de3d6d3f4

This commit is contained in:
gdisirio 2012-03-31 06:41:19 +00:00
parent 7d89970371
commit f5ff03c303
2 changed files with 208 additions and 18 deletions

View File

@ -369,10 +369,12 @@ typedef struct {
#define GRXSTSP_DPID_MASK (3U<<15) /**< Data PID mask. */
#define GRXSTSP_DPID(n) ((n)<<15) /**< Data PID value. */
#define GRXSTSP_BCNT_MASK (0x7FF<<4) /**< Byte count mask. */
#define GRXSTSP_BCNT_OFF 4 /**< Byte count offset. */
#define GRXSTSP_BCNT(n) ((n)<<4) /**< Byte count value. */
#define GRXSTSP_CHNUM_MASK (15U<<0) /**< Channel number mask. */
#define GRXSTSP_CHNUM(n) ((n)<<0) /**< Channel number value. */
#define GRXSTSP_EPNUM_MASK (15U<<0) /**< Endpoint number mask. */
#define GRXSTSP_EPNUM_OFF 0 /**< Endpoint number offset. */
#define GRXSTSP_EPNUM(n) ((n)<<0) /**< Endpoint number value. */
/** @} */
@ -480,7 +482,7 @@ typedef struct {
#define HAINTMSK_HAINTM_MASK (0xFFFFU<<0)/**< Channel interrupt mask
mask. */
#define HAINTMSK_HAINTM(n) ((n)<<0) /**< Channel interrupt mask
value. */
value. */
/** @} */
/**
@ -644,13 +646,12 @@ typedef struct {
* @name DIEPMSK register bit definitions
* @{
*/
#define DIEPMSK_TXFEM (1U<<6) /**< Transmit FIFO empty mask. */
#define DIEPMSK_INEPNEM (1U<<6) /**< IN endpoint NAK effective
mask. */
#define DIEPMSK_INEPNMM (1U<<5) /**< IN Token received with
EP mismatch mask. */
#define DIEPMSK_ITTXFEMSK (1U<<4) /**< IN token received when
TxFIFO empty mask. */
#define DIEPMSK_TOM (1U<<3) /**< Timeout condition mask. */
#define DIEPMSK_TOCM (1U<<3) /**< Timeout condition mask. */
#define DIEPMSK_EPDM (1U<<1) /**< Endpoint disabled
interrupt mask. */
#define DIEPMSK_XFRCM (1U<<0) /**< Transfer completed
@ -662,7 +663,7 @@ typedef struct {
* @{
*/
#define DOEPMSK_OTEPDM (1U<<4) /**< OUT token received when
endpoint disabled mask. */
endpoint disabled mask. */
#define DOEPMSK_STUPM (1U<<3) /**< SETUP phase done mask. */
#define DOEPMSK_EPDM (1U<<1) /**< Endpoint disabled
interrupt mask. */
@ -759,7 +760,7 @@ typedef struct {
* @name DIEPINT register bit definitions
* @{
*/
#define DIEPINT_TXFE (1U<<7) /**< transmit FIFO empty. */
#define DIEPINT_TXFE (1U<<7) /**< Transmit FIFO empty. */
#define DIEPINT_INEPNE (1U<<6) /**< IN endpoint NAK effective. */
#define DIEPINT_ITTXFE (1U<<4) /**< IN Token received when
TxFIFO is empty. */

View File

@ -141,6 +141,8 @@ static void otg_disable_ep(void) {
* @brief Resets the packet memory allocator.
*
* @param[in] usbp pointer to the @p USBDriver object
*
* @notapi
*/
static void otg_pm_reset(USBDriver *usbp) {
@ -152,6 +154,8 @@ static void otg_pm_reset(USBDriver *usbp) {
*
* @param[in] usbp pointer to the @p USBDriver object
* @param[in] size size of the packet buffer to allocate
*
* @notapi
*/
static uint32_t otg_pm_alloc(USBDriver *usbp, size_t size) {
@ -161,6 +165,193 @@ static uint32_t otg_pm_alloc(USBDriver *usbp, size_t size) {
return 0;
}
/**
* @brief Writes to a TX FIFO.
*
* @param[in] ep endpoint number
* @param[in] buf buffer where to copy the endpoint data
* @param[in] n maximum number of bytes to copy
* @return the number of bytes that were effectively written
*
* @notapi
*/
static void otg_fifo_write(usbep_t ep, const uint8_t *buf, size_t n) {
volatile uint32_t *fifop;
fifop = OTG_FIFO(ep);
n = (n + 3) / 4;
while (n) {
uint32_t dw = (uint32_t)buf[0] |
((uint32_t)buf[1] << 8) |
((uint32_t)buf[2] << 16) |
((uint32_t)buf[3] << 24);
*fifop = dw;
n--;
buf += 4;
}
}
/**
* @brief Reads a packet from the RXFIFO.
*
* @param[out] buf buffer where to copy the endpoint data
* @param[in] n number of bytes to pull from the FIFO
* @param[in] max number of bytes to copy into the buffer
*
* @notapi
*/
static void otg_fifo_read(uint8_t *buf, size_t n, size_t max) {
volatile uint32_t *fifop;
fifop = OTG_FIFO(0);
n = (n + 3) / 4;
max = (max + 3) / 4;
while (n) {
uint32_t dw = *fifop;
if (max) {
*buf++ = (uint8_t)dw;
*buf++ = (uint8_t)(dw >> 8);
*buf++ = (uint8_t)(dw >> 16);
*buf++ = (uint8_t)(dw >> 24);
max--;
}
n--;
}
}
/**
* @brief Incoming packets handler.
*
* @param[in] usbp pointer to the @p USBDriver object
*
* @notapi
*/
static void otg_rxfifo_handler(USBDriver *usbp) {
uint32_t sts, cnt, ep;
sts = OTG->GRXSTSP;
switch (sts & GRXSTSP_PKTSTS_MASK) {
case GRXSTSP_SETUP_COMP:
break;
case GRXSTSP_SETUP_DATA:
cnt = (sts & GRXSTSP_BCNT_MASK) >> GRXSTSP_BCNT_OFF;
ep = (sts & GRXSTSP_EPNUM_MASK) >> GRXSTSP_EPNUM_OFF;
if (ep == 0)
otg_fifo_read(usbp->setup, cnt, 8);
else
otg_fifo_read(usbp->epc[ep]->out_state->rxbuf, cnt,
usbp->epc[ep]->out_state->rxsize);
usbp->epc[ep]->out_state->rxcnt = cnt;
break;
case GRXSTSP_OUT_DATA:
cnt = (sts & GRXSTSP_BCNT_MASK) >> GRXSTSP_BCNT_OFF;
ep = (sts & GRXSTSP_EPNUM_MASK) >> GRXSTSP_EPNUM_OFF;
otg_fifo_read(usbp->epc[ep]->out_state->rxbuf, cnt,
usbp->epc[ep]->out_state->rxsize -
usbp->epc[ep]->out_state->rxcnt);
usbp->epc[ep]->out_state->rxbuf += cnt;
usbp->epc[ep]->out_state->rxcnt += cnt;
break;
case GRXSTSP_OUT_GLOBAL_NAK:
case GRXSTSP_OUT_COMP:
default:
;
}
}
/**
* @brief Outgoing packets handler.
*
* @param[in] usbp pointer to the @p USBDriver object
* @param[in] ep endpoint number
*
* @notapi
*/
static void otg_txfifo_handler(USBDriver *usbp, usbep_t ep) {
uint32_t n;
if ((usbp->transmitting & (1 << ep))== 0) {
/* Nothing to transmit.*/
/* ????????????????????? */
OTG->DIEPEMPMSK &= ~DIEPEMPMSK_INEPTXFEM(ep);
return;
}
if (usbp->epc[ep]->in_state->txsize == 0) {
/* Special case, sending zero size packet.*/
OTG->ie[ep].DIEPTSIZ = DIEPTSIZ_PKTCNT(1) | DIEPTSIZ_XFRSIZ(0);
}
else if (usbp->epc[ep]->in_state->txcnt == 0) {
/* Transfer initialization.*/
uint32_t pcnt = (usbp->epc[ep]->in_state->txsize +
(usbp->epc[ep]->in_maxsize - 1) /
usbp->epc[ep]->in_maxsize);
OTG->ie[ep].DIEPTSIZ = DIEPTSIZ_PKTCNT(pcnt) |
DIEPTSIZ_XFRSIZ(usbp->epc[ep]->in_state->txsize);
}
n = usbp->epc[ep]->in_state->txsize - usbp->epc[ep]->in_state->txcnt;
if (n > usbp->epc[ep]->in_maxsize)
n = usbp->epc[ep]->in_maxsize;
OTG->ie[ep].DIEPCTL |= DIEPCTL_EPENA | DIEPCTL_CNAK;
otg_fifo_write(ep, usbp->epc[ep]->in_state->txbuf, n);
usbp->epc[ep]->in_state->txbuf += n;
usbp->epc[ep]->in_state->txcnt += n;
if (usbp->epc[ep]->in_state->txcnt >= usbp->epc[ep]->in_state->txsize) {
/* Transfer finished.*/
/* ????????????????????? */
OTG->DIEPEMPMSK &= ~DIEPEMPMSK_INEPTXFEM(ep);
}
}
/**
* @brief Generic endpoint IN handler.
*
* @param[in] usbp pointer to the @p USBDriver object
* @param[in] ep endpoint number
*
* @notapi
*/
static void otg_epin_handler(USBDriver *usbp, usbep_t ep) {
uint32_t epint = OTG->ie[ep].DIEPINT;
if (epint & DIEPINT_TXFE) {
/* TX FIFO empty or emptying.*/
otg_txfifo_handler(usbp, ep);
}
if (epint & DIEPINT_XFRC) {
/* Transmit transfer complete.*/
_usb_isr_invoke_in_cb(usbp, ep);
}
if (epint & DIEPINT_TOC) {
/* Timeouts not handled yet, not sure how to handle.*/
}
OTG->ie[ep].DIEPINT = 0xFFFFFFFF;
}
/**
* @brief Generic endpoint OUT handler.
*
* @param[in] usbp pointer to the @p USBDriver object
* @param[in] ep endpoint number
*
* @notapi
*/
static void otg_epout_handler(USBDriver *usbp, usbep_t ep) {
uint32_t epint = OTG->oe[ep].DOEPINT;
/* Is it a setup packet?*/
if (epint & DOEPINT_STUP) {
/* Setup packets handling, setup packets are handled using a
specific callback.*/
_usb_isr_invoke_setup_cb(usbp, ep);
}
if (epint & DOEPINT_XFRC) {
/* Receive transfer complete.*/
_usb_isr_invoke_out_cb(usbp, ep);
}
OTG->oe[ep].DOEPINT = 0xFFFFFFFF;
}
/*===========================================================================*/
/* Driver interrupt handlers. */
/*===========================================================================*/
@ -200,13 +391,7 @@ CH_IRQ_HANDLER(OTG_FS_IRQHandler) {
/* RX FIFO not empty handling.*/
if (sts & GINTMSK_RXFLVLM) {
}
/* Non periodic TX FIFO empty handling.*/
if (sts & GINTSTS_NPTXFE) {
OTG->GINTSTS = GINTSTS_NPTXFE;
otg_rxfifo_handler(usbp);
}
/* IN/OUT endpoints event handling, timeout and transfer complete events
@ -360,7 +545,7 @@ void usb_lld_reset(USBDriver *usbp) {
/* Enables also EP-related interrupt sources.*/
OTG->GINTMSK |= GINTMSK_RXFLVLM | GINTMSK_OEPM | GINTMSK_IEPM;
OTG->DIEPMSK = DIEPMSK_TOM | DIEPMSK_XFRCM;
OTG->DIEPMSK = DIEPMSK_TOCM | DIEPMSK_XFRCM;
OTG->DOEPMSK = DOEPMSK_STUPM | DOEPMSK_XFRCM;
// OTG->DAINTMSK = DAINTMSK_OutEpMsk(0) | DAINTMSK_InEpMsk(0);
@ -596,7 +781,8 @@ void usb_lld_start_in(USBDriver *usbp, usbep_t ep) {
void usb_lld_stall_out(USBDriver *usbp, usbep_t ep) {
(void)usbp;
(void)ep;
OTG->oe[ep].DOEPCTL |= DOEPCTL_STALL;
}
/**
@ -610,7 +796,8 @@ void usb_lld_stall_out(USBDriver *usbp, usbep_t ep) {
void usb_lld_stall_in(USBDriver *usbp, usbep_t ep) {
(void)usbp;
(void)ep;
OTG->ie[ep].DIEPCTL |= DIEPCTL_STALL;
}
/**
@ -624,7 +811,8 @@ void usb_lld_stall_in(USBDriver *usbp, usbep_t ep) {
void usb_lld_clear_out(USBDriver *usbp, usbep_t ep) {
(void)usbp;
(void)ep;
OTG->oe[ep].DOEPCTL &= ~DOEPCTL_STALL;
}
/**
@ -638,7 +826,8 @@ void usb_lld_clear_out(USBDriver *usbp, usbep_t ep) {
void usb_lld_clear_in(USBDriver *usbp, usbep_t ep) {
(void)usbp;
(void)ep;
OTG->ie[ep].DIEPCTL &= ~DIEPCTL_STALL;
}
#endif /* HAL_USE_USB */