The following reply was made to PR usb/181987; it has been noted by GNATS.

From: [email protected] (dfilter service)
To: [email protected]
Cc:  
Subject: Re: usb/181987: commit references a PR
Date: Thu, 24 Oct 2013 06:22:52 +0000 (UTC)

 Author: hselasky
 Date: Thu Oct 24 06:22:43 2013
 New Revision: 257041
 URL: http://svnweb.freebsd.org/changeset/base/257041
 
 Log:
   MFC r252912, r254828 and r256548:
   Add host mode support to the Mentor Graphics USB OTG controller driver.
   
   PR:          usb/181987
 
 Modified:
   stable/9/sys/dev/usb/controller/musb_otg.c
   stable/9/sys/dev/usb/controller/musb_otg.h
   stable/9/sys/dev/usb/controller/musb_otg_atmelarm.c
 Directory Properties:
   stable/9/sys/   (props changed)
   stable/9/sys/dev/   (props changed)
 
 Modified: stable/9/sys/dev/usb/controller/musb_otg.c
 ==============================================================================
 --- stable/9/sys/dev/usb/controller/musb_otg.c Thu Oct 24 06:06:17 2013        
(r257040)
 +++ stable/9/sys/dev/usb/controller/musb_otg.c Thu Oct 24 06:22:43 2013        
