From 69599e097b3d54ac3b0baffbb975d21adc76e328 Mon Sep 17 00:00:00 2001 From: pirofti Date: Sun, 13 Jul 2014 17:19:17 +0000 Subject: [PATCH] Keep track of port connections and port resets. Also notify upstream when a port finished reseting and when the connection status changes. Gets things further along to the point where pipe device transfer and control methods are required. --- sys/arch/octeon/dev/octhci.c | 42 +++++++++++++++++++++++++++++++++--- 1 file changed, 39 insertions(+), 3 deletions(-) diff --git a/sys/arch/octeon/dev/octhci.c b/sys/arch/octeon/dev/octhci.c index 4956bce79e7..bc186023041 100644 --- a/sys/arch/octeon/dev/octhci.c +++ b/sys/arch/octeon/dev/octhci.c @@ -1,4 +1,4 @@ -/* $OpenBSD: octhci.c,v 1.15 2014/07/13 10:58:19 pirofti Exp $ */ +/* $OpenBSD: octhci.c,v 1.16 2014/07/13 17:19:17 pirofti Exp $ */ /* * Copyright (c) 2014 Paul Irofti @@ -63,6 +63,10 @@ struct octhci_softc { char sc_vendor[16]; /* Vendor string for root hub */ int sc_id_vendor; /* Vendor ID for root hub */ + + int sc_port_connect; /* Device connected to port */ + int sc_port_change; /* Connect status changed */ + int sc_port_reset; /* Port reset finished */ }; struct pool *octhcixfer; @@ -395,6 +399,7 @@ octhci_intr1(struct octhci_softc *sc) } if (intsts & USBC_GINTSTS_DISCONNINT) { DPRINTFN(16, ("%s: disco interrupt\n", DEVNAME(sc))); + sc->sc_port_connect = 0; octhci_regc_set(sc, USBC_GINTSTS_OFFSET, USBC_GINTSTS_DISCONNINT); } @@ -424,11 +429,34 @@ octhci_intr1(struct octhci_softc *sc) return (1); } +#define OCTHCI_PS_CLEAR \ + (USBC_HPRT_PRTENCHNG | USBC_HPRT_PRTOVRCURRCHNG | USBC_HPRT_PRTCONNDET) int octhci_intr_host_port(struct octhci_softc *sc) { + struct usbd_xfer *xfer = sc->sc_intrxfer; + u_char *p; + int i, m; uint32_t hprt = octhci_regc_read(sc, USBC_HPRT_OFFSET); + if (xfer == NULL) + goto ack; + + p = KERNADDR(&xfer->dmabuf, 0); + m = min(sc->sc_noport, xfer->length * 8 - 1); + memset(p, 0, xfer->length); + for (i = 1; i <= m; i++) { + /* Pick out CHANGE bits from the status reg. */ + if (hprt & OCTHCI_PS_CLEAR) + p[i/8] |= 1 << (i%8); + } + DPRINTF(("%s: change=0x%02x\n", __func__, *p)); + xfer->actlen = xfer->length; + xfer->status = USBD_NORMAL_COMPLETION; + + usb_transfer_complete(xfer); + +ack: octhci_regc_write(sc, USBC_HPRT_OFFSET, hprt); /* Acknowledge */ return (USBD_NORMAL_COMPLETION); @@ -572,6 +600,7 @@ octhci_open(struct usbd_pipe *pipe) return (USBD_NORMAL_COMPLETION); } + DPRINTFN(16, ("%s: Not a Root Hub\n", DEVNAME(sc))); /* XXX: not supported yet */ return (USBD_INVAL); } @@ -883,6 +912,7 @@ octhci_root_ctrl_start(struct usbd_xfer *xfer) case UHF_C_PORT_RESET: octhci_regc_clear(sc, USBC_HPRT_OFFSET, USBC_HPRT_PRTRST); + sc->sc_port_reset = 0; break; default: err = USBD_IOERROR; @@ -943,8 +973,11 @@ octhci_root_ctrl_start(struct usbd_xfer *xfer) i = UPS_HIGH_SPEED; break; } - if (v & USBC_HPRT_PRTCONNSTS) + if (v & USBC_HPRT_PRTCONNSTS) { i |= UPS_CURRENT_CONNECT_STATUS; + sc->sc_port_change = (sc->sc_port_connect != 1); + sc->sc_port_connect = 1; + } if (v & USBC_HPRT_PRTENA) i |= UPS_PORT_ENABLED; if (v & USBC_HPRT_PRTOVRCURRACT) @@ -956,12 +989,14 @@ octhci_root_ctrl_start(struct usbd_xfer *xfer) USETW(ps.wPortStatus, i); i = 0; - if (v & USBC_HPRT_PRTCONNDET) + if (v & USBC_HPRT_PRTCONNDET || sc->sc_port_change) i |= UPS_C_CONNECT_STATUS; if (v & USBC_HPRT_PRTENCHNG) i |= UPS_C_PORT_ENABLED; if (v & USBC_HPRT_PRTOVRCURRCHNG) i |= UPS_C_OVERCURRENT_INDICATOR; + if (sc->sc_port_reset) + i |= UPS_C_PORT_RESET; USETW(ps.wPortChange, i); l = min(len, sizeof ps); @@ -1005,6 +1040,7 @@ octhci_root_ctrl_start(struct usbd_xfer *xfer) /* Terminate reset sequence. */ octhci_regc_clear(sc, USBC_HPRT_OFFSET, USBC_HPRT_PRTRST); + sc->sc_port_reset = 1; break; case UHF_PORT_POWER: DPRINTFN(3, ("set port power %d\n", index)); -- 2.20.1