Annotation of sys/dev/usb/uhci.c, Revision 1.1
1.1 ! nbrk 1: /* $OpenBSD: uhci.c,v 1.61 2007/07/20 14:31:17 mbalmer Exp $ */
! 2: /* $NetBSD: uhci.c,v 1.172 2003/02/23 04:19:26 simonb Exp $ */
! 3: /* $FreeBSD: src/sys/dev/usb/uhci.c,v 1.33 1999/11/17 22:33:41 n_hibma Exp $ */
! 4:
! 5: /*
! 6: * Copyright (c) 1998 The NetBSD Foundation, Inc.
! 7: * All rights reserved.
! 8: *
! 9: * This code is derived from software contributed to The NetBSD Foundation
! 10: * by Lennart Augustsson (lennart@augustsson.net) at
! 11: * Carlstedt Research & Technology.
! 12: *
! 13: * Redistribution and use in source and binary forms, with or without
! 14: * modification, are permitted provided that the following conditions
! 15: * are met:
! 16: * 1. Redistributions of source code must retain the above copyright
! 17: * notice, this list of conditions and the following disclaimer.
! 18: * 2. Redistributions in binary form must reproduce the above copyright
! 19: * notice, this list of conditions and the following disclaimer in the
! 20: * documentation and/or other materials provided with the distribution.
! 21: * 3. All advertising materials mentioning features or use of this software
! 22: * must display the following acknowledgement:
! 23: * This product includes software developed by the NetBSD
! 24: * Foundation, Inc. and its contributors.
! 25: * 4. Neither the name of The NetBSD Foundation nor the names of its
! 26: * contributors may be used to endorse or promote products derived
! 27: * from this software without specific prior written permission.
! 28: *
! 29: * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
! 30: * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
! 31: * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
! 32: * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
! 33: * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
! 34: * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
! 35: * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
! 36: * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
! 37: * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
! 38: * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
! 39: * POSSIBILITY OF SUCH DAMAGE.
! 40: */
! 41:
! 42: /*
! 43: * USB Universal Host Controller driver.
! 44: * Handles e.g. PIIX3 and PIIX4.
! 45: *
! 46: * UHCI spec: http://download.intel.com/technology/usb/UHCI11D.pdf
! 47: * USB spec: http://www.usb.org/developers/docs/usbspec.zip
! 48: * PIIXn spec: ftp://download.intel.com/design/intarch/datashts/29055002.pdf
! 49: * ftp://download.intel.com/design/intarch/datashts/29056201.pdf
! 50: */
! 51:
! 52: #include <sys/param.h>
! 53: #include <sys/systm.h>
! 54: #include <sys/kernel.h>
! 55: #include <sys/malloc.h>
! 56: #include <sys/device.h>
! 57: #include <sys/selinfo.h>
! 58: #include <sys/proc.h>
! 59: #include <sys/queue.h>
! 60:
! 61: #include <machine/bus.h>
! 62: #include <machine/endian.h>
! 63:
! 64: #include <dev/usb/usb.h>
! 65: #include <dev/usb/usbdi.h>
! 66: #include <dev/usb/usbdivar.h>
! 67: #include <dev/usb/usb_mem.h>
! 68: #include <dev/usb/usb_quirks.h>
! 69:
! 70: #include <dev/usb/uhcireg.h>
! 71: #include <dev/usb/uhcivar.h>
! 72:
! 73: /* Use bandwidth reclamation for control transfers. Some devices choke on it. */
! 74: /*#define UHCI_CTL_LOOP */
! 75:
! 76: struct cfdriver uhci_cd = {
! 77: NULL, "uhci", DV_DULL
! 78: };
! 79:
! 80: #ifdef UHCI_DEBUG
! 81: uhci_softc_t *thesc;
! 82: #define DPRINTF(x) if (uhcidebug) printf x
! 83: #define DPRINTFN(n,x) if (uhcidebug>(n)) printf x
! 84: int uhcidebug = 0;
! 85: int uhcinoloop = 0;
! 86: #define bitmask_snprintf(q,f,b,l) snprintf((b), (l), "%b", (q), (f))
! 87: #else
! 88: #define DPRINTF(x)
! 89: #define DPRINTFN(n,x)
! 90: #endif
! 91:
! 92: #define mstohz(ms) ((ms) * hz / 1000)
! 93:
! 94: /*
! 95: * The UHCI controller is little endian, so on big endian machines
! 96: * the data stored in memory needs to be swapped.
! 97: */
! 98:
! 99: struct uhci_pipe {
! 100: struct usbd_pipe pipe;
! 101: int nexttoggle;
! 102:
! 103: u_char aborting;
! 104: usbd_xfer_handle abortstart, abortend;
! 105:
! 106: /* Info needed for different pipe kinds. */
! 107: union {
! 108: /* Control pipe */
! 109: struct {
! 110: uhci_soft_qh_t *sqh;
! 111: usb_dma_t reqdma;
! 112: uhci_soft_td_t *setup, *stat;
! 113: u_int length;
! 114: } ctl;
! 115: /* Interrupt pipe */
! 116: struct {
! 117: int npoll;
! 118: int isread;
! 119: uhci_soft_qh_t **qhs;
! 120: } intr;
! 121: /* Bulk pipe */
! 122: struct {
! 123: uhci_soft_qh_t *sqh;
! 124: u_int length;
! 125: int isread;
! 126: } bulk;
! 127: /* Iso pipe */
! 128: struct iso {
! 129: uhci_soft_td_t **stds;
! 130: int next, inuse;
! 131: } iso;
! 132: } u;
! 133: };
! 134:
! 135: void uhci_globalreset(uhci_softc_t *);
! 136: usbd_status uhci_portreset(uhci_softc_t*, int);
! 137: void uhci_reset(uhci_softc_t *);
! 138: void uhci_shutdown(void *v);
! 139: void uhci_power(int, void *);
! 140: usbd_status uhci_run(uhci_softc_t *, int run);
! 141: uhci_soft_td_t *uhci_alloc_std(uhci_softc_t *);
! 142: void uhci_free_std(uhci_softc_t *, uhci_soft_td_t *);
! 143: uhci_soft_qh_t *uhci_alloc_sqh(uhci_softc_t *);
! 144: void uhci_free_sqh(uhci_softc_t *, uhci_soft_qh_t *);
! 145: #if 0
! 146: void uhci_enter_ctl_q(uhci_softc_t *, uhci_soft_qh_t *,
! 147: uhci_intr_info_t *);
! 148: void uhci_exit_ctl_q(uhci_softc_t *, uhci_soft_qh_t *);
! 149: #endif
! 150:
! 151: void uhci_free_std_chain(uhci_softc_t *,
! 152: uhci_soft_td_t *, uhci_soft_td_t *);
! 153: usbd_status uhci_alloc_std_chain(struct uhci_pipe *,
! 154: uhci_softc_t *, int, int, u_int16_t, usb_dma_t *,
! 155: uhci_soft_td_t **, uhci_soft_td_t **);
! 156: void uhci_poll_hub(void *);
! 157: void uhci_waitintr(uhci_softc_t *, usbd_xfer_handle);
! 158: void uhci_check_intr(uhci_softc_t *, uhci_intr_info_t *);
! 159: void uhci_idone(uhci_intr_info_t *);
! 160:
! 161: void uhci_abort_xfer(usbd_xfer_handle, usbd_status status);
! 162:
! 163: void uhci_timeout(void *);
! 164: void uhci_timeout_task(void *);
! 165: void uhci_add_ls_ctrl(uhci_softc_t *, uhci_soft_qh_t *);
! 166: void uhci_add_hs_ctrl(uhci_softc_t *, uhci_soft_qh_t *);
! 167: void uhci_add_bulk(uhci_softc_t *, uhci_soft_qh_t *);
! 168: void uhci_remove_ls_ctrl(uhci_softc_t *,uhci_soft_qh_t *);
! 169: void uhci_remove_hs_ctrl(uhci_softc_t *,uhci_soft_qh_t *);
! 170: void uhci_remove_bulk(uhci_softc_t *,uhci_soft_qh_t *);
! 171: int uhci_str(usb_string_descriptor_t *, int, char *);
! 172: void uhci_add_loop(uhci_softc_t *sc);
! 173: void uhci_rem_loop(uhci_softc_t *sc);
! 174:
! 175: usbd_status uhci_setup_isoc(usbd_pipe_handle pipe);
! 176: void uhci_device_isoc_enter(usbd_xfer_handle);
! 177:
! 178: usbd_status uhci_allocm(struct usbd_bus *, usb_dma_t *, u_int32_t);
! 179: void uhci_freem(struct usbd_bus *, usb_dma_t *);
! 180:
! 181: usbd_xfer_handle uhci_allocx(struct usbd_bus *);
! 182: void uhci_freex(struct usbd_bus *, usbd_xfer_handle);
! 183:
! 184: usbd_status uhci_device_ctrl_transfer(usbd_xfer_handle);
! 185: usbd_status uhci_device_ctrl_start(usbd_xfer_handle);
! 186: void uhci_device_ctrl_abort(usbd_xfer_handle);
! 187: void uhci_device_ctrl_close(usbd_pipe_handle);
! 188: void uhci_device_ctrl_done(usbd_xfer_handle);
! 189:
! 190: usbd_status uhci_device_intr_transfer(usbd_xfer_handle);
! 191: usbd_status uhci_device_intr_start(usbd_xfer_handle);
! 192: void uhci_device_intr_abort(usbd_xfer_handle);
! 193: void uhci_device_intr_close(usbd_pipe_handle);
! 194: void uhci_device_intr_done(usbd_xfer_handle);
! 195:
! 196: usbd_status uhci_device_bulk_transfer(usbd_xfer_handle);
! 197: usbd_status uhci_device_bulk_start(usbd_xfer_handle);
! 198: void uhci_device_bulk_abort(usbd_xfer_handle);
! 199: void uhci_device_bulk_close(usbd_pipe_handle);
! 200: void uhci_device_bulk_done(usbd_xfer_handle);
! 201:
! 202: usbd_status uhci_device_isoc_transfer(usbd_xfer_handle);
! 203: usbd_status uhci_device_isoc_start(usbd_xfer_handle);
! 204: void uhci_device_isoc_abort(usbd_xfer_handle);
! 205: void uhci_device_isoc_close(usbd_pipe_handle);
! 206: void uhci_device_isoc_done(usbd_xfer_handle);
! 207:
! 208: usbd_status uhci_root_ctrl_transfer(usbd_xfer_handle);
! 209: usbd_status uhci_root_ctrl_start(usbd_xfer_handle);
! 210: void uhci_root_ctrl_abort(usbd_xfer_handle);
! 211: void uhci_root_ctrl_close(usbd_pipe_handle);
! 212: void uhci_root_ctrl_done(usbd_xfer_handle);
! 213:
! 214: usbd_status uhci_root_intr_transfer(usbd_xfer_handle);
! 215: usbd_status uhci_root_intr_start(usbd_xfer_handle);
! 216: void uhci_root_intr_abort(usbd_xfer_handle);
! 217: void uhci_root_intr_close(usbd_pipe_handle);
! 218: void uhci_root_intr_done(usbd_xfer_handle);
! 219:
! 220: usbd_status uhci_open(usbd_pipe_handle);
! 221: void uhci_poll(struct usbd_bus *);
! 222: void uhci_softintr(void *);
! 223:
! 224: usbd_status uhci_device_request(usbd_xfer_handle xfer);
! 225:
! 226: void uhci_add_intr(uhci_softc_t *, uhci_soft_qh_t *);
! 227: void uhci_remove_intr(uhci_softc_t *, uhci_soft_qh_t *);
! 228: usbd_status uhci_device_setintr(uhci_softc_t *sc,
! 229: struct uhci_pipe *pipe, int ival);
! 230:
! 231: void uhci_device_clear_toggle(usbd_pipe_handle pipe);
! 232: void uhci_noop(usbd_pipe_handle pipe);
! 233:
! 234: __inline__ uhci_soft_qh_t *uhci_find_prev_qh(uhci_soft_qh_t *,
! 235: uhci_soft_qh_t *);
! 236:
! 237: #ifdef UHCI_DEBUG
! 238: void uhci_dump_all(uhci_softc_t *);
! 239: void uhci_dumpregs(uhci_softc_t *);
! 240: void uhci_dump_qhs(uhci_soft_qh_t *);
! 241: void uhci_dump_qh(uhci_soft_qh_t *);
! 242: void uhci_dump_tds(uhci_soft_td_t *);
! 243: void uhci_dump_td(uhci_soft_td_t *);
! 244: void uhci_dump_ii(uhci_intr_info_t *ii);
! 245: void uhci_dump(void);
! 246: #endif
! 247:
! 248: #define UBARR(sc) bus_space_barrier((sc)->iot, (sc)->ioh, 0, (sc)->sc_size, \
! 249: BUS_SPACE_BARRIER_READ|BUS_SPACE_BARRIER_WRITE)
! 250: #define UWRITE1(sc, r, x) \
! 251: do { UBARR(sc); bus_space_write_1((sc)->iot, (sc)->ioh, (r), (x)); \
! 252: } while (/*CONSTCOND*/0)
! 253: #define UWRITE2(sc, r, x) \
! 254: do { UBARR(sc); bus_space_write_2((sc)->iot, (sc)->ioh, (r), (x)); \
! 255: } while (/*CONSTCOND*/0)
! 256: #define UWRITE4(sc, r, x) \
! 257: do { UBARR(sc); bus_space_write_4((sc)->iot, (sc)->ioh, (r), (x)); \
! 258: } while (/*CONSTCOND*/0)
! 259: #define UREAD1(sc, r) (UBARR(sc), bus_space_read_1((sc)->iot, (sc)->ioh, (r)))
! 260: #define UREAD2(sc, r) (UBARR(sc), bus_space_read_2((sc)->iot, (sc)->ioh, (r)))
! 261: #define UREAD4(sc, r) (UBARR(sc), bus_space_read_4((sc)->iot, (sc)->ioh, (r)))
! 262:
! 263: #define UHCICMD(sc, cmd) UWRITE2(sc, UHCI_CMD, cmd)
! 264: #define UHCISTS(sc) UREAD2(sc, UHCI_STS)
! 265:
! 266: #define UHCI_RESET_TIMEOUT 100 /* ms, reset timeout */
! 267:
! 268: #define UHCI_CURFRAME(sc) (UREAD2(sc, UHCI_FRNUM) & UHCI_FRNUM_MASK)
! 269:
! 270: #define UHCI_INTR_ENDPT 1
! 271:
! 272: struct usbd_bus_methods uhci_bus_methods = {
! 273: uhci_open,
! 274: uhci_softintr,
! 275: uhci_poll,
! 276: uhci_allocm,
! 277: uhci_freem,
! 278: uhci_allocx,
! 279: uhci_freex,
! 280: };
! 281:
! 282: struct usbd_pipe_methods uhci_root_ctrl_methods = {
! 283: uhci_root_ctrl_transfer,
! 284: uhci_root_ctrl_start,
! 285: uhci_root_ctrl_abort,
! 286: uhci_root_ctrl_close,
! 287: uhci_noop,
! 288: uhci_root_ctrl_done,
! 289: };
! 290:
! 291: struct usbd_pipe_methods uhci_root_intr_methods = {
! 292: uhci_root_intr_transfer,
! 293: uhci_root_intr_start,
! 294: uhci_root_intr_abort,
! 295: uhci_root_intr_close,
! 296: uhci_noop,
! 297: uhci_root_intr_done,
! 298: };
! 299:
! 300: struct usbd_pipe_methods uhci_device_ctrl_methods = {
! 301: uhci_device_ctrl_transfer,
! 302: uhci_device_ctrl_start,
! 303: uhci_device_ctrl_abort,
! 304: uhci_device_ctrl_close,
! 305: uhci_noop,
! 306: uhci_device_ctrl_done,
! 307: };
! 308:
! 309: struct usbd_pipe_methods uhci_device_intr_methods = {
! 310: uhci_device_intr_transfer,
! 311: uhci_device_intr_start,
! 312: uhci_device_intr_abort,
! 313: uhci_device_intr_close,
! 314: uhci_device_clear_toggle,
! 315: uhci_device_intr_done,
! 316: };
! 317:
! 318: struct usbd_pipe_methods uhci_device_bulk_methods = {
! 319: uhci_device_bulk_transfer,
! 320: uhci_device_bulk_start,
! 321: uhci_device_bulk_abort,
! 322: uhci_device_bulk_close,
! 323: uhci_device_clear_toggle,
! 324: uhci_device_bulk_done,
! 325: };
! 326:
! 327: struct usbd_pipe_methods uhci_device_isoc_methods = {
! 328: uhci_device_isoc_transfer,
! 329: uhci_device_isoc_start,
! 330: uhci_device_isoc_abort,
! 331: uhci_device_isoc_close,
! 332: uhci_noop,
! 333: uhci_device_isoc_done,
! 334: };
! 335:
! 336: #define uhci_add_intr_info(sc, ii) \
! 337: LIST_INSERT_HEAD(&(sc)->sc_intrhead, (ii), list)
! 338: #define uhci_del_intr_info(ii) \
! 339: do { \
! 340: LIST_REMOVE((ii), list); \
! 341: (ii)->list.le_prev = NULL; \
! 342: } while (0)
! 343: #define uhci_active_intr_info(ii) ((ii)->list.le_prev != NULL)
! 344:
! 345: __inline__ uhci_soft_qh_t *
! 346: uhci_find_prev_qh(uhci_soft_qh_t *pqh, uhci_soft_qh_t *sqh)
! 347: {
! 348: DPRINTFN(15,("uhci_find_prev_qh: pqh=%p sqh=%p\n", pqh, sqh));
! 349:
! 350: for (; pqh->hlink != sqh; pqh = pqh->hlink) {
! 351: #if defined(DIAGNOSTIC) || defined(UHCI_DEBUG)
! 352: if (letoh32(pqh->qh.qh_hlink) & UHCI_PTR_T) {
! 353: printf("uhci_find_prev_qh: QH not found\n");
! 354: return (NULL);
! 355: }
! 356: #endif
! 357: }
! 358: return (pqh);
! 359: }
! 360:
! 361: void
! 362: uhci_globalreset(uhci_softc_t *sc)
! 363: {
! 364: UHCICMD(sc, UHCI_CMD_GRESET); /* global reset */
! 365: usb_delay_ms(&sc->sc_bus, USB_BUS_RESET_DELAY); /* wait a little */
! 366: UHCICMD(sc, 0); /* do nothing */
! 367: }
! 368:
! 369: usbd_status
! 370: uhci_init(uhci_softc_t *sc)
! 371: {
! 372: usbd_status err;
! 373: int i, j;
! 374: uhci_soft_qh_t *clsqh, *chsqh, *bsqh, *sqh, *lsqh;
! 375: uhci_soft_td_t *std;
! 376:
! 377: DPRINTFN(1,("uhci_init: start\n"));
! 378:
! 379: #ifdef UHCI_DEBUG
! 380: thesc = sc;
! 381:
! 382: if (uhcidebug > 2)
! 383: uhci_dumpregs(sc);
! 384: #endif
! 385:
! 386: /* Save SOF over HC reset. */
! 387: sc->sc_saved_sof = UREAD1(sc, UHCI_SOF);
! 388:
! 389: UWRITE2(sc, UHCI_INTR, 0); /* disable interrupts */
! 390: uhci_globalreset(sc); /* reset the controller */
! 391: uhci_reset(sc);
! 392:
! 393: /* Restore saved SOF. */
! 394: UWRITE1(sc, UHCI_SOF, sc->sc_saved_sof);
! 395:
! 396: /* Allocate and initialize real frame array. */
! 397: err = usb_allocmem(&sc->sc_bus,
! 398: UHCI_FRAMELIST_COUNT * sizeof(uhci_physaddr_t),
! 399: UHCI_FRAMELIST_ALIGN, &sc->sc_dma);
! 400: if (err)
! 401: return (err);
! 402: sc->sc_pframes = KERNADDR(&sc->sc_dma, 0);
! 403: UWRITE2(sc, UHCI_FRNUM, 0); /* set frame number to 0 */
! 404: UWRITE4(sc, UHCI_FLBASEADDR, DMAADDR(&sc->sc_dma, 0)); /* set frame list*/
! 405:
! 406: /*
! 407: * Allocate a TD, inactive, that hangs from the last QH.
! 408: * This is to avoid a bug in the PIIX that makes it run berserk
! 409: * otherwise.
! 410: */
! 411: std = uhci_alloc_std(sc);
! 412: if (std == NULL)
! 413: return (USBD_NOMEM);
! 414: std->link.std = NULL;
! 415: std->td.td_link = htole32(UHCI_PTR_T);
! 416: std->td.td_status = htole32(0); /* inactive */
! 417: std->td.td_token = htole32(0);
! 418: std->td.td_buffer = htole32(0);
! 419:
! 420: /* Allocate the dummy QH marking the end and used for looping the QHs.*/
! 421: lsqh = uhci_alloc_sqh(sc);
! 422: if (lsqh == NULL)
! 423: return (USBD_NOMEM);
! 424: lsqh->hlink = NULL;
! 425: lsqh->qh.qh_hlink = htole32(UHCI_PTR_T); /* end of QH chain */
! 426: lsqh->elink = std;
! 427: lsqh->qh.qh_elink = htole32(std->physaddr | UHCI_PTR_TD);
! 428: sc->sc_last_qh = lsqh;
! 429:
! 430: /* Allocate the dummy QH where bulk traffic will be queued. */
! 431: bsqh = uhci_alloc_sqh(sc);
! 432: if (bsqh == NULL)
! 433: return (USBD_NOMEM);
! 434: bsqh->hlink = lsqh;
! 435: bsqh->qh.qh_hlink = htole32(lsqh->physaddr | UHCI_PTR_QH);
! 436: bsqh->elink = NULL;
! 437: bsqh->qh.qh_elink = htole32(UHCI_PTR_T);
! 438: sc->sc_bulk_start = sc->sc_bulk_end = bsqh;
! 439:
! 440: /* Allocate dummy QH where high speed control traffic will be queued. */
! 441: chsqh = uhci_alloc_sqh(sc);
! 442: if (chsqh == NULL)
! 443: return (USBD_NOMEM);
! 444: chsqh->hlink = bsqh;
! 445: chsqh->qh.qh_hlink = htole32(bsqh->physaddr | UHCI_PTR_QH);
! 446: chsqh->elink = NULL;
! 447: chsqh->qh.qh_elink = htole32(UHCI_PTR_T);
! 448: sc->sc_hctl_start = sc->sc_hctl_end = chsqh;
! 449:
! 450: /* Allocate dummy QH where control traffic will be queued. */
! 451: clsqh = uhci_alloc_sqh(sc);
! 452: if (clsqh == NULL)
! 453: return (USBD_NOMEM);
! 454: clsqh->hlink = bsqh;
! 455: clsqh->qh.qh_hlink = htole32(chsqh->physaddr | UHCI_PTR_QH);
! 456: clsqh->elink = NULL;
! 457: clsqh->qh.qh_elink = htole32(UHCI_PTR_T);
! 458: sc->sc_lctl_start = sc->sc_lctl_end = clsqh;
! 459:
! 460: /*
! 461: * Make all (virtual) frame list pointers point to the interrupt
! 462: * queue heads and the interrupt queue heads at the control
! 463: * queue head and point the physical frame list to the virtual.
! 464: */
! 465: for(i = 0; i < UHCI_VFRAMELIST_COUNT; i++) {
! 466: std = uhci_alloc_std(sc);
! 467: sqh = uhci_alloc_sqh(sc);
! 468: if (std == NULL || sqh == NULL)
! 469: return (USBD_NOMEM);
! 470: std->link.sqh = sqh;
! 471: std->td.td_link = htole32(sqh->physaddr | UHCI_PTR_QH);
! 472: std->td.td_status = htole32(UHCI_TD_IOS); /* iso, inactive */
! 473: std->td.td_token = htole32(0);
! 474: std->td.td_buffer = htole32(0);
! 475: sqh->hlink = clsqh;
! 476: sqh->qh.qh_hlink = htole32(clsqh->physaddr | UHCI_PTR_QH);
! 477: sqh->elink = NULL;
! 478: sqh->qh.qh_elink = htole32(UHCI_PTR_T);
! 479: sc->sc_vframes[i].htd = std;
! 480: sc->sc_vframes[i].etd = std;
! 481: sc->sc_vframes[i].hqh = sqh;
! 482: sc->sc_vframes[i].eqh = sqh;
! 483: for (j = i;
! 484: j < UHCI_FRAMELIST_COUNT;
! 485: j += UHCI_VFRAMELIST_COUNT)
! 486: sc->sc_pframes[j] = htole32(std->physaddr);
! 487: }
! 488:
! 489: LIST_INIT(&sc->sc_intrhead);
! 490:
! 491: SIMPLEQ_INIT(&sc->sc_free_xfers);
! 492:
! 493: timeout_set(&sc->sc_poll_handle, NULL, NULL);
! 494:
! 495: /* Set up the bus struct. */
! 496: sc->sc_bus.methods = &uhci_bus_methods;
! 497: sc->sc_bus.pipe_size = sizeof(struct uhci_pipe);
! 498:
! 499: sc->sc_suspend = PWR_RESUME;
! 500: sc->sc_powerhook = powerhook_establish(uhci_power, sc);
! 501: sc->sc_shutdownhook = shutdownhook_establish(uhci_shutdown, sc);
! 502:
! 503: UHCICMD(sc, UHCI_CMD_MAXP); /* Assume 64 byte packets at frame end */
! 504:
! 505: DPRINTFN(1,("uhci_init: enabling\n"));
! 506: UWRITE2(sc, UHCI_INTR, UHCI_INTR_TOCRCIE | UHCI_INTR_RIE |
! 507: UHCI_INTR_IOCE | UHCI_INTR_SPIE); /* enable interrupts */
! 508:
! 509: return (uhci_run(sc, 1)); /* and here we go... */
! 510: }
! 511:
! 512: int
! 513: uhci_activate(struct device *self, enum devact act)
! 514: {
! 515: struct uhci_softc *sc = (struct uhci_softc *)self;
! 516: int rv = 0;
! 517:
! 518: switch (act) {
! 519: case DVACT_ACTIVATE:
! 520: break;
! 521:
! 522: case DVACT_DEACTIVATE:
! 523: if (sc->sc_child != NULL)
! 524: rv = config_deactivate(sc->sc_child);
! 525: break;
! 526: }
! 527: return (rv);
! 528: }
! 529:
! 530: int
! 531: uhci_detach(struct uhci_softc *sc, int flags)
! 532: {
! 533: usbd_xfer_handle xfer;
! 534: int rv = 0;
! 535:
! 536: if (sc->sc_child != NULL)
! 537: rv = config_detach(sc->sc_child, flags);
! 538:
! 539: if (rv != 0)
! 540: return (rv);
! 541:
! 542: if (sc->sc_powerhook != NULL)
! 543: powerhook_disestablish(sc->sc_powerhook);
! 544: if (sc->sc_shutdownhook != NULL)
! 545: shutdownhook_disestablish(sc->sc_shutdownhook);
! 546:
! 547: /* Free all xfers associated with this HC. */
! 548: for (;;) {
! 549: xfer = SIMPLEQ_FIRST(&sc->sc_free_xfers);
! 550: if (xfer == NULL)
! 551: break;
! 552: SIMPLEQ_REMOVE_HEAD(&sc->sc_free_xfers, next);
! 553: free(xfer, M_USB);
! 554: }
! 555:
! 556: /* XXX free other data structures XXX */
! 557:
! 558: return (rv);
! 559: }
! 560:
! 561: usbd_status
! 562: uhci_allocm(struct usbd_bus *bus, usb_dma_t *dma, u_int32_t size)
! 563: {
! 564: struct uhci_softc *sc = (struct uhci_softc *)bus;
! 565: u_int32_t n;
! 566:
! 567: /*
! 568: * XXX
! 569: * Since we are allocating a buffer we can assume that we will
! 570: * need TDs for it. Since we don't want to allocate those from
! 571: * an interrupt context, we allocate them here and free them again.
! 572: * This is no guarantee that we'll get the TDs next time...
! 573: */
! 574: n = size / 8;
! 575: if (n > 16) {
! 576: u_int32_t i;
! 577: uhci_soft_td_t **stds;
! 578: DPRINTF(("uhci_allocm: get %d TDs\n", n));
! 579: stds = malloc(sizeof(uhci_soft_td_t *) * n, M_TEMP,
! 580: M_NOWAIT);
! 581: if (stds == NULL)
! 582: panic("uhci_allocm");
! 583: memset(stds, 0, sizeof(uhci_soft_td_t *) * n);
! 584: for(i=0; i < n; i++)
! 585: stds[i] = uhci_alloc_std(sc);
! 586: for(i=0; i < n; i++)
! 587: if (stds[i] != NULL)
! 588: uhci_free_std(sc, stds[i]);
! 589: free(stds, M_TEMP);
! 590: }
! 591:
! 592: return (usb_allocmem(&sc->sc_bus, size, 0, dma));
! 593: }
! 594:
! 595: void
! 596: uhci_freem(struct usbd_bus *bus, usb_dma_t *dma)
! 597: {
! 598: usb_freemem(&((struct uhci_softc *)bus)->sc_bus, dma);
! 599: }
! 600:
! 601: usbd_xfer_handle
! 602: uhci_allocx(struct usbd_bus *bus)
! 603: {
! 604: struct uhci_softc *sc = (struct uhci_softc *)bus;
! 605: usbd_xfer_handle xfer;
! 606:
! 607: xfer = SIMPLEQ_FIRST(&sc->sc_free_xfers);
! 608: if (xfer != NULL) {
! 609: SIMPLEQ_REMOVE_HEAD(&sc->sc_free_xfers, next);
! 610: #ifdef DIAGNOSTIC
! 611: if (xfer->busy_free != XFER_FREE) {
! 612: printf("uhci_allocx: xfer=%p not free, 0x%08x\n", xfer,
! 613: xfer->busy_free);
! 614: }
! 615: #endif
! 616: } else {
! 617: xfer = malloc(sizeof(struct uhci_xfer), M_USB, M_NOWAIT);
! 618: }
! 619: if (xfer != NULL) {
! 620: memset(xfer, 0, sizeof (struct uhci_xfer));
! 621: UXFER(xfer)->iinfo.sc = sc;
! 622: #ifdef DIAGNOSTIC
! 623: UXFER(xfer)->iinfo.isdone = 1;
! 624: xfer->busy_free = XFER_BUSY;
! 625: #endif
! 626: }
! 627: return (xfer);
! 628: }
! 629:
! 630: void
! 631: uhci_freex(struct usbd_bus *bus, usbd_xfer_handle xfer)
! 632: {
! 633: struct uhci_softc *sc = (struct uhci_softc *)bus;
! 634:
! 635: #ifdef DIAGNOSTIC
! 636: if (xfer->busy_free != XFER_BUSY) {
! 637: printf("uhci_freex: xfer=%p not busy, 0x%08x\n", xfer,
! 638: xfer->busy_free);
! 639: return;
! 640: }
! 641: xfer->busy_free = XFER_FREE;
! 642: if (!UXFER(xfer)->iinfo.isdone) {
! 643: printf("uhci_freex: !isdone\n");
! 644: return;
! 645: }
! 646: #endif
! 647: SIMPLEQ_INSERT_HEAD(&sc->sc_free_xfers, xfer, next);
! 648: }
! 649:
! 650: /*
! 651: * Shut down the controller when the system is going down.
! 652: */
! 653: void
! 654: uhci_shutdown(void *v)
! 655: {
! 656: uhci_softc_t *sc = v;
! 657:
! 658: DPRINTF(("uhci_shutdown: stopping the HC\n"));
! 659: uhci_run(sc, 0); /* stop the controller */
! 660: }
! 661:
! 662: /*
! 663: * Handle suspend/resume.
! 664: *
! 665: * We need to switch to polling mode here, because this routine is
! 666: * called from an interrupt context. This is all right since we
! 667: * are almost suspended anyway.
! 668: */
! 669: void
! 670: uhci_power(int why, void *v)
! 671: {
! 672: uhci_softc_t *sc = v;
! 673: int cmd;
! 674: int s;
! 675:
! 676: s = splhardusb();
! 677: cmd = UREAD2(sc, UHCI_CMD);
! 678:
! 679: DPRINTF(("uhci_power: sc=%p, why=%d (was %d), cmd=0x%x\n",
! 680: sc, why, sc->sc_suspend, cmd));
! 681:
! 682: switch (why) {
! 683: case PWR_SUSPEND:
! 684: case PWR_STANDBY:
! 685: #ifdef UHCI_DEBUG
! 686: if (uhcidebug > 2)
! 687: uhci_dumpregs(sc);
! 688: #endif
! 689: if (sc->sc_intr_xfer != NULL)
! 690: timeout_del(&sc->sc_poll_handle);
! 691: sc->sc_bus.use_polling++;
! 692: uhci_run(sc, 0); /* stop the controller */
! 693:
! 694: /* save some state if BIOS doesn't */
! 695: sc->sc_saved_frnum = UREAD2(sc, UHCI_FRNUM);
! 696:
! 697: UWRITE2(sc, UHCI_INTR, 0); /* disable intrs */
! 698:
! 699: UHCICMD(sc, cmd | UHCI_CMD_EGSM); /* enter global suspend */
! 700: usb_delay_ms(&sc->sc_bus, USB_RESUME_WAIT);
! 701: sc->sc_suspend = why;
! 702: sc->sc_bus.use_polling--;
! 703: DPRINTF(("uhci_power: cmd=0x%x\n", UREAD2(sc, UHCI_CMD)));
! 704: break;
! 705: case PWR_RESUME:
! 706: #ifdef DIAGNOSTIC
! 707: if (sc->sc_suspend == PWR_RESUME)
! 708: printf("uhci_power: weird, resume without suspend.\n");
! 709: #endif
! 710: sc->sc_bus.use_polling++;
! 711: sc->sc_suspend = why;
! 712: if (cmd & UHCI_CMD_RS)
! 713: uhci_run(sc, 0); /* in case BIOS has started it */
! 714:
! 715: /* restore saved state */
! 716: UWRITE4(sc, UHCI_FLBASEADDR, DMAADDR(&sc->sc_dma, 0));
! 717: UWRITE2(sc, UHCI_FRNUM, sc->sc_saved_frnum);
! 718: UWRITE1(sc, UHCI_SOF, sc->sc_saved_sof);
! 719:
! 720: UHCICMD(sc, cmd | UHCI_CMD_FGR); /* force global resume */
! 721: usb_delay_ms(&sc->sc_bus, USB_RESUME_DELAY);
! 722: UHCICMD(sc, cmd & ~UHCI_CMD_EGSM); /* back to normal */
! 723: UHCICMD(sc, UHCI_CMD_MAXP);
! 724: UWRITE2(sc, UHCI_INTR, UHCI_INTR_TOCRCIE | UHCI_INTR_RIE |
! 725: UHCI_INTR_IOCE | UHCI_INTR_SPIE); /* re-enable intrs */
! 726: uhci_run(sc, 1); /* and start traffic again */
! 727: usb_delay_ms(&sc->sc_bus, USB_RESUME_RECOVERY);
! 728: sc->sc_bus.use_polling--;
! 729: if (sc->sc_intr_xfer != NULL) {
! 730: timeout_del(&sc->sc_poll_handle);
! 731: timeout_set(&sc->sc_poll_handle, uhci_poll_hub,
! 732: sc->sc_intr_xfer);
! 733: timeout_add(&sc->sc_poll_handle, sc->sc_ival);
! 734: }
! 735: #ifdef UHCI_DEBUG
! 736: if (uhcidebug > 2)
! 737: uhci_dumpregs(sc);
! 738: #endif
! 739: break;
! 740: }
! 741: splx(s);
! 742: }
! 743:
! 744: #ifdef UHCI_DEBUG
! 745: void
! 746: uhci_dumpregs(uhci_softc_t *sc)
! 747: {
! 748: DPRINTFN(-1,("%s regs: cmd=%04x, sts=%04x, intr=%04x, frnum=%04x, "
! 749: "flbase=%08x, sof=%04x, portsc1=%04x, portsc2=%04x\n",
! 750: sc->sc_bus.bdev.dv_xname,
! 751: UREAD2(sc, UHCI_CMD),
! 752: UREAD2(sc, UHCI_STS),
! 753: UREAD2(sc, UHCI_INTR),
! 754: UREAD2(sc, UHCI_FRNUM),
! 755: UREAD4(sc, UHCI_FLBASEADDR),
! 756: UREAD1(sc, UHCI_SOF),
! 757: UREAD2(sc, UHCI_PORTSC1),
! 758: UREAD2(sc, UHCI_PORTSC2)));
! 759: }
! 760:
! 761: void
! 762: uhci_dump_td(uhci_soft_td_t *p)
! 763: {
! 764: char sbuf[128], sbuf2[128];
! 765:
! 766: DPRINTFN(-1,("TD(%p) at %08lx = link=0x%08lx status=0x%08lx "
! 767: "token=0x%08lx buffer=0x%08lx\n",
! 768: p, (long)p->physaddr,
! 769: (long)letoh32(p->td.td_link),
! 770: (long)letoh32(p->td.td_status),
! 771: (long)letoh32(p->td.td_token),
! 772: (long)letoh32(p->td.td_buffer)));
! 773:
! 774: bitmask_snprintf((u_int32_t)letoh32(p->td.td_link), "\20\1T\2Q\3VF",
! 775: sbuf, sizeof(sbuf));
! 776: bitmask_snprintf((u_int32_t)letoh32(p->td.td_status),
! 777: "\20\22BITSTUFF\23CRCTO\24NAK\25BABBLE\26DBUFFER\27"
! 778: "STALLED\30ACTIVE\31IOC\32ISO\33LS\36SPD",
! 779: sbuf2, sizeof(sbuf2));
! 780:
! 781: DPRINTFN(-1,(" %s %s,errcnt=%d,actlen=%d pid=%02x,addr=%d,endpt=%d,"
! 782: "D=%d,maxlen=%d\n", sbuf, sbuf2,
! 783: UHCI_TD_GET_ERRCNT(letoh32(p->td.td_status)),
! 784: UHCI_TD_GET_ACTLEN(letoh32(p->td.td_status)),
! 785: UHCI_TD_GET_PID(letoh32(p->td.td_token)),
! 786: UHCI_TD_GET_DEVADDR(letoh32(p->td.td_token)),
! 787: UHCI_TD_GET_ENDPT(letoh32(p->td.td_token)),
! 788: UHCI_TD_GET_DT(letoh32(p->td.td_token)),
! 789: UHCI_TD_GET_MAXLEN(letoh32(p->td.td_token))));
! 790: }
! 791:
! 792: void
! 793: uhci_dump_qh(uhci_soft_qh_t *sqh)
! 794: {
! 795: DPRINTFN(-1,("QH(%p) at %08x: hlink=%08x elink=%08x\n", sqh,
! 796: (int)sqh->physaddr, letoh32(sqh->qh.qh_hlink),
! 797: letoh32(sqh->qh.qh_elink)));
! 798: }
! 799:
! 800:
! 801: void
! 802: uhci_dump(void)
! 803: {
! 804: uhci_dump_all(thesc);
! 805: }
! 806:
! 807: void
! 808: uhci_dump_all(uhci_softc_t *sc)
! 809: {
! 810: uhci_dumpregs(sc);
! 811: printf("intrs=%d\n", sc->sc_bus.no_intrs);
! 812: /*printf("framelist[i].link = %08x\n", sc->sc_framelist[0].link);*/
! 813: uhci_dump_qh(sc->sc_lctl_start);
! 814: }
! 815:
! 816:
! 817: void
! 818: uhci_dump_qhs(uhci_soft_qh_t *sqh)
! 819: {
! 820: uhci_dump_qh(sqh);
! 821:
! 822: /* uhci_dump_qhs displays all the QHs and TDs from the given QH onwards
! 823: * Traverses sideways first, then down.
! 824: *
! 825: * QH1
! 826: * QH2
! 827: * No QH
! 828: * TD2.1
! 829: * TD2.2
! 830: * TD1.1
! 831: * etc.
! 832: *
! 833: * TD2.x being the TDs queued at QH2 and QH1 being referenced from QH1.
! 834: */
! 835:
! 836:
! 837: if (sqh->hlink != NULL && !(letoh32(sqh->qh.qh_hlink) & UHCI_PTR_T))
! 838: uhci_dump_qhs(sqh->hlink);
! 839: else
! 840: DPRINTF(("No QH\n"));
! 841:
! 842: if (sqh->elink != NULL && !(letoh32(sqh->qh.qh_elink) & UHCI_PTR_T))
! 843: uhci_dump_tds(sqh->elink);
! 844: else
! 845: DPRINTF(("No TD\n"));
! 846: }
! 847:
! 848: void
! 849: uhci_dump_tds(uhci_soft_td_t *std)
! 850: {
! 851: uhci_soft_td_t *td;
! 852:
! 853: for(td = std; td != NULL; td = td->link.std) {
! 854: uhci_dump_td(td);
! 855:
! 856: /* Check whether the link pointer in this TD marks
! 857: * the link pointer as end of queue. This avoids
! 858: * printing the free list in case the queue/TD has
! 859: * already been moved there (seatbelt).
! 860: */
! 861: if (letoh32(td->td.td_link) & UHCI_PTR_T ||
! 862: letoh32(td->td.td_link) == 0)
! 863: break;
! 864: }
! 865: }
! 866:
! 867: void
! 868: uhci_dump_ii(uhci_intr_info_t *ii)
! 869: {
! 870: usbd_pipe_handle pipe;
! 871: usb_endpoint_descriptor_t *ed;
! 872: usbd_device_handle dev;
! 873:
! 874: #ifdef DIAGNOSTIC
! 875: #define DONE ii->isdone
! 876: #else
! 877: #define DONE 0
! 878: #endif
! 879: if (ii == NULL) {
! 880: printf("ii NULL\n");
! 881: return;
! 882: }
! 883: if (ii->xfer == NULL) {
! 884: printf("ii %p: done=%d xfer=NULL\n",
! 885: ii, DONE);
! 886: return;
! 887: }
! 888: pipe = ii->xfer->pipe;
! 889: if (pipe == NULL) {
! 890: printf("ii %p: done=%d xfer=%p pipe=NULL\n",
! 891: ii, DONE, ii->xfer);
! 892: return;
! 893: }
! 894: if (pipe->endpoint == NULL) {
! 895: printf("ii %p: done=%d xfer=%p pipe=%p pipe->endpoint=NULL\n",
! 896: ii, DONE, ii->xfer, pipe);
! 897: return;
! 898: }
! 899: if (pipe->device == NULL) {
! 900: printf("ii %p: done=%d xfer=%p pipe=%p pipe->device=NULL\n",
! 901: ii, DONE, ii->xfer, pipe);
! 902: return;
! 903: }
! 904: ed = pipe->endpoint->edesc;
! 905: dev = pipe->device;
! 906: printf("ii %p: done=%d xfer=%p dev=%p vid=0x%04x pid=0x%04x addr=%d pipe=%p ep=0x%02x attr=0x%02x\n",
! 907: ii, DONE, ii->xfer, dev,
! 908: UGETW(dev->ddesc.idVendor),
! 909: UGETW(dev->ddesc.idProduct),
! 910: dev->address, pipe,
! 911: ed->bEndpointAddress, ed->bmAttributes);
! 912: #undef DONE
! 913: }
! 914:
! 915: void uhci_dump_iis(struct uhci_softc *sc);
! 916: void
! 917: uhci_dump_iis(struct uhci_softc *sc)
! 918: {
! 919: uhci_intr_info_t *ii;
! 920:
! 921: printf("intr_info list:\n");
! 922: for (ii = LIST_FIRST(&sc->sc_intrhead); ii; ii = LIST_NEXT(ii, list))
! 923: uhci_dump_ii(ii);
! 924: }
! 925:
! 926: void iidump(void);
! 927: void iidump(void) { uhci_dump_iis(thesc); }
! 928:
! 929: #endif
! 930:
! 931: /*
! 932: * This routine is executed periodically and simulates interrupts
! 933: * from the root controller interrupt pipe for port status change.
! 934: */
! 935: void
! 936: uhci_poll_hub(void *addr)
! 937: {
! 938: usbd_xfer_handle xfer = addr;
! 939: usbd_pipe_handle pipe = xfer->pipe;
! 940: uhci_softc_t *sc = (uhci_softc_t *)pipe->device->bus;
! 941: int s;
! 942: u_char *p;
! 943:
! 944: DPRINTFN(20, ("uhci_poll_hub\n"));
! 945:
! 946: timeout_del(&sc->sc_poll_handle);
! 947: timeout_set(&sc->sc_poll_handle, uhci_poll_hub, xfer);
! 948: timeout_add(&sc->sc_poll_handle, sc->sc_ival);
! 949:
! 950: p = KERNADDR(&xfer->dmabuf, 0);
! 951: p[0] = 0;
! 952: if (UREAD2(sc, UHCI_PORTSC1) & (UHCI_PORTSC_CSC|UHCI_PORTSC_OCIC))
! 953: p[0] |= 1<<1;
! 954: if (UREAD2(sc, UHCI_PORTSC2) & (UHCI_PORTSC_CSC|UHCI_PORTSC_OCIC))
! 955: p[0] |= 1<<2;
! 956: if (p[0] == 0)
! 957: /* No change, try again in a while */
! 958: return;
! 959:
! 960: xfer->actlen = 1;
! 961: xfer->status = USBD_NORMAL_COMPLETION;
! 962: s = splusb();
! 963: xfer->device->bus->intr_context++;
! 964: usb_transfer_complete(xfer);
! 965: xfer->device->bus->intr_context--;
! 966: splx(s);
! 967: }
! 968:
! 969: void
! 970: uhci_root_intr_done(usbd_xfer_handle xfer)
! 971: {
! 972: }
! 973:
! 974: void
! 975: uhci_root_ctrl_done(usbd_xfer_handle xfer)
! 976: {
! 977: }
! 978:
! 979: /*
! 980: * Let the last QH loop back to the high speed control transfer QH.
! 981: * This is what intel calls "bandwidth reclamation" and improves
! 982: * USB performance a lot for some devices.
! 983: * If we are already looping, just count it.
! 984: */
! 985: void
! 986: uhci_add_loop(uhci_softc_t *sc) {
! 987: #ifdef UHCI_DEBUG
! 988: if (uhcinoloop)
! 989: return;
! 990: #endif
! 991: if (++sc->sc_loops == 1) {
! 992: DPRINTFN(5,("uhci_start_loop: add\n"));
! 993: /* Note, we don't loop back the soft pointer. */
! 994: sc->sc_last_qh->qh.qh_hlink =
! 995: htole32(sc->sc_hctl_start->physaddr | UHCI_PTR_QH);
! 996: }
! 997: }
! 998:
! 999: void
! 1000: uhci_rem_loop(uhci_softc_t *sc) {
! 1001: #ifdef UHCI_DEBUG
! 1002: if (uhcinoloop)
! 1003: return;
! 1004: #endif
! 1005: if (--sc->sc_loops == 0) {
! 1006: DPRINTFN(5,("uhci_end_loop: remove\n"));
! 1007: sc->sc_last_qh->qh.qh_hlink = htole32(UHCI_PTR_T);
! 1008: }
! 1009: }
! 1010:
! 1011: /* Add high speed control QH, called at splusb(). */
! 1012: void
! 1013: uhci_add_hs_ctrl(uhci_softc_t *sc, uhci_soft_qh_t *sqh)
! 1014: {
! 1015: uhci_soft_qh_t *eqh;
! 1016:
! 1017: SPLUSBCHECK;
! 1018:
! 1019: DPRINTFN(10, ("uhci_add_ctrl: sqh=%p\n", sqh));
! 1020: eqh = sc->sc_hctl_end;
! 1021: sqh->hlink = eqh->hlink;
! 1022: sqh->qh.qh_hlink = eqh->qh.qh_hlink;
! 1023: eqh->hlink = sqh;
! 1024: eqh->qh.qh_hlink = htole32(sqh->physaddr | UHCI_PTR_QH);
! 1025: sc->sc_hctl_end = sqh;
! 1026: #ifdef UHCI_CTL_LOOP
! 1027: uhci_add_loop(sc);
! 1028: #endif
! 1029: }
! 1030:
! 1031: /* Remove high speed control QH, called at splusb(). */
! 1032: void
! 1033: uhci_remove_hs_ctrl(uhci_softc_t *sc, uhci_soft_qh_t *sqh)
! 1034: {
! 1035: uhci_soft_qh_t *pqh;
! 1036:
! 1037: SPLUSBCHECK;
! 1038:
! 1039: DPRINTFN(10, ("uhci_remove_hs_ctrl: sqh=%p\n", sqh));
! 1040: #ifdef UHCI_CTL_LOOP
! 1041: uhci_rem_loop(sc);
! 1042: #endif
! 1043: /*
! 1044: * The T bit should be set in the elink of the QH so that the HC
! 1045: * doesn't follow the pointer. This condition may fail if the
! 1046: * the transferred packet was short so that the QH still points
! 1047: * at the last used TD.
! 1048: * In this case we set the T bit and wait a little for the HC
! 1049: * to stop looking at the TD.
! 1050: */
! 1051: if (!(sqh->qh.qh_elink & htole32(UHCI_PTR_T))) {
! 1052: sqh->qh.qh_elink = htole32(UHCI_PTR_T);
! 1053: delay(UHCI_QH_REMOVE_DELAY);
! 1054: }
! 1055:
! 1056: pqh = uhci_find_prev_qh(sc->sc_hctl_start, sqh);
! 1057: pqh->hlink = sqh->hlink;
! 1058: pqh->qh.qh_hlink = sqh->qh.qh_hlink;
! 1059: delay(UHCI_QH_REMOVE_DELAY);
! 1060: if (sc->sc_hctl_end == sqh)
! 1061: sc->sc_hctl_end = pqh;
! 1062: }
! 1063:
! 1064: /* Add low speed control QH, called at splusb(). */
! 1065: void
! 1066: uhci_add_ls_ctrl(uhci_softc_t *sc, uhci_soft_qh_t *sqh)
! 1067: {
! 1068: uhci_soft_qh_t *eqh;
! 1069:
! 1070: SPLUSBCHECK;
! 1071:
! 1072: DPRINTFN(10, ("uhci_add_ls_ctrl: sqh=%p\n", sqh));
! 1073: eqh = sc->sc_lctl_end;
! 1074: sqh->hlink = eqh->hlink;
! 1075: sqh->qh.qh_hlink = eqh->qh.qh_hlink;
! 1076: eqh->hlink = sqh;
! 1077: eqh->qh.qh_hlink = htole32(sqh->physaddr | UHCI_PTR_QH);
! 1078: sc->sc_lctl_end = sqh;
! 1079: }
! 1080:
! 1081: /* Remove low speed control QH, called at splusb(). */
! 1082: void
! 1083: uhci_remove_ls_ctrl(uhci_softc_t *sc, uhci_soft_qh_t *sqh)
! 1084: {
! 1085: uhci_soft_qh_t *pqh;
! 1086:
! 1087: SPLUSBCHECK;
! 1088:
! 1089: DPRINTFN(10, ("uhci_remove_ls_ctrl: sqh=%p\n", sqh));
! 1090: /* See comment in uhci_remove_hs_ctrl() */
! 1091: if (!(sqh->qh.qh_elink & htole32(UHCI_PTR_T))) {
! 1092: sqh->qh.qh_elink = htole32(UHCI_PTR_T);
! 1093: delay(UHCI_QH_REMOVE_DELAY);
! 1094: }
! 1095: pqh = uhci_find_prev_qh(sc->sc_lctl_start, sqh);
! 1096: pqh->hlink = sqh->hlink;
! 1097: pqh->qh.qh_hlink = sqh->qh.qh_hlink;
! 1098: delay(UHCI_QH_REMOVE_DELAY);
! 1099: if (sc->sc_lctl_end == sqh)
! 1100: sc->sc_lctl_end = pqh;
! 1101: }
! 1102:
! 1103: /* Add bulk QH, called at splusb(). */
! 1104: void
! 1105: uhci_add_bulk(uhci_softc_t *sc, uhci_soft_qh_t *sqh)
! 1106: {
! 1107: uhci_soft_qh_t *eqh;
! 1108:
! 1109: SPLUSBCHECK;
! 1110:
! 1111: DPRINTFN(10, ("uhci_add_bulk: sqh=%p\n", sqh));
! 1112: eqh = sc->sc_bulk_end;
! 1113: sqh->hlink = eqh->hlink;
! 1114: sqh->qh.qh_hlink = eqh->qh.qh_hlink;
! 1115: eqh->hlink = sqh;
! 1116: eqh->qh.qh_hlink = htole32(sqh->physaddr | UHCI_PTR_QH);
! 1117: sc->sc_bulk_end = sqh;
! 1118: uhci_add_loop(sc);
! 1119: }
! 1120:
! 1121: /* Remove bulk QH, called at splusb(). */
! 1122: void
! 1123: uhci_remove_bulk(uhci_softc_t *sc, uhci_soft_qh_t *sqh)
! 1124: {
! 1125: uhci_soft_qh_t *pqh;
! 1126:
! 1127: SPLUSBCHECK;
! 1128:
! 1129: DPRINTFN(10, ("uhci_remove_bulk: sqh=%p\n", sqh));
! 1130: uhci_rem_loop(sc);
! 1131: /* See comment in uhci_remove_hs_ctrl() */
! 1132: if (!(sqh->qh.qh_elink & htole32(UHCI_PTR_T))) {
! 1133: sqh->qh.qh_elink = htole32(UHCI_PTR_T);
! 1134: delay(UHCI_QH_REMOVE_DELAY);
! 1135: }
! 1136: pqh = uhci_find_prev_qh(sc->sc_bulk_start, sqh);
! 1137: pqh->hlink = sqh->hlink;
! 1138: pqh->qh.qh_hlink = sqh->qh.qh_hlink;
! 1139: delay(UHCI_QH_REMOVE_DELAY);
! 1140: if (sc->sc_bulk_end == sqh)
! 1141: sc->sc_bulk_end = pqh;
! 1142: }
! 1143:
! 1144: int uhci_intr1(uhci_softc_t *);
! 1145:
! 1146: int
! 1147: uhci_intr(void *arg)
! 1148: {
! 1149: uhci_softc_t *sc = arg;
! 1150:
! 1151: if (sc->sc_dying)
! 1152: return (0);
! 1153:
! 1154: if (sc->sc_bus.use_polling) {
! 1155: #ifdef DIAGNOSTIC
! 1156: DPRINTFN(16, ("uhci_intr: ignored interrupt while polling\n"));
! 1157: #endif
! 1158: return (0);
! 1159: }
! 1160: return (uhci_intr1(sc));
! 1161: }
! 1162:
! 1163: int
! 1164: uhci_intr1(uhci_softc_t *sc)
! 1165: {
! 1166: int status;
! 1167: int ack;
! 1168:
! 1169: status = UREAD2(sc, UHCI_STS) & UHCI_STS_ALLINTRS;
! 1170: if (status == 0) /* The interrupt was not for us. */
! 1171: return (0);
! 1172:
! 1173: #ifdef UHCI_DEBUG
! 1174: if (uhcidebug > 15) {
! 1175: DPRINTF(("%s: uhci_intr1\n", sc->sc_bus.bdev.dv_xname));
! 1176: uhci_dumpregs(sc);
! 1177: }
! 1178: #endif
! 1179:
! 1180: if (sc->sc_suspend != PWR_RESUME) {
! 1181: printf("%s: interrupt while not operating ignored\n",
! 1182: sc->sc_bus.bdev.dv_xname);
! 1183: UWRITE2(sc, UHCI_STS, status); /* acknowledge the ints */
! 1184: return (0);
! 1185: }
! 1186:
! 1187: ack = 0;
! 1188: if (status & UHCI_STS_USBINT)
! 1189: ack |= UHCI_STS_USBINT;
! 1190: if (status & UHCI_STS_USBEI)
! 1191: ack |= UHCI_STS_USBEI;
! 1192: if (status & UHCI_STS_RD) {
! 1193: ack |= UHCI_STS_RD;
! 1194: #ifdef UHCI_DEBUG
! 1195: printf("%s: resume detect\n", sc->sc_bus.bdev.dv_xname);
! 1196: #endif
! 1197: }
! 1198: if (status & UHCI_STS_HSE) {
! 1199: ack |= UHCI_STS_HSE;
! 1200: printf("%s: host system error\n", sc->sc_bus.bdev.dv_xname);
! 1201: }
! 1202: if (status & UHCI_STS_HCPE) {
! 1203: ack |= UHCI_STS_HCPE;
! 1204: printf("%s: host controller process error\n",
! 1205: sc->sc_bus.bdev.dv_xname);
! 1206: }
! 1207: if (status & UHCI_STS_HCH) {
! 1208: /* no acknowledge needed */
! 1209: if (!sc->sc_dying) {
! 1210: printf("%s: host controller halted\n",
! 1211: sc->sc_bus.bdev.dv_xname);
! 1212: #ifdef UHCI_DEBUG
! 1213: uhci_dump_all(sc);
! 1214: #endif
! 1215: }
! 1216: sc->sc_dying = 1;
! 1217: }
! 1218:
! 1219: if (!ack)
! 1220: return (0); /* nothing to acknowledge */
! 1221: UWRITE2(sc, UHCI_STS, ack); /* acknowledge the ints */
! 1222:
! 1223: sc->sc_bus.no_intrs++;
! 1224: usb_schedsoftintr(&sc->sc_bus);
! 1225:
! 1226: DPRINTFN(15, ("%s: uhci_intr: exit\n", sc->sc_bus.bdev.dv_xname));
! 1227:
! 1228: return (1);
! 1229: }
! 1230:
! 1231: void
! 1232: uhci_softintr(void *v)
! 1233: {
! 1234: uhci_softc_t *sc = v;
! 1235: uhci_intr_info_t *ii, *nextii;
! 1236:
! 1237: DPRINTFN(10,("%s: uhci_softintr (%d)\n", sc->sc_bus.bdev.dv_xname,
! 1238: sc->sc_bus.intr_context));
! 1239:
! 1240: sc->sc_bus.intr_context++;
! 1241:
! 1242: /*
! 1243: * Interrupts on UHCI really suck. When the host controller
! 1244: * interrupts because a transfer is completed there is no
! 1245: * way of knowing which transfer it was. You can scan down
! 1246: * the TDs and QHs of the previous frame to limit the search,
! 1247: * but that assumes that the interrupt was not delayed by more
! 1248: * than 1 ms, which may not always be true (e.g. after debug
! 1249: * output on a slow console).
! 1250: * We scan all interrupt descriptors to see if any have
! 1251: * completed.
! 1252: */
! 1253: for (ii = LIST_FIRST(&sc->sc_intrhead); ii; ii = nextii) {
! 1254: nextii = LIST_NEXT(ii, list);
! 1255: uhci_check_intr(sc, ii);
! 1256: }
! 1257:
! 1258: #ifdef __HAVE_GENERIC_SOFT_INTERRUPTS
! 1259: if (sc->sc_softwake) {
! 1260: sc->sc_softwake = 0;
! 1261: wakeup(&sc->sc_softwake);
! 1262: }
! 1263: #endif /* __HAVE_GENERIC_SOFT_INTERRUPTS */
! 1264:
! 1265: sc->sc_bus.intr_context--;
! 1266: }
! 1267:
! 1268: /* Check for an interrupt. */
! 1269: void
! 1270: uhci_check_intr(uhci_softc_t *sc, uhci_intr_info_t *ii)
! 1271: {
! 1272: uhci_soft_td_t *std, *lstd;
! 1273: u_int32_t status;
! 1274:
! 1275: DPRINTFN(15, ("uhci_check_intr: ii=%p\n", ii));
! 1276: #ifdef DIAGNOSTIC
! 1277: if (ii == NULL) {
! 1278: printf("uhci_check_intr: no ii? %p\n", ii);
! 1279: return;
! 1280: }
! 1281: #endif
! 1282: if (ii->xfer->status == USBD_CANCELLED ||
! 1283: ii->xfer->status == USBD_TIMEOUT) {
! 1284: DPRINTF(("uhci_check_intr: aborted xfer=%p\n", ii->xfer));
! 1285: return;
! 1286: }
! 1287:
! 1288: if (ii->stdstart == NULL)
! 1289: return;
! 1290: lstd = ii->stdend;
! 1291: #ifdef DIAGNOSTIC
! 1292: if (lstd == NULL) {
! 1293: printf("uhci_check_intr: std==0\n");
! 1294: return;
! 1295: }
! 1296: #endif
! 1297: /*
! 1298: * If the last TD is still active we need to check whether there
! 1299: * is an error somewhere in the middle, or whether there was a
! 1300: * short packet (SPD and not ACTIVE).
! 1301: */
! 1302: if (letoh32(lstd->td.td_status) & UHCI_TD_ACTIVE) {
! 1303: DPRINTFN(12, ("uhci_check_intr: active ii=%p\n", ii));
! 1304: for (std = ii->stdstart; std != lstd; std = std->link.std) {
! 1305: status = letoh32(std->td.td_status);
! 1306: /* If there's an active TD the xfer isn't done. */
! 1307: if (status & UHCI_TD_ACTIVE)
! 1308: break;
! 1309: /* Any kind of error makes the xfer done. */
! 1310: if (status & UHCI_TD_STALLED)
! 1311: goto done;
! 1312: /* We want short packets, and it is short: it's done */
! 1313: if ((status & UHCI_TD_SPD) &&
! 1314: UHCI_TD_GET_ACTLEN(status) <
! 1315: UHCI_TD_GET_MAXLEN(letoh32(std->td.td_token)))
! 1316: goto done;
! 1317: }
! 1318: DPRINTFN(12, ("uhci_check_intr: ii=%p std=%p still active\n",
! 1319: ii, ii->stdstart));
! 1320: return;
! 1321: }
! 1322: done:
! 1323: DPRINTFN(12, ("uhci_check_intr: ii=%p done\n", ii));
! 1324: timeout_del(&ii->xfer->timeout_handle);
! 1325: uhci_idone(ii);
! 1326: }
! 1327:
! 1328: /* Called at splusb() */
! 1329: void
! 1330: uhci_idone(uhci_intr_info_t *ii)
! 1331: {
! 1332: usbd_xfer_handle xfer = ii->xfer;
! 1333: struct uhci_pipe *upipe = (struct uhci_pipe *)xfer->pipe;
! 1334: uhci_soft_td_t *std;
! 1335: u_int32_t status = 0, nstatus;
! 1336: int actlen;
! 1337:
! 1338: DPRINTFN(12, ("uhci_idone: ii=%p\n", ii));
! 1339: #ifdef DIAGNOSTIC
! 1340: {
! 1341: int s = splhigh();
! 1342: if (ii->isdone) {
! 1343: splx(s);
! 1344: #ifdef UHCI_DEBUG
! 1345: printf("uhci_idone: ii is done!\n ");
! 1346: uhci_dump_ii(ii);
! 1347: #else
! 1348: printf("uhci_idone: ii=%p is done!\n", ii);
! 1349: #endif
! 1350: return;
! 1351: }
! 1352: ii->isdone = 1;
! 1353: splx(s);
! 1354: }
! 1355: #endif
! 1356:
! 1357: if (xfer->nframes != 0) {
! 1358: /* Isoc transfer, do things differently. */
! 1359: uhci_soft_td_t **stds = upipe->u.iso.stds;
! 1360: int i, n, nframes, len;
! 1361:
! 1362: DPRINTFN(5,("uhci_idone: ii=%p isoc ready\n", ii));
! 1363:
! 1364: nframes = xfer->nframes;
! 1365: actlen = 0;
! 1366: n = UXFER(xfer)->curframe;
! 1367: for (i = 0; i < nframes; i++) {
! 1368: std = stds[n];
! 1369: #ifdef UHCI_DEBUG
! 1370: if (uhcidebug > 5) {
! 1371: DPRINTFN(-1,("uhci_idone: isoc TD %d\n", i));
! 1372: uhci_dump_td(std);
! 1373: }
! 1374: #endif
! 1375: if (++n >= UHCI_VFRAMELIST_COUNT)
! 1376: n = 0;
! 1377: status = letoh32(std->td.td_status);
! 1378: len = UHCI_TD_GET_ACTLEN(status);
! 1379: xfer->frlengths[i] = len;
! 1380: actlen += len;
! 1381: }
! 1382: upipe->u.iso.inuse -= nframes;
! 1383: xfer->actlen = actlen;
! 1384: xfer->status = USBD_NORMAL_COMPLETION;
! 1385: goto end;
! 1386: }
! 1387:
! 1388: #ifdef UHCI_DEBUG
! 1389: DPRINTFN(10, ("uhci_idone: ii=%p, xfer=%p, pipe=%p ready\n",
! 1390: ii, xfer, upipe));
! 1391: if (uhcidebug > 10)
! 1392: uhci_dump_tds(ii->stdstart);
! 1393: #endif
! 1394:
! 1395: /* The transfer is done, compute actual length and status. */
! 1396: actlen = 0;
! 1397: for (std = ii->stdstart; std != NULL; std = std->link.std) {
! 1398: nstatus = letoh32(std->td.td_status);
! 1399: if (nstatus & UHCI_TD_ACTIVE)
! 1400: break;
! 1401:
! 1402: status = nstatus;
! 1403: if (UHCI_TD_GET_PID(letoh32(std->td.td_token)) !=
! 1404: UHCI_TD_PID_SETUP)
! 1405: actlen += UHCI_TD_GET_ACTLEN(status);
! 1406: else {
! 1407: /*
! 1408: * UHCI will report CRCTO in addition to a STALL or NAK
! 1409: * for a SETUP transaction. See section 3.2.2, "TD
! 1410: * CONTROL AND STATUS".
! 1411: */
! 1412: if (status & (UHCI_TD_STALLED | UHCI_TD_NAK))
! 1413: status &= ~UHCI_TD_CRCTO;
! 1414: }
! 1415: }
! 1416: /* If there are left over TDs we need to update the toggle. */
! 1417: if (std != NULL)
! 1418: upipe->nexttoggle = UHCI_TD_GET_DT(letoh32(std->td.td_token));
! 1419:
! 1420: status &= UHCI_TD_ERROR;
! 1421: DPRINTFN(10, ("uhci_idone: actlen=%d, status=0x%x\n",
! 1422: actlen, status));
! 1423: xfer->actlen = actlen;
! 1424: if (status != 0) {
! 1425: #ifdef UHCI_DEBUG
! 1426: char sbuf[128];
! 1427:
! 1428: bitmask_snprintf((u_int32_t)status,
! 1429: "\20\22BITSTUFF\23CRCTO\24NAK\25"
! 1430: "BABBLE\26DBUFFER\27STALLED\30ACTIVE",
! 1431: sbuf, sizeof(sbuf));
! 1432:
! 1433: DPRINTFN((status == UHCI_TD_STALLED)*10,
! 1434: ("uhci_idone: error, addr=%d, endpt=0x%02x, "
! 1435: "status 0x%s\n",
! 1436: xfer->pipe->device->address,
! 1437: xfer->pipe->endpoint->edesc->bEndpointAddress,
! 1438: sbuf));
! 1439: #endif
! 1440:
! 1441: if (status == UHCI_TD_STALLED)
! 1442: xfer->status = USBD_STALLED;
! 1443: else
! 1444: xfer->status = USBD_IOERROR; /* more info XXX */
! 1445: } else {
! 1446: xfer->status = USBD_NORMAL_COMPLETION;
! 1447: }
! 1448:
! 1449: end:
! 1450: usb_transfer_complete(xfer);
! 1451: DPRINTFN(12, ("uhci_idone: ii=%p done\n", ii));
! 1452: }
! 1453:
! 1454: /*
! 1455: * Called when a request does not complete.
! 1456: */
! 1457: void
! 1458: uhci_timeout(void *addr)
! 1459: {
! 1460: uhci_intr_info_t *ii = addr;
! 1461: struct uhci_xfer *uxfer = UXFER(ii->xfer);
! 1462: struct uhci_pipe *upipe = (struct uhci_pipe *)uxfer->xfer.pipe;
! 1463: uhci_softc_t *sc = (uhci_softc_t *)upipe->pipe.device->bus;
! 1464:
! 1465: DPRINTF(("uhci_timeout: uxfer=%p\n", uxfer));
! 1466:
! 1467: if (sc->sc_dying) {
! 1468: uhci_abort_xfer(&uxfer->xfer, USBD_TIMEOUT);
! 1469: return;
! 1470: }
! 1471:
! 1472: /* Execute the abort in a process context. */
! 1473: usb_init_task(&uxfer->abort_task, uhci_timeout_task, ii->xfer);
! 1474: usb_add_task(uxfer->xfer.pipe->device, &uxfer->abort_task);
! 1475: }
! 1476:
! 1477: void
! 1478: uhci_timeout_task(void *addr)
! 1479: {
! 1480: usbd_xfer_handle xfer = addr;
! 1481: int s;
! 1482:
! 1483: DPRINTF(("uhci_timeout_task: xfer=%p\n", xfer));
! 1484:
! 1485: s = splusb();
! 1486: uhci_abort_xfer(xfer, USBD_TIMEOUT);
! 1487: splx(s);
! 1488: }
! 1489:
! 1490: /*
! 1491: * Wait here until controller claims to have an interrupt.
! 1492: * Then call uhci_intr and return. Use timeout to avoid waiting
! 1493: * too long.
! 1494: * Only used during boot when interrupts are not enabled yet.
! 1495: */
! 1496: void
! 1497: uhci_waitintr(uhci_softc_t *sc, usbd_xfer_handle xfer)
! 1498: {
! 1499: int timo = xfer->timeout;
! 1500: uhci_intr_info_t *ii;
! 1501:
! 1502: DPRINTFN(10,("uhci_waitintr: timeout = %dms\n", timo));
! 1503:
! 1504: xfer->status = USBD_IN_PROGRESS;
! 1505: for (; timo >= 0; timo--) {
! 1506: usb_delay_ms(&sc->sc_bus, 1);
! 1507: DPRINTFN(20,("uhci_waitintr: 0x%04x\n", UREAD2(sc, UHCI_STS)));
! 1508: if (UREAD2(sc, UHCI_STS) & UHCI_STS_ALLINTRS) {
! 1509: uhci_intr1(sc);
! 1510: if (xfer->status != USBD_IN_PROGRESS)
! 1511: return;
! 1512: }
! 1513: }
! 1514:
! 1515: /* Timeout */
! 1516: DPRINTF(("uhci_waitintr: timeout\n"));
! 1517: for (ii = LIST_FIRST(&sc->sc_intrhead);
! 1518: ii != NULL && ii->xfer != xfer;
! 1519: ii = LIST_NEXT(ii, list))
! 1520: ;
! 1521: #ifdef DIAGNOSTIC
! 1522: if (ii == NULL)
! 1523: panic("uhci_waitintr: lost intr_info");
! 1524: #endif
! 1525: uhci_idone(ii);
! 1526: }
! 1527:
! 1528: void
! 1529: uhci_poll(struct usbd_bus *bus)
! 1530: {
! 1531: uhci_softc_t *sc = (uhci_softc_t *)bus;
! 1532:
! 1533: if (UREAD2(sc, UHCI_STS) & UHCI_STS_ALLINTRS)
! 1534: uhci_intr1(sc);
! 1535: }
! 1536:
! 1537: void
! 1538: uhci_reset(uhci_softc_t *sc)
! 1539: {
! 1540: int n;
! 1541:
! 1542: UHCICMD(sc, UHCI_CMD_HCRESET);
! 1543: /* The reset bit goes low when the controller is done. */
! 1544: for (n = 0; n < UHCI_RESET_TIMEOUT &&
! 1545: (UREAD2(sc, UHCI_CMD) & UHCI_CMD_HCRESET); n++)
! 1546: usb_delay_ms(&sc->sc_bus, 1);
! 1547: if (n >= UHCI_RESET_TIMEOUT)
! 1548: printf("%s: controller did not reset\n",
! 1549: sc->sc_bus.bdev.dv_xname);
! 1550: }
! 1551:
! 1552: usbd_status
! 1553: uhci_run(uhci_softc_t *sc, int run)
! 1554: {
! 1555: int s, n, running;
! 1556: u_int16_t cmd;
! 1557:
! 1558: run = run != 0;
! 1559: s = splhardusb();
! 1560: DPRINTF(("uhci_run: setting run=%d\n", run));
! 1561: cmd = UREAD2(sc, UHCI_CMD);
! 1562: if (run)
! 1563: cmd |= UHCI_CMD_RS;
! 1564: else
! 1565: cmd &= ~UHCI_CMD_RS;
! 1566: UHCICMD(sc, cmd);
! 1567: for(n = 0; n < 10; n++) {
! 1568: running = !(UREAD2(sc, UHCI_STS) & UHCI_STS_HCH);
! 1569: /* return when we've entered the state we want */
! 1570: if (run == running) {
! 1571: splx(s);
! 1572: DPRINTF(("uhci_run: done cmd=0x%x sts=0x%x\n",
! 1573: UREAD2(sc, UHCI_CMD), UREAD2(sc, UHCI_STS)));
! 1574: return (USBD_NORMAL_COMPLETION);
! 1575: }
! 1576: usb_delay_ms(&sc->sc_bus, 1);
! 1577: }
! 1578: splx(s);
! 1579: printf("%s: cannot %s\n", sc->sc_bus.bdev.dv_xname,
! 1580: run ? "start" : "stop");
! 1581: return (USBD_IOERROR);
! 1582: }
! 1583:
! 1584: /*
! 1585: * Memory management routines.
! 1586: * uhci_alloc_std allocates TDs
! 1587: * uhci_alloc_sqh allocates QHs
! 1588: * These two routines do their own free list management,
! 1589: * partly for speed, partly because allocating DMAable memory
! 1590: * has page size granularaity so much memory would be wasted if
! 1591: * only one TD/QH (32 bytes) was placed in each allocated chunk.
! 1592: */
! 1593:
! 1594: uhci_soft_td_t *
! 1595: uhci_alloc_std(uhci_softc_t *sc)
! 1596: {
! 1597: uhci_soft_td_t *std;
! 1598: usbd_status err;
! 1599: int i, offs;
! 1600: usb_dma_t dma;
! 1601:
! 1602: if (sc->sc_freetds == NULL) {
! 1603: DPRINTFN(2,("uhci_alloc_std: allocating chunk\n"));
! 1604: err = usb_allocmem(&sc->sc_bus, UHCI_STD_SIZE * UHCI_STD_CHUNK,
! 1605: UHCI_TD_ALIGN, &dma);
! 1606: if (err)
! 1607: return (0);
! 1608: for(i = 0; i < UHCI_STD_CHUNK; i++) {
! 1609: offs = i * UHCI_STD_SIZE;
! 1610: std = KERNADDR(&dma, offs);
! 1611: std->physaddr = DMAADDR(&dma, offs);
! 1612: std->link.std = sc->sc_freetds;
! 1613: sc->sc_freetds = std;
! 1614: }
! 1615: }
! 1616: std = sc->sc_freetds;
! 1617: sc->sc_freetds = std->link.std;
! 1618: memset(&std->td, 0, sizeof(uhci_td_t));
! 1619: return std;
! 1620: }
! 1621:
! 1622: void
! 1623: uhci_free_std(uhci_softc_t *sc, uhci_soft_td_t *std)
! 1624: {
! 1625: #ifdef DIAGNOSTIC
! 1626: #define TD_IS_FREE 0x12345678
! 1627: if (letoh32(std->td.td_token) == TD_IS_FREE) {
! 1628: printf("uhci_free_std: freeing free TD %p\n", std);
! 1629: return;
! 1630: }
! 1631: std->td.td_token = htole32(TD_IS_FREE);
! 1632: #endif
! 1633: std->link.std = sc->sc_freetds;
! 1634: sc->sc_freetds = std;
! 1635: }
! 1636:
! 1637: uhci_soft_qh_t *
! 1638: uhci_alloc_sqh(uhci_softc_t *sc)
! 1639: {
! 1640: uhci_soft_qh_t *sqh;
! 1641: usbd_status err;
! 1642: int i, offs;
! 1643: usb_dma_t dma;
! 1644:
! 1645: if (sc->sc_freeqhs == NULL) {
! 1646: DPRINTFN(2, ("uhci_alloc_sqh: allocating chunk\n"));
! 1647: err = usb_allocmem(&sc->sc_bus, UHCI_SQH_SIZE * UHCI_SQH_CHUNK,
! 1648: UHCI_QH_ALIGN, &dma);
! 1649: if (err)
! 1650: return (0);
! 1651: for(i = 0; i < UHCI_SQH_CHUNK; i++) {
! 1652: offs = i * UHCI_SQH_SIZE;
! 1653: sqh = KERNADDR(&dma, offs);
! 1654: sqh->physaddr = DMAADDR(&dma, offs);
! 1655: sqh->hlink = sc->sc_freeqhs;
! 1656: sc->sc_freeqhs = sqh;
! 1657: }
! 1658: }
! 1659: sqh = sc->sc_freeqhs;
! 1660: sc->sc_freeqhs = sqh->hlink;
! 1661: memset(&sqh->qh, 0, sizeof(uhci_qh_t));
! 1662: return (sqh);
! 1663: }
! 1664:
! 1665: void
! 1666: uhci_free_sqh(uhci_softc_t *sc, uhci_soft_qh_t *sqh)
! 1667: {
! 1668: sqh->hlink = sc->sc_freeqhs;
! 1669: sc->sc_freeqhs = sqh;
! 1670: }
! 1671:
! 1672: void
! 1673: uhci_free_std_chain(uhci_softc_t *sc, uhci_soft_td_t *std,
! 1674: uhci_soft_td_t *stdend)
! 1675: {
! 1676: uhci_soft_td_t *p;
! 1677:
! 1678: for (; std != stdend; std = p) {
! 1679: p = std->link.std;
! 1680: uhci_free_std(sc, std);
! 1681: }
! 1682: }
! 1683:
! 1684: usbd_status
! 1685: uhci_alloc_std_chain(struct uhci_pipe *upipe, uhci_softc_t *sc, int len,
! 1686: int rd, u_int16_t flags, usb_dma_t *dma,
! 1687: uhci_soft_td_t **sp, uhci_soft_td_t **ep)
! 1688: {
! 1689: uhci_soft_td_t *p, *lastp;
! 1690: uhci_physaddr_t lastlink;
! 1691: int i, ntd, l, tog, maxp;
! 1692: u_int32_t status;
! 1693: int addr = upipe->pipe.device->address;
! 1694: int endpt = upipe->pipe.endpoint->edesc->bEndpointAddress;
! 1695:
! 1696: DPRINTFN(8, ("uhci_alloc_std_chain: addr=%d endpt=%d len=%d speed=%d "
! 1697: "flags=0x%x\n", addr, UE_GET_ADDR(endpt), len,
! 1698: upipe->pipe.device->speed, flags));
! 1699: maxp = UGETW(upipe->pipe.endpoint->edesc->wMaxPacketSize);
! 1700: if (maxp == 0) {
! 1701: printf("uhci_alloc_std_chain: maxp=0\n");
! 1702: return (USBD_INVAL);
! 1703: }
! 1704: ntd = (len + maxp - 1) / maxp;
! 1705: if ((flags & USBD_FORCE_SHORT_XFER) && len % maxp == 0)
! 1706: ntd++;
! 1707: DPRINTFN(10, ("uhci_alloc_std_chain: maxp=%d ntd=%d\n", maxp, ntd));
! 1708: if (ntd == 0) {
! 1709: *sp = *ep = 0;
! 1710: DPRINTFN(-1,("uhci_alloc_std_chain: ntd=0\n"));
! 1711: return (USBD_NORMAL_COMPLETION);
! 1712: }
! 1713: tog = upipe->nexttoggle;
! 1714: if (ntd % 2 == 0)
! 1715: tog ^= 1;
! 1716: upipe->nexttoggle = tog ^ 1;
! 1717: lastp = NULL;
! 1718: lastlink = UHCI_PTR_T;
! 1719: ntd--;
! 1720: status = UHCI_TD_ZERO_ACTLEN(UHCI_TD_SET_ERRCNT(3) | UHCI_TD_ACTIVE);
! 1721: if (upipe->pipe.device->speed == USB_SPEED_LOW)
! 1722: status |= UHCI_TD_LS;
! 1723: if (flags & USBD_SHORT_XFER_OK)
! 1724: status |= UHCI_TD_SPD;
! 1725: for (i = ntd; i >= 0; i--) {
! 1726: p = uhci_alloc_std(sc);
! 1727: if (p == NULL) {
! 1728: uhci_free_std_chain(sc, lastp, NULL);
! 1729: return (USBD_NOMEM);
! 1730: }
! 1731: p->link.std = lastp;
! 1732: p->td.td_link = htole32(lastlink | UHCI_PTR_VF | UHCI_PTR_TD);
! 1733: lastp = p;
! 1734: lastlink = p->physaddr;
! 1735: p->td.td_status = htole32(status);
! 1736: if (i == ntd) {
! 1737: /* last TD */
! 1738: l = len % maxp;
! 1739: if (l == 0 && !(flags & USBD_FORCE_SHORT_XFER))
! 1740: l = maxp;
! 1741: *ep = p;
! 1742: } else
! 1743: l = maxp;
! 1744: p->td.td_token =
! 1745: htole32(rd ? UHCI_TD_IN (l, endpt, addr, tog) :
! 1746: UHCI_TD_OUT(l, endpt, addr, tog));
! 1747: p->td.td_buffer = htole32(DMAADDR(dma, i * maxp));
! 1748: tog ^= 1;
! 1749: }
! 1750: *sp = lastp;
! 1751: DPRINTFN(10, ("uhci_alloc_std_chain: nexttog=%d\n",
! 1752: upipe->nexttoggle));
! 1753: return (USBD_NORMAL_COMPLETION);
! 1754: }
! 1755:
! 1756: void
! 1757: uhci_device_clear_toggle(usbd_pipe_handle pipe)
! 1758: {
! 1759: struct uhci_pipe *upipe = (struct uhci_pipe *)pipe;
! 1760: upipe->nexttoggle = 0;
! 1761: }
! 1762:
! 1763: void
! 1764: uhci_noop(usbd_pipe_handle pipe)
! 1765: {
! 1766: }
! 1767:
! 1768: usbd_status
! 1769: uhci_device_bulk_transfer(usbd_xfer_handle xfer)
! 1770: {
! 1771: usbd_status err;
! 1772:
! 1773: /* Insert last in queue. */
! 1774: err = usb_insert_transfer(xfer);
! 1775: if (err)
! 1776: return (err);
! 1777:
! 1778: /*
! 1779: * Pipe isn't running (otherwise err would be USBD_INPROG),
! 1780: * so start it first.
! 1781: */
! 1782: return (uhci_device_bulk_start(SIMPLEQ_FIRST(&xfer->pipe->queue)));
! 1783: }
! 1784:
! 1785: usbd_status
! 1786: uhci_device_bulk_start(usbd_xfer_handle xfer)
! 1787: {
! 1788: struct uhci_pipe *upipe = (struct uhci_pipe *)xfer->pipe;
! 1789: usbd_device_handle dev = upipe->pipe.device;
! 1790: uhci_softc_t *sc = (uhci_softc_t *)dev->bus;
! 1791: uhci_intr_info_t *ii = &UXFER(xfer)->iinfo;
! 1792: uhci_soft_td_t *data, *dataend;
! 1793: uhci_soft_qh_t *sqh;
! 1794: usbd_status err;
! 1795: int len, isread, endpt;
! 1796: int s;
! 1797:
! 1798: DPRINTFN(3, ("uhci_device_bulk_start: xfer=%p len=%d flags=%d ii=%p\n",
! 1799: xfer, xfer->length, xfer->flags, ii));
! 1800:
! 1801: if (sc->sc_dying)
! 1802: return (USBD_IOERROR);
! 1803:
! 1804: #ifdef DIAGNOSTIC
! 1805: if (xfer->rqflags & URQ_REQUEST)
! 1806: panic("uhci_device_bulk_transfer: a request");
! 1807: #endif
! 1808:
! 1809: len = xfer->length;
! 1810: endpt = upipe->pipe.endpoint->edesc->bEndpointAddress;
! 1811: isread = UE_GET_DIR(endpt) == UE_DIR_IN;
! 1812: sqh = upipe->u.bulk.sqh;
! 1813:
! 1814: upipe->u.bulk.isread = isread;
! 1815: upipe->u.bulk.length = len;
! 1816:
! 1817: err = uhci_alloc_std_chain(upipe, sc, len, isread, xfer->flags,
! 1818: &xfer->dmabuf, &data, &dataend);
! 1819: if (err)
! 1820: return (err);
! 1821: dataend->td.td_status |= htole32(UHCI_TD_IOC);
! 1822:
! 1823: #ifdef UHCI_DEBUG
! 1824: if (uhcidebug > 8) {
! 1825: DPRINTF(("uhci_device_bulk_transfer: data(1)\n"));
! 1826: uhci_dump_tds(data);
! 1827: }
! 1828: #endif
! 1829:
! 1830: /* Set up interrupt info. */
! 1831: ii->xfer = xfer;
! 1832: ii->stdstart = data;
! 1833: ii->stdend = dataend;
! 1834: #ifdef DIAGNOSTIC
! 1835: if (!ii->isdone) {
! 1836: printf("uhci_device_bulk_transfer: not done, ii=%p\n", ii);
! 1837: }
! 1838: ii->isdone = 0;
! 1839: #endif
! 1840:
! 1841: sqh->elink = data;
! 1842: sqh->qh.qh_elink = htole32(data->physaddr | UHCI_PTR_TD);
! 1843:
! 1844: s = splusb();
! 1845: uhci_add_bulk(sc, sqh);
! 1846: uhci_add_intr_info(sc, ii);
! 1847:
! 1848: if (xfer->timeout && !sc->sc_bus.use_polling) {
! 1849: timeout_del(&xfer->timeout_handle);
! 1850: timeout_set(&xfer->timeout_handle, uhci_timeout, ii);
! 1851: timeout_add(&xfer->timeout_handle, mstohz(xfer->timeout));
! 1852: }
! 1853: xfer->status = USBD_IN_PROGRESS;
! 1854: splx(s);
! 1855:
! 1856: #ifdef UHCI_DEBUG
! 1857: if (uhcidebug > 10) {
! 1858: DPRINTF(("uhci_device_bulk_transfer: data(2)\n"));
! 1859: uhci_dump_tds(data);
! 1860: }
! 1861: #endif
! 1862:
! 1863: if (sc->sc_bus.use_polling)
! 1864: uhci_waitintr(sc, xfer);
! 1865:
! 1866: return (USBD_IN_PROGRESS);
! 1867: }
! 1868:
! 1869: /* Abort a device bulk request. */
! 1870: void
! 1871: uhci_device_bulk_abort(usbd_xfer_handle xfer)
! 1872: {
! 1873: DPRINTF(("uhci_device_bulk_abort:\n"));
! 1874: uhci_abort_xfer(xfer, USBD_CANCELLED);
! 1875: }
! 1876:
! 1877: /*
! 1878: * Abort a device request.
! 1879: * If this routine is called at splusb() it guarantees that the request
! 1880: * will be removed from the hardware scheduling and that the callback
! 1881: * for it will be called with USBD_CANCELLED status.
! 1882: * It's impossible to guarantee that the requested transfer will not
! 1883: * have happened since the hardware runs concurrently.
! 1884: * If the transaction has already happened we rely on the ordinary
! 1885: * interrupt processing to process it.
! 1886: */
! 1887: void
! 1888: uhci_abort_xfer(usbd_xfer_handle xfer, usbd_status status)
! 1889: {
! 1890: uhci_intr_info_t *ii = &UXFER(xfer)->iinfo;
! 1891: struct uhci_pipe *upipe = (struct uhci_pipe *)xfer->pipe;
! 1892: uhci_softc_t *sc = (uhci_softc_t *)upipe->pipe.device->bus;
! 1893: uhci_soft_td_t *std;
! 1894: int s;
! 1895:
! 1896: DPRINTFN(1,("uhci_abort_xfer: xfer=%p, status=%d\n", xfer, status));
! 1897:
! 1898: if (sc->sc_dying) {
! 1899: /* If we're dying, just do the software part. */
! 1900: s = splusb();
! 1901: xfer->status = status; /* make software ignore it */
! 1902: timeout_del(&xfer->timeout_handle);
! 1903: usb_transfer_complete(xfer);
! 1904: splx(s);
! 1905: return;
! 1906: }
! 1907:
! 1908: if (xfer->device->bus->intr_context || !curproc)
! 1909: panic("uhci_abort_xfer: not in process context");
! 1910:
! 1911: /*
! 1912: * Step 1: Make interrupt routine and hardware ignore xfer.
! 1913: */
! 1914: s = splusb();
! 1915: xfer->status = status; /* make software ignore it */
! 1916: timeout_del(&xfer->timeout_handle);
! 1917: DPRINTFN(1,("uhci_abort_xfer: stop ii=%p\n", ii));
! 1918: for (std = ii->stdstart; std != NULL; std = std->link.std)
! 1919: std->td.td_status &= htole32(~(UHCI_TD_ACTIVE | UHCI_TD_IOC));
! 1920: splx(s);
! 1921:
! 1922: /*
! 1923: * Step 2: Wait until we know hardware has finished any possible
! 1924: * use of the xfer. Also make sure the soft interrupt routine
! 1925: * has run.
! 1926: */
! 1927: usb_delay_ms(upipe->pipe.device->bus, 2); /* Hardware finishes in 1ms */
! 1928: s = splusb();
! 1929: #ifdef __HAVE_GENERIC_SOFT_INTERRUPTS
! 1930: sc->sc_softwake = 1;
! 1931: #endif /* __HAVE_GENERIC_SOFT_INTERRUPTS */
! 1932: usb_schedsoftintr(&sc->sc_bus);
! 1933: #ifdef __HAVE_GENERIC_SOFT_INTERRUPTS
! 1934: DPRINTFN(1,("uhci_abort_xfer: tsleep\n"));
! 1935: tsleep(&sc->sc_softwake, PZERO, "uhciab", 0);
! 1936: #endif /* __HAVE_GENERIC_SOFT_INTERRUPTS */
! 1937: splx(s);
! 1938:
! 1939: /*
! 1940: * Step 3: Execute callback.
! 1941: */
! 1942: DPRINTFN(1,("uhci_abort_xfer: callback\n"));
! 1943: s = splusb();
! 1944: #ifdef DIAGNOSTIC
! 1945: ii->isdone = 1;
! 1946: #endif
! 1947: usb_transfer_complete(xfer);
! 1948: splx(s);
! 1949: }
! 1950:
! 1951: /* Close a device bulk pipe. */
! 1952: void
! 1953: uhci_device_bulk_close(usbd_pipe_handle pipe)
! 1954: {
! 1955: struct uhci_pipe *upipe = (struct uhci_pipe *)pipe;
! 1956: usbd_device_handle dev = upipe->pipe.device;
! 1957: uhci_softc_t *sc = (uhci_softc_t *)dev->bus;
! 1958:
! 1959: uhci_free_sqh(sc, upipe->u.bulk.sqh);
! 1960: pipe->endpoint->savedtoggle = upipe->nexttoggle;
! 1961: }
! 1962:
! 1963: usbd_status
! 1964: uhci_device_ctrl_transfer(usbd_xfer_handle xfer)
! 1965: {
! 1966: usbd_status err;
! 1967:
! 1968: /* Insert last in queue. */
! 1969: err = usb_insert_transfer(xfer);
! 1970: if (err)
! 1971: return (err);
! 1972:
! 1973: /*
! 1974: * Pipe isn't running (otherwise err would be USBD_INPROG),
! 1975: * so start it first.
! 1976: */
! 1977: return (uhci_device_ctrl_start(SIMPLEQ_FIRST(&xfer->pipe->queue)));
! 1978: }
! 1979:
! 1980: usbd_status
! 1981: uhci_device_ctrl_start(usbd_xfer_handle xfer)
! 1982: {
! 1983: uhci_softc_t *sc = (uhci_softc_t *)xfer->pipe->device->bus;
! 1984: usbd_status err;
! 1985:
! 1986: if (sc->sc_dying)
! 1987: return (USBD_IOERROR);
! 1988:
! 1989: #ifdef DIAGNOSTIC
! 1990: if (!(xfer->rqflags & URQ_REQUEST))
! 1991: panic("uhci_device_ctrl_transfer: not a request");
! 1992: #endif
! 1993:
! 1994: err = uhci_device_request(xfer);
! 1995: if (err)
! 1996: return (err);
! 1997:
! 1998: if (sc->sc_bus.use_polling)
! 1999: uhci_waitintr(sc, xfer);
! 2000: return (USBD_IN_PROGRESS);
! 2001: }
! 2002:
! 2003: usbd_status
! 2004: uhci_device_intr_transfer(usbd_xfer_handle xfer)
! 2005: {
! 2006: usbd_status err;
! 2007:
! 2008: /* Insert last in queue. */
! 2009: err = usb_insert_transfer(xfer);
! 2010: if (err)
! 2011: return (err);
! 2012:
! 2013: /*
! 2014: * Pipe isn't running (otherwise err would be USBD_INPROG),
! 2015: * so start it first.
! 2016: */
! 2017: return (uhci_device_intr_start(SIMPLEQ_FIRST(&xfer->pipe->queue)));
! 2018: }
! 2019:
! 2020: usbd_status
! 2021: uhci_device_intr_start(usbd_xfer_handle xfer)
! 2022: {
! 2023: struct uhci_pipe *upipe = (struct uhci_pipe *)xfer->pipe;
! 2024: usbd_device_handle dev = upipe->pipe.device;
! 2025: uhci_softc_t *sc = (uhci_softc_t *)dev->bus;
! 2026: uhci_intr_info_t *ii = &UXFER(xfer)->iinfo;
! 2027: uhci_soft_td_t *data, *dataend;
! 2028: uhci_soft_qh_t *sqh;
! 2029: usbd_status err;
! 2030: int isread, endpt;
! 2031: int i, s;
! 2032:
! 2033: if (sc->sc_dying)
! 2034: return (USBD_IOERROR);
! 2035:
! 2036: DPRINTFN(3,("uhci_device_intr_transfer: xfer=%p len=%d flags=%d\n",
! 2037: xfer, xfer->length, xfer->flags));
! 2038:
! 2039: #ifdef DIAGNOSTIC
! 2040: if (xfer->rqflags & URQ_REQUEST)
! 2041: panic("uhci_device_intr_transfer: a request");
! 2042: #endif
! 2043:
! 2044: endpt = upipe->pipe.endpoint->edesc->bEndpointAddress;
! 2045: isread = UE_GET_DIR(endpt) == UE_DIR_IN;
! 2046:
! 2047: upipe->u.intr.isread = isread;
! 2048:
! 2049: err = uhci_alloc_std_chain(upipe, sc, xfer->length, isread,
! 2050: xfer->flags, &xfer->dmabuf, &data,
! 2051: &dataend);
! 2052:
! 2053: if (err)
! 2054: return (err);
! 2055: dataend->td.td_status |= htole32(UHCI_TD_IOC);
! 2056:
! 2057: #ifdef UHCI_DEBUG
! 2058: if (uhcidebug > 10) {
! 2059: DPRINTF(("uhci_device_intr_transfer: data(1)\n"));
! 2060: uhci_dump_tds(data);
! 2061: uhci_dump_qh(upipe->u.intr.qhs[0]);
! 2062: }
! 2063: #endif
! 2064:
! 2065: s = splusb();
! 2066: /* Set up interrupt info. */
! 2067: ii->xfer = xfer;
! 2068: ii->stdstart = data;
! 2069: ii->stdend = dataend;
! 2070: #ifdef DIAGNOSTIC
! 2071: if (!ii->isdone) {
! 2072: printf("uhci_device_intr_transfer: not done, ii=%p\n", ii);
! 2073: }
! 2074: ii->isdone = 0;
! 2075: #endif
! 2076:
! 2077: DPRINTFN(10,("uhci_device_intr_transfer: qhs[0]=%p\n",
! 2078: upipe->u.intr.qhs[0]));
! 2079: for (i = 0; i < upipe->u.intr.npoll; i++) {
! 2080: sqh = upipe->u.intr.qhs[i];
! 2081: sqh->elink = data;
! 2082: sqh->qh.qh_elink = htole32(data->physaddr | UHCI_PTR_TD);
! 2083: }
! 2084: uhci_add_intr_info(sc, ii);
! 2085: xfer->status = USBD_IN_PROGRESS;
! 2086: splx(s);
! 2087:
! 2088: #ifdef UHCI_DEBUG
! 2089: if (uhcidebug > 10) {
! 2090: DPRINTF(("uhci_device_intr_transfer: data(2)\n"));
! 2091: uhci_dump_tds(data);
! 2092: uhci_dump_qh(upipe->u.intr.qhs[0]);
! 2093: }
! 2094: #endif
! 2095:
! 2096: return (USBD_IN_PROGRESS);
! 2097: }
! 2098:
! 2099: /* Abort a device control request. */
! 2100: void
! 2101: uhci_device_ctrl_abort(usbd_xfer_handle xfer)
! 2102: {
! 2103: DPRINTF(("uhci_device_ctrl_abort:\n"));
! 2104: uhci_abort_xfer(xfer, USBD_CANCELLED);
! 2105: }
! 2106:
! 2107: /* Close a device control pipe. */
! 2108: void
! 2109: uhci_device_ctrl_close(usbd_pipe_handle pipe)
! 2110: {
! 2111: }
! 2112:
! 2113: /* Abort a device interrupt request. */
! 2114: void
! 2115: uhci_device_intr_abort(usbd_xfer_handle xfer)
! 2116: {
! 2117: DPRINTFN(1,("uhci_device_intr_abort: xfer=%p\n", xfer));
! 2118: if (xfer->pipe->intrxfer == xfer) {
! 2119: DPRINTFN(1,("uhci_device_intr_abort: remove\n"));
! 2120: xfer->pipe->intrxfer = NULL;
! 2121: }
! 2122: uhci_abort_xfer(xfer, USBD_CANCELLED);
! 2123: }
! 2124:
! 2125: /* Close a device interrupt pipe. */
! 2126: void
! 2127: uhci_device_intr_close(usbd_pipe_handle pipe)
! 2128: {
! 2129: struct uhci_pipe *upipe = (struct uhci_pipe *)pipe;
! 2130: uhci_softc_t *sc = (uhci_softc_t *)pipe->device->bus;
! 2131: int i, npoll;
! 2132: int s;
! 2133:
! 2134: /* Unlink descriptors from controller data structures. */
! 2135: npoll = upipe->u.intr.npoll;
! 2136: s = splusb();
! 2137: for (i = 0; i < npoll; i++)
! 2138: uhci_remove_intr(sc, upipe->u.intr.qhs[i]);
! 2139: splx(s);
! 2140:
! 2141: /*
! 2142: * We now have to wait for any activity on the physical
! 2143: * descriptors to stop.
! 2144: */
! 2145: usb_delay_ms(&sc->sc_bus, 2);
! 2146:
! 2147: for(i = 0; i < npoll; i++)
! 2148: uhci_free_sqh(sc, upipe->u.intr.qhs[i]);
! 2149: free(upipe->u.intr.qhs, M_USBHC);
! 2150:
! 2151: /* XXX free other resources */
! 2152: }
! 2153:
! 2154: usbd_status
! 2155: uhci_device_request(usbd_xfer_handle xfer)
! 2156: {
! 2157: struct uhci_pipe *upipe = (struct uhci_pipe *)xfer->pipe;
! 2158: usb_device_request_t *req = &xfer->request;
! 2159: usbd_device_handle dev = upipe->pipe.device;
! 2160: uhci_softc_t *sc = (uhci_softc_t *)dev->bus;
! 2161: int addr = dev->address;
! 2162: int endpt = upipe->pipe.endpoint->edesc->bEndpointAddress;
! 2163: uhci_intr_info_t *ii = &UXFER(xfer)->iinfo;
! 2164: uhci_soft_td_t *setup, *data, *stat, *next, *dataend;
! 2165: uhci_soft_qh_t *sqh;
! 2166: int len;
! 2167: u_int32_t ls;
! 2168: usbd_status err;
! 2169: int isread;
! 2170: int s;
! 2171:
! 2172: DPRINTFN(3,("uhci_device_control type=0x%02x, request=0x%02x, "
! 2173: "wValue=0x%04x, wIndex=0x%04x len=%d, addr=%d, endpt=%d\n",
! 2174: req->bmRequestType, req->bRequest, UGETW(req->wValue),
! 2175: UGETW(req->wIndex), UGETW(req->wLength),
! 2176: addr, endpt));
! 2177:
! 2178: ls = dev->speed == USB_SPEED_LOW ? UHCI_TD_LS : 0;
! 2179: isread = req->bmRequestType & UT_READ;
! 2180: len = UGETW(req->wLength);
! 2181:
! 2182: setup = upipe->u.ctl.setup;
! 2183: stat = upipe->u.ctl.stat;
! 2184: sqh = upipe->u.ctl.sqh;
! 2185:
! 2186: /* Set up data transaction */
! 2187: if (len != 0) {
! 2188: upipe->nexttoggle = 1;
! 2189: err = uhci_alloc_std_chain(upipe, sc, len, isread, xfer->flags,
! 2190: &xfer->dmabuf, &data, &dataend);
! 2191: if (err)
! 2192: return (err);
! 2193: next = data;
! 2194: dataend->link.std = stat;
! 2195: dataend->td.td_link = htole32(stat->physaddr | UHCI_PTR_VF | UHCI_PTR_TD);
! 2196: } else {
! 2197: next = stat;
! 2198: }
! 2199: upipe->u.ctl.length = len;
! 2200:
! 2201: memcpy(KERNADDR(&upipe->u.ctl.reqdma, 0), req, sizeof *req);
! 2202:
! 2203: setup->link.std = next;
! 2204: setup->td.td_link = htole32(next->physaddr | UHCI_PTR_VF | UHCI_PTR_TD);
! 2205: setup->td.td_status = htole32(UHCI_TD_SET_ERRCNT(3) | ls |
! 2206: UHCI_TD_ACTIVE);
! 2207: setup->td.td_token = htole32(UHCI_TD_SETUP(sizeof *req, endpt, addr));
! 2208: setup->td.td_buffer = htole32(DMAADDR(&upipe->u.ctl.reqdma, 0));
! 2209:
! 2210: stat->link.std = NULL;
! 2211: stat->td.td_link = htole32(UHCI_PTR_T);
! 2212: stat->td.td_status = htole32(UHCI_TD_SET_ERRCNT(3) | ls |
! 2213: UHCI_TD_ACTIVE | UHCI_TD_IOC);
! 2214: stat->td.td_token =
! 2215: htole32(isread ? UHCI_TD_OUT(0, endpt, addr, 1) :
! 2216: UHCI_TD_IN (0, endpt, addr, 1));
! 2217: stat->td.td_buffer = htole32(0);
! 2218:
! 2219: #ifdef UHCI_DEBUG
! 2220: if (uhcidebug > 10) {
! 2221: DPRINTF(("uhci_device_request: before transfer\n"));
! 2222: uhci_dump_tds(setup);
! 2223: }
! 2224: #endif
! 2225:
! 2226: /* Set up interrupt info. */
! 2227: ii->xfer = xfer;
! 2228: ii->stdstart = setup;
! 2229: ii->stdend = stat;
! 2230: #ifdef DIAGNOSTIC
! 2231: if (!ii->isdone) {
! 2232: printf("uhci_device_request: not done, ii=%p\n", ii);
! 2233: }
! 2234: ii->isdone = 0;
! 2235: #endif
! 2236:
! 2237: sqh->elink = setup;
! 2238: sqh->qh.qh_elink = htole32(setup->physaddr | UHCI_PTR_TD);
! 2239:
! 2240: s = splusb();
! 2241: if (dev->speed == USB_SPEED_LOW)
! 2242: uhci_add_ls_ctrl(sc, sqh);
! 2243: else
! 2244: uhci_add_hs_ctrl(sc, sqh);
! 2245: uhci_add_intr_info(sc, ii);
! 2246: #ifdef UHCI_DEBUG
! 2247: if (uhcidebug > 12) {
! 2248: uhci_soft_td_t *std;
! 2249: uhci_soft_qh_t *xqh;
! 2250: uhci_soft_qh_t *sxqh;
! 2251: int maxqh = 0;
! 2252: uhci_physaddr_t link;
! 2253: DPRINTF(("uhci_enter_ctl_q: follow from [0]\n"));
! 2254: for (std = sc->sc_vframes[0].htd, link = 0;
! 2255: (link & UHCI_PTR_QH) == 0;
! 2256: std = std->link.std) {
! 2257: link = letoh32(std->td.td_link);
! 2258: uhci_dump_td(std);
! 2259: }
! 2260: sxqh = (uhci_soft_qh_t *)std;
! 2261: uhci_dump_qh(sxqh);
! 2262: for (xqh = sxqh;
! 2263: xqh != NULL;
! 2264: xqh = (maxqh++ == 5 || xqh->hlink == sxqh ||
! 2265: xqh->hlink == xqh ? NULL : xqh->hlink)) {
! 2266: uhci_dump_qh(xqh);
! 2267: }
! 2268: DPRINTF(("Enqueued QH:\n"));
! 2269: uhci_dump_qh(sqh);
! 2270: uhci_dump_tds(sqh->elink);
! 2271: }
! 2272: #endif
! 2273: if (xfer->timeout && !sc->sc_bus.use_polling) {
! 2274: timeout_del(&xfer->timeout_handle);
! 2275: timeout_set(&xfer->timeout_handle, uhci_timeout, ii);
! 2276: timeout_add(&xfer->timeout_handle, mstohz(xfer->timeout));
! 2277: }
! 2278: xfer->status = USBD_IN_PROGRESS;
! 2279: splx(s);
! 2280:
! 2281: return (USBD_NORMAL_COMPLETION);
! 2282: }
! 2283:
! 2284: usbd_status
! 2285: uhci_device_isoc_transfer(usbd_xfer_handle xfer)
! 2286: {
! 2287: usbd_status err;
! 2288:
! 2289: DPRINTFN(5,("uhci_device_isoc_transfer: xfer=%p\n", xfer));
! 2290:
! 2291: /* Put it on our queue, */
! 2292: err = usb_insert_transfer(xfer);
! 2293:
! 2294: /* bail out on error, */
! 2295: if (err && err != USBD_IN_PROGRESS)
! 2296: return (err);
! 2297:
! 2298: /* XXX should check inuse here */
! 2299:
! 2300: /* insert into schedule, */
! 2301: uhci_device_isoc_enter(xfer);
! 2302:
! 2303: /* and start if the pipe wasn't running */
! 2304: if (!err)
! 2305: uhci_device_isoc_start(SIMPLEQ_FIRST(&xfer->pipe->queue));
! 2306:
! 2307: return (err);
! 2308: }
! 2309:
! 2310: void
! 2311: uhci_device_isoc_enter(usbd_xfer_handle xfer)
! 2312: {
! 2313: struct uhci_pipe *upipe = (struct uhci_pipe *)xfer->pipe;
! 2314: usbd_device_handle dev = upipe->pipe.device;
! 2315: uhci_softc_t *sc = (uhci_softc_t *)dev->bus;
! 2316: struct iso *iso = &upipe->u.iso;
! 2317: uhci_soft_td_t *std;
! 2318: u_int32_t buf, len, status;
! 2319: int s, i, next, nframes;
! 2320:
! 2321: DPRINTFN(5,("uhci_device_isoc_enter: used=%d next=%d xfer=%p "
! 2322: "nframes=%d\n",
! 2323: iso->inuse, iso->next, xfer, xfer->nframes));
! 2324:
! 2325: if (sc->sc_dying)
! 2326: return;
! 2327:
! 2328: if (xfer->status == USBD_IN_PROGRESS) {
! 2329: /* This request has already been entered into the frame list */
! 2330: printf("uhci_device_isoc_enter: xfer=%p in frame list\n", xfer);
! 2331: /* XXX */
! 2332: }
! 2333:
! 2334: #ifdef DIAGNOSTIC
! 2335: if (iso->inuse >= UHCI_VFRAMELIST_COUNT)
! 2336: printf("uhci_device_isoc_enter: overflow!\n");
! 2337: #endif
! 2338:
! 2339: next = iso->next;
! 2340: if (next == -1) {
! 2341: /* Not in use yet, schedule it a few frames ahead. */
! 2342: next = (UREAD2(sc, UHCI_FRNUM) + 3) % UHCI_VFRAMELIST_COUNT;
! 2343: DPRINTFN(2,("uhci_device_isoc_enter: start next=%d\n", next));
! 2344: }
! 2345:
! 2346: xfer->status = USBD_IN_PROGRESS;
! 2347: UXFER(xfer)->curframe = next;
! 2348:
! 2349: buf = DMAADDR(&xfer->dmabuf, 0);
! 2350: status = UHCI_TD_ZERO_ACTLEN(UHCI_TD_SET_ERRCNT(0) |
! 2351: UHCI_TD_ACTIVE |
! 2352: UHCI_TD_IOS);
! 2353: nframes = xfer->nframes;
! 2354: s = splusb();
! 2355: for (i = 0; i < nframes; i++) {
! 2356: std = iso->stds[next];
! 2357: if (++next >= UHCI_VFRAMELIST_COUNT)
! 2358: next = 0;
! 2359: len = xfer->frlengths[i];
! 2360: std->td.td_buffer = htole32(buf);
! 2361: if (i == nframes - 1)
! 2362: status |= UHCI_TD_IOC;
! 2363: std->td.td_status = htole32(status);
! 2364: std->td.td_token &= htole32(~UHCI_TD_MAXLEN_MASK);
! 2365: std->td.td_token |= htole32(UHCI_TD_SET_MAXLEN(len));
! 2366: #ifdef UHCI_DEBUG
! 2367: if (uhcidebug > 5) {
! 2368: DPRINTFN(5,("uhci_device_isoc_enter: TD %d\n", i));
! 2369: uhci_dump_td(std);
! 2370: }
! 2371: #endif
! 2372: buf += len;
! 2373: }
! 2374: iso->next = next;
! 2375: iso->inuse += xfer->nframes;
! 2376:
! 2377: splx(s);
! 2378: }
! 2379:
! 2380: usbd_status
! 2381: uhci_device_isoc_start(usbd_xfer_handle xfer)
! 2382: {
! 2383: struct uhci_pipe *upipe = (struct uhci_pipe *)xfer->pipe;
! 2384: uhci_softc_t *sc = (uhci_softc_t *)upipe->pipe.device->bus;
! 2385: uhci_intr_info_t *ii = &UXFER(xfer)->iinfo;
! 2386: uhci_soft_td_t *end;
! 2387: int s, i;
! 2388:
! 2389: DPRINTFN(5,("uhci_device_isoc_start: xfer=%p\n", xfer));
! 2390:
! 2391: if (sc->sc_dying)
! 2392: return (USBD_IOERROR);
! 2393:
! 2394: #ifdef DIAGNOSTIC
! 2395: if (xfer->status != USBD_IN_PROGRESS)
! 2396: printf("uhci_device_isoc_start: not in progress %p\n", xfer);
! 2397: #endif
! 2398:
! 2399: /* Find the last TD */
! 2400: i = UXFER(xfer)->curframe + xfer->nframes;
! 2401: if (i >= UHCI_VFRAMELIST_COUNT)
! 2402: i -= UHCI_VFRAMELIST_COUNT;
! 2403: end = upipe->u.iso.stds[i];
! 2404:
! 2405: #ifdef DIAGNOSTIC
! 2406: if (end == NULL) {
! 2407: printf("uhci_device_isoc_start: end == NULL\n");
! 2408: return (USBD_INVAL);
! 2409: }
! 2410: #endif
! 2411:
! 2412: s = splusb();
! 2413:
! 2414: /* Set up interrupt info. */
! 2415: ii->xfer = xfer;
! 2416: ii->stdstart = end;
! 2417: ii->stdend = end;
! 2418: #ifdef DIAGNOSTIC
! 2419: if (!ii->isdone)
! 2420: printf("uhci_device_isoc_start: not done, ii=%p\n", ii);
! 2421: ii->isdone = 0;
! 2422: #endif
! 2423: uhci_add_intr_info(sc, ii);
! 2424:
! 2425: splx(s);
! 2426:
! 2427: return (USBD_IN_PROGRESS);
! 2428: }
! 2429:
! 2430: void
! 2431: uhci_device_isoc_abort(usbd_xfer_handle xfer)
! 2432: {
! 2433: struct uhci_pipe *upipe = (struct uhci_pipe *)xfer->pipe;
! 2434: uhci_soft_td_t **stds = upipe->u.iso.stds;
! 2435: uhci_soft_td_t *std;
! 2436: int i, n, s, nframes, maxlen, len;
! 2437:
! 2438: s = splusb();
! 2439:
! 2440: /* Transfer is already done. */
! 2441: if (xfer->status != USBD_NOT_STARTED &&
! 2442: xfer->status != USBD_IN_PROGRESS) {
! 2443: splx(s);
! 2444: return;
! 2445: }
! 2446:
! 2447: /* Give xfer the requested abort code. */
! 2448: xfer->status = USBD_CANCELLED;
! 2449:
! 2450: /* make hardware ignore it, */
! 2451: nframes = xfer->nframes;
! 2452: n = UXFER(xfer)->curframe;
! 2453: maxlen = 0;
! 2454: for (i = 0; i < nframes; i++) {
! 2455: std = stds[n];
! 2456: std->td.td_status &= htole32(~(UHCI_TD_ACTIVE | UHCI_TD_IOC));
! 2457: len = UHCI_TD_GET_MAXLEN(letoh32(std->td.td_token));
! 2458: if (len > maxlen)
! 2459: maxlen = len;
! 2460: if (++n >= UHCI_VFRAMELIST_COUNT)
! 2461: n = 0;
! 2462: }
! 2463:
! 2464: /* and wait until we are sure the hardware has finished. */
! 2465: delay(maxlen);
! 2466:
! 2467: #ifdef DIAGNOSTIC
! 2468: UXFER(xfer)->iinfo.isdone = 1;
! 2469: #endif
! 2470: /* Run callback and remove from interrupt list. */
! 2471: usb_transfer_complete(xfer);
! 2472:
! 2473: splx(s);
! 2474: }
! 2475:
! 2476: void
! 2477: uhci_device_isoc_close(usbd_pipe_handle pipe)
! 2478: {
! 2479: struct uhci_pipe *upipe = (struct uhci_pipe *)pipe;
! 2480: usbd_device_handle dev = upipe->pipe.device;
! 2481: uhci_softc_t *sc = (uhci_softc_t *)dev->bus;
! 2482: uhci_soft_td_t *std, *vstd;
! 2483: struct iso *iso;
! 2484: int i, s;
! 2485:
! 2486: /*
! 2487: * Make sure all TDs are marked as inactive.
! 2488: * Wait for completion.
! 2489: * Unschedule.
! 2490: * Deallocate.
! 2491: */
! 2492: iso = &upipe->u.iso;
! 2493:
! 2494: for (i = 0; i < UHCI_VFRAMELIST_COUNT; i++)
! 2495: iso->stds[i]->td.td_status &= htole32(~UHCI_TD_ACTIVE);
! 2496: usb_delay_ms(&sc->sc_bus, 2); /* wait for completion */
! 2497:
! 2498: s = splusb();
! 2499: for (i = 0; i < UHCI_VFRAMELIST_COUNT; i++) {
! 2500: std = iso->stds[i];
! 2501: for (vstd = sc->sc_vframes[i].htd;
! 2502: vstd != NULL && vstd->link.std != std;
! 2503: vstd = vstd->link.std)
! 2504: ;
! 2505: if (vstd == NULL) {
! 2506: /*panic*/
! 2507: printf("uhci_device_isoc_close: %p not found\n", std);
! 2508: splx(s);
! 2509: return;
! 2510: }
! 2511: vstd->link = std->link;
! 2512: vstd->td.td_link = std->td.td_link;
! 2513: uhci_free_std(sc, std);
! 2514: }
! 2515: splx(s);
! 2516:
! 2517: free(iso->stds, M_USBHC);
! 2518: }
! 2519:
! 2520: usbd_status
! 2521: uhci_setup_isoc(usbd_pipe_handle pipe)
! 2522: {
! 2523: struct uhci_pipe *upipe = (struct uhci_pipe *)pipe;
! 2524: usbd_device_handle dev = upipe->pipe.device;
! 2525: uhci_softc_t *sc = (uhci_softc_t *)dev->bus;
! 2526: int addr = upipe->pipe.device->address;
! 2527: int endpt = upipe->pipe.endpoint->edesc->bEndpointAddress;
! 2528: int rd = UE_GET_DIR(endpt) == UE_DIR_IN;
! 2529: uhci_soft_td_t *std, *vstd;
! 2530: u_int32_t token;
! 2531: struct iso *iso;
! 2532: int i, s;
! 2533:
! 2534: iso = &upipe->u.iso;
! 2535: iso->stds = malloc(UHCI_VFRAMELIST_COUNT * sizeof (uhci_soft_td_t *),
! 2536: M_USBHC, M_WAITOK);
! 2537:
! 2538: token = rd ? UHCI_TD_IN (0, endpt, addr, 0) :
! 2539: UHCI_TD_OUT(0, endpt, addr, 0);
! 2540:
! 2541: /* Allocate the TDs and mark as inactive; */
! 2542: for (i = 0; i < UHCI_VFRAMELIST_COUNT; i++) {
! 2543: std = uhci_alloc_std(sc);
! 2544: if (std == 0)
! 2545: goto bad;
! 2546: std->td.td_status = htole32(UHCI_TD_IOS); /* iso, inactive */
! 2547: std->td.td_token = htole32(token);
! 2548: iso->stds[i] = std;
! 2549: }
! 2550:
! 2551: /* Insert TDs into schedule. */
! 2552: s = splusb();
! 2553: for (i = 0; i < UHCI_VFRAMELIST_COUNT; i++) {
! 2554: std = iso->stds[i];
! 2555: vstd = sc->sc_vframes[i].htd;
! 2556: std->link = vstd->link;
! 2557: std->td.td_link = vstd->td.td_link;
! 2558: vstd->link.std = std;
! 2559: vstd->td.td_link = htole32(std->physaddr | UHCI_PTR_TD);
! 2560: }
! 2561: splx(s);
! 2562:
! 2563: iso->next = -1;
! 2564: iso->inuse = 0;
! 2565:
! 2566: return (USBD_NORMAL_COMPLETION);
! 2567:
! 2568: bad:
! 2569: while (--i >= 0)
! 2570: uhci_free_std(sc, iso->stds[i]);
! 2571: free(iso->stds, M_USBHC);
! 2572: return (USBD_NOMEM);
! 2573: }
! 2574:
! 2575: void
! 2576: uhci_device_isoc_done(usbd_xfer_handle xfer)
! 2577: {
! 2578: uhci_intr_info_t *ii = &UXFER(xfer)->iinfo;
! 2579:
! 2580: DPRINTFN(4, ("uhci_isoc_done: length=%d\n", xfer->actlen));
! 2581:
! 2582: if (ii->xfer != xfer)
! 2583: /* Not on interrupt list, ignore it. */
! 2584: return;
! 2585:
! 2586: if (!uhci_active_intr_info(ii))
! 2587: return;
! 2588:
! 2589: #ifdef DIAGNOSTIC
! 2590: if (xfer->busy_free == XFER_FREE) {
! 2591: printf("uhci_device_isoc_done: xfer=%p is free\n", xfer);
! 2592: return;
! 2593: }
! 2594:
! 2595: if (ii->stdend == NULL) {
! 2596: printf("uhci_device_isoc_done: xfer=%p stdend==NULL\n", xfer);
! 2597: #ifdef UHCI_DEBUG
! 2598: uhci_dump_ii(ii);
! 2599: #endif
! 2600: return;
! 2601: }
! 2602: #endif
! 2603:
! 2604: /* Turn off the interrupt since it is active even if the TD is not. */
! 2605: ii->stdend->td.td_status &= htole32(~UHCI_TD_IOC);
! 2606:
! 2607: uhci_del_intr_info(ii); /* remove from active list */
! 2608: }
! 2609:
! 2610: void
! 2611: uhci_device_intr_done(usbd_xfer_handle xfer)
! 2612: {
! 2613: uhci_intr_info_t *ii = &UXFER(xfer)->iinfo;
! 2614: uhci_softc_t *sc = ii->sc;
! 2615: struct uhci_pipe *upipe = (struct uhci_pipe *)xfer->pipe;
! 2616: uhci_soft_qh_t *sqh;
! 2617: int i, npoll;
! 2618:
! 2619: DPRINTFN(5, ("uhci_device_intr_done: length=%d\n", xfer->actlen));
! 2620:
! 2621: npoll = upipe->u.intr.npoll;
! 2622: for(i = 0; i < npoll; i++) {
! 2623: sqh = upipe->u.intr.qhs[i];
! 2624: sqh->elink = NULL;
! 2625: sqh->qh.qh_elink = htole32(UHCI_PTR_T);
! 2626: }
! 2627: uhci_free_std_chain(sc, ii->stdstart, NULL);
! 2628:
! 2629: /* XXX Wasteful. */
! 2630: if (xfer->pipe->repeat) {
! 2631: uhci_soft_td_t *data, *dataend;
! 2632:
! 2633: DPRINTFN(5,("uhci_device_intr_done: requeing\n"));
! 2634:
! 2635: /* This alloc cannot fail since we freed the chain above. */
! 2636: uhci_alloc_std_chain(upipe, sc, xfer->length,
! 2637: upipe->u.intr.isread, xfer->flags,
! 2638: &xfer->dmabuf, &data, &dataend);
! 2639: dataend->td.td_status |= htole32(UHCI_TD_IOC);
! 2640:
! 2641: #ifdef UHCI_DEBUG
! 2642: if (uhcidebug > 10) {
! 2643: DPRINTF(("uhci_device_intr_done: data(1)\n"));
! 2644: uhci_dump_tds(data);
! 2645: uhci_dump_qh(upipe->u.intr.qhs[0]);
! 2646: }
! 2647: #endif
! 2648:
! 2649: ii->stdstart = data;
! 2650: ii->stdend = dataend;
! 2651: #ifdef DIAGNOSTIC
! 2652: if (!ii->isdone) {
! 2653: printf("uhci_device_intr_done: not done, ii=%p\n", ii);
! 2654: }
! 2655: ii->isdone = 0;
! 2656: #endif
! 2657: for (i = 0; i < npoll; i++) {
! 2658: sqh = upipe->u.intr.qhs[i];
! 2659: sqh->elink = data;
! 2660: sqh->qh.qh_elink = htole32(data->physaddr | UHCI_PTR_TD);
! 2661: }
! 2662: xfer->status = USBD_IN_PROGRESS;
! 2663: /* The ii is already on the examined list, just leave it. */
! 2664: } else {
! 2665: DPRINTFN(5,("uhci_device_intr_done: removing\n"));
! 2666: if (uhci_active_intr_info(ii))
! 2667: uhci_del_intr_info(ii);
! 2668: }
! 2669: }
! 2670:
! 2671: /* Deallocate request data structures */
! 2672: void
! 2673: uhci_device_ctrl_done(usbd_xfer_handle xfer)
! 2674: {
! 2675: uhci_intr_info_t *ii = &UXFER(xfer)->iinfo;
! 2676: uhci_softc_t *sc = ii->sc;
! 2677: struct uhci_pipe *upipe = (struct uhci_pipe *)xfer->pipe;
! 2678:
! 2679: #ifdef DIAGNOSTIC
! 2680: if (!(xfer->rqflags & URQ_REQUEST))
! 2681: panic("uhci_device_ctrl_done: not a request");
! 2682: #endif
! 2683:
! 2684: if (!uhci_active_intr_info(ii))
! 2685: return;
! 2686:
! 2687: uhci_del_intr_info(ii); /* remove from active list */
! 2688:
! 2689: if (upipe->pipe.device->speed == USB_SPEED_LOW)
! 2690: uhci_remove_ls_ctrl(sc, upipe->u.ctl.sqh);
! 2691: else
! 2692: uhci_remove_hs_ctrl(sc, upipe->u.ctl.sqh);
! 2693:
! 2694: if (upipe->u.ctl.length != 0)
! 2695: uhci_free_std_chain(sc, ii->stdstart->link.std, ii->stdend);
! 2696:
! 2697: DPRINTFN(5, ("uhci_device_ctrl_done: length=%d\n", xfer->actlen));
! 2698: }
! 2699:
! 2700: /* Deallocate request data structures */
! 2701: void
! 2702: uhci_device_bulk_done(usbd_xfer_handle xfer)
! 2703: {
! 2704: uhci_intr_info_t *ii = &UXFER(xfer)->iinfo;
! 2705: uhci_softc_t *sc = ii->sc;
! 2706: struct uhci_pipe *upipe = (struct uhci_pipe *)xfer->pipe;
! 2707:
! 2708: DPRINTFN(5,("uhci_device_bulk_done: xfer=%p ii=%p sc=%p upipe=%p\n",
! 2709: xfer, ii, sc, upipe));
! 2710:
! 2711: if (!uhci_active_intr_info(ii))
! 2712: return;
! 2713:
! 2714: uhci_del_intr_info(ii); /* remove from active list */
! 2715:
! 2716: uhci_remove_bulk(sc, upipe->u.bulk.sqh);
! 2717:
! 2718: uhci_free_std_chain(sc, ii->stdstart, NULL);
! 2719:
! 2720: DPRINTFN(5, ("uhci_device_bulk_done: length=%d\n", xfer->actlen));
! 2721: }
! 2722:
! 2723: /* Add interrupt QH, called with vflock. */
! 2724: void
! 2725: uhci_add_intr(uhci_softc_t *sc, uhci_soft_qh_t *sqh)
! 2726: {
! 2727: struct uhci_vframe *vf = &sc->sc_vframes[sqh->pos];
! 2728: uhci_soft_qh_t *eqh;
! 2729:
! 2730: DPRINTFN(4, ("uhci_add_intr: n=%d sqh=%p\n", sqh->pos, sqh));
! 2731:
! 2732: eqh = vf->eqh;
! 2733: sqh->hlink = eqh->hlink;
! 2734: sqh->qh.qh_hlink = eqh->qh.qh_hlink;
! 2735: eqh->hlink = sqh;
! 2736: eqh->qh.qh_hlink = htole32(sqh->physaddr | UHCI_PTR_QH);
! 2737: vf->eqh = sqh;
! 2738: vf->bandwidth++;
! 2739: }
! 2740:
! 2741: /* Remove interrupt QH. */
! 2742: void
! 2743: uhci_remove_intr(uhci_softc_t *sc, uhci_soft_qh_t *sqh)
! 2744: {
! 2745: struct uhci_vframe *vf = &sc->sc_vframes[sqh->pos];
! 2746: uhci_soft_qh_t *pqh;
! 2747:
! 2748: DPRINTFN(4, ("uhci_remove_intr: n=%d sqh=%p\n", sqh->pos, sqh));
! 2749:
! 2750: /* See comment in uhci_remove_ctrl() */
! 2751: if (!(sqh->qh.qh_elink & htole32(UHCI_PTR_T))) {
! 2752: sqh->qh.qh_elink = htole32(UHCI_PTR_T);
! 2753: delay(UHCI_QH_REMOVE_DELAY);
! 2754: }
! 2755:
! 2756: pqh = uhci_find_prev_qh(vf->hqh, sqh);
! 2757: pqh->hlink = sqh->hlink;
! 2758: pqh->qh.qh_hlink = sqh->qh.qh_hlink;
! 2759: delay(UHCI_QH_REMOVE_DELAY);
! 2760: if (vf->eqh == sqh)
! 2761: vf->eqh = pqh;
! 2762: vf->bandwidth--;
! 2763: }
! 2764:
! 2765: usbd_status
! 2766: uhci_device_setintr(uhci_softc_t *sc, struct uhci_pipe *upipe, int ival)
! 2767: {
! 2768: uhci_soft_qh_t *sqh;
! 2769: int i, npoll, s;
! 2770: u_int bestbw, bw, bestoffs, offs;
! 2771:
! 2772: DPRINTFN(2, ("uhci_device_setintr: pipe=%p\n", upipe));
! 2773: if (ival == 0) {
! 2774: printf("uhci_device_setintr: 0 interval\n");
! 2775: return (USBD_INVAL);
! 2776: }
! 2777:
! 2778: if (ival > UHCI_VFRAMELIST_COUNT)
! 2779: ival = UHCI_VFRAMELIST_COUNT;
! 2780: npoll = (UHCI_VFRAMELIST_COUNT + ival - 1) / ival;
! 2781: DPRINTFN(2, ("uhci_device_setintr: ival=%d npoll=%d\n", ival, npoll));
! 2782:
! 2783: upipe->u.intr.npoll = npoll;
! 2784: upipe->u.intr.qhs =
! 2785: malloc(npoll * sizeof(uhci_soft_qh_t *), M_USBHC, M_WAITOK);
! 2786:
! 2787: /*
! 2788: * Figure out which offset in the schedule that has most
! 2789: * bandwidth left over.
! 2790: */
! 2791: #define MOD(i) ((i) & (UHCI_VFRAMELIST_COUNT-1))
! 2792: for (bestoffs = offs = 0, bestbw = ~0; offs < ival; offs++) {
! 2793: for (bw = i = 0; i < npoll; i++)
! 2794: bw += sc->sc_vframes[MOD(i * ival + offs)].bandwidth;
! 2795: if (bw < bestbw) {
! 2796: bestbw = bw;
! 2797: bestoffs = offs;
! 2798: }
! 2799: }
! 2800: DPRINTFN(1, ("uhci_device_setintr: bw=%d offs=%d\n", bestbw, bestoffs));
! 2801:
! 2802: for(i = 0; i < npoll; i++) {
! 2803: upipe->u.intr.qhs[i] = sqh = uhci_alloc_sqh(sc);
! 2804: sqh->elink = NULL;
! 2805: sqh->qh.qh_elink = htole32(UHCI_PTR_T);
! 2806: sqh->pos = MOD(i * ival + bestoffs);
! 2807: }
! 2808: #undef MOD
! 2809:
! 2810: s = splusb();
! 2811: /* Enter QHs into the controller data structures. */
! 2812: for(i = 0; i < npoll; i++)
! 2813: uhci_add_intr(sc, upipe->u.intr.qhs[i]);
! 2814: splx(s);
! 2815:
! 2816: DPRINTFN(5, ("uhci_device_setintr: returns %p\n", upipe));
! 2817: return (USBD_NORMAL_COMPLETION);
! 2818: }
! 2819:
! 2820: /* Open a new pipe. */
! 2821: usbd_status
! 2822: uhci_open(usbd_pipe_handle pipe)
! 2823: {
! 2824: uhci_softc_t *sc = (uhci_softc_t *)pipe->device->bus;
! 2825: struct uhci_pipe *upipe = (struct uhci_pipe *)pipe;
! 2826: usb_endpoint_descriptor_t *ed = pipe->endpoint->edesc;
! 2827: usbd_status err;
! 2828: int ival;
! 2829:
! 2830: DPRINTFN(1, ("uhci_open: pipe=%p, addr=%d, endpt=%d (%d)\n",
! 2831: pipe, pipe->device->address,
! 2832: ed->bEndpointAddress, sc->sc_addr));
! 2833:
! 2834: upipe->aborting = 0;
! 2835: upipe->nexttoggle = pipe->endpoint->savedtoggle;
! 2836:
! 2837: if (pipe->device->address == sc->sc_addr) {
! 2838: switch (ed->bEndpointAddress) {
! 2839: case USB_CONTROL_ENDPOINT:
! 2840: pipe->methods = &uhci_root_ctrl_methods;
! 2841: break;
! 2842: case UE_DIR_IN | UHCI_INTR_ENDPT:
! 2843: pipe->methods = &uhci_root_intr_methods;
! 2844: break;
! 2845: default:
! 2846: return (USBD_INVAL);
! 2847: }
! 2848: } else {
! 2849: switch (ed->bmAttributes & UE_XFERTYPE) {
! 2850: case UE_CONTROL:
! 2851: pipe->methods = &uhci_device_ctrl_methods;
! 2852: upipe->u.ctl.sqh = uhci_alloc_sqh(sc);
! 2853: if (upipe->u.ctl.sqh == NULL)
! 2854: goto bad;
! 2855: upipe->u.ctl.setup = uhci_alloc_std(sc);
! 2856: if (upipe->u.ctl.setup == NULL) {
! 2857: uhci_free_sqh(sc, upipe->u.ctl.sqh);
! 2858: goto bad;
! 2859: }
! 2860: upipe->u.ctl.stat = uhci_alloc_std(sc);
! 2861: if (upipe->u.ctl.stat == NULL) {
! 2862: uhci_free_sqh(sc, upipe->u.ctl.sqh);
! 2863: uhci_free_std(sc, upipe->u.ctl.setup);
! 2864: goto bad;
! 2865: }
! 2866: err = usb_allocmem(&sc->sc_bus,
! 2867: sizeof(usb_device_request_t),
! 2868: 0, &upipe->u.ctl.reqdma);
! 2869: if (err) {
! 2870: uhci_free_sqh(sc, upipe->u.ctl.sqh);
! 2871: uhci_free_std(sc, upipe->u.ctl.setup);
! 2872: uhci_free_std(sc, upipe->u.ctl.stat);
! 2873: goto bad;
! 2874: }
! 2875: break;
! 2876: case UE_INTERRUPT:
! 2877: pipe->methods = &uhci_device_intr_methods;
! 2878: ival = pipe->interval;
! 2879: if (ival == USBD_DEFAULT_INTERVAL)
! 2880: ival = ed->bInterval;
! 2881: return (uhci_device_setintr(sc, upipe, ival));
! 2882: case UE_ISOCHRONOUS:
! 2883: pipe->methods = &uhci_device_isoc_methods;
! 2884: return (uhci_setup_isoc(pipe));
! 2885: case UE_BULK:
! 2886: pipe->methods = &uhci_device_bulk_methods;
! 2887: upipe->u.bulk.sqh = uhci_alloc_sqh(sc);
! 2888: if (upipe->u.bulk.sqh == NULL)
! 2889: goto bad;
! 2890: break;
! 2891: }
! 2892: }
! 2893: return (USBD_NORMAL_COMPLETION);
! 2894:
! 2895: bad:
! 2896: return (USBD_NOMEM);
! 2897: }
! 2898:
! 2899: /*
! 2900: * Data structures and routines to emulate the root hub.
! 2901: */
! 2902: usb_device_descriptor_t uhci_devd = {
! 2903: USB_DEVICE_DESCRIPTOR_SIZE,
! 2904: UDESC_DEVICE, /* type */
! 2905: {0x00, 0x01}, /* USB version */
! 2906: UDCLASS_HUB, /* class */
! 2907: UDSUBCLASS_HUB, /* subclass */
! 2908: UDPROTO_FSHUB, /* protocol */
! 2909: 64, /* max packet */
! 2910: {0},{0},{0x00,0x01}, /* device id */
! 2911: 1,2,0, /* string indices */
! 2912: 1 /* # of configurations */
! 2913: };
! 2914:
! 2915: usb_config_descriptor_t uhci_confd = {
! 2916: USB_CONFIG_DESCRIPTOR_SIZE,
! 2917: UDESC_CONFIG,
! 2918: {USB_CONFIG_DESCRIPTOR_SIZE +
! 2919: USB_INTERFACE_DESCRIPTOR_SIZE +
! 2920: USB_ENDPOINT_DESCRIPTOR_SIZE},
! 2921: 1,
! 2922: 1,
! 2923: 0,
! 2924: UC_SELF_POWERED,
! 2925: 0 /* max power */
! 2926: };
! 2927:
! 2928: usb_interface_descriptor_t uhci_ifcd = {
! 2929: USB_INTERFACE_DESCRIPTOR_SIZE,
! 2930: UDESC_INTERFACE,
! 2931: 0,
! 2932: 0,
! 2933: 1,
! 2934: UICLASS_HUB,
! 2935: UISUBCLASS_HUB,
! 2936: UIPROTO_FSHUB,
! 2937: 0
! 2938: };
! 2939:
! 2940: usb_endpoint_descriptor_t uhci_endpd = {
! 2941: USB_ENDPOINT_DESCRIPTOR_SIZE,
! 2942: UDESC_ENDPOINT,
! 2943: UE_DIR_IN | UHCI_INTR_ENDPT,
! 2944: UE_INTERRUPT,
! 2945: {8},
! 2946: 255
! 2947: };
! 2948:
! 2949: usb_hub_descriptor_t uhci_hubd_piix = {
! 2950: USB_HUB_DESCRIPTOR_SIZE,
! 2951: UDESC_HUB,
! 2952: 2,
! 2953: { UHD_PWR_NO_SWITCH | UHD_OC_INDIVIDUAL, 0 },
! 2954: 50, /* power on to power good */
! 2955: 0,
! 2956: { 0x00 }, /* both ports are removable */
! 2957: };
! 2958:
! 2959: int
! 2960: uhci_str(usb_string_descriptor_t *p, int l, char *s)
! 2961: {
! 2962: int i;
! 2963:
! 2964: if (l == 0)
! 2965: return (0);
! 2966: p->bLength = 2 * strlen(s) + 2;
! 2967: if (l == 1)
! 2968: return (1);
! 2969: p->bDescriptorType = UDESC_STRING;
! 2970: l -= 2;
! 2971: for (i = 0; s[i] && l > 1; i++, l -= 2)
! 2972: USETW2(p->bString[i], 0, s[i]);
! 2973: return (2*i+2);
! 2974: }
! 2975:
! 2976: /*
! 2977: * The USB hub protocol requires that SET_FEATURE(PORT_RESET) also
! 2978: * enables the port, and also states that SET_FEATURE(PORT_ENABLE)
! 2979: * should not be used by the USB subsystem. As we cannot issue a
! 2980: * SET_FEATURE(PORT_ENABLE) externally, we must ensure that the port
! 2981: * will be enabled as part of the reset.
! 2982: *
! 2983: * On the VT83C572, the port cannot be successfully enabled until the
! 2984: * outstanding "port enable change" and "connection status change"
! 2985: * events have been reset.
! 2986: */
! 2987: usbd_status
! 2988: uhci_portreset(uhci_softc_t *sc, int index)
! 2989: {
! 2990: int lim, port, x;
! 2991:
! 2992: if (index == 1)
! 2993: port = UHCI_PORTSC1;
! 2994: else if (index == 2)
! 2995: port = UHCI_PORTSC2;
! 2996: else
! 2997: return (USBD_IOERROR);
! 2998:
! 2999: x = URWMASK(UREAD2(sc, port));
! 3000: UWRITE2(sc, port, x | UHCI_PORTSC_PR);
! 3001:
! 3002: usb_delay_ms(&sc->sc_bus, USB_PORT_ROOT_RESET_DELAY);
! 3003:
! 3004: DPRINTFN(3,("uhci port %d reset, status0 = 0x%04x\n",
! 3005: index, UREAD2(sc, port)));
! 3006:
! 3007: x = URWMASK(UREAD2(sc, port));
! 3008: UWRITE2(sc, port, x & ~UHCI_PORTSC_PR);
! 3009:
! 3010: delay(100);
! 3011:
! 3012: DPRINTFN(3,("uhci port %d reset, status1 = 0x%04x\n",
! 3013: index, UREAD2(sc, port)));
! 3014:
! 3015: x = URWMASK(UREAD2(sc, port));
! 3016: UWRITE2(sc, port, x | UHCI_PORTSC_PE);
! 3017:
! 3018: for (lim = 10; --lim > 0;) {
! 3019: usb_delay_ms(&sc->sc_bus, USB_PORT_RESET_DELAY);
! 3020:
! 3021: x = UREAD2(sc, port);
! 3022:
! 3023: DPRINTFN(3,("uhci port %d iteration %u, status = 0x%04x\n",
! 3024: index, lim, x));
! 3025:
! 3026: if (!(x & UHCI_PORTSC_CCS)) {
! 3027: /*
! 3028: * No device is connected (or was disconnected
! 3029: * during reset). Consider the port reset.
! 3030: * The delay must be long enough to ensure on
! 3031: * the initial iteration that the device
! 3032: * connection will have been registered. 50ms
! 3033: * appears to be sufficient, but 20ms is not.
! 3034: */
! 3035: DPRINTFN(3,("uhci port %d loop %u, device detached\n",
! 3036: index, lim));
! 3037: break;
! 3038: }
! 3039:
! 3040: if (x & (UHCI_PORTSC_POEDC | UHCI_PORTSC_CSC)) {
! 3041: /*
! 3042: * Port enabled changed and/or connection
! 3043: * status changed were set. Reset either or
! 3044: * both raised flags (by writing a 1 to that
! 3045: * bit), and wait again for state to settle.
! 3046: */
! 3047: UWRITE2(sc, port, URWMASK(x) |
! 3048: (x & (UHCI_PORTSC_POEDC | UHCI_PORTSC_CSC)));
! 3049: continue;
! 3050: }
! 3051:
! 3052: if (x & UHCI_PORTSC_PE)
! 3053: /* Port is enabled */
! 3054: break;
! 3055:
! 3056: UWRITE2(sc, port, URWMASK(x) | UHCI_PORTSC_PE);
! 3057: }
! 3058:
! 3059: DPRINTFN(3,("uhci port %d reset, status2 = 0x%04x\n",
! 3060: index, UREAD2(sc, port)));
! 3061:
! 3062: if (lim <= 0) {
! 3063: DPRINTFN(1,("uhci port %d reset timed out\n", index));
! 3064: return (USBD_TIMEOUT);
! 3065: }
! 3066:
! 3067: sc->sc_isreset = 1;
! 3068: return (USBD_NORMAL_COMPLETION);
! 3069: }
! 3070:
! 3071: /*
! 3072: * Simulate a hardware hub by handling all the necessary requests.
! 3073: */
! 3074: usbd_status
! 3075: uhci_root_ctrl_transfer(usbd_xfer_handle xfer)
! 3076: {
! 3077: usbd_status err;
! 3078:
! 3079: /* Insert last in queue. */
! 3080: err = usb_insert_transfer(xfer);
! 3081: if (err)
! 3082: return (err);
! 3083:
! 3084: /*
! 3085: * Pipe isn't running (otherwise err would be USBD_INPROG),
! 3086: * so start it first.
! 3087: */
! 3088: return (uhci_root_ctrl_start(SIMPLEQ_FIRST(&xfer->pipe->queue)));
! 3089: }
! 3090:
! 3091: usbd_status
! 3092: uhci_root_ctrl_start(usbd_xfer_handle xfer)
! 3093: {
! 3094: uhci_softc_t *sc = (uhci_softc_t *)xfer->pipe->device->bus;
! 3095: usb_device_request_t *req;
! 3096: void *buf = NULL;
! 3097: int port, x;
! 3098: int s, len, value, index, status, change, l, totlen = 0;
! 3099: usb_port_status_t ps;
! 3100: usbd_status err;
! 3101:
! 3102: if (sc->sc_dying)
! 3103: return (USBD_IOERROR);
! 3104:
! 3105: #ifdef DIAGNOSTIC
! 3106: if (!(xfer->rqflags & URQ_REQUEST))
! 3107: panic("uhci_root_ctrl_transfer: not a request");
! 3108: #endif
! 3109: req = &xfer->request;
! 3110:
! 3111: DPRINTFN(2,("uhci_root_ctrl_control type=0x%02x request=%02x\n",
! 3112: req->bmRequestType, req->bRequest));
! 3113:
! 3114: len = UGETW(req->wLength);
! 3115: value = UGETW(req->wValue);
! 3116: index = UGETW(req->wIndex);
! 3117:
! 3118: if (len != 0)
! 3119: buf = KERNADDR(&xfer->dmabuf, 0);
! 3120:
! 3121: #define C(x,y) ((x) | ((y) << 8))
! 3122: switch(C(req->bRequest, req->bmRequestType)) {
! 3123: case C(UR_CLEAR_FEATURE, UT_WRITE_DEVICE):
! 3124: case C(UR_CLEAR_FEATURE, UT_WRITE_INTERFACE):
! 3125: case C(UR_CLEAR_FEATURE, UT_WRITE_ENDPOINT):
! 3126: /*
! 3127: * DEVICE_REMOTE_WAKEUP and ENDPOINT_HALT are no-ops
! 3128: * for the integrated root hub.
! 3129: */
! 3130: break;
! 3131: case C(UR_GET_CONFIG, UT_READ_DEVICE):
! 3132: if (len > 0) {
! 3133: *(u_int8_t *)buf = sc->sc_conf;
! 3134: totlen = 1;
! 3135: }
! 3136: break;
! 3137: case C(UR_GET_DESCRIPTOR, UT_READ_DEVICE):
! 3138: DPRINTFN(2,("uhci_root_ctrl_control wValue=0x%04x\n", value));
! 3139: switch(value >> 8) {
! 3140: case UDESC_DEVICE:
! 3141: if ((value & 0xff) != 0) {
! 3142: err = USBD_IOERROR;
! 3143: goto ret;
! 3144: }
! 3145: totlen = l = min(len, USB_DEVICE_DESCRIPTOR_SIZE);
! 3146: USETW(uhci_devd.idVendor, sc->sc_id_vendor);
! 3147: memcpy(buf, &uhci_devd, l);
! 3148: break;
! 3149: case UDESC_CONFIG:
! 3150: if ((value & 0xff) != 0) {
! 3151: err = USBD_IOERROR;
! 3152: goto ret;
! 3153: }
! 3154: totlen = l = min(len, USB_CONFIG_DESCRIPTOR_SIZE);
! 3155: memcpy(buf, &uhci_confd, l);
! 3156: buf = (char *)buf + l;
! 3157: len -= l;
! 3158: l = min(len, USB_INTERFACE_DESCRIPTOR_SIZE);
! 3159: totlen += l;
! 3160: memcpy(buf, &uhci_ifcd, l);
! 3161: buf = (char *)buf + l;
! 3162: len -= l;
! 3163: l = min(len, USB_ENDPOINT_DESCRIPTOR_SIZE);
! 3164: totlen += l;
! 3165: memcpy(buf, &uhci_endpd, l);
! 3166: break;
! 3167: case UDESC_STRING:
! 3168: if (len == 0)
! 3169: break;
! 3170: *(u_int8_t *)buf = 0;
! 3171: totlen = 1;
! 3172: switch (value & 0xff) {
! 3173: case 0: /* Language table */
! 3174: totlen = uhci_str(buf, len, "\001");
! 3175: break;
! 3176: case 1: /* Vendor */
! 3177: totlen = uhci_str(buf, len, sc->sc_vendor);
! 3178: break;
! 3179: case 2: /* Product */
! 3180: totlen = uhci_str(buf, len, "UHCI root hub");
! 3181: break;
! 3182: }
! 3183: break;
! 3184: default:
! 3185: err = USBD_IOERROR;
! 3186: goto ret;
! 3187: }
! 3188: break;
! 3189: case C(UR_GET_INTERFACE, UT_READ_INTERFACE):
! 3190: if (len > 0) {
! 3191: *(u_int8_t *)buf = 0;
! 3192: totlen = 1;
! 3193: }
! 3194: break;
! 3195: case C(UR_GET_STATUS, UT_READ_DEVICE):
! 3196: if (len > 1) {
! 3197: USETW(((usb_status_t *)buf)->wStatus,UDS_SELF_POWERED);
! 3198: totlen = 2;
! 3199: }
! 3200: break;
! 3201: case C(UR_GET_STATUS, UT_READ_INTERFACE):
! 3202: case C(UR_GET_STATUS, UT_READ_ENDPOINT):
! 3203: if (len > 1) {
! 3204: USETW(((usb_status_t *)buf)->wStatus, 0);
! 3205: totlen = 2;
! 3206: }
! 3207: break;
! 3208: case C(UR_SET_ADDRESS, UT_WRITE_DEVICE):
! 3209: if (value >= USB_MAX_DEVICES) {
! 3210: err = USBD_IOERROR;
! 3211: goto ret;
! 3212: }
! 3213: sc->sc_addr = value;
! 3214: break;
! 3215: case C(UR_SET_CONFIG, UT_WRITE_DEVICE):
! 3216: if (value != 0 && value != 1) {
! 3217: err = USBD_IOERROR;
! 3218: goto ret;
! 3219: }
! 3220: sc->sc_conf = value;
! 3221: break;
! 3222: case C(UR_SET_DESCRIPTOR, UT_WRITE_DEVICE):
! 3223: break;
! 3224: case C(UR_SET_FEATURE, UT_WRITE_DEVICE):
! 3225: case C(UR_SET_FEATURE, UT_WRITE_INTERFACE):
! 3226: case C(UR_SET_FEATURE, UT_WRITE_ENDPOINT):
! 3227: err = USBD_IOERROR;
! 3228: goto ret;
! 3229: case C(UR_SET_INTERFACE, UT_WRITE_INTERFACE):
! 3230: break;
! 3231: case C(UR_SYNCH_FRAME, UT_WRITE_ENDPOINT):
! 3232: break;
! 3233: /* Hub requests */
! 3234: case C(UR_CLEAR_FEATURE, UT_WRITE_CLASS_DEVICE):
! 3235: break;
! 3236: case C(UR_CLEAR_FEATURE, UT_WRITE_CLASS_OTHER):
! 3237: DPRINTFN(3, ("uhci_root_ctrl_control: UR_CLEAR_PORT_FEATURE "
! 3238: "port=%d feature=%d\n",
! 3239: index, value));
! 3240: if (index == 1)
! 3241: port = UHCI_PORTSC1;
! 3242: else if (index == 2)
! 3243: port = UHCI_PORTSC2;
! 3244: else {
! 3245: err = USBD_IOERROR;
! 3246: goto ret;
! 3247: }
! 3248: switch(value) {
! 3249: case UHF_PORT_ENABLE:
! 3250: x = URWMASK(UREAD2(sc, port));
! 3251: UWRITE2(sc, port, x & ~UHCI_PORTSC_PE);
! 3252: break;
! 3253: case UHF_PORT_SUSPEND:
! 3254: x = URWMASK(UREAD2(sc, port));
! 3255: UWRITE2(sc, port, x & ~UHCI_PORTSC_SUSP);
! 3256: break;
! 3257: case UHF_PORT_RESET:
! 3258: x = URWMASK(UREAD2(sc, port));
! 3259: UWRITE2(sc, port, x & ~UHCI_PORTSC_PR);
! 3260: break;
! 3261: case UHF_C_PORT_CONNECTION:
! 3262: x = URWMASK(UREAD2(sc, port));
! 3263: UWRITE2(sc, port, x | UHCI_PORTSC_CSC);
! 3264: break;
! 3265: case UHF_C_PORT_ENABLE:
! 3266: x = URWMASK(UREAD2(sc, port));
! 3267: UWRITE2(sc, port, x | UHCI_PORTSC_POEDC);
! 3268: break;
! 3269: case UHF_C_PORT_OVER_CURRENT:
! 3270: x = URWMASK(UREAD2(sc, port));
! 3271: UWRITE2(sc, port, x | UHCI_PORTSC_OCIC);
! 3272: break;
! 3273: case UHF_C_PORT_RESET:
! 3274: sc->sc_isreset = 0;
! 3275: err = USBD_NORMAL_COMPLETION;
! 3276: goto ret;
! 3277: case UHF_PORT_CONNECTION:
! 3278: case UHF_PORT_OVER_CURRENT:
! 3279: case UHF_PORT_POWER:
! 3280: case UHF_PORT_LOW_SPEED:
! 3281: case UHF_C_PORT_SUSPEND:
! 3282: default:
! 3283: err = USBD_IOERROR;
! 3284: goto ret;
! 3285: }
! 3286: break;
! 3287: case C(UR_GET_BUS_STATE, UT_READ_CLASS_OTHER):
! 3288: if (index == 1)
! 3289: port = UHCI_PORTSC1;
! 3290: else if (index == 2)
! 3291: port = UHCI_PORTSC2;
! 3292: else {
! 3293: err = USBD_IOERROR;
! 3294: goto ret;
! 3295: }
! 3296: if (len > 0) {
! 3297: *(u_int8_t *)buf =
! 3298: (UREAD2(sc, port) & UHCI_PORTSC_LS) >>
! 3299: UHCI_PORTSC_LS_SHIFT;
! 3300: totlen = 1;
! 3301: }
! 3302: break;
! 3303: case C(UR_GET_DESCRIPTOR, UT_READ_CLASS_DEVICE):
! 3304: if ((value & 0xff) != 0) {
! 3305: err = USBD_IOERROR;
! 3306: goto ret;
! 3307: }
! 3308: l = min(len, USB_HUB_DESCRIPTOR_SIZE);
! 3309: totlen = l;
! 3310: memcpy(buf, &uhci_hubd_piix, l);
! 3311: break;
! 3312: case C(UR_GET_STATUS, UT_READ_CLASS_DEVICE):
! 3313: if (len != 4) {
! 3314: err = USBD_IOERROR;
! 3315: goto ret;
! 3316: }
! 3317: memset(buf, 0, len);
! 3318: totlen = len;
! 3319: break;
! 3320: case C(UR_GET_STATUS, UT_READ_CLASS_OTHER):
! 3321: if (index == 1)
! 3322: port = UHCI_PORTSC1;
! 3323: else if (index == 2)
! 3324: port = UHCI_PORTSC2;
! 3325: else {
! 3326: err = USBD_IOERROR;
! 3327: goto ret;
! 3328: }
! 3329: if (len != 4) {
! 3330: err = USBD_IOERROR;
! 3331: goto ret;
! 3332: }
! 3333: x = UREAD2(sc, port);
! 3334: status = change = 0;
! 3335: if (x & UHCI_PORTSC_CCS)
! 3336: status |= UPS_CURRENT_CONNECT_STATUS;
! 3337: if (x & UHCI_PORTSC_CSC)
! 3338: change |= UPS_C_CONNECT_STATUS;
! 3339: if (x & UHCI_PORTSC_PE)
! 3340: status |= UPS_PORT_ENABLED;
! 3341: if (x & UHCI_PORTSC_POEDC)
! 3342: change |= UPS_C_PORT_ENABLED;
! 3343: if (x & UHCI_PORTSC_OCI)
! 3344: status |= UPS_OVERCURRENT_INDICATOR;
! 3345: if (x & UHCI_PORTSC_OCIC)
! 3346: change |= UPS_C_OVERCURRENT_INDICATOR;
! 3347: if (x & UHCI_PORTSC_SUSP)
! 3348: status |= UPS_SUSPEND;
! 3349: if (x & UHCI_PORTSC_LSDA)
! 3350: status |= UPS_LOW_SPEED;
! 3351: status |= UPS_PORT_POWER;
! 3352: if (sc->sc_isreset)
! 3353: change |= UPS_C_PORT_RESET;
! 3354: USETW(ps.wPortStatus, status);
! 3355: USETW(ps.wPortChange, change);
! 3356: l = min(len, sizeof ps);
! 3357: memcpy(buf, &ps, l);
! 3358: totlen = l;
! 3359: break;
! 3360: case C(UR_SET_DESCRIPTOR, UT_WRITE_CLASS_DEVICE):
! 3361: err = USBD_IOERROR;
! 3362: goto ret;
! 3363: case C(UR_SET_FEATURE, UT_WRITE_CLASS_DEVICE):
! 3364: break;
! 3365: case C(UR_SET_FEATURE, UT_WRITE_CLASS_OTHER):
! 3366: if (index == 1)
! 3367: port = UHCI_PORTSC1;
! 3368: else if (index == 2)
! 3369: port = UHCI_PORTSC2;
! 3370: else {
! 3371: err = USBD_IOERROR;
! 3372: goto ret;
! 3373: }
! 3374: switch(value) {
! 3375: case UHF_PORT_ENABLE:
! 3376: x = URWMASK(UREAD2(sc, port));
! 3377: UWRITE2(sc, port, x | UHCI_PORTSC_PE);
! 3378: break;
! 3379: case UHF_PORT_SUSPEND:
! 3380: x = URWMASK(UREAD2(sc, port));
! 3381: UWRITE2(sc, port, x | UHCI_PORTSC_SUSP);
! 3382: break;
! 3383: case UHF_PORT_RESET:
! 3384: err = uhci_portreset(sc, index);
! 3385: goto ret;
! 3386: case UHF_PORT_POWER:
! 3387: /* Pretend we turned on power */
! 3388: err = USBD_NORMAL_COMPLETION;
! 3389: goto ret;
! 3390: case UHF_C_PORT_CONNECTION:
! 3391: case UHF_C_PORT_ENABLE:
! 3392: case UHF_C_PORT_OVER_CURRENT:
! 3393: case UHF_PORT_CONNECTION:
! 3394: case UHF_PORT_OVER_CURRENT:
! 3395: case UHF_PORT_LOW_SPEED:
! 3396: case UHF_C_PORT_SUSPEND:
! 3397: case UHF_C_PORT_RESET:
! 3398: default:
! 3399: err = USBD_IOERROR;
! 3400: goto ret;
! 3401: }
! 3402: break;
! 3403: default:
! 3404: err = USBD_IOERROR;
! 3405: goto ret;
! 3406: }
! 3407: xfer->actlen = totlen;
! 3408: err = USBD_NORMAL_COMPLETION;
! 3409: ret:
! 3410: xfer->status = err;
! 3411: s = splusb();
! 3412: usb_transfer_complete(xfer);
! 3413: splx(s);
! 3414: return (USBD_IN_PROGRESS);
! 3415: }
! 3416:
! 3417: /* Abort a root control request. */
! 3418: void
! 3419: uhci_root_ctrl_abort(usbd_xfer_handle xfer)
! 3420: {
! 3421: /* Nothing to do, all transfers are synchronous. */
! 3422: }
! 3423:
! 3424: /* Close the root pipe. */
! 3425: void
! 3426: uhci_root_ctrl_close(usbd_pipe_handle pipe)
! 3427: {
! 3428: DPRINTF(("uhci_root_ctrl_close\n"));
! 3429: }
! 3430:
! 3431: /* Abort a root interrupt request. */
! 3432: void
! 3433: uhci_root_intr_abort(usbd_xfer_handle xfer)
! 3434: {
! 3435: uhci_softc_t *sc = (uhci_softc_t *)xfer->pipe->device->bus;
! 3436:
! 3437: timeout_del(&sc->sc_poll_handle);
! 3438: sc->sc_intr_xfer = NULL;
! 3439:
! 3440: if (xfer->pipe->intrxfer == xfer) {
! 3441: DPRINTF(("uhci_root_intr_abort: remove\n"));
! 3442: xfer->pipe->intrxfer = 0;
! 3443: }
! 3444: xfer->status = USBD_CANCELLED;
! 3445: #ifdef DIAGNOSTIC
! 3446: UXFER(xfer)->iinfo.isdone = 1;
! 3447: #endif
! 3448: usb_transfer_complete(xfer);
! 3449: }
! 3450:
! 3451: usbd_status
! 3452: uhci_root_intr_transfer(usbd_xfer_handle xfer)
! 3453: {
! 3454: usbd_status err;
! 3455:
! 3456: /* Insert last in queue. */
! 3457: err = usb_insert_transfer(xfer);
! 3458: if (err)
! 3459: return (err);
! 3460:
! 3461: /* Pipe isn't running (otherwise err would be USBD_INPROG),
! 3462: * start first
! 3463: */
! 3464: return (uhci_root_intr_start(SIMPLEQ_FIRST(&xfer->pipe->queue)));
! 3465: }
! 3466:
! 3467: /* Start a transfer on the root interrupt pipe */
! 3468: usbd_status
! 3469: uhci_root_intr_start(usbd_xfer_handle xfer)
! 3470: {
! 3471: usbd_pipe_handle pipe = xfer->pipe;
! 3472: uhci_softc_t *sc = (uhci_softc_t *)pipe->device->bus;
! 3473:
! 3474: DPRINTFN(3, ("uhci_root_intr_start: xfer=%p len=%d flags=%d\n",
! 3475: xfer, xfer->length, xfer->flags));
! 3476:
! 3477: if (sc->sc_dying)
! 3478: return (USBD_IOERROR);
! 3479:
! 3480: sc->sc_ival = mstohz(xfer->pipe->endpoint->edesc->bInterval);
! 3481: timeout_del(&sc->sc_poll_handle);
! 3482: timeout_set(&sc->sc_poll_handle, uhci_poll_hub, xfer);
! 3483: timeout_add(&sc->sc_poll_handle, sc->sc_ival);
! 3484: sc->sc_intr_xfer = xfer;
! 3485: return (USBD_IN_PROGRESS);
! 3486: }
! 3487:
! 3488: /* Close the root interrupt pipe. */
! 3489: void
! 3490: uhci_root_intr_close(usbd_pipe_handle pipe)
! 3491: {
! 3492: uhci_softc_t *sc = (uhci_softc_t *)pipe->device->bus;
! 3493:
! 3494: timeout_del(&sc->sc_poll_handle);
! 3495: sc->sc_intr_xfer = NULL;
! 3496: DPRINTF(("uhci_root_intr_close\n"));
! 3497: }
CVSweb