*ppf = NULL;
}
+static void
+dwc_otg_write_fifo(struct dwc_otg_softc *sc, struct usb_page_cache *pc,
+ uint32_t offset, uint32_t fifo, uint32_t count)
+{
+ uint32_t temp;
+
+ /* round down length to nearest 4-bytes */
+ temp = count & ~3;
+
+ /* check if we can write the data directly */
+ if (temp != 0 && usb_pc_buffer_is_aligned(pc, offset, temp, 3)) {
+ struct usb_page_search buf_res;
+
+ /* pre-subtract length */
+ count -= temp;
+
+ /* iterate buffer list */
+ do {
+ /* get current buffer pointer */
+ usbd_get_page(pc, offset, &buf_res);
+
+ if (buf_res.length > temp)
+ buf_res.length = temp;
+
+ /* transfer data into FIFO */
+ bus_space_write_region_4(sc->sc_io_tag, sc->sc_io_hdl,
+ fifo, buf_res.buffer, buf_res.length / 4);
+
+ offset += buf_res.length;
+ fifo += buf_res.length;
+ temp -= buf_res.length;
+ } while (temp != 0);
+ }
+
+ /* check for remainder */
+ if (count != 0) {
+ /* clear topmost word before copy */
+ sc->sc_bounce_buffer[(count - 1) / 4] = 0;
+
+ /* copy out data */
+ usbd_copy_out(pc, offset,
+ sc->sc_bounce_buffer, count);
+
+ /* transfer data into FIFO */
+ bus_space_write_region_4(sc->sc_io_tag,
+ sc->sc_io_hdl, fifo, sc->sc_bounce_buffer,
+ (count + 3) / 4);
+ }
+}
+
+static void
+dwc_otg_read_fifo(struct dwc_otg_softc *sc, struct usb_page_cache *pc,
+ uint32_t offset, uint32_t count)
+{
+ uint32_t temp;
+
+ /* round down length to nearest 4-bytes */
+ temp = count & ~3;
+
+ /* check if we can read the data directly */
+ if (temp != 0 && usb_pc_buffer_is_aligned(pc, offset, temp, 3)) {
+ struct usb_page_search buf_res;
+
+ /* pre-subtract length */
+ count -= temp;
+
+ /* iterate buffer list */
+ do {
+ /* get current buffer pointer */
+ usbd_get_page(pc, offset, &buf_res);
+
+ if (buf_res.length > temp)
+ buf_res.length = temp;
+
+ /* transfer data from FIFO */
+ bus_space_read_region_4(sc->sc_io_tag, sc->sc_io_hdl,
+ sc->sc_current_rx_fifo, buf_res.buffer, buf_res.length / 4);
+
+ offset += buf_res.length;
+ sc->sc_current_rx_fifo += buf_res.length;
+ sc->sc_current_rx_bytes -= buf_res.length;
+ temp -= buf_res.length;
+ } while (temp != 0);
+ }
+
+ /* check for remainder */
+ if (count != 0) {
+ /* read data into bounce buffer */
+ bus_space_read_region_4(sc->sc_io_tag, sc->sc_io_hdl,
+ sc->sc_current_rx_fifo,
+ sc->sc_bounce_buffer, (count + 3) / 4);
+
+ /* store data into proper buffer */
+ usbd_copy_in(pc, offset, sc->sc_bounce_buffer, count);
+
+ /* round length up to nearest 4 bytes */
+ count = (count + 3) & ~3;
+
+ /* update counters */
+ sc->sc_current_rx_bytes -= count;
+ sc->sc_current_rx_fifo += count;
+ }
+}
+
static void
dwc_otg_tx_fifo_reset(struct dwc_otg_softc *sc, uint32_t value)
{
sc->sc_irq_mask |= GINTMSK_RXFLVLMSK;
DWC_OTG_WRITE_4(sc, DOTG_GINTMSK, sc->sc_irq_mask);
+ if (sc->sc_current_rx_bytes != 0) {
+ /* need to dump remaining data */
+ bus_space_read_region_4(sc->sc_io_tag, sc->sc_io_hdl,
+ sc->sc_current_rx_fifo, sc->sc_bounce_buffer,
+ sc->sc_current_rx_bytes / 4);
+ /* clear number of active bytes to receive */
+ sc->sc_current_rx_bytes = 0;
+ }
/* clear cached status */
sc->sc_last_rx_status = 0;
}
td->channel[x] != GRXSTSRD_CHNUM_GET(sc->sc_last_rx_status))
continue;
dwc_otg_common_rx_ack(sc);
+ break;
}
}
td->state = DWC_CHAN_ST_WAIT_ANE;
}
+ /* copy out control request */
usbd_copy_out(td->pc, 0, &req, sizeof(req));
DWC_OTG_WRITE_4(sc, DOTG_HCTSIZ(td->channel[0]),
goto not_complete;
}
- /* copy in control request */
- memcpy(&req, sc->sc_rx_bounce_buffer, sizeof(req));
+ /* read FIFO */
+ dwc_otg_read_fifo(sc, td->pc, 0, sizeof(req));
- /* copy data into real buffer */
- usbd_copy_in(td->pc, 0, &req, sizeof(req));
+ /* copy out control request */
+ usbd_copy_out(td->pc, 0, &req, sizeof(req));
td->offset = sizeof(req);
td->remainder = 0;
goto complete;
}
- usbd_copy_in(td->pc, td->offset,
- sc->sc_rx_bounce_buffer, count);
+ /* read data from FIFO */
+ dwc_otg_read_fifo(sc, td->pc, td->offset, count);
td->remainder -= count;
td->offset += count;
return (0); /* we are complete */
}
- usbd_copy_in(td->pc, td->offset, sc->sc_rx_bounce_buffer, count);
+ /* read data from FIFO */
+ dwc_otg_read_fifo(sc, td->pc, td->offset, count);
+
td->remainder -= count;
td->offset += count;
DWC_OTG_WRITE_4(sc, DOTG_HCCHAR(channel), hcchar);
if (count != 0) {
- /* clear topmost word before copy */
- sc->sc_tx_bounce_buffer[(count - 1) / 4] = 0;
-
- /* copy out data */
- usbd_copy_out(td->pc, td->offset + td->tx_bytes,
- sc->sc_tx_bounce_buffer, count);
-
- /* transfer data into FIFO */
- bus_space_write_region_4(sc->sc_io_tag, sc->sc_io_hdl,
- DOTG_DFIFO(channel),
- sc->sc_tx_bounce_buffer, (count + 3) / 4);
+ /* write data into FIFO */
+ dwc_otg_write_fifo(sc, td->pc, td->offset +
+ td->tx_bytes, DOTG_DFIFO(channel), count);
}
/* store number of bytes transmitted */
count = fifo_left;
if (count != 0) {
-
- /* clear topmost word before copy */
- sc->sc_tx_bounce_buffer[(count - 1) / 4] = 0;
-
- /* copy out data */
- usbd_copy_out(td->pc, td->offset,
- sc->sc_tx_bounce_buffer, count);
-
- /* transfer data into FIFO */
- bus_space_write_region_4(sc->sc_io_tag, sc->sc_io_hdl,
- DOTG_DFIFO(td->ep_no),
- sc->sc_tx_bounce_buffer, (count + 3) / 4);
+ /* write data into FIFO */
+ dwc_otg_write_fifo(sc, td->pc, td->offset,
+ DOTG_DFIFO(td->ep_no), count);
td->tx_bytes -= count;
td->remainder -= count;
sc->sc_chan_state[ep_no].wait_halted = 0;
DPRINTFN(5, "channel halt complete ch=%u\n", ep_no);
}
+ /* store bytes and FIFO offset */
+ sc->sc_current_rx_bytes = 0;
+ sc->sc_current_rx_fifo = 0;
+
+ /* acknowledge status */
dwc_otg_common_rx_ack(sc);
goto repeat;
}
ep_no = GRXSTSRD_CHNUM_GET(
sc->sc_last_rx_status);
- /* receive data, if any */
- if (temp != 0) {
- DPRINTF("Reading %d bytes from ep %d\n", temp, ep_no);
- bus_space_read_region_4(sc->sc_io_tag, sc->sc_io_hdl,
- DOTG_DFIFO(ep_no),
- sc->sc_rx_bounce_buffer, (temp + 3) / 4);
- }
+ /* store bytes and FIFO offset */
+ sc->sc_current_rx_bytes = (temp + 3) & ~3;
+ sc->sc_current_rx_fifo = DOTG_DFIFO(ep_no);
+
+ DPRINTF("Reading %d bytes from ep %d\n", temp, ep_no);
/* check if we should dump the data */
if (!(sc->sc_active_rx_ep & (1U << ep_no))) {