Date: Sun, 8 Nov 2009 20:54:03 +0000 (UTC) From: Andrew Thompson <thompsa@FreeBSD.org> To: src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org Subject: svn commit: r199059 - in head/sys/dev/usb: . controller Message-ID: <200911082054.nA8Ks30X097596@svn.freebsd.org>
next in thread | raw e-mail | index | archive | help
Author: thompsa Date: Sun Nov 8 20:54:03 2009 New Revision: 199059 URL: http://svn.freebsd.org/changeset/base/199059 Log: improve support for high speed isochronous endpoints which does not run 1:1, but needs intervalling 1:2, 1:4 or 1:8 Submitted by: Hans Petter Selasky Modified: head/sys/dev/usb/controller/ehci.c head/sys/dev/usb/usb_core.h head/sys/dev/usb/usb_transfer.c head/sys/dev/usb/usbdi.h Modified: head/sys/dev/usb/controller/ehci.c ============================================================================== --- head/sys/dev/usb/controller/ehci.c Sun Nov 8 20:51:15 2009 (r199058) +++ head/sys/dev/usb/controller/ehci.c Sun Nov 8 20:54:03 2009 (r199059) @@ -2140,7 +2140,7 @@ ehci_isoc_hs_done(ehci_softc_t *sc, stru DPRINTFN(13, "xfer=%p endpoint=%p transfer done\n", xfer, xfer->endpoint); - while (nframes--) { + while (nframes) { if (td == NULL) { panic("%s:%d: out of TD's\n", __FUNCTION__, __LINE__); @@ -2162,21 +2162,26 @@ ehci_isoc_hs_done(ehci_softc_t *sc, stru DPRINTFN(2, "status=0x%08x, len=%u\n", status, len); - if (*plen >= len) { - /* - * The length is valid. NOTE: The complete - * length is written back into the status - * field, and not the remainder like with - * other transfer descriptor types. - */ - } else { - /* Invalid length - truncate */ - len = 0; - } + if (xfer->usb_smask & (1 << td_no)) { - *plen = len; + if (*plen >= len) { + /* + * The length is valid. NOTE: The + * complete length is written back + * into the status field, and not the + * remainder like with other transfer + * descriptor types. + */ + } else { + /* Invalid length - truncate */ + len = 0; + } + + *plen = len; + plen++; + nframes--; + } - plen++; td_no++; if ((td_no == 8) || (nframes == 0)) { @@ -2393,10 +2398,9 @@ static void ehci_device_intr_close(struct usb_xfer *xfer) { ehci_softc_t *sc = EHCI_BUS2SC(xfer->xroot->bus); - uint8_t slot; - slot = usb_intr_schedule_adjust - (xfer->xroot->udev, -(xfer->max_frame_size), xfer->usb_uframe); + usb_intr_schedule_adjust(xfer->xroot->udev, + -(xfer->max_frame_size), xfer->usb_uframe); sc->sc_intr_stat[xfer->qh_pos]--; @@ -2722,6 +2726,28 @@ ehci_device_isoc_hs_open(struct usb_xfer ehci_itd_t *td; uint32_t temp; uint8_t ds; + uint8_t slot; + + slot = usb_intr_schedule_adjust(xfer->xroot->udev, xfer->max_frame_size, + USB_HS_MICRO_FRAMES_MAX); + + xfer->usb_uframe = slot; + xfer->usb_cmask = 0; + + switch (usbd_xfer_get_fps_shift(xfer)) { + case 0: + xfer->usb_smask = 0xFF; + break; + case 1: + xfer->usb_smask = 0x55 << (slot & 1); + break; + case 2: + xfer->usb_smask = 0x11 << (slot & 3); + break; + default: + xfer->usb_smask = 0x01 << (slot & 7); + break; + } /* initialize all TD's */ @@ -2765,6 +2791,10 @@ ehci_device_isoc_hs_open(struct usb_xfer static void ehci_device_isoc_hs_close(struct usb_xfer *xfer) { + + usb_intr_schedule_adjust(xfer->xroot->udev, + -(xfer->max_frame_size), xfer->usb_uframe); + ehci_device_done(xfer, USB_ERR_CANCELLED); } @@ -2854,7 +2884,7 @@ ehci_device_isoc_hs_enter(struct usb_xfe xfer->qh_pos = xfer->endpoint->isoc_next; - while (nframes--) { + while (nframes) { if (td == NULL) { panic("%s:%d: out of TD's\n", __FUNCTION__, __LINE__); @@ -2874,13 +2904,21 @@ ehci_device_isoc_hs_enter(struct usb_xfe #endif *plen = xfer->max_frame_size; } - status = (EHCI_ITD_SET_LEN(*plen) | - EHCI_ITD_ACTIVE | - EHCI_ITD_SET_PG(0)); - td->itd_status[td_no] = htohc32(sc, status); - itd_offset[td_no] = buf_offset; - buf_offset += *plen; - plen++; + + if (xfer->usb_smask & (1 << td_no)) { + status = (EHCI_ITD_SET_LEN(*plen) | + EHCI_ITD_ACTIVE | + EHCI_ITD_SET_PG(0)); + td->itd_status[td_no] = htohc32(sc, status); + itd_offset[td_no] = buf_offset; + buf_offset += *plen; + plen++; + nframes --; + } else { + td->itd_status[td_no] = 0; /* not active */ + itd_offset[td_no] = buf_offset; + } + td_no++; if ((td_no == 8) || (nframes == 0)) { @@ -2937,7 +2975,7 @@ ehci_device_isoc_hs_enter(struct usb_xfe } /* set IOC bit if we are complete */ if (nframes == 0) { - td->itd_status[7] |= htohc32(sc, EHCI_ITD_IOC); + td->itd_status[td_no - 1] |= htohc32(sc, EHCI_ITD_IOC); } usb_pc_cpu_flush(td->page_cache); #if USB_DEBUG @@ -3583,7 +3621,8 @@ ehci_xfer_setup(struct usb_setup_params usbd_transfer_setup_sub(parm); - nitd = (xfer->nframes + 7) / 8; + nitd = ((xfer->nframes + 7) / 8) << + usbd_xfer_get_fps_shift(xfer); } else { Modified: head/sys/dev/usb/usb_core.h ============================================================================== --- head/sys/dev/usb/usb_core.h Sun Nov 8 20:51:15 2009 (r199058) +++ head/sys/dev/usb/usb_core.h Sun Nov 8 20:54:03 2009 (r199059) @@ -165,6 +165,7 @@ struct usb_xfer { uint8_t usb_cmask; uint8_t usb_uframe; uint8_t usb_state; + uint8_t fps_shift; /* down shift of FPS, 0..3 */ usb_error_t error; Modified: head/sys/dev/usb/usb_transfer.c ============================================================================== --- head/sys/dev/usb/usb_transfer.c Sun Nov 8 20:51:15 2009 (r199058) +++ head/sys/dev/usb/usb_transfer.c Sun Nov 8 20:54:03 2009 (r199059) @@ -416,9 +416,15 @@ usbd_transfer_setup_sub(struct usb_setup case USB_SPEED_LOW: case USB_SPEED_FULL: frame_limit = USB_MAX_FS_ISOC_FRAMES_PER_XFER; + xfer->fps_shift = 0; break; default: frame_limit = USB_MAX_HS_ISOC_FRAMES_PER_XFER; + xfer->fps_shift = edesc->bInterval; + if (xfer->fps_shift > 0) + xfer->fps_shift--; + if (xfer->fps_shift > 3) + xfer->fps_shift = 3; break; } @@ -1826,6 +1832,23 @@ usbd_xfer_get_frame(struct usb_xfer *xfe return (&xfer->frbuffers[frindex]); } +/*------------------------------------------------------------------------* + * usbd_xfer_get_fps_shift + * + * The following function is only useful for isochronous transfers. It + * returns how many times the frame execution rate has been shifted + * down. + * + * Return value: + * Success: 0..3 + * Failure: 0 + *------------------------------------------------------------------------*/ +uint8_t +usbd_xfer_get_fps_shift(struct usb_xfer *xfer) +{ + return (xfer->fps_shift); +} + usb_frlength_t usbd_xfer_frame_len(struct usb_xfer *xfer, usb_frcount_t frindex) { Modified: head/sys/dev/usb/usbdi.h ============================================================================== --- head/sys/dev/usb/usbdi.h Sun Nov 8 20:51:15 2009 (r199058) +++ head/sys/dev/usb/usbdi.h Sun Nov 8 20:54:03 2009 (r199059) @@ -478,6 +478,7 @@ void usbd_xfer_set_frame_offset(struct u usb_frlength_t usbd_xfer_max_len(struct usb_xfer *xfer); usb_frlength_t usbd_xfer_max_framelen(struct usb_xfer *xfer); usb_frcount_t usbd_xfer_max_frames(struct usb_xfer *xfer); +uint8_t usbd_xfer_get_fps_shift(struct usb_xfer *xfer); usb_frlength_t usbd_xfer_frame_len(struct usb_xfer *xfer, usb_frcount_t frindex); void usbd_xfer_set_frame_len(struct usb_xfer *xfer, usb_frcount_t frindex,
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?200911082054.nA8Ks30X097596>