summaryrefslogtreecommitdiff
path: root/sys/dev/usb/uhci.c
diff options
context:
space:
mode:
Diffstat (limited to 'sys/dev/usb/uhci.c')
-rw-r--r--sys/dev/usb/uhci.c803
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;