atmegadci_device_isoc_fs_enter(struct usb_xfer *xfer)
{
struct atmegadci_softc *sc = ATMEGA_BUS2SC(xfer->xroot->bus);
- uint32_t temp;
uint32_t nframes;
DPRINTFN(6, "xfer=%p next=%d nframes=%d\n",
(ATMEGA_READ_1(sc, ATMEGA_UDFNUMH) << 8) |
(ATMEGA_READ_1(sc, ATMEGA_UDFNUML));
- nframes &= ATMEGA_FRAME_MASK;
-
- /*
- * check if the frame index is within the window where the frames
- * will be inserted
- */
- temp = (nframes - xfer->endpoint->isoc_next) & ATMEGA_FRAME_MASK;
-
- if ((xfer->endpoint->is_synced == 0) ||
- (temp < xfer->nframes)) {
- /*
- * If there is data underflow or the pipe queue is
- * empty we schedule the transfer a few frames ahead
- * of the current frame position. Else two isochronous
- * transfers might overlap.
- */
- xfer->endpoint->isoc_next = (nframes + 3) & ATMEGA_FRAME_MASK;
- xfer->endpoint->is_synced = 1;
+ if (usbd_xfer_get_isochronous_start_frame(
+ xfer, nframes, 0, 1, ATMEGA_FRAME_MASK, NULL))
DPRINTFN(3, "start next=%d\n", xfer->endpoint->isoc_next);
- }
- /*
- * compute how many milliseconds the insertion is ahead of the
- * current frame position:
- */
- temp = (xfer->endpoint->isoc_next - nframes) & ATMEGA_FRAME_MASK;
-
- /*
- * pre-compute when the isochronous transfer will be finished:
- */
- xfer->isoc_time_complete =
- usb_isoc_time_expand(&sc->sc_bus, nframes) + temp +
- xfer->nframes;
-
- /* compute frame number for next insertion */
- xfer->endpoint->isoc_next += xfer->nframes;
/* setup TDs */
atmegadci_setup_standard_chain(xfer);
avr32dci_device_isoc_fs_enter(struct usb_xfer *xfer)
{
struct avr32dci_softc *sc = AVR32_BUS2SC(xfer->xroot->bus);
- uint32_t temp;
uint32_t nframes;
uint8_t ep_no;
ep_no = xfer->endpointno & UE_ADDR;
nframes = (AVR32_READ_4(sc, AVR32_FNUM) / 8);
- nframes &= AVR32_FRAME_MASK;
-
- /*
- * check if the frame index is within the window where the frames
- * will be inserted
- */
- temp = (nframes - xfer->endpoint->isoc_next) & AVR32_FRAME_MASK;
-
- if ((xfer->endpoint->is_synced == 0) ||
- (temp < xfer->nframes)) {
- /*
- * If there is data underflow or the pipe queue is
- * empty we schedule the transfer a few frames ahead
- * of the current frame position. Else two isochronous
- * transfers might overlap.
- */
- xfer->endpoint->isoc_next = (nframes + 3) & AVR32_FRAME_MASK;
- xfer->endpoint->is_synced = 1;
+ if (usbd_xfer_get_isochronous_start_frame(
+ xfer, nframes, 0, 1, AVR32_FRAME_MASK, NULL))
DPRINTFN(3, "start next=%d\n", xfer->endpoint->isoc_next);
- }
- /*
- * compute how many milliseconds the insertion is ahead of the
- * current frame position:
- */
- temp = (xfer->endpoint->isoc_next - nframes) & AVR32_FRAME_MASK;
-
- /*
- * pre-compute when the isochronous transfer will be finished:
- */
- xfer->isoc_time_complete =
- usb_isoc_time_expand(&sc->sc_bus, nframes) + temp +
- xfer->nframes;
-
- /* compute frame number for next insertion */
- xfer->endpoint->isoc_next += xfer->nframes;
/* setup TDs */
avr32dci_setup_standard_chain(xfer);
{
struct dwc_otg_softc *sc = DWC_OTG_BUS2SC(xfer->xroot->bus);
uint32_t temp;
- uint32_t msframes;
uint32_t framenum;
- uint8_t shift = usbd_xfer_get_fps_shift(xfer);
DPRINTFN(6, "xfer=%p next=%d nframes=%d\n",
xfer, xfer->endpoint->isoc_next, xfer->nframes);
if (sc->sc_flags.status_high_speed)
framenum /= 8;
- framenum &= DWC_OTG_FRAME_MASK;
-
- /*
- * Compute number of milliseconds worth of data traffic for
- * this USB transfer:
- */
- if (xfer->xroot->udev->speed == USB_SPEED_HIGH)
- msframes = ((xfer->nframes << shift) + 7) / 8;
- else
- msframes = xfer->nframes;
-
- /*
- * check if the frame index is within the window where the frames
- * will be inserted
- */
- temp = (framenum - xfer->endpoint->isoc_next) & DWC_OTG_FRAME_MASK;
-
- if ((xfer->endpoint->is_synced == 0) || (temp < msframes)) {
- /*
- * If there is data underflow or the pipe queue is
- * empty we schedule the transfer a few frames ahead
- * of the current frame position. Else two isochronous
- * transfers might overlap.
- */
- xfer->endpoint->isoc_next = (framenum + 3) & DWC_OTG_FRAME_MASK;
- xfer->endpoint->is_synced = 1;
+ if (usbd_xfer_get_isochronous_start_frame(
+ xfer, framenum, 0, 1, DWC_OTG_FRAME_MASK, NULL))
DPRINTFN(3, "start next=%d\n", xfer->endpoint->isoc_next);
- }
- /*
- * compute how many milliseconds the insertion is ahead of the
- * current frame position:
- */
- temp = (xfer->endpoint->isoc_next - framenum) & DWC_OTG_FRAME_MASK;
-
- /*
- * pre-compute when the isochronous transfer will be finished:
- */
- xfer->isoc_time_complete =
- usb_isoc_time_expand(&sc->sc_bus, framenum) + temp + msframes;
/* setup TDs */
dwc_otg_setup_standard_chain(xfer);
- /* compute frame number for next insertion */
- xfer->endpoint->isoc_next += msframes;
-
/* start TD chain */
dwc_otg_start_standard_chain(xfer);
}
uint32_t *plen;
uint32_t buf_offset;
uint32_t nframes;
+ uint32_t startframe;
uint32_t temp;
uint32_t sitd_mask;
uint16_t tlen;
nframes = EOREAD4(sc, EHCI_FRINDEX) / 8;
- /*
- * check if the frame index is within the window where the frames
- * will be inserted
- */
- buf_offset = (nframes - xfer->endpoint->isoc_next) &
- (EHCI_VIRTUAL_FRAMELIST_COUNT - 1);
-
- if ((xfer->endpoint->is_synced == 0) ||
- (buf_offset < xfer->nframes)) {
- /*
- * If there is data underflow or the pipe queue is empty we
- * schedule the transfer a few frames ahead of the current
- * frame position. Else two isochronous transfers might
- * overlap.
- */
- xfer->endpoint->isoc_next = (nframes + 3) &
- (EHCI_VIRTUAL_FRAMELIST_COUNT - 1);
- xfer->endpoint->is_synced = 1;
- DPRINTFN(3, "start next=%d\n", xfer->endpoint->isoc_next);
- }
- /*
- * compute how many milliseconds the insertion is ahead of the
- * current frame position:
- */
- buf_offset = (xfer->endpoint->isoc_next - nframes) &
- (EHCI_VIRTUAL_FRAMELIST_COUNT - 1);
-
- /*
- * pre-compute when the isochronous transfer will be finished:
- */
- xfer->isoc_time_complete =
- usb_isoc_time_expand(&sc->sc_bus, nframes) +
- buf_offset + xfer->nframes;
+ if (usbd_xfer_get_isochronous_start_frame(
+ xfer, nframes, 0, 1, EHCI_VIRTUAL_FRAMELIST_COUNT - 1, &startframe))
+ DPRINTFN(3, "start next=%d\n", startframe);
/* get the real number of frames */
td = xfer->td_start[xfer->flags_int.curr_dma_set];
xfer->td_transfer_first = td;
- pp_last = &sc->sc_isoc_fs_p_last[xfer->endpoint->isoc_next];
+ pp_last = &sc->sc_isoc_fs_p_last[startframe];
/* store starting position */
- xfer->qh_pos = xfer->endpoint->isoc_next;
+ xfer->qh_pos = startframe;
while (nframes--) {
if (td == NULL) {
xfer->td_transfer_last = td_last;
- /* update isoc_next */
- xfer->endpoint->isoc_next = (pp_last - &sc->sc_isoc_fs_p_last[0]) &
- (EHCI_VIRTUAL_FRAMELIST_COUNT - 1);
-
/*
* We don't allow cancelling of the SPLIT transaction USB FULL
* speed transfer, because it disturbs the bandwidth
uint32_t status;
uint32_t buf_offset;
uint32_t nframes;
+ uint32_t startframe;
uint32_t itd_offset[8 + 1];
uint8_t x;
uint8_t td_no;
uint8_t page_no;
- uint8_t shift = usbd_xfer_get_fps_shift(xfer);
#ifdef USB_DEBUG
uint8_t once = 1;
#endif
DPRINTFN(6, "xfer=%p next=%d nframes=%d shift=%d\n",
- xfer, xfer->endpoint->isoc_next, xfer->nframes, (int)shift);
+ xfer, xfer->endpoint->isoc_next, xfer->nframes,
+ usbd_xfer_get_fps_shift(xfer));
/* get the current frame index */
nframes = EOREAD4(sc, EHCI_FRINDEX) / 8;
- /*
- * check if the frame index is within the window where the frames
- * will be inserted
- */
- buf_offset = (nframes - xfer->endpoint->isoc_next) &
- (EHCI_VIRTUAL_FRAMELIST_COUNT - 1);
-
- if ((xfer->endpoint->is_synced == 0) ||
- (buf_offset < (((xfer->nframes << shift) + 7) / 8))) {
- /*
- * If there is data underflow or the pipe queue is empty we
- * schedule the transfer a few frames ahead of the current
- * frame position. Else two isochronous transfers might
- * overlap.
- */
- xfer->endpoint->isoc_next = (nframes + 3) &
- (EHCI_VIRTUAL_FRAMELIST_COUNT - 1);
- xfer->endpoint->is_synced = 1;
- DPRINTFN(3, "start next=%d\n", xfer->endpoint->isoc_next);
- }
- /*
- * compute how many milliseconds the insertion is ahead of the
- * current frame position:
- */
- buf_offset = (xfer->endpoint->isoc_next - nframes) &
- (EHCI_VIRTUAL_FRAMELIST_COUNT - 1);
-
- /*
- * pre-compute when the isochronous transfer will be finished:
- */
- xfer->isoc_time_complete =
- usb_isoc_time_expand(&sc->sc_bus, nframes) + buf_offset +
- (((xfer->nframes << shift) + 7) / 8);
-
- /* get the real number of frames */
+ if (usbd_xfer_get_isochronous_start_frame(
+ xfer, nframes, 0, 1, EHCI_VIRTUAL_FRAMELIST_COUNT - 1, &startframe))
+ DPRINTFN(3, "start next=%d\n", startframe);
nframes = xfer->nframes;
td = xfer->td_start[xfer->flags_int.curr_dma_set];
xfer->td_transfer_first = td;
- pp_last = &sc->sc_isoc_hs_p_last[xfer->endpoint->isoc_next];
+ pp_last = &sc->sc_isoc_hs_p_last[startframe];
/* store starting position */
- xfer->qh_pos = xfer->endpoint->isoc_next;
+ xfer->qh_pos = startframe;
while (nframes) {
if (td == NULL) {
}
xfer->td_transfer_last = td_last;
-
- /* update isoc_next */
- xfer->endpoint->isoc_next = (pp_last - &sc->sc_isoc_hs_p_last[0]) &
- (EHCI_VIRTUAL_FRAMELIST_COUNT - 1);
}
static void
musbotg_device_isoc_enter(struct usb_xfer *xfer)
{
struct musbotg_softc *sc = MUSBOTG_BUS2SC(xfer->xroot->bus);
- uint32_t temp;
uint32_t nframes;
- uint32_t fs_frames;
DPRINTFN(5, "xfer=%p next=%d nframes=%d\n",
xfer, xfer->endpoint->isoc_next, xfer->nframes);
nframes = MUSB2_READ_2(sc, MUSB2_REG_FRAME);
- /*
- * check if the frame index is within the window where the frames
- * will be inserted
- */
- temp = (nframes - xfer->endpoint->isoc_next) & MUSB2_MASK_FRAME;
-
- if (usbd_get_speed(xfer->xroot->udev) == USB_SPEED_HIGH) {
- fs_frames = (xfer->nframes + 7) / 8;
- } else {
- fs_frames = xfer->nframes;
- }
-
- if ((xfer->endpoint->is_synced == 0) ||
- (temp < fs_frames)) {
- /*
- * If there is data underflow or the pipe queue is
- * empty we schedule the transfer a few frames ahead
- * of the current frame position. Else two isochronous
- * transfers might overlap.
- */
- xfer->endpoint->isoc_next = (nframes + 3) & MUSB2_MASK_FRAME;
- xfer->endpoint->is_synced = 1;
+ if (usbd_xfer_get_isochronous_start_frame(
+ xfer, nframes, 0, 1, MUSB2_MASK_FRAME, NULL))
DPRINTFN(2, "start next=%d\n", xfer->endpoint->isoc_next);
- }
- /*
- * compute how many milliseconds the insertion is ahead of the
- * current frame position:
- */
- temp = (xfer->endpoint->isoc_next - nframes) & MUSB2_MASK_FRAME;
-
- /*
- * pre-compute when the isochronous transfer will be finished:
- */
- xfer->isoc_time_complete =
- usb_isoc_time_expand(&sc->sc_bus, nframes) + temp +
- fs_frames;
-
- /* compute frame number for next insertion */
- xfer->endpoint->isoc_next += fs_frames;
/* setup TDs */
musbotg_setup_standard_chain(xfer);
struct ohci_hcca *hcca;
uint32_t buf_offset;
uint32_t nframes;
+ uint32_t startframe;
uint32_t ed_flags;
uint32_t *plen;
uint16_t itd_offset[OHCI_ITD_NOFFSET];
DPRINTFN(6, "xfer=%p isoc_next=%u nframes=%u hcca_fn=%u\n",
xfer, xfer->endpoint->isoc_next, xfer->nframes, nframes);
- if ((xfer->endpoint->is_synced == 0) ||
- (((nframes - xfer->endpoint->isoc_next) & 0xFFFF) < xfer->nframes) ||
- (((xfer->endpoint->isoc_next - nframes) & 0xFFFF) >= 128)) {
- /*
- * If there is data underflow or the pipe queue is empty we
- * schedule the transfer a few frames ahead of the current
- * frame position. Else two isochronous transfers might
- * overlap.
- */
- xfer->endpoint->isoc_next = (nframes + 3) & 0xFFFF;
- xfer->endpoint->is_synced = 1;
- DPRINTFN(3, "start next=%d\n", xfer->endpoint->isoc_next);
- }
- /*
- * compute how many milliseconds the insertion is ahead of the
- * current frame position:
- */
- buf_offset = ((xfer->endpoint->isoc_next - nframes) & 0xFFFF);
-
- /*
- * pre-compute when the isochronous transfer will be finished:
- */
- xfer->isoc_time_complete =
- (usb_isoc_time_expand(&sc->sc_bus, nframes) + buf_offset +
- xfer->nframes);
+ if (usbd_xfer_get_isochronous_start_frame(
+ xfer, nframes, 0, 1, 0xFFFF, &startframe))
+ DPRINTFN(3, "start next=%d\n", startframe);
/* get the real number of frames */
/* fill current ITD */
td->itd_flags = htole32(
OHCI_ITD_NOCC |
- OHCI_ITD_SET_SF(xfer->endpoint->isoc_next) |
+ OHCI_ITD_SET_SF(startframe) |
OHCI_ITD_NOINTR |
OHCI_ITD_SET_FC(ncur));
td->frames = ncur;
- xfer->endpoint->isoc_next += ncur;
+ startframe += ncur;
if (length == 0) {
/* all zero */
saf1761_otg_device_isoc_enter(struct usb_xfer *xfer)
{
struct saf1761_otg_softc *sc = SAF1761_OTG_BUS2SC(xfer->xroot->bus);
- uint32_t temp;
uint32_t nframes;
DPRINTFN(6, "xfer=%p next=%d nframes=%d\n",
nframes = SAF1761_READ_LE_4(sc, SOTG_FRAME_NUM);
- /*
- * check if the frame index is within the window where the
- * frames will be inserted
- */
- temp = (nframes - xfer->endpoint->isoc_next) & SOTG_FRAME_NUM_SOFR_MASK;
-
- if ((xfer->endpoint->is_synced == 0) ||
- (temp < xfer->nframes)) {
- /*
- * If there is data underflow or the pipe queue is
- * empty we schedule the transfer a few frames ahead
- * of the current frame position. Else two isochronous
- * transfers might overlap.
- */
- xfer->endpoint->isoc_next = (nframes + 3) & SOTG_FRAME_NUM_SOFR_MASK;
- xfer->endpoint->is_synced = 1;
+ if (usbd_xfer_get_isochronous_start_frame(
+ xfer, nframes, 0, 1, SOTG_FRAME_NUM_SOFR_MASK, NULL))
DPRINTFN(3, "start next=%d\n", xfer->endpoint->isoc_next);
- }
- /*
- * compute how many milliseconds the insertion is ahead of the
- * current frame position:
- */
- temp = (xfer->endpoint->isoc_next - nframes) & SOTG_FRAME_NUM_SOFR_MASK;
-
- /*
- * pre-compute when the isochronous transfer will be finished:
- */
- xfer->isoc_time_complete =
- usb_isoc_time_expand(&sc->sc_bus, nframes) + temp +
- xfer->nframes;
-
- /* compute frame number for next insertion */
- xfer->endpoint->isoc_next += xfer->nframes;
/* setup TDs */
saf1761_otg_setup_standard_chain(xfer);
saf1761_otg_host_isoc_enter(struct usb_xfer *xfer)
{
struct saf1761_otg_softc *sc = SAF1761_OTG_BUS2SC(xfer->xroot->bus);
- uint32_t temp;
uint32_t nframes;
DPRINTFN(6, "xfer=%p next=%d nframes=%d\n",
nframes = (SAF1761_READ_LE_4(sc, SOTG_FRINDEX) & SOTG_FRINDEX_MASK) >> 3;
- /*
- * check if the frame index is within the window where the
- * frames will be inserted
- */
- temp = (nframes - xfer->endpoint->isoc_next) & (SOTG_FRINDEX_MASK >> 3);
-
- if ((xfer->endpoint->is_synced == 0) ||
- (temp < xfer->nframes)) {
- /*
- * If there is data underflow or the pipe queue is
- * empty we schedule the transfer a few frames ahead
- * of the current frame position. Else two isochronous
- * transfers might overlap.
- */
- xfer->endpoint->isoc_next = (nframes + 3) & (SOTG_FRINDEX_MASK >> 3);
- xfer->endpoint->is_synced = 1;
+ if (usbd_xfer_get_isochronous_start_frame(
+ xfer, nframes, 0, 1, SOTG_FRINDEX_MASK >> 3, NULL))
DPRINTFN(3, "start next=%d\n", xfer->endpoint->isoc_next);
- }
- /*
- * compute how many milliseconds the insertion is ahead of the
- * current frame position:
- */
- temp = (xfer->endpoint->isoc_next - nframes) & (SOTG_FRINDEX_MASK >> 3);
-
- /*
- * pre-compute when the isochronous transfer will be finished:
- */
- xfer->isoc_time_complete =
- usb_isoc_time_expand(&sc->sc_bus, nframes) + temp +
- xfer->nframes;
-
- /* compute frame number for next insertion */
- xfer->endpoint->isoc_next += xfer->nframes;
/* setup TDs */
saf1761_otg_setup_standard_chain(xfer);
struct uhci_mem_layout ml;
uhci_softc_t *sc = UHCI_BUS2SC(xfer->xroot->bus);
uint32_t nframes;
- uint32_t temp;
+ uint32_t startframe;
uint32_t *plen;
#ifdef USB_DEBUG
nframes = UREAD2(sc, UHCI_FRNUM);
- temp = (nframes - xfer->endpoint->isoc_next) &
- (UHCI_VFRAMELIST_COUNT - 1);
-
- if ((xfer->endpoint->is_synced == 0) ||
- (temp < xfer->nframes)) {
- /*
- * If there is data underflow or the pipe queue is empty we
- * schedule the transfer a few frames ahead of the current
- * frame position. Else two isochronous transfers might
- * overlap.
- */
- xfer->endpoint->isoc_next = (nframes + 3) & (UHCI_VFRAMELIST_COUNT - 1);
- xfer->endpoint->is_synced = 1;
- DPRINTFN(3, "start next=%d\n", xfer->endpoint->isoc_next);
- }
- /*
- * compute how many milliseconds the insertion is ahead of the
- * current frame position:
- */
- temp = (xfer->endpoint->isoc_next - nframes) &
- (UHCI_VFRAMELIST_COUNT - 1);
-
- /*
- * pre-compute when the isochronous transfer will be finished:
- */
- xfer->isoc_time_complete =
- usb_isoc_time_expand(&sc->sc_bus, nframes) + temp +
- xfer->nframes;
+ if (usbd_xfer_get_isochronous_start_frame(
+ xfer, nframes, 0, 1, UHCI_VFRAMELIST_COUNT - 1, &startframe))
+ DPRINTFN(3, "start next=%d\n", startframe);
/* get the real number of frames */
td = xfer->td_start[xfer->flags_int.curr_dma_set];
xfer->td_transfer_first = td;
- pp_last = &sc->sc_isoc_p_last[xfer->endpoint->isoc_next];
+ pp_last = &sc->sc_isoc_p_last[startframe];
/* store starting position */
- xfer->qh_pos = xfer->endpoint->isoc_next;
+ xfer->qh_pos = startframe;
while (nframes--) {
if (td == NULL) {
}
xfer->td_transfer_last = td_last;
-
- /* update isoc_next */
- xfer->endpoint->isoc_next = (pp_last - &sc->sc_isoc_p_last[0]) &
- (UHCI_VFRAMELIST_COUNT - 1);
}
static void
uss820dci_device_isoc_fs_enter(struct usb_xfer *xfer)
{
struct uss820dci_softc *sc = USS820_DCI_BUS2SC(xfer->xroot->bus);
- uint32_t temp;
uint32_t nframes;
DPRINTFN(6, "xfer=%p next=%d nframes=%d\n",
nframes = USS820_READ_1(sc, USS820_SOFL);
- /*
- * check if the frame index is within the window where the
- * frames will be inserted
- */
- temp = (nframes - xfer->endpoint->isoc_next) & USS820_SOFL_MASK;
-
- if ((xfer->endpoint->is_synced == 0) ||
- (temp < xfer->nframes)) {
- /*
- * If there is data underflow or the pipe queue is
- * empty we schedule the transfer a few frames ahead
- * of the current frame position. Else two isochronous
- * transfers might overlap.
- */
- xfer->endpoint->isoc_next = (nframes + 3) & USS820_SOFL_MASK;
- xfer->endpoint->is_synced = 1;
+ if (usbd_xfer_get_isochronous_start_frame(
+ xfer, nframes, 0, 1, USS820_SOFL_MASK, NULL))
DPRINTFN(3, "start next=%d\n", xfer->endpoint->isoc_next);
- }
- /*
- * compute how many milliseconds the insertion is ahead of the
- * current frame position:
- */
- temp = (xfer->endpoint->isoc_next - nframes) & USS820_SOFL_MASK;
-
- /*
- * pre-compute when the isochronous transfer will be finished:
- */
- xfer->isoc_time_complete =
- usb_isoc_time_expand(&sc->sc_bus, nframes) + temp +
- xfer->nframes;
-
- /* compute frame number for next insertion */
- xfer->endpoint->isoc_next += xfer->nframes;
/* setup TDs */
uss820dci_setup_standard_chain(xfer);
uint32_t offset;
uint32_t max_packet_size;
uint32_t average;
+ uint32_t isoc_frame;
uint16_t isoc_delta;
- uint16_t isoc_frame;
uint8_t shortpkt;
uint8_t multishort;
uint8_t last_frame;
x = XREAD4(temp.sc, runt, XHCI_MFINDEX);
- DPRINTF("MFINDEX=0x%08x IST=0x%x\n", x, sc->sc_ist);
-
- /* add isochronous scheduling threshold */
- if (temp.sc->sc_ist & 8)
- x += (temp.sc->sc_ist & 7) << 3;
- else
- x += (temp.sc->sc_ist & 7);
+ DPRINTF("MFINDEX=0x%08x IST=0x%x\n", x, temp.sc->sc_ist);
switch (usbd_get_speed(xfer->xroot->udev)) {
case USB_SPEED_FULL:
shift = 3;
temp.isoc_delta = 8; /* 1ms */
- x += temp.isoc_delta - 1;
- x &= ~(temp.isoc_delta - 1);
break;
default:
shift = usbd_xfer_get_fps_shift(xfer);
temp.isoc_delta = 1U << shift;
- x += temp.isoc_delta - 1;
- x &= ~(temp.isoc_delta - 1);
- /* simple frame load balancing */
- x += xfer->endpoint->usb_uframe;
break;
}
- y = XHCI_MFINDEX_GET(x - xfer->endpoint->isoc_next);
+ /* Compute isochronous scheduling threshold. */
+ if (temp.sc->sc_ist & 8)
+ y = (temp.sc->sc_ist & 7) << 3;
+ else
+ y = (temp.sc->sc_ist & 7);
- if ((xfer->endpoint->is_synced == 0) ||
- (y < (xfer->nframes << shift)) ||
- (XHCI_MFINDEX_GET(-y) >= (128 * 8))) {
+ /* Range check the IST. */
+ if (y < 8) {
+ y = 0;
+ } else if (y > 15) {
+ DPRINTFN(3, "IST(%d) is too big!\n", temp.sc->sc_ist);
/*
- * If there is data underflow or the pipe
- * queue is empty we schedule the transfer a
- * few frames ahead of the current frame
- * position. Else two isochronous transfers
- * might overlap.
+ * The USB stack minimum isochronous transfer
+ * size is typically 2x2 ms of payload. If the
+ * IST makes is above 15 microframes, we have
+ * an effective scheduling delay of more than
+ * or equal to 2 milliseconds, which is too
+ * much.
*/
- xfer->endpoint->isoc_next = XHCI_MFINDEX_GET(x + (3 * 8));
- xfer->endpoint->is_synced = 1;
- temp.do_isoc_sync = 1;
-
- DPRINTFN(3, "start next=%d\n", xfer->endpoint->isoc_next);
+ y = 7;
+ } else {
+ /*
+ * Subtract one millisecond, because the
+ * generic code adds that to the latency.
+ */
+ y -= 8;
}
- /* compute isochronous completion time */
-
- y = XHCI_MFINDEX_GET(xfer->endpoint->isoc_next - (x & ~7));
+ if (usbd_xfer_get_isochronous_start_frame(
+ xfer, x, y, 8, XHCI_MFINDEX_GET(-1), &temp.isoc_frame)) {
+ /* Start isochronous transfer at specified time. */
+ temp.do_isoc_sync = 1;
- xfer->isoc_time_complete =
- usb_isoc_time_expand(&temp.sc->sc_bus, x / 8) +
- (y / 8) + (((xfer->nframes << shift) + 7) / 8);
+ DPRINTFN(3, "start next=%d\n", temp.isoc_frame);
+ }
x = 0;
- temp.isoc_frame = xfer->endpoint->isoc_next;
temp.trb_type = XHCI_TRB_TYPE_ISOCH;
- xfer->endpoint->isoc_next += xfer->nframes << shift;
-
} else if (xfer->flags_int.control_xfr) {
/* check if we should prepend a setup message */
static void
xhci_device_generic_open(struct usb_xfer *xfer)
{
- if (xfer->flags_int.isochronous_xfr) {
- switch (xfer->xroot->udev->speed) {
- case USB_SPEED_FULL:
- break;
- default:
- usb_hs_bandwidth_alloc(xfer);
- break;
- }
- }
+ DPRINTF("\n");
}
static void
DPRINTF("\n");
xhci_device_done(xfer, USB_ERR_CANCELLED);
-
- if (xfer->flags_int.isochronous_xfr) {
- switch (xfer->xroot->udev->speed) {
- case USB_SPEED_FULL:
- break;
- default:
- usb_hs_bandwidth_free(xfer);
- break;
- }
- }
}
static void
{
return (xfer->flags_int.maxp_was_clamped);
}
+
+/*
+ * The following function computes the next isochronous frame number
+ * where the first isochronous packet should be queued.
+ *
+ * The function returns non-zero if there was a discontinuity.
+ * Else zero is returned for normal operation.
+ */
+uint8_t
+usbd_xfer_get_isochronous_start_frame(struct usb_xfer *xfer, uint32_t frame_curr,
+ uint32_t frame_min, uint32_t frame_ms, uint32_t frame_mask, uint32_t *p_frame_start)
+{
+ uint32_t duration;
+ uint32_t delta;
+ uint8_t retval;
+ uint8_t shift;
+
+ /* Compute time ahead of current schedule. */
+ delta = (xfer->endpoint->isoc_next - frame_curr) & frame_mask;
+
+ /*
+ * Check if it is the first transfer or if the future frame
+ * delta is less than one millisecond or if the frame delta is
+ * negative:
+ */
+ if (xfer->endpoint->is_synced == 0 ||
+ delta < (frame_ms + frame_min) ||
+ delta > (frame_mask / 2)) {
+ /* Schedule transfer 2 milliseconds into the future. */
+ xfer->endpoint->isoc_next = (frame_curr + 2 * frame_ms + frame_min) & frame_mask;
+ xfer->endpoint->is_synced = 1;
+
+ retval = 1;
+ } else {
+ retval = 0;
+ }
+
+ /* Store start time, if any. */
+ if (p_frame_start != NULL)
+ *p_frame_start = xfer->endpoint->isoc_next & frame_mask;
+
+ /* Get relative completion time, in milliseconds. */
+ delta = xfer->endpoint->isoc_next - frame_curr + (frame_curr % frame_ms);
+ delta &= frame_mask;
+ delta /= frame_ms;
+
+ switch (usbd_get_speed(xfer->xroot->udev)) {
+ case USB_SPEED_FULL:
+ shift = 3;
+ break;
+ default:
+ shift = usbd_xfer_get_fps_shift(xfer);
+ break;
+ }
+
+ /* Get duration in milliseconds, rounded up. */
+ duration = ((xfer->nframes << shift) + 7) / 8;
+
+ /* Compute full 32-bit completion time, in milliseconds. */
+ xfer->isoc_time_complete =
+ usb_isoc_time_expand(xfer->xroot->bus, frame_curr / frame_ms) +
+ delta + duration;
+
+ /* Compute next isochronous frame. */
+ xfer->endpoint->isoc_next += duration * frame_ms;
+ xfer->endpoint->isoc_next &= frame_mask;
+
+ return (retval);
+}
void (*cb) (void *arg), usb_timeout_t ms);
usb_timeout_t usbd_get_dma_delay(struct usb_device *udev);
void usbd_transfer_power_ref(struct usb_xfer *xfer, int val);
+uint8_t usbd_xfer_get_isochronous_start_frame(struct usb_xfer *, uint32_t, uint32_t, uint32_t, uint32_t, uint32_t *);
#endif /* _USB_TRANSFER_H_ */