aboutsummaryrefslogtreecommitdiffstats
path: root/os/hal
diff options
context:
space:
mode:
authorgdisirio <gdisirio@35acf78f-673a-0410-8e92-d51de3d6d3f4>2012-03-31 06:41:19 +0000
committergdisirio <gdisirio@35acf78f-673a-0410-8e92-d51de3d6d3f4>2012-03-31 06:41:19 +0000
commitf5ff03c303492299bc7736230eff3326db4dd521 (patch)
treebe64e23ac17574fd416b472b5ccc8b188fe0bbf3 /os/hal
parent7d899703719670bccd436325e958d17301cb3cec (diff)
downloadChibiOS-f5ff03c303492299bc7736230eff3326db4dd521.tar.gz
ChibiOS-f5ff03c303492299bc7736230eff3326db4dd521.tar.bz2
ChibiOS-f5ff03c303492299bc7736230eff3326db4dd521.zip
git-svn-id: svn://svn.code.sf.net/p/chibios/svn/trunk@4063 35acf78f-673a-0410-8e92-d51de3d6d3f4
Diffstat (limited to 'os/hal')
-rw-r--r--os/hal/platforms/STM32/OTGv1/stm32_otg.h13
-rw-r--r--os/hal/platforms/STM32/OTGv1/usb_lld.c213
2 files changed, 208 insertions, 18 deletions
diff --git a/os/hal/platforms/STM32/OTGv1/stm32_otg.h b/os/hal/platforms/STM32/OTGv1/stm32_otg.h
index b12cefdea..fec44c9ad 100644
--- a/os/hal/platforms/STM32/OTGv1/stm32_otg.h
+++ b/os/hal/platforms/STM32/OTGv1/stm32_otg.h
@@ -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. */
diff --git a/os/hal/platforms/STM32/OTGv1/usb_lld.c b/os/hal/platforms/STM32/OTGv1/usb_lld.c
index 711f1c3bf..b79d17f1c 100644
--- a/os/hal/platforms/STM32/OTGv1/usb_lld.c
+++ b/os/hal/platforms/STM32/OTGv1/usb_lld.c
@@ -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 */