diff options
Diffstat (limited to 'sys/dev/usb/uhci.c')
-rw-r--r-- | sys/dev/usb/uhci.c | 803 |
1 files changed, 441 insertions, 362 deletions
diff --git a/sys/dev/usb/uhci.c b/sys/dev/usb/uhci.c index daeeac9e198..0e003af212e 100644 --- a/sys/dev/usb/uhci.c +++ b/sys/dev/usb/uhci.c @@ -1,5 +1,5 @@ -/* $OpenBSD: uhci.c,v 1.14 2000/09/06 22:42:10 rahnds Exp $ */ -/* $NetBSD: uhci.c,v 1.110 2000/04/14 14:11:36 augustss Exp $ */ +/* $OpenBSD: uhci.c,v 1.15 2000/11/08 18:10:38 aaron Exp $ */ +/* $NetBSD: uhci.c,v 1.125 2000/09/23 21:00:10 augustss Exp $ */ /* $FreeBSD: src/sys/dev/usb/uhci.c,v 1.33 1999/11/17 22:33:41 n_hibma Exp $ */ /* @@ -79,6 +79,9 @@ #include <dev/usb/uhcireg.h> #include <dev/usb/uhcivar.h> +/* Use bandwidth reclamation for control transfers. Some devices choke on it. */ +/*#define UHCI_CTL_LOOP */ + #if defined(__FreeBSD__) #include <machine/clock.h> @@ -98,11 +101,29 @@ uhci_softc_t *thesc; #define DPRINTF(x) if (uhcidebug) printf x #define DPRINTFN(n,x) if (uhcidebug>(n)) printf x int uhcidebug = 0; +int uhcinoloop = 0; +#ifndef __NetBSD__ +#define bitmask_snprintf(q,f,b,l) snprintf((b), (l), "%b", (q), (f)) +#endif #else #define DPRINTF(x) #define DPRINTFN(n,x) #endif +/* + * The UHCI controller is little endian, so on big endian machines + * the data strored in memory needs to be swapped. + */ +#if defined(__FreeBSD__) || defined(__OpenBSD__) +#if BYTE_ORDER == BIG_ENDIAN +#define htole32(x) (bswap32(x)) +#define le32toh(x) (bswap32(x)) +#else +#define htole32(x) (x) +#define le32toh(x) (x) +#endif +#endif + struct uhci_pipe { struct usbd_pipe pipe; int nexttoggle; @@ -138,122 +159,127 @@ struct uhci_pipe { } u; }; -Static void uhci_busreset __P((uhci_softc_t *)); -Static void uhci_shutdown __P((void *v)); -Static void uhci_power __P((int, void *)); -Static usbd_status uhci_run __P((uhci_softc_t *, int run)); -Static uhci_soft_td_t *uhci_alloc_std __P((uhci_softc_t *)); -Static void uhci_free_std __P((uhci_softc_t *, uhci_soft_td_t *)); -Static uhci_soft_qh_t *uhci_alloc_sqh __P((uhci_softc_t *)); -Static void uhci_free_sqh __P((uhci_softc_t *, uhci_soft_qh_t *)); +Static void uhci_busreset(uhci_softc_t *); +Static void uhci_shutdown(void *v); +Static void uhci_power(int, void *); +Static usbd_status uhci_run(uhci_softc_t *, int run); +Static uhci_soft_td_t *uhci_alloc_std(uhci_softc_t *); +Static void uhci_free_std(uhci_softc_t *, uhci_soft_td_t *); +Static uhci_soft_qh_t *uhci_alloc_sqh(uhci_softc_t *); +Static void uhci_free_sqh(uhci_softc_t *, uhci_soft_qh_t *); #if 0 -Static void uhci_enter_ctl_q __P((uhci_softc_t *, uhci_soft_qh_t *, - uhci_intr_info_t *)); -Static void uhci_exit_ctl_q __P((uhci_softc_t *, uhci_soft_qh_t *)); +Static void uhci_enter_ctl_q(uhci_softc_t *, uhci_soft_qh_t *, + uhci_intr_info_t *); +Static void uhci_exit_ctl_q(uhci_softc_t *, uhci_soft_qh_t *); #endif -Static void uhci_free_std_chain __P((uhci_softc_t *, - uhci_soft_td_t *, uhci_soft_td_t *)); -Static usbd_status uhci_alloc_std_chain __P((struct uhci_pipe *, +Static void uhci_free_std_chain(uhci_softc_t *, + uhci_soft_td_t *, uhci_soft_td_t *); +Static usbd_status uhci_alloc_std_chain(struct uhci_pipe *, uhci_softc_t *, int, int, u_int16_t, usb_dma_t *, - uhci_soft_td_t **, uhci_soft_td_t **)); -Static void uhci_poll_hub __P((void *)); -Static void uhci_waitintr __P((uhci_softc_t *, - usbd_xfer_handle)); -Static void uhci_check_intr __P((uhci_softc_t *, - uhci_intr_info_t *)); -Static void uhci_idone __P((uhci_intr_info_t *)); - -Static void uhci_abort_xfer __P((usbd_xfer_handle, - usbd_status status)); - -Static void uhci_timeout __P((void *)); -Static void uhci_add_ctrl __P((uhci_softc_t *, uhci_soft_qh_t *)); -Static void uhci_add_bulk __P((uhci_softc_t *, uhci_soft_qh_t *)); -Static void uhci_remove_ctrl __P((uhci_softc_t *,uhci_soft_qh_t *)); -Static void uhci_remove_bulk __P((uhci_softc_t *,uhci_soft_qh_t *)); -Static int uhci_str __P((usb_string_descriptor_t *, int, char *)); - -Static usbd_status uhci_setup_isoc __P((usbd_pipe_handle pipe)); -Static void uhci_device_isoc_enter __P((usbd_xfer_handle)); - -Static usbd_status uhci_allocm __P((struct usbd_bus *, usb_dma_t *, - u_int32_t)); -Static void uhci_freem __P((struct usbd_bus *, usb_dma_t *)); - -Static usbd_xfer_handle uhci_allocx __P((struct usbd_bus *)); -Static void uhci_freex __P((struct usbd_bus *, usbd_xfer_handle)); - -Static usbd_status uhci_device_ctrl_transfer __P((usbd_xfer_handle)); -Static usbd_status uhci_device_ctrl_start __P((usbd_xfer_handle)); -Static void uhci_device_ctrl_abort __P((usbd_xfer_handle)); -Static void uhci_device_ctrl_close __P((usbd_pipe_handle)); -Static void uhci_device_ctrl_done __P((usbd_xfer_handle)); - -Static usbd_status uhci_device_intr_transfer __P((usbd_xfer_handle)); -Static usbd_status uhci_device_intr_start __P((usbd_xfer_handle)); -Static void uhci_device_intr_abort __P((usbd_xfer_handle)); -Static void uhci_device_intr_close __P((usbd_pipe_handle)); -Static void uhci_device_intr_done __P((usbd_xfer_handle)); - -Static usbd_status uhci_device_bulk_transfer __P((usbd_xfer_handle)); -Static usbd_status uhci_device_bulk_start __P((usbd_xfer_handle)); -Static void uhci_device_bulk_abort __P((usbd_xfer_handle)); -Static void uhci_device_bulk_close __P((usbd_pipe_handle)); -Static void uhci_device_bulk_done __P((usbd_xfer_handle)); - -Static usbd_status uhci_device_isoc_transfer __P((usbd_xfer_handle)); -Static usbd_status uhci_device_isoc_start __P((usbd_xfer_handle)); -Static void uhci_device_isoc_abort __P((usbd_xfer_handle)); -Static void uhci_device_isoc_close __P((usbd_pipe_handle)); -Static void uhci_device_isoc_done __P((usbd_xfer_handle)); - -Static usbd_status uhci_root_ctrl_transfer __P((usbd_xfer_handle)); -Static usbd_status uhci_root_ctrl_start __P((usbd_xfer_handle)); -Static void uhci_root_ctrl_abort __P((usbd_xfer_handle)); -Static void uhci_root_ctrl_close __P((usbd_pipe_handle)); -Static void uhci_root_ctrl_done __P((usbd_xfer_handle)); - -Static usbd_status uhci_root_intr_transfer __P((usbd_xfer_handle)); -Static usbd_status uhci_root_intr_start __P((usbd_xfer_handle)); -Static void uhci_root_intr_abort __P((usbd_xfer_handle)); -Static void uhci_root_intr_close __P((usbd_pipe_handle)); -Static void uhci_root_intr_done __P((usbd_xfer_handle)); - -Static usbd_status uhci_open __P((usbd_pipe_handle)); -Static void uhci_poll __P((struct usbd_bus *)); -Static void uhci_softintr __P((struct usbd_bus *)); - -Static usbd_status uhci_device_request __P((usbd_xfer_handle xfer)); - -Static void uhci_add_intr __P((uhci_softc_t *, uhci_soft_qh_t *)); -Static void uhci_remove_intr __P((uhci_softc_t*, uhci_soft_qh_t*)); -Static usbd_status uhci_device_setintr __P((uhci_softc_t *sc, - struct uhci_pipe *pipe, int ival)); - -Static void uhci_device_clear_toggle __P((usbd_pipe_handle pipe)); -Static void uhci_noop __P((usbd_pipe_handle pipe)); - -Static __inline__ uhci_soft_qh_t *uhci_find_prev_qh - __P((uhci_soft_qh_t *, uhci_soft_qh_t *)); + uhci_soft_td_t **, uhci_soft_td_t **); +Static void uhci_poll_hub(void *); +Static void uhci_waitintr(uhci_softc_t *, usbd_xfer_handle); +Static void uhci_check_intr(uhci_softc_t *, uhci_intr_info_t *); +Static void uhci_idone(uhci_intr_info_t *); + +Static void uhci_abort_xfer(usbd_xfer_handle, usbd_status status); + +Static void uhci_timeout(void *); +Static void uhci_add_ls_ctrl(uhci_softc_t *, uhci_soft_qh_t *); +Static void uhci_add_hs_ctrl(uhci_softc_t *, uhci_soft_qh_t *); +Static void uhci_add_bulk(uhci_softc_t *, uhci_soft_qh_t *); +Static void uhci_remove_ls_ctrl(uhci_softc_t *,uhci_soft_qh_t *); +Static void uhci_remove_hs_ctrl(uhci_softc_t *,uhci_soft_qh_t *); +Static void uhci_remove_bulk(uhci_softc_t *,uhci_soft_qh_t *); +Static int uhci_str(usb_string_descriptor_t *, int, char *); +Static void uhci_add_loop(uhci_softc_t *sc); +Static void uhci_rem_loop(uhci_softc_t *sc); + +Static usbd_status uhci_setup_isoc(usbd_pipe_handle pipe); +Static void uhci_device_isoc_enter(usbd_xfer_handle); + +Static usbd_status uhci_allocm(struct usbd_bus *, usb_dma_t *, u_int32_t); +Static void uhci_freem(struct usbd_bus *, usb_dma_t *); + +Static usbd_xfer_handle uhci_allocx(struct usbd_bus *); +Static void uhci_freex(struct usbd_bus *, usbd_xfer_handle); + +Static usbd_status uhci_device_ctrl_transfer(usbd_xfer_handle); +Static usbd_status uhci_device_ctrl_start(usbd_xfer_handle); +Static void uhci_device_ctrl_abort(usbd_xfer_handle); +Static void uhci_device_ctrl_close(usbd_pipe_handle); +Static void uhci_device_ctrl_done(usbd_xfer_handle); + +Static usbd_status uhci_device_intr_transfer(usbd_xfer_handle); +Static usbd_status uhci_device_intr_start(usbd_xfer_handle); +Static void uhci_device_intr_abort(usbd_xfer_handle); +Static void uhci_device_intr_close(usbd_pipe_handle); +Static void uhci_device_intr_done(usbd_xfer_handle); + +Static usbd_status uhci_device_bulk_transfer(usbd_xfer_handle); +Static usbd_status uhci_device_bulk_start(usbd_xfer_handle); +Static void uhci_device_bulk_abort(usbd_xfer_handle); +Static void uhci_device_bulk_close(usbd_pipe_handle); +Static void uhci_device_bulk_done(usbd_xfer_handle); + +Static usbd_status uhci_device_isoc_transfer(usbd_xfer_handle); +Static usbd_status uhci_device_isoc_start(usbd_xfer_handle); +Static void uhci_device_isoc_abort(usbd_xfer_handle); +Static void uhci_device_isoc_close(usbd_pipe_handle); +Static void uhci_device_isoc_done(usbd_xfer_handle); + +Static usbd_status uhci_root_ctrl_transfer(usbd_xfer_handle); +Static usbd_status uhci_root_ctrl_start(usbd_xfer_handle); +Static void uhci_root_ctrl_abort(usbd_xfer_handle); +Static void uhci_root_ctrl_close(usbd_pipe_handle); +Static void uhci_root_ctrl_done(usbd_xfer_handle); + +Static usbd_status uhci_root_intr_transfer(usbd_xfer_handle); +Static usbd_status uhci_root_intr_start(usbd_xfer_handle); +Static void uhci_root_intr_abort(usbd_xfer_handle); +Static void uhci_root_intr_close(usbd_pipe_handle); +Static void uhci_root_intr_done(usbd_xfer_handle); + +Static usbd_status uhci_open(usbd_pipe_handle); +Static void uhci_poll(struct usbd_bus *); +Static void uhci_softintr(struct usbd_bus *); + +Static usbd_status uhci_device_request(usbd_xfer_handle xfer); + +Static void uhci_add_intr(uhci_softc_t *, uhci_soft_qh_t *); +Static void uhci_remove_intr(uhci_softc_t*, uhci_soft_qh_t*); +Static usbd_status uhci_device_setintr(uhci_softc_t *sc, + struct uhci_pipe *pipe, int ival); + +Static void uhci_device_clear_toggle(usbd_pipe_handle pipe); +Static void uhci_noop(usbd_pipe_handle pipe); + +Static __inline__ uhci_soft_qh_t *uhci_find_prev_qh(uhci_soft_qh_t *, + uhci_soft_qh_t *); #ifdef UHCI_DEBUG -Static void uhci_dump_all __P((uhci_softc_t *)); -Static void uhci_dumpregs __P((uhci_softc_t *)); -Static void uhci_dump_qhs __P((uhci_soft_qh_t *)); -Static void uhci_dump_qh __P((uhci_soft_qh_t *)); -Static void uhci_dump_tds __P((uhci_soft_td_t *)); -Static void uhci_dump_td __P((uhci_soft_td_t *)); -Static void uhci_dump_ii __P((uhci_intr_info_t *ii)); -Static void uhci_dump __P((void)); -#endif - -#define UWRITE1(sc, r, x) bus_space_write_1((sc)->iot, (sc)->ioh, (r), (x)) -#define UWRITE2(sc, r, x) bus_space_write_2((sc)->iot, (sc)->ioh, (r), (x)) -#define UWRITE4(sc, r, x) bus_space_write_4((sc)->iot, (sc)->ioh, (r), (x)) -#define UREAD1(sc, r) bus_space_read_1((sc)->iot, (sc)->ioh, (r)) -#define UREAD2(sc, r) bus_space_read_2((sc)->iot, (sc)->ioh, (r)) -#define UREAD4(sc, r) bus_space_read_4((sc)->iot, (sc)->ioh, (r)) +Static void uhci_dump_all(uhci_softc_t *); +Static void uhci_dumpregs(uhci_softc_t *); +Static void uhci_dump_qhs(uhci_soft_qh_t *); +Static void uhci_dump_qh(uhci_soft_qh_t *); +Static void uhci_dump_tds(uhci_soft_td_t *); +Static void uhci_dump_td(uhci_soft_td_t *); +Static void uhci_dump_ii(uhci_intr_info_t *ii); +void uhci_dump(void); +#endif + +#define UBARR(sc) bus_space_barrier((sc)->iot, (sc)->ioh, 0, (sc)->sc_size, \ + BUS_SPACE_BARRIER_READ|BUS_SPACE_BARRIER_WRITE) +#define UWRITE1(sc, r, x) \ + do { UBARR(sc); bus_space_write_1((sc)->iot, (sc)->ioh, (r), (x)); } while (0) +#define UWRITE2(sc, r, x) \ + do { UBARR(sc); bus_space_write_2((sc)->iot, (sc)->ioh, (r), (x)); } while (0) +#define UWRITE4(sc, r, x) \ + do { UBARR(sc); bus_space_write_4((sc)->iot, (sc)->ioh, (r), (x)); } while (0) +#define UREAD1(sc, r) (UBARR(sc), bus_space_read_1((sc)->iot, (sc)->ioh, (r))) +#define UREAD2(sc, r) (UBARR(sc), bus_space_read_2((sc)->iot, (sc)->ioh, (r))) +#define UREAD4(sc, r) (UBARR(sc), bus_space_read_4((sc)->iot, (sc)->ioh, (r))) #define UHCICMD(sc, cmd) UWRITE2(sc, UHCI_CMD, cmd) #define UHCISTS(sc) UREAD2(sc, UHCI_STS) @@ -334,8 +360,7 @@ struct usbd_pipe_methods uhci_device_isoc_methods = { LIST_REMOVE((ii), list) Static __inline__ uhci_soft_qh_t * -uhci_find_prev_qh(pqh, sqh) - uhci_soft_qh_t *pqh, *sqh; +uhci_find_prev_qh(uhci_soft_qh_t *pqh, uhci_soft_qh_t *sqh) { DPRINTFN(15,("uhci_find_prev_qh: pqh=%p sqh=%p\n", pqh, sqh)); @@ -351,8 +376,7 @@ uhci_find_prev_qh(pqh, sqh) } void -uhci_busreset(sc) - uhci_softc_t *sc; +uhci_busreset(uhci_softc_t *sc) { UHCICMD(sc, UHCI_CMD_GRESET); /* global reset */ usb_delay_ms(&sc->sc_bus, USB_BUS_RESET_DELAY); /* wait a little */ @@ -360,12 +384,11 @@ uhci_busreset(sc) } usbd_status -uhci_init(sc) - uhci_softc_t *sc; +uhci_init(uhci_softc_t *sc) { usbd_status err; int i, j; - uhci_soft_qh_t *csqh, *bsqh, *sqh; + uhci_soft_qh_t *clsqh, *chsqh, *bsqh, *sqh, *lsqh; uhci_soft_td_t *std; DPRINTFN(1,("uhci_init: start\n")); @@ -392,22 +415,59 @@ uhci_init(sc) UWRITE2(sc, UHCI_FRNUM, 0); /* set frame number to 0 */ UWRITE4(sc, UHCI_FLBASEADDR, DMAADDR(&sc->sc_dma)); /* set frame list*/ + /* + * Allocate a TD, inactive, that hangs from the last QH. + * This is to avoid a bug in the PIIX that makes it run berserk + * otherwise. + */ + std = uhci_alloc_std(sc); + if (std == NULL) + return (USBD_NOMEM); + std->link.std = NULL; + std->td.td_link = htole32(UHCI_PTR_T); + std->td.td_status = htole32(0); /* inactive */ + std->td.td_token = htole32(0); + std->td.td_buffer = htole32(0); + + /* Allocate the dummy QH marking the end and used for looping the QHs.*/ + lsqh = uhci_alloc_sqh(sc); + if (lsqh == NULL) + return (USBD_NOMEM); + lsqh->hlink = NULL; + lsqh->qh.qh_hlink = htole32(UHCI_PTR_T); /* end of QH chain */ + lsqh->elink = std; + lsqh->qh.qh_elink = htole32(std->physaddr | UHCI_PTR_TD); + sc->sc_last_qh = lsqh; + /* Allocate the dummy QH where bulk traffic will be queued. */ bsqh = uhci_alloc_sqh(sc); if (bsqh == NULL) return (USBD_NOMEM); - bsqh->qh.qh_hlink = htole32(UHCI_PTR_T); /* end of QH chain */ + bsqh->hlink = lsqh; + bsqh->qh.qh_hlink = htole32(lsqh->physaddr | UHCI_PTR_QH); + bsqh->elink = NULL; bsqh->qh.qh_elink = htole32(UHCI_PTR_T); sc->sc_bulk_start = sc->sc_bulk_end = bsqh; - /* Allocate the dummy QH where control traffic will be queued. */ - csqh = uhci_alloc_sqh(sc); - if (csqh == NULL) + /* Allocate dummy QH where high speed control traffic will be queued. */ + chsqh = uhci_alloc_sqh(sc); + if (chsqh == NULL) + return (USBD_NOMEM); + chsqh->hlink = bsqh; + chsqh->qh.qh_hlink = htole32(bsqh->physaddr | UHCI_PTR_QH); + chsqh->elink = NULL; + chsqh->qh.qh_elink = htole32(UHCI_PTR_T); + sc->sc_hctl_start = sc->sc_hctl_end = chsqh; + + /* Allocate dummy QH where control traffic will be queued. */ + clsqh = uhci_alloc_sqh(sc); + if (clsqh == NULL) return (USBD_NOMEM); - csqh->hlink = bsqh; - csqh->qh.qh_hlink = htole32(bsqh->physaddr | UHCI_PTR_Q); - csqh->qh.qh_elink = htole32(UHCI_PTR_T); - sc->sc_ctl_start = sc->sc_ctl_end = csqh; + clsqh->hlink = bsqh; + clsqh->qh.qh_hlink = htole32(chsqh->physaddr | UHCI_PTR_QH); + clsqh->elink = NULL; + clsqh->qh.qh_elink = htole32(UHCI_PTR_T); + sc->sc_lctl_start = sc->sc_lctl_end = clsqh; /* * Make all (virtual) frame list pointers point to the interrupt @@ -420,13 +480,13 @@ uhci_init(sc) if (std == NULL || sqh == NULL) return (USBD_NOMEM); std->link.sqh = sqh; - std->td.td_link = htole32(sqh->physaddr | UHCI_PTR_Q); + std->td.td_link = htole32(sqh->physaddr | UHCI_PTR_QH); std->td.td_status = htole32(UHCI_TD_IOS); /* iso, inactive */ std->td.td_token = htole32(0); std->td.td_buffer = htole32(0); - sqh->hlink = csqh; - sqh->qh.qh_hlink = htole32(csqh->physaddr | UHCI_PTR_Q); - sqh->elink = 0; + sqh->hlink = clsqh; + sqh->qh.qh_hlink = htole32(clsqh->physaddr | UHCI_PTR_QH); + sqh->elink = NULL; sqh->qh.qh_elink = htole32(UHCI_PTR_T); sc->sc_vframes[i].htd = std; sc->sc_vframes[i].etd = std; @@ -465,9 +525,7 @@ uhci_init(sc) #if defined(__NetBSD__) || defined(__OpenBSD__) int -uhci_activate(self, act) - device_ptr_t self; - enum devact act; +uhci_activate(device_ptr_t self, enum devact act) { struct uhci_softc *sc = (struct uhci_softc *)self; int rv = 0; @@ -486,9 +544,7 @@ uhci_activate(self, act) } int -uhci_detach(sc, flags) - struct uhci_softc *sc; - int flags; +uhci_detach(struct uhci_softc *sc, int flags) { usbd_xfer_handle xfer; int rv = 0; @@ -520,10 +576,7 @@ uhci_detach(sc, flags) #endif usbd_status -uhci_allocm(bus, dma, size) - struct usbd_bus *bus; - usb_dma_t *dma; - u_int32_t size; +uhci_allocm(struct usbd_bus *bus, usb_dma_t *dma, u_int32_t size) { struct uhci_softc *sc = (struct uhci_softc *)bus; u_int32_t n; @@ -554,16 +607,13 @@ uhci_allocm(bus, dma, size) } void -uhci_freem(bus, dma) - struct usbd_bus *bus; - usb_dma_t *dma; +uhci_freem(struct usbd_bus *bus, usb_dma_t *dma) { usb_freemem(&((struct uhci_softc *)bus)->sc_bus, dma); } usbd_xfer_handle -uhci_allocx(bus) - struct usbd_bus *bus; +uhci_allocx(struct usbd_bus *bus) { struct uhci_softc *sc = (struct uhci_softc *)bus; usbd_xfer_handle xfer; @@ -594,9 +644,7 @@ uhci_allocx(bus) } void -uhci_freex(bus, xfer) - struct usbd_bus *bus; - usbd_xfer_handle xfer; +uhci_freex(struct usbd_bus *bus, usbd_xfer_handle xfer) { struct uhci_softc *sc = (struct uhci_softc *)bus; @@ -619,8 +667,7 @@ uhci_freex(bus, xfer) * Shut down the controller when the system is going down. */ void -uhci_shutdown(v) - void *v; +uhci_shutdown(void *v) { uhci_softc_t *sc = v; @@ -636,9 +683,7 @@ uhci_shutdown(v) * are almost suspended anyway. */ void -uhci_power(why, v) - int why; - void *v; +uhci_power(int why, void *v) { uhci_softc_t *sc = v; int cmd; @@ -706,8 +751,7 @@ uhci_power(why, v) #ifdef UHCI_DEBUG Static void -uhci_dumpregs(sc) - uhci_softc_t *sc; +uhci_dumpregs(uhci_softc_t *sc) { DPRINTFN(-1,("%s regs: cmd=%04x, sts=%04x, intr=%04x, frnum=%04x, " "flbase=%08x, sof=%04x, portsc1=%04x, portsc2=%04x\n", @@ -723,9 +767,10 @@ uhci_dumpregs(sc) } void -uhci_dump_td(p) - uhci_soft_td_t *p; +uhci_dump_td(uhci_soft_td_t *p) { + char sbuf[128], sbuf2[128]; + DPRINTFN(-1,("TD(%p) at %08lx = link=0x%08lx status=0x%08lx " "token=0x%08lx buffer=0x%08lx\n", p, (long)p->physaddr, @@ -733,13 +778,16 @@ uhci_dump_td(p) (long)le32toh(p->td.td_status), (long)le32toh(p->td.td_token), (long)le32toh(p->td.td_buffer))); - DPRINTFN(-1,(" %b %b,errcnt=%d,actlen=%d pid=%02x,addr=%d,endpt=%d," - "D=%d,maxlen=%d\n", - (int)le32toh(p->td.td_link), - "\20\1T\2Q\3VF", - (int)le32toh(p->td.td_status), - "\20\22BITSTUFF\23CRCTO\24NAK\25BABBLE\26DBUFFER\27" - "STALLED\30ACTIVE\31IOC\32ISO\33LS\36SPD", + + bitmask_snprintf((int)le32toh(p->td.td_link), "\20\1T\2Q\3VF", + sbuf, sizeof(sbuf)); + bitmask_snprintf((int)le32toh(p->td.td_status), + "\20\22BITSTUFF\23CRCTO\24NAK\25BABBLE\26DBUFFER\27" + "STALLED\30ACTIVE\31IOC\32ISO\33LS\36SPD", + sbuf2, sizeof(sbuf2)); + + DPRINTFN(-1,(" %s %s,errcnt=%d,actlen=%d pid=%02x,addr=%d,endpt=%d," + "D=%d,maxlen=%d\n", sbuf, sbuf2, UHCI_TD_GET_ERRCNT(le32toh(p->td.td_status)), UHCI_TD_GET_ACTLEN(le32toh(p->td.td_status)), UHCI_TD_GET_PID(le32toh(p->td.td_token)), @@ -750,8 +798,7 @@ uhci_dump_td(p) } void -uhci_dump_qh(sqh) - uhci_soft_qh_t *sqh; +uhci_dump_qh(uhci_soft_qh_t *sqh) { DPRINTFN(-1,("QH(%p) at %08x: hlink=%08x elink=%08x\n", sqh, (int)sqh->physaddr, le32toh(sqh->qh.qh_hlink), @@ -761,26 +808,24 @@ uhci_dump_qh(sqh) #if 1 void -uhci_dump() +uhci_dump(void) { uhci_dump_all(thesc); } #endif void -uhci_dump_all(sc) - uhci_softc_t *sc; +uhci_dump_all(uhci_softc_t *sc) { uhci_dumpregs(sc); printf("intrs=%d\n", sc->sc_bus.no_intrs); /*printf("framelist[i].link = %08x\n", sc->sc_framelist[0].link);*/ - uhci_dump_qh(sc->sc_ctl_start); + uhci_dump_qh(sc->sc_lctl_start); } void -uhci_dump_qhs(sqh) - uhci_soft_qh_t *sqh; +uhci_dump_qhs(uhci_soft_qh_t *sqh) { uhci_dump_qh(sqh); @@ -811,8 +856,7 @@ uhci_dump_qhs(sqh) } void -uhci_dump_tds(std) - uhci_soft_td_t *std; +uhci_dump_tds(uhci_soft_td_t *std) { uhci_soft_td_t *td; @@ -831,8 +875,7 @@ uhci_dump_tds(std) } Static void -uhci_dump_ii(ii) - uhci_intr_info_t *ii; +uhci_dump_ii(uhci_intr_info_t *ii) { usbd_pipe_handle pipe; usb_endpoint_descriptor_t *ed; @@ -869,10 +912,9 @@ uhci_dump_ii(ii) #undef DONE } -void uhci_dump_iis(struct uhci_softc *); +void uhci_dump_iis(struct uhci_softc *sc); void -uhci_dump_iis(sc) - struct uhci_softc *sc; +uhci_dump_iis(struct uhci_softc *sc) { uhci_intr_info_t *ii; @@ -882,7 +924,7 @@ uhci_dump_iis(sc) } void iidump(void); -void iidump() { uhci_dump_iis(thesc); } +void iidump(void) { uhci_dump_iis(thesc); } #endif @@ -891,8 +933,7 @@ void iidump() { uhci_dump_iis(thesc); } * from the root controller interrupt pipe for port status change. */ void -uhci_poll_hub(addr) - void *addr; +uhci_poll_hub(void *addr) { usbd_xfer_handle xfer = addr; usbd_pipe_handle pipe = xfer->pipe; @@ -924,59 +965,142 @@ uhci_poll_hub(addr) } void -uhci_root_intr_done(xfer) - usbd_xfer_handle xfer; +uhci_root_intr_done(usbd_xfer_handle xfer) { } void -uhci_root_ctrl_done(xfer) - usbd_xfer_handle xfer; +uhci_root_ctrl_done(usbd_xfer_handle xfer) { } -/* Add control QH, called at splusb(). */ +/* + * Let the last QH loop back to the high speed control transfer QH. + * This is what intel calls "bandwidth reclamation" and improves + * USB performance a lot for some devices. + * If we are already looping, just count it. + */ void -uhci_add_ctrl(sc, sqh) - uhci_softc_t *sc; - uhci_soft_qh_t *sqh; +uhci_add_loop(uhci_softc_t *sc) { +#ifdef UHCI_DEBUG + if (uhcinoloop) + return; +#endif + if (++sc->sc_loops == 1) { + DPRINTFN(5,("uhci_start_loop: add\n")); + /* Note, we don't loop back the soft pointer. */ + sc->sc_last_qh->qh.qh_hlink = + htole32(sc->sc_hctl_start->physaddr | UHCI_PTR_QH); + } +} + +void +uhci_rem_loop(uhci_softc_t *sc) { +#ifdef UHCI_DEBUG + if (uhcinoloop) + return; +#endif + if (--sc->sc_loops == 0) { + DPRINTFN(5,("uhci_end_loop: remove\n")); + sc->sc_last_qh->qh.qh_hlink = htole32(UHCI_PTR_T); + } +} + +/* Add high speed control QH, called at splusb(). */ +void +uhci_add_hs_ctrl(uhci_softc_t *sc, uhci_soft_qh_t *sqh) { uhci_soft_qh_t *eqh; SPLUSBCHECK; DPRINTFN(10, ("uhci_add_ctrl: sqh=%p\n", sqh)); - eqh = sc->sc_ctl_end; + eqh = sc->sc_hctl_end; sqh->hlink = eqh->hlink; sqh->qh.qh_hlink = eqh->qh.qh_hlink; eqh->hlink = sqh; - eqh->qh.qh_hlink = htole32(sqh->physaddr | UHCI_PTR_Q); - sc->sc_ctl_end = sqh; + eqh->qh.qh_hlink = htole32(sqh->physaddr | UHCI_PTR_QH); + sc->sc_hctl_end = sqh; +#ifdef UHCI_CTL_LOOP + uhci_add_loop(sc); +#endif } -/* Remove control QH, called at splusb(). */ +/* Remove high speed control QH, called at splusb(). */ void -uhci_remove_ctrl(sc, sqh) - uhci_softc_t *sc; - uhci_soft_qh_t *sqh; +uhci_remove_hs_ctrl(uhci_softc_t *sc, uhci_soft_qh_t *sqh) +{ + uhci_soft_qh_t *pqh; + + SPLUSBCHECK; + + DPRINTFN(10, ("uhci_remove_hs_ctrl: sqh=%p\n", sqh)); +#ifdef UHCI_CTL_LOOP + uhci_rem_loop(sc); +#endif + /* + * The T bit should be set in the elink of the QH so that the HC + * doesn't follow the pointer. This condition may fail if the + * the transferred packet was short so that the QH still points + * at the last used TD. + * In this case we set the T bit and wait a little for the HC + * to stop looking at the TD. + */ + if (!(sqh->qh.qh_elink & htole32(UHCI_PTR_T))) { + sqh->qh.qh_elink = htole32(UHCI_PTR_T); + delay(UHCI_QH_REMOVE_DELAY); + } + + pqh = uhci_find_prev_qh(sc->sc_hctl_start, sqh); + pqh->hlink = sqh->hlink; + pqh->qh.qh_hlink = sqh->qh.qh_hlink; + delay(UHCI_QH_REMOVE_DELAY); + if (sc->sc_hctl_end == sqh) + sc->sc_hctl_end = pqh; +} + +/* Add low speed control QH, called at splusb(). */ +void +uhci_add_ls_ctrl(uhci_softc_t *sc, uhci_soft_qh_t *sqh) +{ + uhci_soft_qh_t *eqh; + + SPLUSBCHECK; + + DPRINTFN(10, ("uhci_add_ls_ctrl: sqh=%p\n", sqh)); + eqh = sc->sc_lctl_end; + sqh->hlink = eqh->hlink; + sqh->qh.qh_hlink = eqh->qh.qh_hlink; + eqh->hlink = sqh; + eqh->qh.qh_hlink = htole32(sqh->physaddr | UHCI_PTR_QH); + sc->sc_lctl_end = sqh; +} + +/* Remove low speed control QH, called at splusb(). */ +void +uhci_remove_ls_ctrl(uhci_softc_t *sc, uhci_soft_qh_t *sqh) { uhci_soft_qh_t *pqh; SPLUSBCHECK; - DPRINTFN(10, ("uhci_remove_ctrl: sqh=%p\n", sqh)); - pqh = uhci_find_prev_qh(sc->sc_ctl_start, sqh); + DPRINTFN(10, ("uhci_remove_ls_ctrl: sqh=%p\n", sqh)); + /* See comment in uhci_remove_hs_ctrl() */ + if (!(sqh->qh.qh_elink & htole32(UHCI_PTR_T))) { + sqh->qh.qh_elink = htole32(UHCI_PTR_T); + delay(UHCI_QH_REMOVE_DELAY); + } + pqh = uhci_find_prev_qh(sc->sc_lctl_start, sqh); pqh->hlink = sqh->hlink; pqh->qh.qh_hlink = sqh->qh.qh_hlink; - if (sc->sc_ctl_end == sqh) - sc->sc_ctl_end = pqh; + delay(UHCI_QH_REMOVE_DELAY); + if (sc->sc_lctl_end == sqh) + sc->sc_lctl_end = pqh; } /* Add bulk QH, called at splusb(). */ void -uhci_add_bulk(sc, sqh) - uhci_softc_t *sc; - uhci_soft_qh_t *sqh; +uhci_add_bulk(uhci_softc_t *sc, uhci_soft_qh_t *sqh) { uhci_soft_qh_t *eqh; @@ -987,31 +1111,36 @@ uhci_add_bulk(sc, sqh) sqh->hlink = eqh->hlink; sqh->qh.qh_hlink = eqh->qh.qh_hlink; eqh->hlink = sqh; - eqh->qh.qh_hlink = htole32(sqh->physaddr | UHCI_PTR_Q); + eqh->qh.qh_hlink = htole32(sqh->physaddr | UHCI_PTR_QH); sc->sc_bulk_end = sqh; + uhci_add_loop(sc); } /* Remove bulk QH, called at splusb(). */ void -uhci_remove_bulk(sc, sqh) - uhci_softc_t *sc; - uhci_soft_qh_t *sqh; +uhci_remove_bulk(uhci_softc_t *sc, uhci_soft_qh_t *sqh) { uhci_soft_qh_t *pqh; SPLUSBCHECK; DPRINTFN(10, ("uhci_remove_bulk: sqh=%p\n", sqh)); + uhci_rem_loop(sc); + /* See comment in uhci_remove_hs_ctrl() */ + if (!(sqh->qh.qh_elink & htole32(UHCI_PTR_T))) { + sqh->qh.qh_elink = htole32(UHCI_PTR_T); + delay(UHCI_QH_REMOVE_DELAY); + } pqh = uhci_find_prev_qh(sc->sc_bulk_start, sqh); pqh->hlink = sqh->hlink; pqh->qh.qh_hlink = sqh->qh.qh_hlink; + delay(UHCI_QH_REMOVE_DELAY); if (sc->sc_bulk_end == sqh) sc->sc_bulk_end = pqh; } int -uhci_intr(arg) - void *arg; +uhci_intr(void *arg) { uhci_softc_t *sc = arg; int status; @@ -1046,7 +1175,9 @@ uhci_intr(arg) ack |= UHCI_STS_USBEI; if (status & UHCI_STS_RD) { ack |= UHCI_STS_RD; +#ifdef UHCI_DEBUG printf("%s: resume detect\n", USBDEVNAME(sc->sc_bus.bdev)); +#endif } if (status & UHCI_STS_HSE) { ack |= UHCI_STS_HSE; @@ -1082,8 +1213,7 @@ uhci_intr(arg) } void -uhci_softintr(bus) - struct usbd_bus *bus; +uhci_softintr(struct usbd_bus *bus) { uhci_softc_t *sc = (uhci_softc_t *)bus; uhci_intr_info_t *ii; @@ -1111,9 +1241,7 @@ uhci_softintr(bus) /* Check for an interrupt. */ void -uhci_check_intr(sc, ii) - uhci_softc_t *sc; - uhci_intr_info_t *ii; +uhci_check_intr(uhci_softc_t *sc, uhci_intr_info_t *ii) { uhci_soft_td_t *std, *lstd; u_int32_t status; @@ -1167,8 +1295,7 @@ uhci_check_intr(sc, ii) /* Called at splusb() */ void -uhci_idone(ii) - uhci_intr_info_t *ii; +uhci_idone(uhci_intr_info_t *ii) { usbd_xfer_handle xfer = ii->xfer; struct uhci_pipe *upipe = (struct uhci_pipe *)xfer->pipe; @@ -1258,14 +1385,21 @@ uhci_idone(ii) actlen, status)); xfer->actlen = actlen; if (status != 0) { +#ifdef UHCI_DEBUG + char sbuf[128]; + + bitmask_snprintf((int)status, "\20\22BITSTUFF\23CRCTO\24NAK\25" + "BABBLE\26DBUFFER\27STALLED\30ACTIVE", + sbuf, sizeof(sbuf)); + DPRINTFN((status == UHCI_TD_STALLED)*10, ("uhci_idone: error, addr=%d, endpt=0x%02x, " - "status 0x%b\n", + "status 0x%s\n", xfer->pipe->device->address, xfer->pipe->endpoint->edesc->bEndpointAddress, - (int)status, - "\20\22BITSTUFF\23CRCTO\24NAK\25BABBLE\26DBUFFER\27" - "STALLED\30ACTIVE")); + sbuf)); +#endif + if (status == UHCI_TD_STALLED) xfer->status = USBD_STALLED; else @@ -1280,8 +1414,7 @@ uhci_idone(ii) * Called when a request does not complete. */ void -uhci_timeout(addr) - void *addr; +uhci_timeout(void *addr) { uhci_intr_info_t *ii = addr; @@ -1304,9 +1437,7 @@ uhci_timeout(addr) * Only used during boot when interrupts are not enabled yet. */ void -uhci_waitintr(sc, xfer) - uhci_softc_t *sc; - usbd_xfer_handle xfer; +uhci_waitintr(uhci_softc_t *sc, usbd_xfer_handle xfer) { int timo = xfer->timeout; uhci_intr_info_t *ii; @@ -1338,8 +1469,7 @@ uhci_waitintr(sc, xfer) } void -uhci_poll(bus) - struct usbd_bus *bus; +uhci_poll(struct usbd_bus *bus) { uhci_softc_t *sc = (uhci_softc_t *)bus; @@ -1349,8 +1479,7 @@ uhci_poll(bus) #if 0 void -uhci_reset(sc) - uhci_softc_t *sc; +uhci_reset(uhci_softc_t *sc) { int n; @@ -1366,9 +1495,7 @@ uhci_reset(sc) #endif usbd_status -uhci_run(sc, run) - uhci_softc_t *sc; - int run; +uhci_run(uhci_softc_t *sc, int run) { int s, n, running; u_int16_t cmd; @@ -1410,8 +1537,7 @@ uhci_run(sc, run) */ uhci_soft_td_t * -uhci_alloc_std(sc) - uhci_softc_t *sc; +uhci_alloc_std(uhci_softc_t *sc) { uhci_soft_td_t *std; usbd_status err; @@ -1439,9 +1565,7 @@ uhci_alloc_std(sc) } void -uhci_free_std(sc, std) - uhci_softc_t *sc; - uhci_soft_td_t *std; +uhci_free_std(uhci_softc_t *sc, uhci_soft_td_t *std) { #ifdef DIAGNOSTIC #define TD_IS_FREE 0x12345678 @@ -1456,8 +1580,7 @@ uhci_free_std(sc, std) } uhci_soft_qh_t * -uhci_alloc_sqh(sc) - uhci_softc_t *sc; +uhci_alloc_sqh(uhci_softc_t *sc) { uhci_soft_qh_t *sqh; usbd_status err; @@ -1485,19 +1608,15 @@ uhci_alloc_sqh(sc) } void -uhci_free_sqh(sc, sqh) - uhci_softc_t *sc; - uhci_soft_qh_t *sqh; +uhci_free_sqh(uhci_softc_t *sc, uhci_soft_qh_t *sqh) { sqh->hlink = sc->sc_freeqhs; sc->sc_freeqhs = sqh; } void -uhci_free_std_chain(sc, std, stdend) - uhci_softc_t *sc; - uhci_soft_td_t *std; - uhci_soft_td_t *stdend; +uhci_free_std_chain(uhci_softc_t *sc, uhci_soft_td_t *std, + uhci_soft_td_t *stdend) { uhci_soft_td_t *p; @@ -1508,13 +1627,9 @@ uhci_free_std_chain(sc, std, stdend) } usbd_status -uhci_alloc_std_chain(upipe, sc, len, rd, flags, dma, sp, ep) - struct uhci_pipe *upipe; - uhci_softc_t *sc; - int len, rd; - u_int16_t flags; - usb_dma_t *dma; - uhci_soft_td_t **sp, **ep; +uhci_alloc_std_chain(struct uhci_pipe *upipe, uhci_softc_t *sc, int len, + int rd, u_int16_t flags, usb_dma_t *dma, + uhci_soft_td_t **sp, uhci_soft_td_t **ep) { uhci_soft_td_t *p, *lastp; uhci_physaddr_t lastlink; @@ -1544,7 +1659,7 @@ uhci_alloc_std_chain(upipe, sc, len, rd, flags, dma, sp, ep) if (ntd % 2 == 0) tog ^= 1; upipe->nexttoggle = tog ^ 1; - lastp = 0; + lastp = NULL; lastlink = UHCI_PTR_T; ntd--; status = UHCI_TD_ZERO_ACTLEN(UHCI_TD_SET_ERRCNT(3) | UHCI_TD_ACTIVE); @@ -1559,10 +1674,7 @@ uhci_alloc_std_chain(upipe, sc, len, rd, flags, dma, sp, ep) return (USBD_NOMEM); } p->link.std = lastp; - if (lastlink == UHCI_PTR_T) - p->td.td_link = htole32(lastlink); - else - p->td.td_link = htole32(lastlink|UHCI_PTR_VF); + p->td.td_link = htole32(lastlink | UHCI_PTR_VF | UHCI_PTR_TD); lastp = p; lastlink = p->physaddr; p->td.td_status = htole32(status); @@ -1587,22 +1699,19 @@ uhci_alloc_std_chain(upipe, sc, len, rd, flags, dma, sp, ep) } void -uhci_device_clear_toggle(pipe) - usbd_pipe_handle pipe; +uhci_device_clear_toggle(usbd_pipe_handle pipe) { struct uhci_pipe *upipe = (struct uhci_pipe *)pipe; upipe->nexttoggle = 0; } void -uhci_noop(pipe) - usbd_pipe_handle pipe; +uhci_noop(usbd_pipe_handle pipe) { } usbd_status -uhci_device_bulk_transfer(xfer) - usbd_xfer_handle xfer; +uhci_device_bulk_transfer(usbd_xfer_handle xfer) { usbd_status err; @@ -1619,8 +1728,7 @@ uhci_device_bulk_transfer(xfer) } usbd_status -uhci_device_bulk_start(xfer) - usbd_xfer_handle xfer; +uhci_device_bulk_start(usbd_xfer_handle xfer) { struct uhci_pipe *upipe = (struct uhci_pipe *)xfer->pipe; usbd_device_handle dev = upipe->pipe.device; @@ -1676,7 +1784,7 @@ uhci_device_bulk_start(xfer) #endif sqh->elink = data; - sqh->qh.qh_elink = htole32(data->physaddr); + sqh->qh.qh_elink = htole32(data->physaddr | UHCI_PTR_TD); s = splusb(); uhci_add_bulk(sc, sqh); @@ -1704,8 +1812,7 @@ uhci_device_bulk_start(xfer) /* Abort a device bulk request. */ void -uhci_device_bulk_abort(xfer) - usbd_xfer_handle xfer; +uhci_device_bulk_abort(usbd_xfer_handle xfer) { DPRINTF(("uhci_device_bulk_abort:\n")); uhci_abort_xfer(xfer, USBD_CANCELLED); @@ -1717,9 +1824,7 @@ uhci_device_bulk_abort(xfer) * I apologize for the delay(). */ void -uhci_abort_xfer(xfer, status) - usbd_xfer_handle xfer; - usbd_status status; +uhci_abort_xfer(usbd_xfer_handle xfer, usbd_status status) { uhci_intr_info_t *ii = &UXFER(xfer)->iinfo; uhci_soft_td_t *std; @@ -1762,8 +1867,7 @@ uhci_abort_xfer(xfer, status) /* Close a device bulk pipe. */ void -uhci_device_bulk_close(pipe) - usbd_pipe_handle pipe; +uhci_device_bulk_close(usbd_pipe_handle pipe) { struct uhci_pipe *upipe = (struct uhci_pipe *)pipe; usbd_device_handle dev = upipe->pipe.device; @@ -1773,8 +1877,7 @@ uhci_device_bulk_close(pipe) } usbd_status -uhci_device_ctrl_transfer(xfer) - usbd_xfer_handle xfer; +uhci_device_ctrl_transfer(usbd_xfer_handle xfer) { usbd_status err; @@ -1791,8 +1894,7 @@ uhci_device_ctrl_transfer(xfer) } usbd_status -uhci_device_ctrl_start(xfer) - usbd_xfer_handle xfer; +uhci_device_ctrl_start(usbd_xfer_handle xfer) { uhci_softc_t *sc = (uhci_softc_t *)xfer->pipe->device->bus; usbd_status err; @@ -1815,8 +1917,7 @@ uhci_device_ctrl_start(xfer) } usbd_status -uhci_device_intr_transfer(xfer) - usbd_xfer_handle xfer; +uhci_device_intr_transfer(usbd_xfer_handle xfer) { usbd_status err; @@ -1833,8 +1934,7 @@ uhci_device_intr_transfer(xfer) } usbd_status -uhci_device_intr_start(xfer) - usbd_xfer_handle xfer; +uhci_device_intr_start(usbd_xfer_handle xfer) { struct uhci_pipe *upipe = (struct uhci_pipe *)xfer->pipe; usbd_device_handle dev = upipe->pipe.device; @@ -1887,7 +1987,7 @@ uhci_device_intr_start(xfer) for (i = 0; i < upipe->u.intr.npoll; i++) { sqh = upipe->u.intr.qhs[i]; sqh->elink = data; - sqh->qh.qh_elink = htole32(data->physaddr); + sqh->qh.qh_elink = htole32(data->physaddr | UHCI_PTR_TD); } uhci_add_intr_info(sc, ii); xfer->status = USBD_IN_PROGRESS; @@ -1906,8 +2006,7 @@ uhci_device_intr_start(xfer) /* Abort a device control request. */ void -uhci_device_ctrl_abort(xfer) - usbd_xfer_handle xfer; +uhci_device_ctrl_abort(usbd_xfer_handle xfer) { DPRINTF(("uhci_device_ctrl_abort:\n")); uhci_abort_xfer(xfer, USBD_CANCELLED); @@ -1915,15 +2014,13 @@ uhci_device_ctrl_abort(xfer) /* Close a device control pipe. */ void -uhci_device_ctrl_close(pipe) - usbd_pipe_handle pipe; +uhci_device_ctrl_close(usbd_pipe_handle pipe) { } /* Abort a device interrupt request. */ void -uhci_device_intr_abort(xfer) - usbd_xfer_handle xfer; +uhci_device_intr_abort(usbd_xfer_handle xfer) { DPRINTFN(1,("uhci_device_intr_abort: xfer=%p\n", xfer)); if (xfer->pipe->intrxfer == xfer) { @@ -1935,8 +2032,7 @@ uhci_device_intr_abort(xfer) /* Close a device interrupt pipe. */ void -uhci_device_intr_close(pipe) - usbd_pipe_handle pipe; +uhci_device_intr_close(usbd_pipe_handle pipe) { struct uhci_pipe *upipe = (struct uhci_pipe *)pipe; uhci_softc_t *sc = (uhci_softc_t *)pipe->device->bus; @@ -1964,8 +2060,7 @@ uhci_device_intr_close(pipe) } usbd_status -uhci_device_request(xfer) - usbd_xfer_handle xfer; +uhci_device_request(usbd_xfer_handle xfer) { struct uhci_pipe *upipe = (struct uhci_pipe *)xfer->pipe; usb_device_request_t *req = &xfer->request; @@ -2005,7 +2100,7 @@ uhci_device_request(xfer) return (err); next = data; dataend->link.std = stat; - dataend->td.td_link = htole32(stat->physaddr | UHCI_PTR_VF); + dataend->td.td_link = htole32(stat->physaddr | UHCI_PTR_VF | UHCI_PTR_TD); } else { next = stat; } @@ -2014,7 +2109,7 @@ uhci_device_request(xfer) memcpy(KERNADDR(&upipe->u.ctl.reqdma), req, sizeof *req); setup->link.std = next; - setup->td.td_link = htole32(next->physaddr | UHCI_PTR_VF); + setup->td.td_link = htole32(next->physaddr | UHCI_PTR_VF | UHCI_PTR_TD); setup->td.td_status = htole32(UHCI_TD_SET_ERRCNT(3) | ls | UHCI_TD_ACTIVE); setup->td.td_token = htole32(UHCI_TD_SETUP(sizeof *req, endpt, addr)); @@ -2048,10 +2143,13 @@ uhci_device_request(xfer) #endif sqh->elink = setup; - sqh->qh.qh_elink = htole32(setup->physaddr); + sqh->qh.qh_elink = htole32(setup->physaddr | UHCI_PTR_TD); s = splusb(); - uhci_add_ctrl(sc, sqh); + if (dev->lowspeed) + uhci_add_ls_ctrl(sc, sqh); + else + uhci_add_hs_ctrl(sc, sqh); uhci_add_intr_info(sc, ii); #ifdef UHCI_DEBUG if (uhcidebug > 12) { @@ -2062,7 +2160,7 @@ uhci_device_request(xfer) uhci_physaddr_t link; DPRINTF(("uhci_enter_ctl_q: follow from [0]\n")); for (std = sc->sc_vframes[0].htd, link = 0; - (link & UHCI_PTR_Q) == 0; + (link & UHCI_PTR_QH) == 0; std = std->link.std) { link = le32toh(std->td.td_link); uhci_dump_td(std); @@ -2071,8 +2169,8 @@ uhci_device_request(xfer) uhci_dump_qh(sxqh); for (xqh = sxqh; xqh != NULL; - xqh = (maxqh++ == 5 || xqh->hlink==sxqh || - xqh->hlink==xqh ? NULL : xqh->hlink)) { + xqh = (maxqh++ == 5 || xqh->hlink == sxqh || + xqh->hlink == xqh ? NULL : xqh->hlink)) { uhci_dump_qh(xqh); } DPRINTF(("Enqueued QH:\n")); @@ -2091,8 +2189,7 @@ uhci_device_request(xfer) } usbd_status -uhci_device_isoc_transfer(xfer) - usbd_xfer_handle xfer; +uhci_device_isoc_transfer(usbd_xfer_handle xfer) { usbd_status err; @@ -2118,8 +2215,7 @@ uhci_device_isoc_transfer(xfer) } void -uhci_device_isoc_enter(xfer) - usbd_xfer_handle xfer; +uhci_device_isoc_enter(usbd_xfer_handle xfer) { struct uhci_pipe *upipe = (struct uhci_pipe *)xfer->pipe; usbd_device_handle dev = upipe->pipe.device; @@ -2189,8 +2285,7 @@ uhci_device_isoc_enter(xfer) } usbd_status -uhci_device_isoc_start(xfer) - usbd_xfer_handle xfer; +uhci_device_isoc_start(usbd_xfer_handle xfer) { struct uhci_pipe *upipe = (struct uhci_pipe *)xfer->pipe; uhci_softc_t *sc = (uhci_softc_t *)upipe->pipe.device->bus; @@ -2240,8 +2335,7 @@ uhci_device_isoc_start(xfer) } void -uhci_device_isoc_abort(xfer) - usbd_xfer_handle xfer; +uhci_device_isoc_abort(usbd_xfer_handle xfer) { struct uhci_pipe *upipe = (struct uhci_pipe *)xfer->pipe; uhci_soft_td_t **stds = upipe->u.iso.stds; @@ -2287,8 +2381,7 @@ uhci_device_isoc_abort(xfer) } void -uhci_device_isoc_close(pipe) - usbd_pipe_handle pipe; +uhci_device_isoc_close(usbd_pipe_handle pipe) { struct uhci_pipe *upipe = (struct uhci_pipe *)pipe; usbd_device_handle dev = upipe->pipe.device; @@ -2332,8 +2425,7 @@ uhci_device_isoc_close(pipe) } usbd_status -uhci_setup_isoc(pipe) - usbd_pipe_handle pipe; +uhci_setup_isoc(usbd_pipe_handle pipe) { struct uhci_pipe *upipe = (struct uhci_pipe *)pipe; usbd_device_handle dev = upipe->pipe.device; @@ -2371,7 +2463,7 @@ uhci_setup_isoc(pipe) std->link = vstd->link; std->td.td_link = vstd->td.td_link; vstd->link.std = std; - vstd->td.td_link = htole32(std->physaddr); + vstd->td.td_link = htole32(std->physaddr | UHCI_PTR_TD); } splx(s); @@ -2388,8 +2480,7 @@ uhci_setup_isoc(pipe) } void -uhci_device_isoc_done(xfer) - usbd_xfer_handle xfer; +uhci_device_isoc_done(usbd_xfer_handle xfer) { uhci_intr_info_t *ii = &UXFER(xfer)->iinfo; @@ -2422,8 +2513,7 @@ uhci_device_isoc_done(xfer) } void -uhci_device_intr_done(xfer) - usbd_xfer_handle xfer; +uhci_device_intr_done(usbd_xfer_handle xfer) { uhci_intr_info_t *ii = &UXFER(xfer)->iinfo; uhci_softc_t *sc = ii->sc; @@ -2436,7 +2526,7 @@ uhci_device_intr_done(xfer) npoll = upipe->u.intr.npoll; for(i = 0; i < npoll; i++) { sqh = upipe->u.intr.qhs[i]; - sqh->elink = 0; + sqh->elink = NULL; sqh->qh.qh_elink = htole32(UHCI_PTR_T); } uhci_free_std_chain(sc, ii->stdstart, 0); @@ -2471,7 +2561,7 @@ uhci_device_intr_done(xfer) for (i = 0; i < npoll; i++) { sqh = upipe->u.intr.qhs[i]; sqh->elink = data; - sqh->qh.qh_elink = htole32(data->physaddr); + sqh->qh.qh_elink = htole32(data->physaddr | UHCI_PTR_TD); } xfer->status = USBD_IN_PROGRESS; /* The ii is already on the examined list, just leave it. */ @@ -2483,8 +2573,7 @@ uhci_device_intr_done(xfer) /* Deallocate request data structures */ void -uhci_device_ctrl_done(xfer) - usbd_xfer_handle xfer; +uhci_device_ctrl_done(usbd_xfer_handle xfer) { uhci_intr_info_t *ii = &UXFER(xfer)->iinfo; uhci_softc_t *sc = ii->sc; @@ -2497,7 +2586,10 @@ uhci_device_ctrl_done(xfer) uhci_del_intr_info(ii); /* remove from active list */ - uhci_remove_ctrl(sc, upipe->u.ctl.sqh); + if (upipe->pipe.device->lowspeed) + uhci_remove_ls_ctrl(sc, upipe->u.ctl.sqh); + else + uhci_remove_hs_ctrl(sc, upipe->u.ctl.sqh); if (upipe->u.ctl.length != 0) uhci_free_std_chain(sc, ii->stdstart->link.std, ii->stdend); @@ -2507,8 +2599,7 @@ uhci_device_ctrl_done(xfer) /* Deallocate request data structures */ void -uhci_device_bulk_done(xfer) - usbd_xfer_handle xfer; +uhci_device_bulk_done(usbd_xfer_handle xfer) { uhci_intr_info_t *ii = &UXFER(xfer)->iinfo; uhci_softc_t *sc = ii->sc; @@ -2525,9 +2616,7 @@ uhci_device_bulk_done(xfer) /* Add interrupt QH, called with vflock. */ void -uhci_add_intr(sc, sqh) - uhci_softc_t *sc; - uhci_soft_qh_t *sqh; +uhci_add_intr(uhci_softc_t *sc, uhci_soft_qh_t *sqh) { struct uhci_vframe *vf = &sc->sc_vframes[sqh->pos]; uhci_soft_qh_t *eqh; @@ -2538,35 +2627,37 @@ uhci_add_intr(sc, sqh) sqh->hlink = eqh->hlink; sqh->qh.qh_hlink = eqh->qh.qh_hlink; eqh->hlink = sqh; - eqh->qh.qh_hlink = htole32(sqh->physaddr | UHCI_PTR_Q); + eqh->qh.qh_hlink = htole32(sqh->physaddr | UHCI_PTR_QH); vf->eqh = sqh; vf->bandwidth++; } /* Remove interrupt QH. */ void -uhci_remove_intr(sc, sqh) - uhci_softc_t *sc; - uhci_soft_qh_t *sqh; +uhci_remove_intr(uhci_softc_t *sc, uhci_soft_qh_t *sqh) { struct uhci_vframe *vf = &sc->sc_vframes[sqh->pos]; uhci_soft_qh_t *pqh; DPRINTFN(4, ("uhci_remove_intr: n=%d sqh=%p\n", sqh->pos, sqh)); + /* See comment in uhci_remove_ctrl() */ + if (!(sqh->qh.qh_elink & htole32(UHCI_PTR_T))) { + sqh->qh.qh_elink = htole32(UHCI_PTR_T); + delay(UHCI_QH_REMOVE_DELAY); + } + pqh = uhci_find_prev_qh(vf->hqh, sqh); pqh->hlink = sqh->hlink; pqh->qh.qh_hlink = sqh->qh.qh_hlink; + delay(UHCI_QH_REMOVE_DELAY); if (vf->eqh == sqh) vf->eqh = pqh; vf->bandwidth--; } usbd_status -uhci_device_setintr(sc, upipe, ival) - uhci_softc_t *sc; - struct uhci_pipe *upipe; - int ival; +uhci_device_setintr(uhci_softc_t *sc, struct uhci_pipe *upipe, int ival) { uhci_soft_qh_t *sqh; int i, npoll, s; @@ -2604,7 +2695,7 @@ uhci_device_setintr(sc, upipe, ival) for(i = 0; i < npoll; i++) { upipe->u.intr.qhs[i] = sqh = uhci_alloc_sqh(sc); - sqh->elink = 0; + sqh->elink = NULL; sqh->qh.qh_elink = htole32(UHCI_PTR_T); sqh->pos = MOD(i * ival + bestoffs); } @@ -2622,8 +2713,7 @@ uhci_device_setintr(sc, upipe, ival) /* Open a new pipe. */ usbd_status -uhci_open(pipe) - usbd_pipe_handle pipe; +uhci_open(usbd_pipe_handle pipe) { uhci_softc_t *sc = (uhci_softc_t *)pipe->device->bus; struct uhci_pipe *upipe = (struct uhci_pipe *)pipe; @@ -2761,10 +2851,7 @@ usb_hub_descriptor_t uhci_hubd_piix = { }; int -uhci_str(p, l, s) - usb_string_descriptor_t *p; - int l; - char *s; +uhci_str(usb_string_descriptor_t *p, int l, char *s) { int i; @@ -2784,8 +2871,7 @@ uhci_str(p, l, s) * Simulate a hardware hub by handling all the necessary requests. */ usbd_status -uhci_root_ctrl_transfer(xfer) - usbd_xfer_handle xfer; +uhci_root_ctrl_transfer(usbd_xfer_handle xfer) { usbd_status err; @@ -2802,8 +2888,7 @@ uhci_root_ctrl_transfer(xfer) } usbd_status -uhci_root_ctrl_start(xfer) - usbd_xfer_handle xfer; +uhci_root_ctrl_start(usbd_xfer_handle xfer) { uhci_softc_t *sc = (uhci_softc_t *)xfer->pipe->device->bus; usb_device_request_t *req; @@ -3094,12 +3179,12 @@ uhci_root_ctrl_start(xfer) case UHF_PORT_RESET: x = UREAD2(sc, port); UWRITE2(sc, port, x | UHCI_PORTSC_PR); - usb_delay_ms(&sc->sc_bus, 10); + usb_delay_ms(&sc->sc_bus, 50); /*XXX USB v1.1 7.1.7.3 */ UWRITE2(sc, port, x & ~UHCI_PORTSC_PR); delay(100); x = UREAD2(sc, port); UWRITE2(sc, port, x | UHCI_PORTSC_PE); - delay(100); + usb_delay_ms(&sc->sc_bus, 10); /* XXX */ DPRINTFN(3,("uhci port %d reset, status = 0x%04x\n", index, UREAD2(sc, port))); sc->sc_isreset = 1; @@ -3137,24 +3222,21 @@ uhci_root_ctrl_start(xfer) /* Abort a root control request. */ void -uhci_root_ctrl_abort(xfer) - usbd_xfer_handle xfer; +uhci_root_ctrl_abort(usbd_xfer_handle xfer) { /* Nothing to do, all transfers are synchronous. */ } /* Close the root pipe. */ void -uhci_root_ctrl_close(pipe) - usbd_pipe_handle pipe; +uhci_root_ctrl_close(usbd_pipe_handle pipe) { DPRINTF(("uhci_root_ctrl_close\n")); } /* Abort a root interrupt request. */ void -uhci_root_intr_abort(xfer) - usbd_xfer_handle xfer; +uhci_root_intr_abort(usbd_xfer_handle xfer) { uhci_softc_t *sc = (uhci_softc_t *)xfer->pipe->device->bus; @@ -3173,8 +3255,7 @@ uhci_root_intr_abort(xfer) } usbd_status -uhci_root_intr_transfer(xfer) - usbd_xfer_handle xfer; +uhci_root_intr_transfer(usbd_xfer_handle xfer) { usbd_status err; @@ -3191,8 +3272,7 @@ uhci_root_intr_transfer(xfer) /* Start a transfer on the root interrupt pipe */ usbd_status -uhci_root_intr_start(xfer) - usbd_xfer_handle xfer; +uhci_root_intr_start(usbd_xfer_handle xfer) { usbd_pipe_handle pipe = xfer->pipe; uhci_softc_t *sc = (uhci_softc_t *)pipe->device->bus; @@ -3211,8 +3291,7 @@ uhci_root_intr_start(xfer) /* Close the root interrupt pipe. */ void -uhci_root_intr_close(pipe) - usbd_pipe_handle pipe; +uhci_root_intr_close(usbd_pipe_handle pipe) { uhci_softc_t *sc = (uhci_softc_t *)pipe->device->bus; |