(r257041)
 @@ -90,6 +90,8 @@ SYSCTL_INT(_hw_usb_musbotg, OID_AUTO, de
      &musbotgdebug, 0, "Debug level");
  #endif
  
 +#define       MAX_NAK_TO      16
 +
  /* prototypes */
  
  struct usb_bus_methods musbotg_bus_methods;
 @@ -98,17 +100,35 @@ struct usb_pipe_methods musbotg_device_c
  struct usb_pipe_methods musbotg_device_intr_methods;
  struct usb_pipe_methods musbotg_device_isoc_methods;
  
 -static musbotg_cmd_t musbotg_setup_rx;
 -static musbotg_cmd_t musbotg_setup_data_rx;
 -static musbotg_cmd_t musbotg_setup_data_tx;
 -static musbotg_cmd_t musbotg_setup_status;
 -static musbotg_cmd_t musbotg_data_rx;
 -static musbotg_cmd_t musbotg_data_tx;
 +/* Control transfers: Device mode */
 +static musbotg_cmd_t musbotg_dev_ctrl_setup_rx;
 +static musbotg_cmd_t musbotg_dev_ctrl_data_rx;
 +static musbotg_cmd_t musbotg_dev_ctrl_data_tx;
 +static musbotg_cmd_t musbotg_dev_ctrl_status;
 +
 +/* Control transfers: Host mode */
 +static musbotg_cmd_t musbotg_host_ctrl_setup_tx;
 +static musbotg_cmd_t musbotg_host_ctrl_data_rx;
 +static musbotg_cmd_t musbotg_host_ctrl_data_tx;
 +static musbotg_cmd_t musbotg_host_ctrl_status_rx;
 +static musbotg_cmd_t musbotg_host_ctrl_status_tx;
 +
 +/* Bulk, Interrupt, Isochronous: Device mode */
 +static musbotg_cmd_t musbotg_dev_data_rx;
 +static musbotg_cmd_t musbotg_dev_data_tx;
 +
 +/* Bulk, Interrupt, Isochronous: Host mode */
 +static musbotg_cmd_t musbotg_host_data_rx;
 +static musbotg_cmd_t musbotg_host_data_tx;
 +
  static void   musbotg_device_done(struct usb_xfer *, usb_error_t);
  static void   musbotg_do_poll(struct usb_bus *);
  static void   musbotg_standard_done(struct usb_xfer *);
  static void   musbotg_interrupt_poll(struct musbotg_softc *);
  static void   musbotg_root_intr(struct musbotg_softc *);
 +static int    musbotg_channel_alloc(struct musbotg_softc *, struct musbotg_td 
*td);
 +static void   musbotg_channel_free(struct musbotg_softc *, struct musbotg_td 
*td);
 +static void   musbotg_ep_int_set(struct musbotg_softc *sc, int channel, int 
on);
  
  /*
   * Here is a configuration that the chip supports.
 @@ -123,6 +143,64 @@ static const struct usb_hw_ep_profile mu
        }
  };
  
 +static int
 +musbotg_channel_alloc(struct musbotg_softc *sc, struct musbotg_td *td)
 +{
 +      int ch;
 +      int ep;
 +
 +      ep = td->ep_no;
 +
 +      /* In device mode each EP got its own channel */
 +      if (sc->sc_mode == MUSB2_DEVICE_MODE) {
 +              musbotg_ep_int_set(sc, ep, 1);
 +              return (ep);
 +      }
 +
 +      /*
 +       * All control transactions go through EP0
 +       */
 +      if (ep == 0) {
 +              if (sc->sc_channel_mask & (1 << 0))
 +                      return (-1);
 +              sc->sc_channel_mask |= (1 << 0);
 +              musbotg_ep_int_set(sc, ep, 1);
 +              return (0);
 +      }
 +
 +      for (ch = 1; ch < MUSB2_EP_MAX; ch++) {
 +              if (!(sc->sc_channel_mask & (1 << ch))) {
 +                      sc->sc_channel_mask |= (1 << ch);
 +                      musbotg_ep_int_set(sc, ch, 1);
 +                      return (ch);
 +              }
 +      }
 +
 +      DPRINTFN(-1, "No available channels. Mask: %04x\n",  
sc->sc_channel_mask);
 +
 +      return (-1);
 +}
 +
 +static void   
 +musbotg_channel_free(struct musbotg_softc *sc, struct musbotg_td *td)
 +{
 +
 +      DPRINTFN(1, "ep_no=%d\n", td->channel);
 +
 +      if (sc->sc_mode == MUSB2_DEVICE_MODE)
 +              return;
 +
 +      if (td == NULL)
 +              return;
 +      if (td->channel == -1)
 +              return;
 +
 +      musbotg_ep_int_set(sc, td->channel, 0);
 +      sc->sc_channel_mask &= ~(1 << td->channel);
 +
 +      td->channel = -1;
 +}
 +
  static void
  musbotg_get_hw_ep_profile(struct usb_device *udev,
      const struct usb_hw_ep_profile **ppf, uint8_t ep_addr)
 @@ -213,6 +291,46 @@ musbotg_pull_down(struct musbotg_softc *
  }
  
  static void
 +musbotg_suspend_host(struct musbotg_softc *sc)
 +{
 +      uint8_t temp;
 +
 +      if (sc->sc_flags.status_suspend) {
 +              return;
 +      }
 +
 +      temp = MUSB2_READ_1(sc, MUSB2_REG_POWER);
 +      temp |= MUSB2_MASK_SUSPMODE;
 +      MUSB2_WRITE_1(sc, MUSB2_REG_POWER, temp);
 +      sc->sc_flags.status_suspend = 1;
 +}
 +
 +static void
 +musbotg_wakeup_host(struct musbotg_softc *sc)
 +{
 +      uint8_t temp;
 +
 +      if (!(sc->sc_flags.status_suspend)) {
 +              return;
 +      }
 +
 +      temp = MUSB2_READ_1(sc, MUSB2_REG_POWER);
 +      temp &= ~MUSB2_MASK_SUSPMODE;
 +      temp |= MUSB2_MASK_RESUME;
 +      MUSB2_WRITE_1(sc, MUSB2_REG_POWER, temp);
 +
 +      /* wait 20 milliseconds */
 +      /* Wait for reset to complete. */
 +      usb_pause_mtx(&sc->sc_bus.bus_mtx, hz / 50);
 +
 +      temp = MUSB2_READ_1(sc, MUSB2_REG_POWER);
 +      temp &= ~MUSB2_MASK_RESUME;
 +      MUSB2_WRITE_1(sc, MUSB2_REG_POWER, temp);
 +
 +      sc->sc_flags.status_suspend = 0;
 +}
 +
 +static void
  musbotg_wakeup_peer(struct musbotg_softc *sc)
  {
        uint8_t temp;
 @@ -243,7 +361,7 @@ musbotg_set_address(struct musbotg_softc
  }
  
  static uint8_t
 -musbotg_setup_rx(struct musbotg_td *td)
 +musbotg_dev_ctrl_setup_rx(struct musbotg_td *td)
  {
        struct musbotg_softc *sc;
        struct usb_device_request req;
 @@ -253,6 +371,15 @@ musbotg_setup_rx(struct musbotg_td *td)
        /* get pointer to softc */
        sc = MUSBOTG_PC2SC(td->pc);
  
 +      if (td->channel == -1)
 +              td->channel = musbotg_channel_alloc(sc, td);
 +
 +      /* EP0 is busy, wait */
 +      if (td->channel == -1)
 +              return (1);
 +
 +      DPRINTFN(1, "ep_no=%d\n", td->channel);
 +
        /* select endpoint 0 */
        MUSB2_WRITE_1(sc, MUSB2_REG_EPINDEX, 0);
  
 @@ -269,8 +396,10 @@ musbotg_setup_rx(struct musbotg_td *td)
                /* do not stall at this point */
                td->did_stall = 1;
                /* wait for interrupt */
 +              DPRINTFN(0, "CSR0 DATAEND\n");
                goto not_complete;
        }
 +
        if (csr & MUSB2_MASK_CSR0L_SENTSTALL) {
                /* clear SENTSTALL */
                MUSB2_WRITE_1(sc, MUSB2_REG_TXCSRL, 0);
 @@ -289,6 +418,7 @@ musbotg_setup_rx(struct musbotg_td *td)
                sc->sc_ep0_busy = 0;
        }
        if (sc->sc_ep0_busy) {
 +              DPRINTFN(0, "EP0 BUSY\n");
                goto not_complete;
        }
        if (!(csr & MUSB2_MASK_CSR0L_RXPKTRDY)) {
 @@ -337,6 +467,8 @@ musbotg_setup_rx(struct musbotg_td *td)
        } else {
                sc->sc_dv_addr = 0xFF;
        }
 +
 +      musbotg_channel_free(sc, td);
        return (0);                     /* complete */
  
  not_complete:
 @@ -350,10 +482,117 @@ not_complete:
        return (1);                     /* not complete */
  }
  
 +static uint8_t
 +musbotg_host_ctrl_setup_tx(struct musbotg_td *td)
 +{
 +      struct musbotg_softc *sc;
 +      struct usb_device_request req;
 +      uint8_t csr, csrh;
 +
 +      /* get pointer to softc */
 +      sc = MUSBOTG_PC2SC(td->pc);
 +
 +      if (td->channel == -1)
 +              td->channel = musbotg_channel_alloc(sc, td);
 +
 +      /* EP0 is busy, wait */
 +      if (td->channel == -1)
 +              return (1);
 +
 +      DPRINTFN(1, "ep_no=%d\n", td->channel);
 +
 +      /* select endpoint 0 */
 +      MUSB2_WRITE_1(sc, MUSB2_REG_EPINDEX, 0);
 +
 +      /* read out FIFO status */
 +      csr = MUSB2_READ_1(sc, MUSB2_REG_TXCSRL);
 +      DPRINTFN(4, "csr=0x%02x\n", csr);
 +
 +      /* Not ready yet yet */
 +      if (csr & MUSB2_MASK_CSR0L_TXPKTRDY)
 +              return (1);
 +
 +      /* Failed */
 +      if (csr & (MUSB2_MASK_CSR0L_RXSTALL |
 +          MUSB2_MASK_CSR0L_ERROR))
 +      {
 +              /* Clear status bit */
 +              MUSB2_WRITE_1(sc, MUSB2_REG_TXCSRL, 0);
 +              DPRINTFN(1, "error bit set, csr=0x%02x\n", csr);
 +              td->error = 1;
 +      }
 +
 +      if (csr & MUSB2_MASK_CSR0L_NAKTIMO) {
 +              DPRINTFN(1, "NAK timeout\n");
 +
 +              if (csr & MUSB2_MASK_CSR0L_TXFIFONEMPTY) {
 +                      csrh = MUSB2_READ_1(sc, MUSB2_REG_TXCSRH);
 +                      csrh |= MUSB2_MASK_CSR0H_FFLUSH;
 +                      MUSB2_WRITE_1(sc, MUSB2_REG_TXCSRH, csrh);
 +                      csr = MUSB2_READ_1(sc, MUSB2_REG_TXCSRL);
 +                      if (csr & MUSB2_MASK_CSR0L_TXFIFONEMPTY) {
 +                              csrh = MUSB2_READ_1(sc, MUSB2_REG_TXCSRH);
 +                              csrh |= MUSB2_MASK_CSR0H_FFLUSH;
 +                              MUSB2_WRITE_1(sc, MUSB2_REG_TXCSRH, csrh);
 +                              csr = MUSB2_READ_1(sc, MUSB2_REG_TXCSRL);
 +                      }
 +              }
 +
 +              csr &= ~MUSB2_MASK_CSR0L_NAKTIMO;
 +              MUSB2_WRITE_1(sc, MUSB2_REG_TXCSRL, csr);
 +
 +              td->error = 1;
 +      }
 +
 +      if (td->error) {
 +              musbotg_channel_free(sc, td);
 +              return (0);
 +      }
 +
 +      /* Fifo is not empty and there is no NAK timeout */
 +      if (csr & MUSB2_MASK_CSR0L_TXPKTRDY)
 +              return (1);
 +
 +      /* check if we are complete */
 +      if (td->remainder == 0) {
 +              /* we are complete */
 +              musbotg_channel_free(sc, td);
 +              return (0);
 +      }
 +
 +      /* copy data into real buffer */
 +      usbd_copy_out(td->pc, 0, &req, sizeof(req));
 +
 +      /* send data */
 +      bus_space_write_multi_1(sc->sc_io_tag, sc->sc_io_hdl,
 +          MUSB2_REG_EPFIFO(0), (void *)&req, sizeof(req));
 +
 +      /* update offset and remainder */
 +      td->offset += sizeof(req);
 +      td->remainder -= sizeof(req);
 +
 +
 +      MUSB2_WRITE_1(sc, MUSB2_REG_TXNAKLIMIT, MAX_NAK_TO);
 +      MUSB2_WRITE_1(sc, MUSB2_REG_TXFADDR(0), td->dev_addr);
 +      MUSB2_WRITE_1(sc, MUSB2_REG_TXHADDR(0), td->haddr);
 +      MUSB2_WRITE_1(sc, MUSB2_REG_TXHUBPORT(0), td->hport);
 +      MUSB2_WRITE_1(sc, MUSB2_REG_TXTI, td->transfer_type);
 +
 +      /* write command */
 +      MUSB2_WRITE_1(sc, MUSB2_REG_TXCSRL,
 +          MUSB2_MASK_CSR0L_TXPKTRDY | 
 +          MUSB2_MASK_CSR0L_SETUPPKT);
 +
 +      /* Just to be consistent, not used above */
 +      td->transaction_started = 1;
 +
 +      return (1);                     /* in progress */
 +}
 +
  /* Control endpoint only data handling functions (RX/TX/SYNC) */
  
  static uint8_t
 -musbotg_setup_data_rx(struct musbotg_td *td)
 +musbotg_dev_ctrl_data_rx(struct musbotg_td *td)
  {
        struct usb_page_search buf_res;
        struct musbotg_softc *sc;
 @@ -496,7 +735,7 @@ musbotg_setup_data_rx(struct musbotg_td 
  }
  
  static uint8_t
 -musbotg_setup_data_tx(struct musbotg_td *td)
 +musbotg_dev_ctrl_data_tx(struct musbotg_td *td)
  {
        struct usb_page_search buf_res;
        struct musbotg_softc *sc;
 @@ -614,77 +853,943 @@ musbotg_setup_data_tx(struct musbotg_td 
  }
  
  static uint8_t
 -musbotg_setup_status(struct musbotg_td *td)
 +musbotg_host_ctrl_data_rx(struct musbotg_td *td)
  {
 +      struct usb_page_search buf_res;
        struct musbotg_softc *sc;
 +      uint16_t count;
        uint8_t csr;
 +      uint8_t got_short;
  
        /* get pointer to softc */
        sc = MUSBOTG_PC2SC(td->pc);
  
 +      if (td->channel == -1)
 +              td->channel = musbotg_channel_alloc(sc, td);
 +
 +      /* EP0 is busy, wait */
 +      if (td->channel == -1)
 +              return (1);
 +
 +      DPRINTFN(1, "ep_no=%d\n", td->channel);
 +
        /* select endpoint 0 */
        MUSB2_WRITE_1(sc, MUSB2_REG_EPINDEX, 0);
  
 -      if (sc->sc_ep0_busy) {
 -              sc->sc_ep0_busy = 0;
 -              sc->sc_ep0_cmd |= MUSB2_MASK_CSR0L_DATAEND;
 -              MUSB2_WRITE_1(sc, MUSB2_REG_TXCSRL, sc->sc_ep0_cmd);
 -              sc->sc_ep0_cmd = 0;
 -      }
        /* read out FIFO status */
        csr = MUSB2_READ_1(sc, MUSB2_REG_TXCSRL);
  
        DPRINTFN(4, "csr=0x%02x\n", csr);
  
 -      if (csr & MUSB2_MASK_CSR0L_DATAEND) {
 -              /* wait for interrupt */
 -              return (1);             /* not complete */
 +      got_short = 0;
 +      if (!td->transaction_started) {
 +              td->transaction_started = 1;
 +
 +              MUSB2_WRITE_1(sc, MUSB2_REG_RXNAKLIMIT, MAX_NAK_TO);
 +
 +              MUSB2_WRITE_1(sc, MUSB2_REG_RXFADDR(0),
 +                  td->dev_addr);
 +              MUSB2_WRITE_1(sc, MUSB2_REG_RXHADDR(0), td->haddr);
 +              MUSB2_WRITE_1(sc, MUSB2_REG_RXHUBPORT(0), td->hport);
 +              MUSB2_WRITE_1(sc, MUSB2_REG_RXTI, td->transfer_type);
 +
 +              MUSB2_WRITE_1(sc, MUSB2_REG_TXCSRL,
 +                  MUSB2_MASK_CSR0L_REQPKT);
 +
 +              return (1);
 +      }
 +
 +      if (csr & MUSB2_MASK_CSR0L_NAKTIMO) {
 +              csr &= ~MUSB2_MASK_CSR0L_REQPKT;
 +              MUSB2_WRITE_1(sc, MUSB2_REG_TXCSRL, csr);
 +
 +              csr &= ~MUSB2_MASK_CSR0L_NAKTIMO;
 +              MUSB2_WRITE_1(sc, MUSB2_REG_TXCSRL, csr);
 +
 +              td->error = 1;
 +      }
 +
 +      /* Failed */
 +      if (csr & (MUSB2_MASK_CSR0L_RXSTALL |
 +          MUSB2_MASK_CSR0L_ERROR))
 +      {
 +              /* Clear status bit */
 +              MUSB2_WRITE_1(sc, MUSB2_REG_TXCSRL, 0);
 +              DPRINTFN(1, "error bit set, csr=0x%02x\n", csr);
 +              td->error = 1;
 +      }
 +
 +      if (td->error) {
 +              musbotg_channel_free(sc, td);
 +              return (0);     /* we are complete */
 +      }
 +
 +      if (!(csr & MUSB2_MASK_CSR0L_RXPKTRDY))
 +              return (1); /* not yet */
 +
 +      /* get the packet byte count */
 +      count = MUSB2_READ_2(sc, MUSB2_REG_RXCOUNT);
 +
 +      /* verify the packet byte count */
 +      if (count != td->max_frame_size) {
 +              if (count < td->max_frame_size) {
 +                      /* we have a short packet */
 +                      td->short_pkt = 1;
 +                      got_short = 1;
 +              } else {
 +                      /* invalid USB packet */
 +                      td->error = 1;
 +                      musbotg_channel_free(sc, td);
 +                      return (0);     /* we are complete */
 +              }
 +      }
 +      /* verify the packet byte count */
 +      if (count > td->remainder) {
 +              /* invalid USB packet */
 +              td->error = 1;
 +              musbotg_channel_free(sc, td);
 +              return (0);             /* we are complete */
 +      }
 +      while (count > 0) {
 +              uint32_t temp;
 +
 +              usbd_get_page(td->pc, td->offset, &buf_res);
 +
 +              /* get correct length */
 +              if (buf_res.length > count) {
 +                      buf_res.length = count;
 +              }
 +              /* check for unaligned memory address */
 +              if (USB_P2U(buf_res.buffer) & 3) {
 +
 +                      temp = count & ~3;
 +
 +                      if (temp) {
 +                              /* receive data 4 bytes at a time */
 +                              bus_space_read_multi_4(sc->sc_io_tag, 
sc->sc_io_hdl,
 +                                  MUSB2_REG_EPFIFO(0), sc->sc_bounce_buf,
 +                                  temp / 4);
 +                      }
 +                      temp = count & 3;
 +                      if (temp) {
 +                              /* receive data 1 byte at a time */
 +                              bus_space_read_multi_1(sc->sc_io_tag, 
sc->sc_io_hdl,
 +                                  MUSB2_REG_EPFIFO(0),
 +                                  (void *)(&sc->sc_bounce_buf[count / 4]), 
temp);
 +                      }
 +                      usbd_copy_in(td->pc, td->offset,
 +                          sc->sc_bounce_buf, count);
 +
 +                      /* update offset and remainder */
 +                      td->offset += count;
 +                      td->remainder -= count;
 +                      break;
 +              }
 +              /* check if we can optimise */
 +              if (buf_res.length >= 4) {
 +
 +                      /* receive data 4 bytes at a time */
 +                      bus_space_read_multi_4(sc->sc_io_tag, sc->sc_io_hdl,
 +                          MUSB2_REG_EPFIFO(0), buf_res.buffer,
 +                          buf_res.length / 4);
 +
 +                      temp = buf_res.length & ~3;
 +
 +                      /* update counters */
 +                      count -= temp;
 +                      td->offset += temp;
 +                      td->remainder -= temp;
 +                      continue;
 +              }
 +              /* receive data */
 +              bus_space_read_multi_1(sc->sc_io_tag, sc->sc_io_hdl,
 +                  MUSB2_REG_EPFIFO(0), buf_res.buffer, buf_res.length);
 +
 +              /* update counters */
 +              count -= buf_res.length;
 +              td->offset += buf_res.length;
 +              td->remainder -= buf_res.length;
 +      }
 +
 +      csr &= ~MUSB2_MASK_CSR0L_RXPKTRDY;
 +      MUSB2_WRITE_1(sc, MUSB2_REG_TXCSRL, csr);
 +
 +      /* check if we are complete */
 +      if ((td->remainder == 0) || got_short) {
 +              if (td->short_pkt) {
 +                      /* we are complete */
 +
 +                      musbotg_channel_free(sc, td);
 +                      return (0);
 +              }
 +              /* else need to receive a zero length packet */
 +      }
 +
 +      td->transaction_started = 1;
 +      MUSB2_WRITE_1(sc, MUSB2_REG_TXCSRL,
 +          MUSB2_MASK_CSR0L_REQPKT);
 +
 +      return (1);                     /* not complete */
 +}
 +
 +static uint8_t
 +musbotg_host_ctrl_data_tx(struct musbotg_td *td)
 +{
 +      struct usb_page_search buf_res;
 +      struct musbotg_softc *sc;
 +      uint16_t count;
 +      uint8_t csr, csrh;
 +
 +      /* get pointer to softc */
 +      sc = MUSBOTG_PC2SC(td->pc);
 +
 +      if (td->channel == -1)
 +              td->channel = musbotg_channel_alloc(sc, td);
 +
 +      /* No free EPs */
 +      if (td->channel == -1)
 +              return (1);
 +
 +      DPRINTFN(1, "ep_no=%d\n", td->channel);
 +
 +      /* select endpoint */
 +      MUSB2_WRITE_1(sc, MUSB2_REG_EPINDEX, 0);
 +
 +      /* read out FIFO status */
 +      csr = MUSB2_READ_1(sc, MUSB2_REG_TXCSRL);
 +      DPRINTFN(4, "csr=0x%02x\n", csr);
 +
 +      if (csr & (MUSB2_MASK_CSR0L_RXSTALL |
 +          MUSB2_MASK_CSR0L_ERROR)) {
 +              /* clear status bits */
 +              MUSB2_WRITE_1(sc, MUSB2_REG_TXCSRL, 0);
 +              td->error = 1;
 +      }
 +
 +      if (csr & MUSB2_MASK_CSR0L_NAKTIMO ) {
 +
 +              if (csr & MUSB2_MASK_CSR0L_TXFIFONEMPTY) {
 +                      csrh = MUSB2_READ_1(sc, MUSB2_REG_TXCSRH);
 +                      csrh |= MUSB2_MASK_CSR0H_FFLUSH;
 +                      MUSB2_WRITE_1(sc, MUSB2_REG_TXCSRH, csrh);
 +                      csr = MUSB2_READ_1(sc, MUSB2_REG_TXCSRL);
 +                      if (csr & MUSB2_MASK_CSR0L_TXFIFONEMPTY) {
 +                              csrh = MUSB2_READ_1(sc, MUSB2_REG_TXCSRH);
 +                              csrh |= MUSB2_MASK_CSR0H_FFLUSH;
 +                              MUSB2_WRITE_1(sc, MUSB2_REG_TXCSRH, csrh);
 +                              csr = MUSB2_READ_1(sc, MUSB2_REG_TXCSRL);
 +                      }
 +              }
 +
 +              csr &= ~MUSB2_MASK_CSR0L_NAKTIMO;
 +              MUSB2_WRITE_1(sc, MUSB2_REG_TXCSRL, csr);
 +
 +              td->error = 1;
 +      }
 +
 +
 +      if (td->error) {
 +              musbotg_channel_free(sc, td);
 +              return (0);     /* complete */
 +      }
 +
 +      /*
 +       * Wait while FIFO is empty. 
 +       * Do not flush it because it will cause transactions
 +       * with size more then packet size. It might upset
 +       * some devices
 +       */
 +      if (csr & MUSB2_MASK_CSR0L_TXFIFONEMPTY)
 +              return (1);
 +
 +      /* Packet still being processed */
 +      if (csr & MUSB2_MASK_CSR0L_TXPKTRDY)
 +              return (1);
 +
 +      if (td->transaction_started) {
 +              /* check remainder */
 +              if (td->remainder == 0) {
 +                      if (td->short_pkt) {
 +                              musbotg_channel_free(sc, td);
 +                              return (0);     /* complete */
 +                      }
 +                      /* else we need to transmit a short packet */
 +              }
 +
 +              /* We're not complete - more transactions required */
 +              td->transaction_started = 0;
 +      }
 +
 +      /* check for short packet */
 +      count = td->max_frame_size;
 +      if (td->remainder < count) {
 +              /* we have a short packet */
 +              td->short_pkt = 1;
 +              count = td->remainder;
 +      }
 +
 +      while (count > 0) {
 +              uint32_t temp;
 +
 +              usbd_get_page(td->pc, td->offset, &buf_res);
 +
 +              /* get correct length */
 +              if (buf_res.length > count) {
 +                      buf_res.length = count;
 +              }
 +              /* check for unaligned memory address */
 +              if (USB_P2U(buf_res.buffer) & 3) {
 +
 +                      usbd_copy_out(td->pc, td->offset,
 +                          sc->sc_bounce_buf, count);
 +
 +                      temp = count & ~3;
 +
 +                      if (temp) {
 +                              /* transmit data 4 bytes at a time */
 +                              bus_space_write_multi_4(sc->sc_io_tag,
 +                                  sc->sc_io_hdl, MUSB2_REG_EPFIFO(0),
 +                                  sc->sc_bounce_buf, temp / 4);
 +                      }
 +                      temp = count & 3;
 +                      if (temp) {
 +                              /* receive data 1 byte at a time */
 +                              bus_space_write_multi_1(sc->sc_io_tag, 
sc->sc_io_hdl,
 +                                  MUSB2_REG_EPFIFO(0),
 +                                  ((void *)&sc->sc_bounce_buf[count / 4]), 
temp);
 +                      }
 +                      /* update offset and remainder */
 +                      td->offset += count;
 +                      td->remainder -= count;
 +                      break;
 +              }
 +              /* check if we can optimise */
 +              if (buf_res.length >= 4) {
 +
 +                      /* transmit data 4 bytes at a time */
 +                      bus_space_write_multi_4(sc->sc_io_tag, sc->sc_io_hdl,
 +                          MUSB2_REG_EPFIFO(0), buf_res.buffer,
 +                          buf_res.length / 4);
 +
 +                      temp = buf_res.length & ~3;
 +
 +                      /* update counters */
 +                      count -= temp;
 +                      td->offset += temp;
 +                      td->remainder -= temp;
 +                      continue;
 +              }
 +              /* transmit data */
 +              bus_space_write_multi_1(sc->sc_io_tag, sc->sc_io_hdl,
 +                  MUSB2_REG_EPFIFO(0), buf_res.buffer,
 +                  buf_res.length);
 +
 +              /* update counters */
 +              count -= buf_res.length;
 +              td->offset += buf_res.length;
 +              td->remainder -= buf_res.length;
 +      }
 +
 +      /* Function address */
 +      MUSB2_WRITE_1(sc, MUSB2_REG_TXFADDR(0), td->dev_addr);
 +      MUSB2_WRITE_1(sc, MUSB2_REG_TXHADDR(0), td->haddr);
 +      MUSB2_WRITE_1(sc, MUSB2_REG_TXHUBPORT(0), td->hport);
 +      MUSB2_WRITE_1(sc, MUSB2_REG_TXTI, td->transfer_type);
 +
 +      /* TX NAK timeout */
 +      MUSB2_WRITE_1(sc, MUSB2_REG_TXNAKLIMIT, MAX_NAK_TO);
 +
 +      /* write command */
 +      MUSB2_WRITE_1(sc, MUSB2_REG_TXCSRL,
 +          MUSB2_MASK_CSR0L_TXPKTRDY);
 +
 +      td->transaction_started = 1;
 +
 +      return (1);                     /* not complete */
 +}
 +
 +static uint8_t
 +musbotg_dev_ctrl_status(struct musbotg_td *td)
 +{
 +      struct musbotg_softc *sc;
 +      uint8_t csr;
 +
 +      /* get pointer to softc */
 +      sc = MUSBOTG_PC2SC(td->pc);
 +
 +      /* select endpoint 0 */
 +      MUSB2_WRITE_1(sc, MUSB2_REG_EPINDEX, 0);
 +
 +      if (sc->sc_ep0_busy) {
 +              sc->sc_ep0_busy = 0;
 +              sc->sc_ep0_cmd |= MUSB2_MASK_CSR0L_DATAEND;
 +              MUSB2_WRITE_1(sc, MUSB2_REG_TXCSRL, sc->sc_ep0_cmd);
 +              sc->sc_ep0_cmd = 0;
 +      }
 +      /* read out FIFO status */
 +      csr = MUSB2_READ_1(sc, MUSB2_REG_TXCSRL);
 +
 +      DPRINTFN(4, "csr=0x%02x\n", csr);
 +
 +      if (csr & MUSB2_MASK_CSR0L_DATAEND) {
 +              /* wait for interrupt */
 +              return (1);             /* not complete */
 +      }
 +      if (sc->sc_dv_addr != 0xFF) {
 +              /* write function address */
 +              musbotg_set_address(sc, sc->sc_dv_addr);
 +      }
 +
 +      musbotg_channel_free(sc, td);
 +      return (0);                     /* complete */
 +}
 +
 +static uint8_t
 +musbotg_host_ctrl_status_rx(struct musbotg_td *td)
 +{
 +      struct musbotg_softc *sc;
 +      uint8_t csr, csrh;
 +
 +      /* get pointer to softc */
 +      sc = MUSBOTG_PC2SC(td->pc);
 +
 +      if (td->channel == -1)
 +              td->channel = musbotg_channel_alloc(sc, td);
 +
 +      /* EP0 is busy, wait */
 +      if (td->channel == -1)
 +              return (1);
 +
 +      DPRINTFN(1, "ep_no=%d\n", td->channel);
 +
 +      /* select endpoint 0 */
 +      MUSB2_WRITE_1(sc, MUSB2_REG_EPINDEX, 0);
 +
 +      if (!td->transaction_started) {
 +              MUSB2_WRITE_1(sc, MUSB2_REG_RXFADDR(0),
 +                  td->dev_addr);
 +
 +              MUSB2_WRITE_1(sc, MUSB2_REG_RXHADDR(0), td->haddr);
 +              MUSB2_WRITE_1(sc, MUSB2_REG_RXHUBPORT(0), td->hport);
 +              MUSB2_WRITE_1(sc, MUSB2_REG_RXTI, td->transfer_type);
 +
 +              /* RX NAK timeout */
 +              MUSB2_WRITE_1(sc, MUSB2_REG_RXNAKLIMIT, MAX_NAK_TO);
 +
 +              td->transaction_started = 1;
 +
 +              /* Disable PING */
 +              csrh = MUSB2_READ_1(sc, MUSB2_REG_RXCSRH);
 +              csrh |= MUSB2_MASK_CSR0H_PING_DIS;
 +              MUSB2_WRITE_1(sc, MUSB2_REG_RXCSRH, csrh);
 +
 +              /* write command */
 +              MUSB2_WRITE_1(sc, MUSB2_REG_TXCSRL,
 +                  MUSB2_MASK_CSR0L_STATUSPKT | 
 +                  MUSB2_MASK_CSR0L_REQPKT);
 +
 +              return (1); /* Just started */
 +
 +      }
 +
 +      csr = MUSB2_READ_1(sc, MUSB2_REG_TXCSRL);
 +
 +      DPRINTFN(4, "IN STATUS csr=0x%02x\n", csr);
 +
 +      if (csr & MUSB2_MASK_CSR0L_RXPKTRDY) {
 +              MUSB2_WRITE_1(sc, MUSB2_REG_TXCSRL,
 +                  MUSB2_MASK_CSR0L_RXPKTRDY_CLR);
 +              musbotg_channel_free(sc, td);
 +              return (0); /* complete */
 +      }
 +
 +      if (csr & MUSB2_MASK_CSR0L_NAKTIMO) {
 +              csr &= ~ (MUSB2_MASK_CSR0L_STATUSPKT |
 +                  MUSB2_MASK_CSR0L_REQPKT);
 +              MUSB2_WRITE_1(sc, MUSB2_REG_TXCSRL, csr);
 +
 +              csr &= ~MUSB2_MASK_CSR0L_NAKTIMO;
 +              MUSB2_WRITE_1(sc, MUSB2_REG_TXCSRL, csr);
 +              td->error = 1;
 +      }
 +
 +      /* Failed */
 +      if (csr & (MUSB2_MASK_CSR0L_RXSTALL |
 +          MUSB2_MASK_CSR0L_ERROR))
 +      {
 +              /* Clear status bit */
 +              MUSB2_WRITE_1(sc, MUSB2_REG_TXCSRL, 0);
 +              DPRINTFN(1, "error bit set, csr=0x%02x\n", csr);
 +              td->error = 1;
 +      }
 +
 +      if (td->error) {
 +              musbotg_channel_free(sc, td);
 +              return (0);
 +      }
 +
 +      return (1);                     /* Not ready yet */
 +}
 +
 +static uint8_t
 +musbotg_host_ctrl_status_tx(struct musbotg_td *td)
 +{
 +      struct musbotg_softc *sc;
 +      uint8_t csr;
 +
 +      /* get pointer to softc */
 +      sc = MUSBOTG_PC2SC(td->pc);
 +
 +      if (td->channel == -1)
 +              td->channel = musbotg_channel_alloc(sc, td);
 +
 +      /* EP0 is busy, wait */
 +      if (td->channel == -1)
 +              return (1);
 +
 +      DPRINTFN(1, "ep_no=%d/%d [%d@%d.%d/%02x]\n", td->channel, 
td->transaction_started, 
 +                      td->dev_addr,td->haddr,td->hport, td->transfer_type);
 +
 +      /* select endpoint 0 */
 +      MUSB2_WRITE_1(sc, MUSB2_REG_EPINDEX, 0);
 +
 +      csr = MUSB2_READ_1(sc, MUSB2_REG_TXCSRL);
 +      DPRINTFN(4, "csr=0x%02x\n", csr);
 +
 +      /* Not yet */
 +      if (csr & MUSB2_MASK_CSR0L_TXPKTRDY)
 +              return (1);
 +
 +      /* Failed */
 +      if (csr & (MUSB2_MASK_CSR0L_RXSTALL |
 +          MUSB2_MASK_CSR0L_ERROR))
 +      {
 +              /* Clear status bit */
 +              MUSB2_WRITE_1(sc, MUSB2_REG_TXCSRL, 0);
 +              DPRINTFN(1, "error bit set, csr=0x%02x\n", csr);
 +              td->error = 1;
 +              musbotg_channel_free(sc, td);
 +              return (0); /* complete */
 +      }
 +
 +      if (td->transaction_started) {
 +              musbotg_channel_free(sc, td);
 +              return (0); /* complete */
 +      } 
 +
 +      MUSB2_WRITE_1(sc, MUSB2_REG_RXCSRH, MUSB2_MASK_CSR0H_PING_DIS);
 +
 +      MUSB2_WRITE_1(sc, MUSB2_REG_TXFADDR(0), td->dev_addr);
 +      MUSB2_WRITE_1(sc, MUSB2_REG_TXHADDR(0), td->haddr);
 +      MUSB2_WRITE_1(sc, MUSB2_REG_TXHUBPORT(0), td->hport);
 +      MUSB2_WRITE_1(sc, MUSB2_REG_TXTI, td->transfer_type);
 +
 +      /* TX NAK timeout */
 +      MUSB2_WRITE_1(sc, MUSB2_REG_TXNAKLIMIT, MAX_NAK_TO);
 +
 +      td->transaction_started = 1;
 +
 +      /* write command */
 +      MUSB2_WRITE_1(sc, MUSB2_REG_TXCSRL,
 +          MUSB2_MASK_CSR0L_STATUSPKT | 
 +          MUSB2_MASK_CSR0L_TXPKTRDY);
 +
 +      return (1);                     /* wait for interrupt */
 +}
 +
 +static uint8_t
 +musbotg_dev_data_rx(struct musbotg_td *td)
 +{
 +      struct usb_page_search buf_res;
 +      struct musbotg_softc *sc;
 +      uint16_t count;
 +      uint8_t csr;
 +      uint8_t to;
 +      uint8_t got_short;
 +
 +      to = 8;                         /* don't loop forever! */
 +      got_short = 0;
 +
 +      /* get pointer to softc */
 +      sc = MUSBOTG_PC2SC(td->pc);
 +
 +      if (td->channel == -1)
 +              td->channel = musbotg_channel_alloc(sc, td);
 +
 +      /* EP0 is busy, wait */
 +      if (td->channel == -1)
 +              return (1);
 +
 +      /* select endpoint */
 +      MUSB2_WRITE_1(sc, MUSB2_REG_EPINDEX, td->channel);
 +
 +repeat:
 +      /* read out FIFO status */
 +      csr = MUSB2_READ_1(sc, MUSB2_REG_RXCSRL);
 +
 +      DPRINTFN(4, "csr=0x%02x\n", csr);
 +
 +      /* clear overrun */
 +      if (csr & MUSB2_MASK_CSRL_RXOVERRUN) {
 +              /* make sure we don't clear "RXPKTRDY" */
 +              MUSB2_WRITE_1(sc, MUSB2_REG_RXCSRL,
 +                  MUSB2_MASK_CSRL_RXPKTRDY);
 +      }
 +
 +      /* check status */
 +      if (!(csr & MUSB2_MASK_CSRL_RXPKTRDY))
 +              return (1); /* not complete */
 +
 +      /* get the packet byte count */
 +      count = MUSB2_READ_2(sc, MUSB2_REG_RXCOUNT);
 +
 +      DPRINTFN(4, "count=0x%04x\n", count);
 +
 +      /*
 +       * Check for short or invalid packet:
 +       */
 +      if (count != td->max_frame_size) {
 +              if (count < td->max_frame_size) {
 +                      /* we have a short packet */
 +                      td->short_pkt = 1;
 +                      got_short = 1;
 +              } else {
 +                      /* invalid USB packet */
 +                      td->error = 1;
 +                      musbotg_channel_free(sc, td);
 +                      return (0);     /* we are complete */
 +              }
 +      }
 +      /* verify the packet byte count */
 +      if (count > td->remainder) {
 +              /* invalid USB packet */
 +              td->error = 1;
 +              musbotg_channel_free(sc, td);
 +              return (0);             /* we are complete */
 +      }
 +      while (count > 0) {
 +              uint32_t temp;
 +
 +              usbd_get_page(td->pc, td->offset, &buf_res);
 +
 +              /* get correct length */
 +              if (buf_res.length > count) {
 +                      buf_res.length = count;
 +              }
 +              /* check for unaligned memory address */
 +              if (USB_P2U(buf_res.buffer) & 3) {
 +
 +                      temp = count & ~3;
 +
 +                      if (temp) {
 +                              /* receive data 4 bytes at a time */
 +                              bus_space_read_multi_4(sc->sc_io_tag, 
sc->sc_io_hdl,
 +                                  MUSB2_REG_EPFIFO(td->channel), 
sc->sc_bounce_buf,
 +                                  temp / 4);
 +                      }
 +                      temp = count & 3;
 +                      if (temp) {
 +                              /* receive data 1 byte at a time */
 +                              bus_space_read_multi_1(sc->sc_io_tag,
 +                                  sc->sc_io_hdl, 
MUSB2_REG_EPFIFO(td->channel),
 +                                  ((void *)&sc->sc_bounce_buf[count / 4]), 
temp);
 
 *** DIFF OUTPUT TRUNCATED AT 1000 LINES ***
 _______________________________________________
 [email protected] mailing list
 http://lists.freebsd.org/mailman/listinfo/svn-src-all
 To unsubscribe, send any mail to "[email protected]"
 
_______________________________________________
[email protected] mailing list
http://lists.freebsd.org/mailman/listinfo/freebsd-usb
To unsubscribe, send any mail to "[email protected]"

Reply via email to