From f5ff03c303492299bc7736230eff3326db4dd521 Mon Sep 17 00:00:00 2001
From: gdisirio <gdisirio@35acf78f-673a-0410-8e92-d51de3d6d3f4>
Date: Sat, 31 Mar 2012 06:41:19 +0000
Subject: git-svn-id: svn://svn.code.sf.net/p/chibios/svn/trunk@4063
 35acf78f-673a-0410-8e92-d51de3d6d3f4

---
 os/hal/platforms/STM32/OTGv1/stm32_otg.h |  13 +-
 os/hal/platforms/STM32/OTGv1/usb_lld.c   | 213 +++++++++++++++++++++++++++++--
 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 */
-- 
cgit v1.2.3