Annotation of sys/dev/usb/ehci.c, Revision 1.1
1.1 ! nbrk 1: /* $OpenBSD: ehci.c,v 1.77 2007/06/15 11:41:47 mbalmer Exp $ */
! 2: /* $NetBSD: ehci.c,v 1.66 2004/06/30 03:11:56 mycroft Exp $ */
! 3:
! 4: /*
! 5: * Copyright (c) 2004 The NetBSD Foundation, Inc.
! 6: * All rights reserved.
! 7: *
! 8: * This code is derived from software contributed to The NetBSD Foundation
! 9: * by Lennart Augustsson (lennart@augustsson.net) and by Charles M. Hannum.
! 10: *
! 11: * Redistribution and use in source and binary forms, with or without
! 12: * modification, are permitted provided that the following conditions
! 13: * are met:
! 14: * 1. Redistributions of source code must retain the above copyright
! 15: * notice, this list of conditions and the following disclaimer.
! 16: * 2. Redistributions in binary form must reproduce the above copyright
! 17: * notice, this list of conditions and the following disclaimer in the
! 18: * documentation and/or other materials provided with the distribution.
! 19: * 3. All advertising materials mentioning features or use of this software
! 20: * must display the following acknowledgement:
! 21: * This product includes software developed by the NetBSD
! 22: * Foundation, Inc. and its contributors.
! 23: * 4. Neither the name of The NetBSD Foundation nor the names of its
! 24: * contributors may be used to endorse or promote products derived
! 25: * from this software without specific prior written permission.
! 26: *
! 27: * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
! 28: * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
! 29: * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
! 30: * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
! 31: * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
! 32: * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
! 33: * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
! 34: * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
! 35: * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
! 36: * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
! 37: * POSSIBILITY OF SUCH DAMAGE.
! 38: */
! 39:
! 40: /*
! 41: * USB Enhanced Host Controller Driver, a.k.a. USB 2.0 controller.
! 42: *
! 43: * The EHCI 1.0 spec can be found at
! 44: * http://developer.intel.com/technology/usb/download/ehci-r10.pdf
! 45: * and the USB 2.0 spec at
! 46: * http://www.usb.org/developers/docs/usb_20.zip
! 47: */
! 48:
! 49: /*
! 50: * TODO:
! 51: * 1) The meaty part to implement is isochronous transactions. They are
! 52: * needed for USB 1 devices below USB 2.0 hubs. They are quite complicated
! 53: * since they need to be able to do "transaction translation", ie,
! 54: * converting to/from USB 2 and USB 1.
! 55: * So the hub driver needs to handle and schedule these things, to
! 56: * assign place in frame where different devices get to go. See chapter
! 57: * on hubs in USB 2.0 for details.
! 58: *
! 59: * 2) Command failures are not recovered correctly.
! 60: */
! 61:
! 62: #include <sys/param.h>
! 63: #include <sys/systm.h>
! 64: #include <sys/kernel.h>
! 65: #include <sys/rwlock.h>
! 66: #include <sys/malloc.h>
! 67: #include <sys/device.h>
! 68: #include <sys/selinfo.h>
! 69: #include <sys/proc.h>
! 70: #include <sys/queue.h>
! 71: #include <sys/timeout.h>
! 72:
! 73: #include <machine/bus.h>
! 74: #include <machine/endian.h>
! 75:
! 76: #include <dev/usb/usb.h>
! 77: #include <dev/usb/usbdi.h>
! 78: #include <dev/usb/usbdivar.h>
! 79: #include <dev/usb/usb_mem.h>
! 80: #include <dev/usb/usb_quirks.h>
! 81:
! 82: #include <dev/usb/ehcireg.h>
! 83: #include <dev/usb/ehcivar.h>
! 84:
! 85: #include <dev/rndvar.h>
! 86:
! 87: struct cfdriver ehci_cd = {
! 88: NULL, "ehci", DV_DULL
! 89: };
! 90:
! 91: #ifdef USB_DEBUG
! 92: #define EHCI_DEBUG
! 93: #endif
! 94:
! 95: #ifdef EHCI_DEBUG
! 96: #define DPRINTF(x) do { if (ehcidebug) printf x; } while(0)
! 97: #define DPRINTFN(n,x) do { if (ehcidebug>(n)) printf x; } while (0)
! 98: int ehcidebug = 0;
! 99: #define bitmask_snprintf(q,f,b,l) snprintf((b), (l), "%b", (q), (f))
! 100: #else
! 101: #define DPRINTF(x)
! 102: #define DPRINTFN(n,x)
! 103: #endif
! 104:
! 105: #define mstohz(ms) ((ms) * hz / 1000)
! 106:
! 107: struct ehci_pipe {
! 108: struct usbd_pipe pipe;
! 109:
! 110: ehci_soft_qh_t *sqh;
! 111: union {
! 112: ehci_soft_qtd_t *qtd;
! 113: /* ehci_soft_itd_t *itd; */
! 114: } tail;
! 115: union {
! 116: /* Control pipe */
! 117: struct {
! 118: usb_dma_t reqdma;
! 119: u_int length;
! 120: /*ehci_soft_qtd_t *setup, *data, *stat;*/
! 121: } ctl;
! 122: /* Interrupt pipe */
! 123: struct {
! 124: u_int length;
! 125: } intr;
! 126: /* Bulk pipe */
! 127: struct {
! 128: u_int length;
! 129: } bulk;
! 130: /* Iso pipe */
! 131: /* XXX */
! 132: } u;
! 133: };
! 134:
! 135: u_int8_t ehci_reverse_bits(u_int8_t, int);
! 136:
! 137: void ehci_power(int, void *);
! 138:
! 139: usbd_status ehci_open(usbd_pipe_handle);
! 140: void ehci_poll(struct usbd_bus *);
! 141: void ehci_softintr(void *);
! 142: int ehci_intr1(ehci_softc_t *);
! 143: void ehci_waitintr(ehci_softc_t *, usbd_xfer_handle);
! 144: void ehci_check_intr(ehci_softc_t *, struct ehci_xfer *);
! 145: void ehci_idone(struct ehci_xfer *);
! 146: void ehci_timeout(void *);
! 147: void ehci_timeout_task(void *);
! 148: void ehci_intrlist_timeout(void *);
! 149:
! 150: usbd_status ehci_allocm(struct usbd_bus *, usb_dma_t *, u_int32_t);
! 151: void ehci_freem(struct usbd_bus *, usb_dma_t *);
! 152:
! 153: usbd_xfer_handle ehci_allocx(struct usbd_bus *);
! 154: void ehci_freex(struct usbd_bus *, usbd_xfer_handle);
! 155:
! 156: usbd_status ehci_root_ctrl_transfer(usbd_xfer_handle);
! 157: usbd_status ehci_root_ctrl_start(usbd_xfer_handle);
! 158: void ehci_root_ctrl_abort(usbd_xfer_handle);
! 159: void ehci_root_ctrl_close(usbd_pipe_handle);
! 160: void ehci_root_ctrl_done(usbd_xfer_handle);
! 161:
! 162: usbd_status ehci_root_intr_transfer(usbd_xfer_handle);
! 163: usbd_status ehci_root_intr_start(usbd_xfer_handle);
! 164: void ehci_root_intr_abort(usbd_xfer_handle);
! 165: void ehci_root_intr_close(usbd_pipe_handle);
! 166: void ehci_root_intr_done(usbd_xfer_handle);
! 167:
! 168: usbd_status ehci_device_ctrl_transfer(usbd_xfer_handle);
! 169: usbd_status ehci_device_ctrl_start(usbd_xfer_handle);
! 170: void ehci_device_ctrl_abort(usbd_xfer_handle);
! 171: void ehci_device_ctrl_close(usbd_pipe_handle);
! 172: void ehci_device_ctrl_done(usbd_xfer_handle);
! 173:
! 174: usbd_status ehci_device_bulk_transfer(usbd_xfer_handle);
! 175: usbd_status ehci_device_bulk_start(usbd_xfer_handle);
! 176: void ehci_device_bulk_abort(usbd_xfer_handle);
! 177: void ehci_device_bulk_close(usbd_pipe_handle);
! 178: void ehci_device_bulk_done(usbd_xfer_handle);
! 179:
! 180: usbd_status ehci_device_intr_transfer(usbd_xfer_handle);
! 181: usbd_status ehci_device_intr_start(usbd_xfer_handle);
! 182: void ehci_device_intr_abort(usbd_xfer_handle);
! 183: void ehci_device_intr_close(usbd_pipe_handle);
! 184: void ehci_device_intr_done(usbd_xfer_handle);
! 185:
! 186: usbd_status ehci_device_isoc_transfer(usbd_xfer_handle);
! 187: usbd_status ehci_device_isoc_start(usbd_xfer_handle);
! 188: void ehci_device_isoc_abort(usbd_xfer_handle);
! 189: void ehci_device_isoc_close(usbd_pipe_handle);
! 190: void ehci_device_isoc_done(usbd_xfer_handle);
! 191:
! 192: void ehci_device_clear_toggle(usbd_pipe_handle pipe);
! 193: void ehci_noop(usbd_pipe_handle pipe);
! 194:
! 195: int ehci_str(usb_string_descriptor_t *, int, const char *);
! 196: void ehci_pcd(ehci_softc_t *, usbd_xfer_handle);
! 197: void ehci_pcd_able(ehci_softc_t *, int);
! 198: void ehci_pcd_enable(void *);
! 199: void ehci_disown(ehci_softc_t *, int, int);
! 200:
! 201: ehci_soft_qh_t *ehci_alloc_sqh(ehci_softc_t *);
! 202: void ehci_free_sqh(ehci_softc_t *, ehci_soft_qh_t *);
! 203:
! 204: ehci_soft_qtd_t *ehci_alloc_sqtd(ehci_softc_t *);
! 205: void ehci_free_sqtd(ehci_softc_t *, ehci_soft_qtd_t *);
! 206: usbd_status ehci_alloc_sqtd_chain(struct ehci_pipe *,
! 207: ehci_softc_t *, int, int, usbd_xfer_handle,
! 208: ehci_soft_qtd_t **, ehci_soft_qtd_t **);
! 209: void ehci_free_sqtd_chain(ehci_softc_t *, ehci_soft_qtd_t *,
! 210: ehci_soft_qtd_t *);
! 211:
! 212: usbd_status ehci_device_request(usbd_xfer_handle xfer);
! 213:
! 214: usbd_status ehci_device_setintr(ehci_softc_t *, ehci_soft_qh_t *,
! 215: int ival);
! 216:
! 217: void ehci_add_qh(ehci_soft_qh_t *, ehci_soft_qh_t *);
! 218: void ehci_rem_qh(ehci_softc_t *, ehci_soft_qh_t *,
! 219: ehci_soft_qh_t *);
! 220: void ehci_set_qh_qtd(ehci_soft_qh_t *, ehci_soft_qtd_t *);
! 221: void ehci_sync_hc(ehci_softc_t *);
! 222:
! 223: void ehci_close_pipe(usbd_pipe_handle, ehci_soft_qh_t *);
! 224: void ehci_abort_xfer(usbd_xfer_handle, usbd_status);
! 225:
! 226: #ifdef EHCI_DEBUG
! 227: void ehci_dump_regs(ehci_softc_t *);
! 228: void ehci_dump(void);
! 229: ehci_softc_t *theehci;
! 230: void ehci_dump_link(ehci_link_t, int);
! 231: void ehci_dump_sqtds(ehci_soft_qtd_t *);
! 232: void ehci_dump_sqtd(ehci_soft_qtd_t *);
! 233: void ehci_dump_qtd(ehci_qtd_t *);
! 234: void ehci_dump_sqh(ehci_soft_qh_t *);
! 235: #ifdef DIAGNOSTIC
! 236: void ehci_dump_exfer(struct ehci_xfer *);
! 237: #endif
! 238: #endif
! 239:
! 240: #define EHCI_NULL htole32(EHCI_LINK_TERMINATE)
! 241:
! 242: #define EHCI_INTR_ENDPT 1
! 243:
! 244: #define ehci_add_intr_list(sc, ex) \
! 245: LIST_INSERT_HEAD(&(sc)->sc_intrhead, (ex), inext);
! 246: #define ehci_del_intr_list(ex) \
! 247: do { \
! 248: LIST_REMOVE((ex), inext); \
! 249: (ex)->inext.le_prev = NULL; \
! 250: } while (0)
! 251: #define ehci_active_intr_list(ex) ((ex)->inext.le_prev != NULL)
! 252:
! 253: struct usbd_bus_methods ehci_bus_methods = {
! 254: ehci_open,
! 255: ehci_softintr,
! 256: ehci_poll,
! 257: ehci_allocm,
! 258: ehci_freem,
! 259: ehci_allocx,
! 260: ehci_freex,
! 261: };
! 262:
! 263: struct usbd_pipe_methods ehci_root_ctrl_methods = {
! 264: ehci_root_ctrl_transfer,
! 265: ehci_root_ctrl_start,
! 266: ehci_root_ctrl_abort,
! 267: ehci_root_ctrl_close,
! 268: ehci_noop,
! 269: ehci_root_ctrl_done,
! 270: };
! 271:
! 272: struct usbd_pipe_methods ehci_root_intr_methods = {
! 273: ehci_root_intr_transfer,
! 274: ehci_root_intr_start,
! 275: ehci_root_intr_abort,
! 276: ehci_root_intr_close,
! 277: ehci_noop,
! 278: ehci_root_intr_done,
! 279: };
! 280:
! 281: struct usbd_pipe_methods ehci_device_ctrl_methods = {
! 282: ehci_device_ctrl_transfer,
! 283: ehci_device_ctrl_start,
! 284: ehci_device_ctrl_abort,
! 285: ehci_device_ctrl_close,
! 286: ehci_noop,
! 287: ehci_device_ctrl_done,
! 288: };
! 289:
! 290: struct usbd_pipe_methods ehci_device_intr_methods = {
! 291: ehci_device_intr_transfer,
! 292: ehci_device_intr_start,
! 293: ehci_device_intr_abort,
! 294: ehci_device_intr_close,
! 295: ehci_device_clear_toggle,
! 296: ehci_device_intr_done,
! 297: };
! 298:
! 299: struct usbd_pipe_methods ehci_device_bulk_methods = {
! 300: ehci_device_bulk_transfer,
! 301: ehci_device_bulk_start,
! 302: ehci_device_bulk_abort,
! 303: ehci_device_bulk_close,
! 304: ehci_device_clear_toggle,
! 305: ehci_device_bulk_done,
! 306: };
! 307:
! 308: struct usbd_pipe_methods ehci_device_isoc_methods = {
! 309: ehci_device_isoc_transfer,
! 310: ehci_device_isoc_start,
! 311: ehci_device_isoc_abort,
! 312: ehci_device_isoc_close,
! 313: ehci_noop,
! 314: ehci_device_isoc_done,
! 315: };
! 316:
! 317: /*
! 318: * Reverse a number with nbits bits. Used to evenly distribute lower-level
! 319: * interrupt heads in the periodic schedule.
! 320: * Suitable for use with EHCI_IPOLLRATES <= 9.
! 321: */
! 322: u_int8_t
! 323: ehci_reverse_bits(u_int8_t c, int nbits)
! 324: {
! 325: c = ((c >> 1) & 0x55) | ((c << 1) & 0xaa);
! 326: c = ((c >> 2) & 0x33) | ((c << 2) & 0xcc);
! 327: c = ((c >> 4) & 0x0f) | ((c << 4) & 0xf0);
! 328:
! 329: return c >> (8 - nbits);
! 330: }
! 331:
! 332: usbd_status
! 333: ehci_init(ehci_softc_t *sc)
! 334: {
! 335: u_int32_t sparams, cparams, hcr;
! 336: u_int i, j;
! 337: usbd_status err;
! 338: ehci_soft_qh_t *sqh;
! 339:
! 340: #ifdef EHCI_DEBUG
! 341: u_int32_t vers;
! 342: theehci = sc;
! 343:
! 344: DPRINTF(("ehci_init: start\n"));
! 345:
! 346: vers = EREAD2(sc, EHCI_HCIVERSION);
! 347: DPRINTF(("%s: EHCI version %x.%x\n", sc->sc_bus.bdev.dv_xname,
! 348: vers >> 8, vers & 0xff));
! 349: #endif
! 350:
! 351: sc->sc_offs = EREAD1(sc, EHCI_CAPLENGTH);
! 352:
! 353: sparams = EREAD4(sc, EHCI_HCSPARAMS);
! 354: DPRINTF(("ehci_init: sparams=0x%x\n", sparams));
! 355: sc->sc_noport = EHCI_HCS_N_PORTS(sparams);
! 356: cparams = EREAD4(sc, EHCI_HCCPARAMS);
! 357: DPRINTF(("ehci_init: cparams=0x%x\n", cparams));
! 358:
! 359: /* MUST clear segment register if 64 bit capable. */
! 360: if (EHCI_HCC_64BIT(cparams))
! 361: EWRITE4(sc, EHCI_CTRLDSSEGMENT, 0);
! 362:
! 363: sc->sc_bus.usbrev = USBREV_2_0;
! 364:
! 365: /* Reset the controller */
! 366: DPRINTF(("%s: resetting\n", sc->sc_bus.bdev.dv_xname));
! 367: EOWRITE4(sc, EHCI_USBCMD, 0); /* Halt controller */
! 368: usb_delay_ms(&sc->sc_bus, 1);
! 369: EOWRITE4(sc, EHCI_USBCMD, EHCI_CMD_HCRESET);
! 370: for (i = 0; i < 100; i++) {
! 371: usb_delay_ms(&sc->sc_bus, 1);
! 372: hcr = EOREAD4(sc, EHCI_USBCMD) & EHCI_CMD_HCRESET;
! 373: if (!hcr)
! 374: break;
! 375: }
! 376: if (hcr) {
! 377: printf("%s: reset timeout\n",
! 378: sc->sc_bus.bdev.dv_xname);
! 379: return (USBD_IOERROR);
! 380: }
! 381:
! 382: /* XXX need proper intr scheduling */
! 383: sc->sc_rand = 96;
! 384:
! 385: /* frame list size at default, read back what we got and use that */
! 386: switch (EHCI_CMD_FLS(EOREAD4(sc, EHCI_USBCMD))) {
! 387: case 0: sc->sc_flsize = 1024; break;
! 388: case 1: sc->sc_flsize = 512; break;
! 389: case 2: sc->sc_flsize = 256; break;
! 390: case 3: return (USBD_IOERROR);
! 391: }
! 392: err = usb_allocmem(&sc->sc_bus, sc->sc_flsize * sizeof(ehci_link_t),
! 393: EHCI_FLALIGN_ALIGN, &sc->sc_fldma);
! 394: if (err)
! 395: return (err);
! 396: DPRINTF(("%s: flsize=%d\n", sc->sc_bus.bdev.dv_xname,sc->sc_flsize));
! 397: sc->sc_flist = KERNADDR(&sc->sc_fldma, 0);
! 398: EOWRITE4(sc, EHCI_PERIODICLISTBASE, DMAADDR(&sc->sc_fldma, 0));
! 399:
! 400: /* Set up the bus struct. */
! 401: sc->sc_bus.methods = &ehci_bus_methods;
! 402: sc->sc_bus.pipe_size = sizeof(struct ehci_pipe);
! 403:
! 404: sc->sc_powerhook = powerhook_establish(ehci_power, sc);
! 405:
! 406: sc->sc_eintrs = EHCI_NORMAL_INTRS;
! 407:
! 408: /*
! 409: * Allocate the interrupt dummy QHs. These are arranged to give poll
! 410: * intervals that are powers of 2 times 1ms.
! 411: */
! 412: for (i = 0; i < EHCI_INTRQHS; i++) {
! 413: sqh = ehci_alloc_sqh(sc);
! 414: if (sqh == NULL) {
! 415: err = USBD_NOMEM;
! 416: goto bad1;
! 417: }
! 418: sc->sc_islots[i].sqh = sqh;
! 419: }
! 420: for (i = 0; i < EHCI_INTRQHS; i++) {
! 421: sqh = sc->sc_islots[i].sqh;
! 422: if (i == 0) {
! 423: /* The last (1ms) QH terminates. */
! 424: sqh->qh.qh_link = EHCI_NULL;
! 425: sqh->next = NULL;
! 426: } else {
! 427: /* Otherwise the next QH has half the poll interval */
! 428: sqh->next = sc->sc_islots[(i + 1) / 2 - 1].sqh;
! 429: sqh->qh.qh_link = htole32(sqh->next->physaddr |
! 430: EHCI_LINK_QH);
! 431: }
! 432: sqh->qh.qh_endp = htole32(EHCI_QH_SET_EPS(EHCI_QH_SPEED_HIGH));
! 433: sqh->qh.qh_endphub = htole32(EHCI_QH_SET_MULT(1));
! 434: sqh->qh.qh_curqtd = EHCI_NULL;
! 435: sqh->qh.qh_qtd.qtd_next = EHCI_NULL;
! 436: sqh->qh.qh_qtd.qtd_altnext = EHCI_NULL;
! 437: sqh->qh.qh_qtd.qtd_status = htole32(EHCI_QTD_HALTED);
! 438: sqh->sqtd = NULL;
! 439: }
! 440: /* Point the frame list at the last level (128ms). */
! 441: for (i = 0; i < (1 << (EHCI_IPOLLRATES - 1)); i++)
! 442: for (j = i; j < sc->sc_flsize; j += 1 << (EHCI_IPOLLRATES - 1))
! 443: sc->sc_flist[j] = htole32(EHCI_LINK_QH | sc->sc_islots[
! 444: EHCI_IQHIDX(EHCI_IPOLLRATES - 1, ehci_reverse_bits(
! 445: i, EHCI_IPOLLRATES - 1))].sqh->physaddr);
! 446:
! 447: /* Allocate dummy QH that starts the async list. */
! 448: sqh = ehci_alloc_sqh(sc);
! 449: if (sqh == NULL) {
! 450: err = USBD_NOMEM;
! 451: goto bad1;
! 452: }
! 453: /* Fill the QH */
! 454: sqh->qh.qh_endp =
! 455: htole32(EHCI_QH_SET_EPS(EHCI_QH_SPEED_HIGH) | EHCI_QH_HRECL);
! 456: sqh->qh.qh_link =
! 457: htole32(sqh->physaddr | EHCI_LINK_QH);
! 458: sqh->qh.qh_curqtd = EHCI_NULL;
! 459: sqh->prev = sqh; /*It's a circular list.. */
! 460: sqh->next = sqh;
! 461: /* Fill the overlay qTD */
! 462: sqh->qh.qh_qtd.qtd_next = EHCI_NULL;
! 463: sqh->qh.qh_qtd.qtd_altnext = EHCI_NULL;
! 464: sqh->qh.qh_qtd.qtd_status = htole32(EHCI_QTD_HALTED);
! 465: sqh->sqtd = NULL;
! 466: #ifdef EHCI_DEBUG
! 467: if (ehcidebug)
! 468: ehci_dump_sqh(sqh);
! 469: #endif
! 470:
! 471: /* Point to async list */
! 472: sc->sc_async_head = sqh;
! 473: EOWRITE4(sc, EHCI_ASYNCLISTADDR, sqh->physaddr | EHCI_LINK_QH);
! 474:
! 475: timeout_set(&sc->sc_tmo_pcd, NULL, NULL);
! 476: timeout_set(&sc->sc_tmo_intrlist, NULL, NULL);
! 477:
! 478: rw_init(&sc->sc_doorbell_lock, "ehcidb");
! 479:
! 480: /* Turn on controller */
! 481: EOWRITE4(sc, EHCI_USBCMD,
! 482: EHCI_CMD_ITC_2 | /* 2 microframes interrupt delay */
! 483: (EOREAD4(sc, EHCI_USBCMD) & EHCI_CMD_FLS_M) |
! 484: EHCI_CMD_ASE |
! 485: EHCI_CMD_PSE |
! 486: EHCI_CMD_RS);
! 487:
! 488: /* Take over port ownership */
! 489: EOWRITE4(sc, EHCI_CONFIGFLAG, EHCI_CONF_CF);
! 490:
! 491: for (i = 0; i < 100; i++) {
! 492: usb_delay_ms(&sc->sc_bus, 1);
! 493: hcr = EOREAD4(sc, EHCI_USBSTS) & EHCI_STS_HCH;
! 494: if (!hcr)
! 495: break;
! 496: }
! 497: if (hcr) {
! 498: printf("%s: run timeout\n", sc->sc_bus.bdev.dv_xname);
! 499: return (USBD_IOERROR);
! 500: }
! 501:
! 502: /* Enable interrupts */
! 503: DPRINTFN(1,("ehci_init: enabling\n"));
! 504: EOWRITE4(sc, EHCI_USBINTR, sc->sc_eintrs);
! 505:
! 506: return (USBD_NORMAL_COMPLETION);
! 507:
! 508: #if 0
! 509: bad2:
! 510: ehci_free_sqh(sc, sc->sc_async_head);
! 511: #endif
! 512: bad1:
! 513: usb_freemem(&sc->sc_bus, &sc->sc_fldma);
! 514: return (err);
! 515: }
! 516:
! 517: int
! 518: ehci_intr(void *v)
! 519: {
! 520: ehci_softc_t *sc = v;
! 521:
! 522: if (sc == NULL || sc->sc_dying)
! 523: return (0);
! 524:
! 525: /* If we get an interrupt while polling, then just ignore it. */
! 526: if (sc->sc_bus.use_polling) {
! 527: u_int32_t intrs = EHCI_STS_INTRS(EOREAD4(sc, EHCI_USBSTS));
! 528:
! 529: if (intrs)
! 530: EOWRITE4(sc, EHCI_USBSTS, intrs); /* Acknowledge */
! 531: return (0);
! 532: }
! 533:
! 534: return (ehci_intr1(sc));
! 535: }
! 536:
! 537: int
! 538: ehci_intr1(ehci_softc_t *sc)
! 539: {
! 540: u_int32_t intrs, eintrs;
! 541:
! 542: DPRINTFN(20,("ehci_intr1: enter\n"));
! 543:
! 544: /* In case the interrupt occurs before initialization has completed. */
! 545: if (sc == NULL) {
! 546: #ifdef DIAGNOSTIC
! 547: printf("ehci_intr1: sc == NULL\n");
! 548: #endif
! 549: return (0);
! 550: }
! 551:
! 552: intrs = EHCI_STS_INTRS(EOREAD4(sc, EHCI_USBSTS));
! 553: if (!intrs)
! 554: return (0);
! 555:
! 556: eintrs = intrs & sc->sc_eintrs;
! 557: DPRINTFN(7, ("ehci_intr1: sc=%p intrs=0x%x(0x%x) eintrs=0x%x\n",
! 558: sc, (u_int)intrs, EOREAD4(sc, EHCI_USBSTS), (u_int)eintrs));
! 559: if (!eintrs)
! 560: return (0);
! 561:
! 562: EOWRITE4(sc, EHCI_USBSTS, intrs); /* Acknowledge */
! 563: sc->sc_bus.intr_context++;
! 564: sc->sc_bus.no_intrs++;
! 565: if (eintrs & EHCI_STS_IAA) {
! 566: DPRINTF(("ehci_intr1: door bell\n"));
! 567: wakeup(&sc->sc_async_head);
! 568: eintrs &= ~EHCI_STS_IAA;
! 569: }
! 570: if (eintrs & (EHCI_STS_INT | EHCI_STS_ERRINT)) {
! 571: DPRINTFN(5,("ehci_intr1: %s %s\n",
! 572: eintrs & EHCI_STS_INT ? "INT" : "",
! 573: eintrs & EHCI_STS_ERRINT ? "ERRINT" : ""));
! 574: usb_schedsoftintr(&sc->sc_bus);
! 575: eintrs &= ~(EHCI_STS_INT | EHCI_STS_ERRINT);
! 576: }
! 577: if (eintrs & EHCI_STS_HSE) {
! 578: printf("%s: unrecoverable error, controller halted\n",
! 579: sc->sc_bus.bdev.dv_xname);
! 580: /* XXX what else */
! 581: }
! 582: if (eintrs & EHCI_STS_PCD) {
! 583: ehci_pcd(sc, sc->sc_intrxfer);
! 584: /*
! 585: * Disable PCD interrupt for now, because it will be
! 586: * on until the port has been reset.
! 587: */
! 588: ehci_pcd_able(sc, 0);
! 589: /* Do not allow RHSC interrupts > 1 per second */
! 590: timeout_del(&sc->sc_tmo_pcd);
! 591: timeout_set(&sc->sc_tmo_pcd, ehci_pcd_enable, sc);
! 592: timeout_add(&sc->sc_tmo_pcd, hz);
! 593: eintrs &= ~EHCI_STS_PCD;
! 594: }
! 595:
! 596: sc->sc_bus.intr_context--;
! 597:
! 598: if (eintrs != 0) {
! 599: /* Block unprocessed interrupts. */
! 600: sc->sc_eintrs &= ~eintrs;
! 601: EOWRITE4(sc, EHCI_USBINTR, sc->sc_eintrs);
! 602: printf("%s: blocking intrs 0x%x\n",
! 603: sc->sc_bus.bdev.dv_xname, eintrs);
! 604: }
! 605:
! 606: return (1);
! 607: }
! 608:
! 609: void
! 610: ehci_pcd_able(ehci_softc_t *sc, int on)
! 611: {
! 612: DPRINTFN(4, ("ehci_pcd_able: on=%d\n", on));
! 613: if (on)
! 614: sc->sc_eintrs |= EHCI_STS_PCD;
! 615: else
! 616: sc->sc_eintrs &= ~EHCI_STS_PCD;
! 617: EOWRITE4(sc, EHCI_USBINTR, sc->sc_eintrs);
! 618: }
! 619:
! 620: void
! 621: ehci_pcd_enable(void *v_sc)
! 622: {
! 623: ehci_softc_t *sc = v_sc;
! 624:
! 625: ehci_pcd_able(sc, 1);
! 626: }
! 627:
! 628: void
! 629: ehci_pcd(ehci_softc_t *sc, usbd_xfer_handle xfer)
! 630: {
! 631: usbd_pipe_handle pipe;
! 632: u_char *p;
! 633: int i, m;
! 634:
! 635: if (xfer == NULL) {
! 636: /* Just ignore the change. */
! 637: return;
! 638: }
! 639:
! 640: pipe = xfer->pipe;
! 641:
! 642: p = KERNADDR(&xfer->dmabuf, 0);
! 643: m = min(sc->sc_noport, xfer->length * 8 - 1);
! 644: memset(p, 0, xfer->length);
! 645: for (i = 1; i <= m; i++) {
! 646: /* Pick out CHANGE bits from the status reg. */
! 647: if (EOREAD4(sc, EHCI_PORTSC(i)) & EHCI_PS_CLEAR)
! 648: p[i/8] |= 1 << (i%8);
! 649: }
! 650: DPRINTF(("ehci_pcd: change=0x%02x\n", *p));
! 651: xfer->actlen = xfer->length;
! 652: xfer->status = USBD_NORMAL_COMPLETION;
! 653:
! 654: usb_transfer_complete(xfer);
! 655: }
! 656:
! 657: void
! 658: ehci_softintr(void *v)
! 659: {
! 660: ehci_softc_t *sc = v;
! 661: struct ehci_xfer *ex, *nextex;
! 662:
! 663: DPRINTFN(10,("%s: ehci_softintr (%d)\n", sc->sc_bus.bdev.dv_xname,
! 664: sc->sc_bus.intr_context));
! 665:
! 666: sc->sc_bus.intr_context++;
! 667:
! 668: /*
! 669: * The only explanation I can think of for why EHCI is as brain dead
! 670: * as UHCI interrupt-wise is that Intel was involved in both.
! 671: * An interrupt just tells us that something is done, we have no
! 672: * clue what, so we need to scan through all active transfers. :-(
! 673: */
! 674: for (ex = LIST_FIRST(&sc->sc_intrhead); ex; ex = nextex) {
! 675: nextex = LIST_NEXT(ex, inext);
! 676: ehci_check_intr(sc, ex);
! 677: }
! 678:
! 679: /* Schedule a callout to catch any dropped transactions. */
! 680: if ((sc->sc_flags & EHCIF_DROPPED_INTR_WORKAROUND) &&
! 681: !LIST_EMPTY(&sc->sc_intrhead)) {
! 682: timeout_del(&sc->sc_tmo_intrlist);
! 683: timeout_set(&sc->sc_tmo_intrlist, ehci_intrlist_timeout, sc);
! 684: timeout_add(&sc->sc_tmo_intrlist, hz);
! 685: }
! 686:
! 687: #ifdef __HAVE_GENERIC_SOFT_INTERRUPTS
! 688: if (sc->sc_softwake) {
! 689: sc->sc_softwake = 0;
! 690: wakeup(&sc->sc_softwake);
! 691: }
! 692: #endif /* __HAVE_GENERIC_SOFT_INTERRUPTS */
! 693:
! 694: sc->sc_bus.intr_context--;
! 695: }
! 696:
! 697: /* Check for an interrupt. */
! 698: void
! 699: ehci_check_intr(ehci_softc_t *sc, struct ehci_xfer *ex)
! 700: {
! 701: ehci_soft_qtd_t *sqtd, *lsqtd;
! 702: u_int32_t status;
! 703:
! 704: DPRINTFN(/*15*/2, ("ehci_check_intr: ex=%p\n", ex));
! 705:
! 706: if (ex->sqtdstart == NULL) {
! 707: printf("ehci_check_intr: sqtdstart=NULL\n");
! 708: return;
! 709: }
! 710: lsqtd = ex->sqtdend;
! 711: #ifdef DIAGNOSTIC
! 712: if (lsqtd == NULL) {
! 713: printf("ehci_check_intr: lsqtd==0\n");
! 714: return;
! 715: }
! 716: #endif
! 717: /*
! 718: * If the last TD is still active we need to check whether there
! 719: * is a an error somewhere in the middle, or whether there was a
! 720: * short packet (SPD and not ACTIVE).
! 721: */
! 722: if (letoh32(lsqtd->qtd.qtd_status) & EHCI_QTD_ACTIVE) {
! 723: DPRINTFN(12, ("ehci_check_intr: active ex=%p\n", ex));
! 724: for (sqtd = ex->sqtdstart; sqtd != lsqtd; sqtd=sqtd->nextqtd) {
! 725: status = letoh32(sqtd->qtd.qtd_status);
! 726: /* If there's an active QTD the xfer isn't done. */
! 727: if (status & EHCI_QTD_ACTIVE)
! 728: break;
! 729: /* Any kind of error makes the xfer done. */
! 730: if (status & EHCI_QTD_HALTED)
! 731: goto done;
! 732: /* We want short packets, and it is short: it's done */
! 733: if (EHCI_QTD_GET_BYTES(status) != 0)
! 734: goto done;
! 735: }
! 736: DPRINTFN(12, ("ehci_check_intr: ex=%p std=%p still active\n",
! 737: ex, ex->sqtdstart));
! 738: return;
! 739: }
! 740: done:
! 741: DPRINTFN(12, ("ehci_check_intr: ex=%p done\n", ex));
! 742: timeout_del(&ex->xfer.timeout_handle);
! 743: usb_rem_task(ex->xfer.pipe->device, &ex->abort_task);
! 744: ehci_idone(ex);
! 745: }
! 746:
! 747: void
! 748: ehci_idone(struct ehci_xfer *ex)
! 749: {
! 750: usbd_xfer_handle xfer = &ex->xfer;
! 751: #ifdef EHCI_DEBUG
! 752: struct ehci_pipe *epipe = (struct ehci_pipe *)xfer->pipe;
! 753: #endif
! 754: ehci_soft_qtd_t *sqtd, *lsqtd;
! 755: u_int32_t status = 0, nstatus = 0;
! 756: int actlen, cerr;
! 757:
! 758: DPRINTFN(/*12*/2, ("ehci_idone: ex=%p\n", ex));
! 759: #ifdef DIAGNOSTIC
! 760: {
! 761: int s = splhigh();
! 762: if (ex->isdone) {
! 763: splx(s);
! 764: #ifdef EHCI_DEBUG
! 765: printf("ehci_idone: ex is done!\n ");
! 766: ehci_dump_exfer(ex);
! 767: #else
! 768: printf("ehci_idone: ex=%p is done!\n", ex);
! 769: #endif
! 770: return;
! 771: }
! 772: ex->isdone = 1;
! 773: splx(s);
! 774: }
! 775: #endif
! 776:
! 777: if (xfer->status == USBD_CANCELLED ||
! 778: xfer->status == USBD_TIMEOUT) {
! 779: DPRINTF(("ehci_idone: aborted xfer=%p\n", xfer));
! 780: return;
! 781: }
! 782:
! 783: #ifdef EHCI_DEBUG
! 784: DPRINTFN(/*10*/2, ("ehci_idone: xfer=%p, pipe=%p ready\n", xfer, epipe));
! 785: if (ehcidebug > 10)
! 786: ehci_dump_sqtds(ex->sqtdstart);
! 787: #endif
! 788:
! 789: /* The transfer is done, compute actual length and status. */
! 790: lsqtd = ex->sqtdend;
! 791: actlen = 0;
! 792: for (sqtd = ex->sqtdstart; sqtd != lsqtd->nextqtd;
! 793: sqtd = sqtd->nextqtd) {
! 794: nstatus = letoh32(sqtd->qtd.qtd_status);
! 795: if (nstatus & EHCI_QTD_ACTIVE)
! 796: break;
! 797:
! 798: status = nstatus;
! 799: /* halt is ok if descriptor is last, and complete */
! 800: if (sqtd->qtd.qtd_next == EHCI_NULL &&
! 801: EHCI_QTD_GET_BYTES(status) == 0)
! 802: status &= ~EHCI_QTD_HALTED;
! 803: if (EHCI_QTD_GET_PID(status) != EHCI_QTD_PID_SETUP)
! 804: actlen += sqtd->len - EHCI_QTD_GET_BYTES(status);
! 805: }
! 806:
! 807: cerr = EHCI_QTD_GET_CERR(status);
! 808: DPRINTFN(/*10*/2, ("ehci_idone: len=%d, actlen=%d, cerr=%d, "
! 809: "status=0x%x\n", xfer->length, actlen, cerr, status));
! 810: xfer->actlen = actlen;
! 811: if ((status & EHCI_QTD_HALTED) != 0) {
! 812: #ifdef EHCI_DEBUG
! 813: char sbuf[128];
! 814:
! 815: bitmask_snprintf((u_int32_t)status,
! 816: "\20\7HALTED\6BUFERR\5BABBLE\4XACTERR"
! 817: "\3MISSED\2SPLIT\1PING", sbuf, sizeof(sbuf));
! 818:
! 819: DPRINTFN(2,
! 820: ("ehci_idone: error, addr=%d, endpt=0x%02x, "
! 821: "status 0x%s\n",
! 822: xfer->pipe->device->address,
! 823: xfer->pipe->endpoint->edesc->bEndpointAddress,
! 824: sbuf));
! 825: if (ehcidebug > 2) {
! 826: ehci_dump_sqh(epipe->sqh);
! 827: ehci_dump_sqtds(ex->sqtdstart);
! 828: }
! 829: #endif
! 830: if ((status & EHCI_QTD_BABBLE) == 0 && cerr > 0)
! 831: xfer->status = USBD_STALLED;
! 832: else
! 833: xfer->status = USBD_IOERROR; /* more info XXX */
! 834: } else
! 835: xfer->status = USBD_NORMAL_COMPLETION;
! 836:
! 837: usb_transfer_complete(xfer);
! 838: DPRINTFN(/*12*/2, ("ehci_idone: ex=%p done\n", ex));
! 839: }
! 840:
! 841: /*
! 842: * Wait here until controller claims to have an interrupt.
! 843: * Then call ehci_intr and return. Use timeout to avoid waiting
! 844: * too long.
! 845: */
! 846: void
! 847: ehci_waitintr(ehci_softc_t *sc, usbd_xfer_handle xfer)
! 848: {
! 849: int timo;
! 850: u_int32_t intrs;
! 851:
! 852: xfer->status = USBD_IN_PROGRESS;
! 853: for (timo = xfer->timeout; timo >= 0; timo--) {
! 854: usb_delay_ms(&sc->sc_bus, 1);
! 855: if (sc->sc_dying)
! 856: break;
! 857: intrs = EHCI_STS_INTRS(EOREAD4(sc, EHCI_USBSTS)) &
! 858: sc->sc_eintrs;
! 859: DPRINTFN(15,("ehci_waitintr: 0x%04x\n", intrs));
! 860: #ifdef EHCI_DEBUG
! 861: if (ehcidebug > 15)
! 862: ehci_dump_regs(sc);
! 863: #endif
! 864: if (intrs) {
! 865: ehci_intr1(sc);
! 866: if (xfer->status != USBD_IN_PROGRESS)
! 867: return;
! 868: }
! 869: }
! 870:
! 871: /* Timeout */
! 872: DPRINTF(("ehci_waitintr: timeout\n"));
! 873: xfer->status = USBD_TIMEOUT;
! 874: usb_transfer_complete(xfer);
! 875: /* XXX should free TD */
! 876: }
! 877:
! 878: void
! 879: ehci_poll(struct usbd_bus *bus)
! 880: {
! 881: ehci_softc_t *sc = (ehci_softc_t *)bus;
! 882: #ifdef EHCI_DEBUG
! 883: static int last;
! 884: int new;
! 885: new = EHCI_STS_INTRS(EOREAD4(sc, EHCI_USBSTS));
! 886: if (new != last) {
! 887: DPRINTFN(10,("ehci_poll: intrs=0x%04x\n", new));
! 888: last = new;
! 889: }
! 890: #endif
! 891:
! 892: if (EOREAD4(sc, EHCI_USBSTS) & sc->sc_eintrs)
! 893: ehci_intr1(sc);
! 894: }
! 895:
! 896: int
! 897: ehci_detach(struct ehci_softc *sc, int flags)
! 898: {
! 899: int rv = 0;
! 900:
! 901: if (sc->sc_child != NULL)
! 902: rv = config_detach(sc->sc_child, flags);
! 903:
! 904: if (rv != 0)
! 905: return (rv);
! 906:
! 907: timeout_del(&sc->sc_tmo_intrlist);
! 908: timeout_del(&sc->sc_tmo_pcd);
! 909:
! 910: if (sc->sc_powerhook != NULL)
! 911: powerhook_disestablish(sc->sc_powerhook);
! 912: if (sc->sc_shutdownhook != NULL)
! 913: shutdownhook_disestablish(sc->sc_shutdownhook);
! 914:
! 915: usb_delay_ms(&sc->sc_bus, 300); /* XXX let stray task complete */
! 916:
! 917: /* XXX free other data structures XXX */
! 918:
! 919: return (rv);
! 920: }
! 921:
! 922:
! 923: int
! 924: ehci_activate(struct device *self, enum devact act)
! 925: {
! 926: struct ehci_softc *sc = (struct ehci_softc *)self;
! 927: int rv = 0;
! 928:
! 929: switch (act) {
! 930: case DVACT_ACTIVATE:
! 931: break;
! 932:
! 933: case DVACT_DEACTIVATE:
! 934: if (sc->sc_child != NULL)
! 935: rv = config_deactivate(sc->sc_child);
! 936: sc->sc_dying = 1;
! 937: break;
! 938: }
! 939: return (rv);
! 940: }
! 941:
! 942: /*
! 943: * Handle suspend/resume.
! 944: *
! 945: * We need to switch to polling mode here, because this routine is
! 946: * called from an interrupt context. This is all right since we
! 947: * are almost suspended anyway.
! 948: */
! 949: void
! 950: ehci_power(int why, void *v)
! 951: {
! 952: ehci_softc_t *sc = v;
! 953: u_int32_t cmd, hcr;
! 954: int s, i;
! 955:
! 956: #ifdef EHCI_DEBUG
! 957: DPRINTF(("ehci_power: sc=%p, why=%d\n", sc, why));
! 958: if (ehcidebug > 0)
! 959: ehci_dump_regs(sc);
! 960: #endif
! 961:
! 962: s = splhardusb();
! 963: switch (why) {
! 964: case PWR_SUSPEND:
! 965: case PWR_STANDBY:
! 966: sc->sc_bus.use_polling++;
! 967:
! 968: for (i = 1; i <= sc->sc_noport; i++) {
! 969: cmd = EOREAD4(sc, EHCI_PORTSC(i));
! 970: if ((cmd & (EHCI_PS_PO|EHCI_PS_PE)) == EHCI_PS_PE)
! 971: EOWRITE4(sc, EHCI_PORTSC(i),
! 972: cmd | EHCI_PS_SUSP);
! 973: }
! 974:
! 975: sc->sc_cmd = EOREAD4(sc, EHCI_USBCMD);
! 976: cmd = sc->sc_cmd & ~(EHCI_CMD_ASE | EHCI_CMD_PSE);
! 977: EOWRITE4(sc, EHCI_USBCMD, cmd);
! 978:
! 979: for (i = 0; i < 100; i++) {
! 980: hcr = EOREAD4(sc, EHCI_USBSTS) &
! 981: (EHCI_STS_ASS | EHCI_STS_PSS);
! 982: if (hcr == 0)
! 983: break;
! 984:
! 985: usb_delay_ms(&sc->sc_bus, 1);
! 986: }
! 987: if (hcr != 0)
! 988: printf("%s: reset timeout\n",
! 989: sc->sc_bus.bdev.dv_xname);
! 990:
! 991: cmd &= ~EHCI_CMD_RS;
! 992: EOWRITE4(sc, EHCI_USBCMD, cmd);
! 993:
! 994: for (i = 0; i < 100; i++) {
! 995: hcr = EOREAD4(sc, EHCI_USBSTS) & EHCI_STS_HCH;
! 996: if (hcr == EHCI_STS_HCH)
! 997: break;
! 998:
! 999: usb_delay_ms(&sc->sc_bus, 1);
! 1000: }
! 1001: if (hcr != EHCI_STS_HCH)
! 1002: printf("%s: config timeout\n",
! 1003: sc->sc_bus.bdev.dv_xname);
! 1004:
! 1005: sc->sc_bus.use_polling--;
! 1006: break;
! 1007:
! 1008: case PWR_RESUME:
! 1009: sc->sc_bus.use_polling++;
! 1010:
! 1011: /* restore things in case the bios sucks */
! 1012: EOWRITE4(sc, EHCI_CTRLDSSEGMENT, 0);
! 1013: EOWRITE4(sc, EHCI_PERIODICLISTBASE, DMAADDR(&sc->sc_fldma, 0));
! 1014: EOWRITE4(sc, EHCI_ASYNCLISTADDR,
! 1015: sc->sc_async_head->physaddr | EHCI_LINK_QH);
! 1016: EOWRITE4(sc, EHCI_USBINTR, sc->sc_eintrs);
! 1017:
! 1018: hcr = 0;
! 1019: for (i = 1; i <= sc->sc_noport; i++) {
! 1020: cmd = EOREAD4(sc, EHCI_PORTSC(i));
! 1021: if ((cmd & (EHCI_PS_PO|EHCI_PS_SUSP)) == EHCI_PS_SUSP) {
! 1022: EOWRITE4(sc, EHCI_PORTSC(i),
! 1023: cmd | EHCI_PS_FPR);
! 1024: hcr = 1;
! 1025: }
! 1026: }
! 1027:
! 1028: if (hcr) {
! 1029: usb_delay_ms(&sc->sc_bus, USB_RESUME_WAIT);
! 1030: for (i = 1; i <= sc->sc_noport; i++) {
! 1031: cmd = EOREAD4(sc, EHCI_PORTSC(i));
! 1032: if ((cmd & (EHCI_PS_PO|EHCI_PS_SUSP)) ==
! 1033: EHCI_PS_SUSP)
! 1034: EOWRITE4(sc, EHCI_PORTSC(i),
! 1035: cmd & ~EHCI_PS_FPR);
! 1036: }
! 1037: }
! 1038:
! 1039: EOWRITE4(sc, EHCI_USBCMD, sc->sc_cmd);
! 1040:
! 1041: /* Take over port ownership */
! 1042: EOWRITE4(sc, EHCI_CONFIGFLAG, EHCI_CONF_CF);
! 1043:
! 1044: for (i = 0; i < 100; i++) {
! 1045: hcr = EOREAD4(sc, EHCI_USBSTS) & EHCI_STS_HCH;
! 1046: if (hcr != EHCI_STS_HCH)
! 1047: break;
! 1048:
! 1049: usb_delay_ms(&sc->sc_bus, 1);
! 1050: }
! 1051: if (hcr == EHCI_STS_HCH)
! 1052: printf("%s: config timeout\n",
! 1053: sc->sc_bus.bdev.dv_xname);
! 1054:
! 1055: usb_delay_ms(&sc->sc_bus, USB_RESUME_WAIT);
! 1056:
! 1057: sc->sc_bus.use_polling--;
! 1058: break;
! 1059: }
! 1060: splx(s);
! 1061:
! 1062: #ifdef EHCI_DEBUG
! 1063: DPRINTF(("ehci_power: sc=%p\n", sc));
! 1064: if (ehcidebug > 0)
! 1065: ehci_dump_regs(sc);
! 1066: #endif
! 1067: }
! 1068:
! 1069: /*
! 1070: * Shut down the controller when the system is going down.
! 1071: */
! 1072: void
! 1073: ehci_shutdown(void *v)
! 1074: {
! 1075: ehci_softc_t *sc = v;
! 1076:
! 1077: DPRINTF(("ehci_shutdown: stopping the HC\n"));
! 1078: EOWRITE4(sc, EHCI_USBCMD, 0); /* Halt controller */
! 1079: EOWRITE4(sc, EHCI_USBCMD, EHCI_CMD_HCRESET);
! 1080: }
! 1081:
! 1082: usbd_status
! 1083: ehci_allocm(struct usbd_bus *bus, usb_dma_t *dma, u_int32_t size)
! 1084: {
! 1085: struct ehci_softc *sc = (struct ehci_softc *)bus;
! 1086: usbd_status err;
! 1087:
! 1088: err = usb_allocmem(&sc->sc_bus, size, 0, dma);
! 1089: #ifdef EHCI_DEBUG
! 1090: if (err)
! 1091: printf("ehci_allocm: usb_allocmem()=%d\n", err);
! 1092: #endif
! 1093: return (err);
! 1094: }
! 1095:
! 1096: void
! 1097: ehci_freem(struct usbd_bus *bus, usb_dma_t *dma)
! 1098: {
! 1099: struct ehci_softc *sc = (struct ehci_softc *)bus;
! 1100:
! 1101: usb_freemem(&sc->sc_bus, dma);
! 1102: }
! 1103:
! 1104: usbd_xfer_handle
! 1105: ehci_allocx(struct usbd_bus *bus)
! 1106: {
! 1107: struct ehci_softc *sc = (struct ehci_softc *)bus;
! 1108: usbd_xfer_handle xfer;
! 1109:
! 1110: xfer = SIMPLEQ_FIRST(&sc->sc_free_xfers);
! 1111: if (xfer != NULL) {
! 1112: SIMPLEQ_REMOVE_HEAD(&sc->sc_free_xfers, next);
! 1113: #ifdef DIAGNOSTIC
! 1114: if (xfer->busy_free != XFER_FREE)
! 1115: printf("ehci_allocx: xfer=%p not free, 0x%08x\n",
! 1116: xfer, xfer->busy_free);
! 1117: #endif
! 1118: } else
! 1119: xfer = malloc(sizeof(struct ehci_xfer), M_USB, M_NOWAIT);
! 1120:
! 1121: if (xfer != NULL) {
! 1122: memset(xfer, 0, sizeof(struct ehci_xfer));
! 1123: usb_init_task(&EXFER(xfer)->abort_task, ehci_timeout_task,
! 1124: xfer);
! 1125: EXFER(xfer)->ehci_xfer_flags = 0;
! 1126: #ifdef DIAGNOSTIC
! 1127: EXFER(xfer)->isdone = 1;
! 1128: xfer->busy_free = XFER_BUSY;
! 1129: #endif
! 1130: }
! 1131: return (xfer);
! 1132: }
! 1133:
! 1134: void
! 1135: ehci_freex(struct usbd_bus *bus, usbd_xfer_handle xfer)
! 1136: {
! 1137: struct ehci_softc *sc = (struct ehci_softc *)bus;
! 1138:
! 1139: #ifdef DIAGNOSTIC
! 1140: if (xfer->busy_free != XFER_BUSY) {
! 1141: printf("ehci_freex: xfer=%p not busy, 0x%08x\n", xfer,
! 1142: xfer->busy_free);
! 1143: return;
! 1144: }
! 1145: xfer->busy_free = XFER_FREE;
! 1146: if (!EXFER(xfer)->isdone) {
! 1147: printf("ehci_freex: !isdone\n");
! 1148: return;
! 1149: }
! 1150: #endif
! 1151: SIMPLEQ_INSERT_HEAD(&sc->sc_free_xfers, xfer, next);
! 1152: }
! 1153:
! 1154: void
! 1155: ehci_device_clear_toggle(usbd_pipe_handle pipe)
! 1156: {
! 1157: struct ehci_pipe *epipe = (struct ehci_pipe *)pipe;
! 1158:
! 1159: DPRINTF(("ehci_device_clear_toggle: epipe=%p status=0x%x\n",
! 1160: epipe, epipe->sqh->qh.qh_qtd.qtd_status));
! 1161: #ifdef USB_DEBUG
! 1162: if (ehcidebug)
! 1163: usbd_dump_pipe(pipe);
! 1164: #endif
! 1165: #ifdef DIAGNOSTIC
! 1166: if ((epipe->sqh->qh.qh_qtd.qtd_status & htole32(EHCI_QTD_ACTIVE)) != 0)
! 1167: panic("ehci_device_clear_toggle: queue active");
! 1168: #endif
! 1169: epipe->sqh->qh.qh_qtd.qtd_status &= htole32(~EHCI_QTD_TOGGLE_MASK);
! 1170: }
! 1171:
! 1172: void
! 1173: ehci_noop(usbd_pipe_handle pipe)
! 1174: {
! 1175: }
! 1176:
! 1177: #ifdef EHCI_DEBUG
! 1178: void
! 1179: ehci_dump_regs(ehci_softc_t *sc)
! 1180: {
! 1181: int i;
! 1182:
! 1183: printf("cmd=0x%08x, sts=0x%08x, ien=0x%08x\n",
! 1184: EOREAD4(sc, EHCI_USBCMD),
! 1185: EOREAD4(sc, EHCI_USBSTS),
! 1186: EOREAD4(sc, EHCI_USBINTR));
! 1187: printf("frindex=0x%08x ctrdsegm=0x%08x periodic=0x%08x async=0x%08x\n",
! 1188: EOREAD4(sc, EHCI_FRINDEX),
! 1189: EOREAD4(sc, EHCI_CTRLDSSEGMENT),
! 1190: EOREAD4(sc, EHCI_PERIODICLISTBASE),
! 1191: EOREAD4(sc, EHCI_ASYNCLISTADDR));
! 1192: for (i = 1; i <= sc->sc_noport; i++)
! 1193: printf("port %d status=0x%08x\n", i,
! 1194: EOREAD4(sc, EHCI_PORTSC(i)));
! 1195: }
! 1196:
! 1197: /*
! 1198: * Unused function - this is meant to be called from a kernel
! 1199: * debugger.
! 1200: */
! 1201: void
! 1202: ehci_dump()
! 1203: {
! 1204: ehci_dump_regs(theehci);
! 1205: }
! 1206:
! 1207: void
! 1208: ehci_dump_link(ehci_link_t link, int type)
! 1209: {
! 1210: link = letoh32(link);
! 1211: printf("0x%08x", link);
! 1212: if (link & EHCI_LINK_TERMINATE)
! 1213: printf("<T>");
! 1214: else {
! 1215: printf("<");
! 1216: if (type) {
! 1217: switch (EHCI_LINK_TYPE(link)) {
! 1218: case EHCI_LINK_ITD: printf("ITD"); break;
! 1219: case EHCI_LINK_QH: printf("QH"); break;
! 1220: case EHCI_LINK_SITD: printf("SITD"); break;
! 1221: case EHCI_LINK_FSTN: printf("FSTN"); break;
! 1222: }
! 1223: }
! 1224: printf(">");
! 1225: }
! 1226: }
! 1227:
! 1228: void
! 1229: ehci_dump_sqtds(ehci_soft_qtd_t *sqtd)
! 1230: {
! 1231: int i;
! 1232: u_int32_t stop;
! 1233:
! 1234: stop = 0;
! 1235: for (i = 0; sqtd && i < 20 && !stop; sqtd = sqtd->nextqtd, i++) {
! 1236: ehci_dump_sqtd(sqtd);
! 1237: stop = sqtd->qtd.qtd_next & htole32(EHCI_LINK_TERMINATE);
! 1238: }
! 1239: if (!stop)
! 1240: printf("dump aborted, too many TDs\n");
! 1241: }
! 1242:
! 1243: void
! 1244: ehci_dump_sqtd(ehci_soft_qtd_t *sqtd)
! 1245: {
! 1246: printf("QTD(%p) at 0x%08x:\n", sqtd, sqtd->physaddr);
! 1247: ehci_dump_qtd(&sqtd->qtd);
! 1248: }
! 1249:
! 1250: void
! 1251: ehci_dump_qtd(ehci_qtd_t *qtd)
! 1252: {
! 1253: u_int32_t s;
! 1254: char sbuf[128];
! 1255:
! 1256: printf(" next="); ehci_dump_link(qtd->qtd_next, 0);
! 1257: printf(" altnext="); ehci_dump_link(qtd->qtd_altnext, 0);
! 1258: printf("\n");
! 1259: s = letoh32(qtd->qtd_status);
! 1260: bitmask_snprintf(EHCI_QTD_GET_STATUS(s), "\20\10ACTIVE\7HALTED"
! 1261: "\6BUFERR\5BABBLE\4XACTERR\3MISSED\2SPLIT\1PING",
! 1262: sbuf, sizeof(sbuf));
! 1263: printf(" status=0x%08x: toggle=%d bytes=0x%x ioc=%d c_page=0x%x\n",
! 1264: s, EHCI_QTD_GET_TOGGLE(s), EHCI_QTD_GET_BYTES(s),
! 1265: EHCI_QTD_GET_IOC(s), EHCI_QTD_GET_C_PAGE(s));
! 1266: printf(" cerr=%d pid=%d stat=0x%s\n", EHCI_QTD_GET_CERR(s),
! 1267: EHCI_QTD_GET_PID(s), sbuf);
! 1268: for (s = 0; s < 5; s++)
! 1269: printf(" buffer[%d]=0x%08x\n", s, letoh32(qtd->qtd_buffer[s]));
! 1270: }
! 1271:
! 1272: void
! 1273: ehci_dump_sqh(ehci_soft_qh_t *sqh)
! 1274: {
! 1275: ehci_qh_t *qh = &sqh->qh;
! 1276: u_int32_t endp, endphub;
! 1277:
! 1278: printf("QH(%p) at 0x%08x:\n", sqh, sqh->physaddr);
! 1279: printf(" link="); ehci_dump_link(qh->qh_link, 1); printf("\n");
! 1280: endp = letoh32(qh->qh_endp);
! 1281: printf(" endp=0x%08x\n", endp);
! 1282: printf(" addr=0x%02x inact=%d endpt=%d eps=%d dtc=%d hrecl=%d\n",
! 1283: EHCI_QH_GET_ADDR(endp), EHCI_QH_GET_INACT(endp),
! 1284: EHCI_QH_GET_ENDPT(endp), EHCI_QH_GET_EPS(endp),
! 1285: EHCI_QH_GET_DTC(endp), EHCI_QH_GET_HRECL(endp));
! 1286: printf(" mpl=0x%x ctl=%d nrl=%d\n",
! 1287: EHCI_QH_GET_MPL(endp), EHCI_QH_GET_CTL(endp),
! 1288: EHCI_QH_GET_NRL(endp));
! 1289: endphub = letoh32(qh->qh_endphub);
! 1290: printf(" endphub=0x%08x\n", endphub);
! 1291: printf(" smask=0x%02x cmask=0x%02x huba=0x%02x port=%d mult=%d\n",
! 1292: EHCI_QH_GET_SMASK(endphub), EHCI_QH_GET_CMASK(endphub),
! 1293: EHCI_QH_GET_HUBA(endphub), EHCI_QH_GET_PORT(endphub),
! 1294: EHCI_QH_GET_MULT(endphub));
! 1295: printf(" curqtd="); ehci_dump_link(qh->qh_curqtd, 0); printf("\n");
! 1296: printf("Overlay qTD:\n");
! 1297: ehci_dump_qtd(&qh->qh_qtd);
! 1298: }
! 1299:
! 1300: #ifdef DIAGNOSTIC
! 1301: void
! 1302: ehci_dump_exfer(struct ehci_xfer *ex)
! 1303: {
! 1304: printf("ehci_dump_exfer: ex=%p\n", ex);
! 1305: }
! 1306: #endif
! 1307: #endif /* EHCI_DEBUG */
! 1308:
! 1309: usbd_status
! 1310: ehci_open(usbd_pipe_handle pipe)
! 1311: {
! 1312: usbd_device_handle dev = pipe->device;
! 1313: ehci_softc_t *sc = (ehci_softc_t *)dev->bus;
! 1314: usb_endpoint_descriptor_t *ed = pipe->endpoint->edesc;
! 1315: u_int8_t addr = dev->address;
! 1316: u_int8_t xfertype = ed->bmAttributes & UE_XFERTYPE;
! 1317: struct ehci_pipe *epipe = (struct ehci_pipe *)pipe;
! 1318: ehci_soft_qh_t *sqh;
! 1319: usbd_status err;
! 1320: int s;
! 1321: int ival, speed, naks;
! 1322: int hshubaddr, hshubport;
! 1323:
! 1324: DPRINTFN(1, ("ehci_open: pipe=%p, addr=%d, endpt=%d (%d)\n",
! 1325: pipe, addr, ed->bEndpointAddress, sc->sc_addr));
! 1326:
! 1327: if (sc->sc_dying)
! 1328: return (USBD_IOERROR);
! 1329:
! 1330: if (dev->myhsport) {
! 1331: hshubaddr = dev->myhsport->parent->address;
! 1332: hshubport = dev->myhsport->portno;
! 1333: } else {
! 1334: hshubaddr = 0;
! 1335: hshubport = 0;
! 1336: }
! 1337:
! 1338: if (addr == sc->sc_addr) {
! 1339: switch (ed->bEndpointAddress) {
! 1340: case USB_CONTROL_ENDPOINT:
! 1341: pipe->methods = &ehci_root_ctrl_methods;
! 1342: break;
! 1343: case UE_DIR_IN | EHCI_INTR_ENDPT:
! 1344: pipe->methods = &ehci_root_intr_methods;
! 1345: break;
! 1346: default:
! 1347: return (USBD_INVAL);
! 1348: }
! 1349: return (USBD_NORMAL_COMPLETION);
! 1350: }
! 1351:
! 1352: /* XXX All this stuff is only valid for async. */
! 1353: switch (dev->speed) {
! 1354: case USB_SPEED_LOW: speed = EHCI_QH_SPEED_LOW; break;
! 1355: case USB_SPEED_FULL: speed = EHCI_QH_SPEED_FULL; break;
! 1356: case USB_SPEED_HIGH: speed = EHCI_QH_SPEED_HIGH; break;
! 1357: default: panic("ehci_open: bad device speed %d", dev->speed);
! 1358: }
! 1359: if (speed != EHCI_QH_SPEED_HIGH && xfertype == UE_ISOCHRONOUS) {
! 1360: printf("%s: *** WARNING: opening low/full speed isochronous "
! 1361: "device, this does not work yet.\n",
! 1362: sc->sc_bus.bdev.dv_xname);
! 1363: DPRINTFN(1,("ehci_open: hshubaddr=%d hshubport=%d\n",
! 1364: hshubaddr, hshubport));
! 1365: return (USBD_INVAL);
! 1366: }
! 1367:
! 1368: naks = 8; /* XXX */
! 1369: sqh = ehci_alloc_sqh(sc);
! 1370: if (sqh == NULL)
! 1371: goto bad0;
! 1372: /* qh_link filled when the QH is added */
! 1373: sqh->qh.qh_endp = htole32(
! 1374: EHCI_QH_SET_ADDR(addr) |
! 1375: EHCI_QH_SET_ENDPT(UE_GET_ADDR(ed->bEndpointAddress)) |
! 1376: EHCI_QH_SET_EPS(speed) |
! 1377: (xfertype == UE_CONTROL ? EHCI_QH_DTC : 0) |
! 1378: EHCI_QH_SET_MPL(UGETW(ed->wMaxPacketSize)) |
! 1379: (speed != EHCI_QH_SPEED_HIGH && xfertype == UE_CONTROL ?
! 1380: EHCI_QH_CTL : 0) |
! 1381: EHCI_QH_SET_NRL(naks));
! 1382: sqh->qh.qh_endphub = htole32(
! 1383: EHCI_QH_SET_MULT(1) |
! 1384: EHCI_QH_SET_HUBA(hshubaddr) |
! 1385: EHCI_QH_SET_PORT(hshubport) |
! 1386: EHCI_QH_SET_CMASK(0x1c) | /* XXX */
! 1387: EHCI_QH_SET_SMASK(xfertype == UE_INTERRUPT ? 0x01 : 0));
! 1388: sqh->qh.qh_curqtd = EHCI_NULL;
! 1389: /* Fill the overlay qTD */
! 1390: sqh->qh.qh_qtd.qtd_next = EHCI_NULL;
! 1391: sqh->qh.qh_qtd.qtd_altnext = EHCI_NULL;
! 1392: sqh->qh.qh_qtd.qtd_status =
! 1393: htole32(EHCI_QTD_SET_TOGGLE(pipe->endpoint->savedtoggle));
! 1394:
! 1395: epipe->sqh = sqh;
! 1396:
! 1397: switch (xfertype) {
! 1398: case UE_CONTROL:
! 1399: err = usb_allocmem(&sc->sc_bus, sizeof(usb_device_request_t),
! 1400: 0, &epipe->u.ctl.reqdma);
! 1401: #ifdef EHCI_DEBUG
! 1402: if (err)
! 1403: printf("ehci_open: usb_allocmem()=%d\n", err);
! 1404: #endif
! 1405: if (err)
! 1406: goto bad1;
! 1407: pipe->methods = &ehci_device_ctrl_methods;
! 1408: s = splusb();
! 1409: ehci_add_qh(sqh, sc->sc_async_head);
! 1410: splx(s);
! 1411: break;
! 1412: case UE_BULK:
! 1413: pipe->methods = &ehci_device_bulk_methods;
! 1414: s = splusb();
! 1415: ehci_add_qh(sqh, sc->sc_async_head);
! 1416: splx(s);
! 1417: break;
! 1418: case UE_INTERRUPT:
! 1419: pipe->methods = &ehci_device_intr_methods;
! 1420: ival = pipe->interval;
! 1421: if (ival == USBD_DEFAULT_INTERVAL)
! 1422: ival = ed->bInterval;
! 1423: return (ehci_device_setintr(sc, sqh, ival));
! 1424: case UE_ISOCHRONOUS:
! 1425: pipe->methods = &ehci_device_isoc_methods;
! 1426: return (USBD_INVAL);
! 1427: default:
! 1428: return (USBD_INVAL);
! 1429: }
! 1430: return (USBD_NORMAL_COMPLETION);
! 1431:
! 1432: bad1:
! 1433: ehci_free_sqh(sc, sqh);
! 1434: bad0:
! 1435: return (USBD_NOMEM);
! 1436: }
! 1437:
! 1438: /*
! 1439: * Add an ED to the schedule. Called at splusb().
! 1440: * If in the async schedule, it will always have a next.
! 1441: * If in the intr schedule it may not.
! 1442: */
! 1443: void
! 1444: ehci_add_qh(ehci_soft_qh_t *sqh, ehci_soft_qh_t *head)
! 1445: {
! 1446: SPLUSBCHECK;
! 1447:
! 1448: sqh->next = head->next;
! 1449: sqh->prev = head;
! 1450: sqh->qh.qh_link = head->qh.qh_link;
! 1451: head->next = sqh;
! 1452: if (sqh->next)
! 1453: sqh->next->prev = sqh;
! 1454: head->qh.qh_link = htole32(sqh->physaddr | EHCI_LINK_QH);
! 1455:
! 1456: #ifdef EHCI_DEBUG
! 1457: if (ehcidebug > 5) {
! 1458: printf("ehci_add_qh:\n");
! 1459: ehci_dump_sqh(sqh);
! 1460: }
! 1461: #endif
! 1462: }
! 1463:
! 1464: /*
! 1465: * Remove an ED from the schedule. Called at splusb().
! 1466: * Will always have a 'next' if it's in the async list as it's circular.
! 1467: */
! 1468: void
! 1469: ehci_rem_qh(ehci_softc_t *sc, ehci_soft_qh_t *sqh, ehci_soft_qh_t *head)
! 1470: {
! 1471: SPLUSBCHECK;
! 1472: /* XXX */
! 1473: sqh->prev->qh.qh_link = sqh->qh.qh_link;
! 1474: sqh->prev->next = sqh->next;
! 1475: if (sqh->next)
! 1476: sqh->next->prev = sqh->prev;
! 1477: ehci_sync_hc(sc);
! 1478: }
! 1479:
! 1480: void
! 1481: ehci_set_qh_qtd(ehci_soft_qh_t *sqh, ehci_soft_qtd_t *sqtd)
! 1482: {
! 1483: int i;
! 1484: u_int32_t status;
! 1485:
! 1486: /* Save toggle bit and ping status. */
! 1487: status = sqh->qh.qh_qtd.qtd_status &
! 1488: htole32(EHCI_QTD_TOGGLE_MASK |
! 1489: EHCI_QTD_SET_STATUS(EHCI_QTD_PINGSTATE));
! 1490: /* Set HALTED to make hw leave it alone. */
! 1491: sqh->qh.qh_qtd.qtd_status =
! 1492: htole32(EHCI_QTD_SET_STATUS(EHCI_QTD_HALTED));
! 1493: sqh->qh.qh_curqtd = 0;
! 1494: sqh->qh.qh_qtd.qtd_next = htole32(sqtd->physaddr);
! 1495: sqh->qh.qh_qtd.qtd_altnext = EHCI_NULL;
! 1496: for (i = 0; i < EHCI_QTD_NBUFFERS; i++)
! 1497: sqh->qh.qh_qtd.qtd_buffer[i] = 0;
! 1498: sqh->sqtd = sqtd;
! 1499: /* Set !HALTED && !ACTIVE to start execution, preserve some fields */
! 1500: sqh->qh.qh_qtd.qtd_status = status;
! 1501: }
! 1502:
! 1503: /*
! 1504: * Ensure that the HC has released all references to the QH. We do this
! 1505: * by asking for a Async Advance Doorbell interrupt and then we wait for
! 1506: * the interrupt.
! 1507: * To make this easier we first obtain exclusive use of the doorbell.
! 1508: */
! 1509: void
! 1510: ehci_sync_hc(ehci_softc_t *sc)
! 1511: {
! 1512: int s, error;
! 1513: int tries = 0;
! 1514:
! 1515: if (sc->sc_dying) {
! 1516: DPRINTFN(2,("ehci_sync_hc: dying\n"));
! 1517: return;
! 1518: }
! 1519: DPRINTFN(2,("ehci_sync_hc: enter\n"));
! 1520: /* get doorbell */
! 1521: rw_enter_write(&sc->sc_doorbell_lock);
! 1522: s = splhardusb();
! 1523: do {
! 1524: /* ask for doorbell */
! 1525: EOWRITE4(sc, EHCI_USBCMD, EOREAD4(sc, EHCI_USBCMD) |
! 1526: EHCI_CMD_IAAD);
! 1527: DPRINTFN(1,("ehci_sync_hc: cmd=0x%08x sts=0x%08x\n",
! 1528: EOREAD4(sc, EHCI_USBCMD), EOREAD4(sc, EHCI_USBSTS)));
! 1529: /* bell wait */
! 1530: error = tsleep(&sc->sc_async_head, PZERO, "ehcidi", hz / 2);
! 1531: DPRINTFN(1,("ehci_sync_hc: cmd=0x%08x sts=0x%08x\n",
! 1532: EOREAD4(sc, EHCI_USBCMD), EOREAD4(sc, EHCI_USBSTS)));
! 1533: } while (error && ++tries < 10);
! 1534: splx(s);
! 1535: /* release doorbell */
! 1536: rw_exit_write(&sc->sc_doorbell_lock);
! 1537: #ifdef DIAGNOSTIC
! 1538: if (error)
! 1539: printf("ehci_sync_hc: tsleep() = %d\n", error);
! 1540: #endif
! 1541: DPRINTFN(2,("ehci_sync_hc: exit\n"));
! 1542: }
! 1543:
! 1544: /***********/
! 1545:
! 1546: /*
! 1547: * Data structures and routines to emulate the root hub.
! 1548: */
! 1549: usb_device_descriptor_t ehci_devd = {
! 1550: USB_DEVICE_DESCRIPTOR_SIZE,
! 1551: UDESC_DEVICE, /* type */
! 1552: {0x00, 0x02}, /* USB version */
! 1553: UDCLASS_HUB, /* class */
! 1554: UDSUBCLASS_HUB, /* subclass */
! 1555: UDPROTO_HSHUBSTT, /* protocol */
! 1556: 64, /* max packet */
! 1557: {0},{0},{0x00,0x01}, /* device id */
! 1558: 1,2,0, /* string indicies */
! 1559: 1 /* # of configurations */
! 1560: };
! 1561:
! 1562: usb_device_qualifier_t ehci_odevd = {
! 1563: USB_DEVICE_DESCRIPTOR_SIZE,
! 1564: UDESC_DEVICE_QUALIFIER, /* type */
! 1565: {0x00, 0x02}, /* USB version */
! 1566: UDCLASS_HUB, /* class */
! 1567: UDSUBCLASS_HUB, /* subclass */
! 1568: UDPROTO_FSHUB, /* protocol */
! 1569: 64, /* max packet */
! 1570: 1, /* # of configurations */
! 1571: 0
! 1572: };
! 1573:
! 1574: usb_config_descriptor_t ehci_confd = {
! 1575: USB_CONFIG_DESCRIPTOR_SIZE,
! 1576: UDESC_CONFIG,
! 1577: {USB_CONFIG_DESCRIPTOR_SIZE +
! 1578: USB_INTERFACE_DESCRIPTOR_SIZE +
! 1579: USB_ENDPOINT_DESCRIPTOR_SIZE},
! 1580: 1,
! 1581: 1,
! 1582: 0,
! 1583: UC_SELF_POWERED,
! 1584: 0 /* max power */
! 1585: };
! 1586:
! 1587: usb_interface_descriptor_t ehci_ifcd = {
! 1588: USB_INTERFACE_DESCRIPTOR_SIZE,
! 1589: UDESC_INTERFACE,
! 1590: 0,
! 1591: 0,
! 1592: 1,
! 1593: UICLASS_HUB,
! 1594: UISUBCLASS_HUB,
! 1595: UIPROTO_HSHUBSTT,
! 1596: 0
! 1597: };
! 1598:
! 1599: usb_endpoint_descriptor_t ehci_endpd = {
! 1600: USB_ENDPOINT_DESCRIPTOR_SIZE,
! 1601: UDESC_ENDPOINT,
! 1602: UE_DIR_IN | EHCI_INTR_ENDPT,
! 1603: UE_INTERRUPT,
! 1604: {8, 0}, /* max packet */
! 1605: 255
! 1606: };
! 1607:
! 1608: usb_hub_descriptor_t ehci_hubd = {
! 1609: USB_HUB_DESCRIPTOR_SIZE,
! 1610: UDESC_HUB,
! 1611: 0,
! 1612: {0,0},
! 1613: 0,
! 1614: 0,
! 1615: {0},
! 1616: };
! 1617:
! 1618: int
! 1619: ehci_str(usb_string_descriptor_t *p, int l, const char *s)
! 1620: {
! 1621: int i;
! 1622:
! 1623: if (l == 0)
! 1624: return (0);
! 1625: p->bLength = 2 * strlen(s) + 2;
! 1626: if (l == 1)
! 1627: return (1);
! 1628: p->bDescriptorType = UDESC_STRING;
! 1629: l -= 2;
! 1630: for (i = 0; s[i] && l > 1; i++, l -= 2)
! 1631: USETW2(p->bString[i], 0, s[i]);
! 1632: return (2*i+2);
! 1633: }
! 1634:
! 1635: /*
! 1636: * Simulate a hardware hub by handling all the necessary requests.
! 1637: */
! 1638: usbd_status
! 1639: ehci_root_ctrl_transfer(usbd_xfer_handle xfer)
! 1640: {
! 1641: usbd_status err;
! 1642:
! 1643: /* Insert last in queue. */
! 1644: err = usb_insert_transfer(xfer);
! 1645: if (err)
! 1646: return (err);
! 1647:
! 1648: /* Pipe isn't running, start first */
! 1649: return (ehci_root_ctrl_start(SIMPLEQ_FIRST(&xfer->pipe->queue)));
! 1650: }
! 1651:
! 1652: usbd_status
! 1653: ehci_root_ctrl_start(usbd_xfer_handle xfer)
! 1654: {
! 1655: ehci_softc_t *sc = (ehci_softc_t *)xfer->pipe->device->bus;
! 1656: usb_device_request_t *req;
! 1657: void *buf = NULL;
! 1658: int port, i;
! 1659: int s, len, value, index, l, totlen = 0;
! 1660: usb_port_status_t ps;
! 1661: usb_hub_descriptor_t hubd;
! 1662: usbd_status err;
! 1663: u_int32_t v;
! 1664:
! 1665: if (sc->sc_dying)
! 1666: return (USBD_IOERROR);
! 1667:
! 1668: #ifdef DIAGNOSTIC
! 1669: if (!(xfer->rqflags & URQ_REQUEST))
! 1670: /* XXX panic */
! 1671: return (USBD_INVAL);
! 1672: #endif
! 1673: req = &xfer->request;
! 1674:
! 1675: DPRINTFN(4,("ehci_root_ctrl_start: type=0x%02x request=%02x\n",
! 1676: req->bmRequestType, req->bRequest));
! 1677:
! 1678: len = UGETW(req->wLength);
! 1679: value = UGETW(req->wValue);
! 1680: index = UGETW(req->wIndex);
! 1681:
! 1682: if (len != 0)
! 1683: buf = KERNADDR(&xfer->dmabuf, 0);
! 1684:
! 1685: #define C(x,y) ((x) | ((y) << 8))
! 1686: switch(C(req->bRequest, req->bmRequestType)) {
! 1687: case C(UR_CLEAR_FEATURE, UT_WRITE_DEVICE):
! 1688: case C(UR_CLEAR_FEATURE, UT_WRITE_INTERFACE):
! 1689: case C(UR_CLEAR_FEATURE, UT_WRITE_ENDPOINT):
! 1690: /*
! 1691: * DEVICE_REMOTE_WAKEUP and ENDPOINT_HALT are no-ops
! 1692: * for the integrated root hub.
! 1693: */
! 1694: break;
! 1695: case C(UR_GET_CONFIG, UT_READ_DEVICE):
! 1696: if (len > 0) {
! 1697: *(u_int8_t *)buf = sc->sc_conf;
! 1698: totlen = 1;
! 1699: }
! 1700: break;
! 1701: case C(UR_GET_DESCRIPTOR, UT_READ_DEVICE):
! 1702: DPRINTFN(8,("ehci_root_ctrl_start: wValue=0x%04x\n", value));
! 1703: switch(value >> 8) {
! 1704: case UDESC_DEVICE:
! 1705: if ((value & 0xff) != 0) {
! 1706: err = USBD_IOERROR;
! 1707: goto ret;
! 1708: }
! 1709: totlen = l = min(len, USB_DEVICE_DESCRIPTOR_SIZE);
! 1710: USETW(ehci_devd.idVendor, sc->sc_id_vendor);
! 1711: memcpy(buf, &ehci_devd, l);
! 1712: break;
! 1713: /*
! 1714: * We can't really operate at another speed, but the spec says
! 1715: * we need this descriptor.
! 1716: */
! 1717: case UDESC_DEVICE_QUALIFIER:
! 1718: if ((value & 0xff) != 0) {
! 1719: err = USBD_IOERROR;
! 1720: goto ret;
! 1721: }
! 1722: totlen = l = min(len, USB_DEVICE_DESCRIPTOR_SIZE);
! 1723: memcpy(buf, &ehci_odevd, l);
! 1724: break;
! 1725: /*
! 1726: * We can't really operate at another speed, but the spec says
! 1727: * we need this descriptor.
! 1728: */
! 1729: case UDESC_OTHER_SPEED_CONFIGURATION:
! 1730: case UDESC_CONFIG:
! 1731: if ((value & 0xff) != 0) {
! 1732: err = USBD_IOERROR;
! 1733: goto ret;
! 1734: }
! 1735: totlen = l = min(len, USB_CONFIG_DESCRIPTOR_SIZE);
! 1736: memcpy(buf, &ehci_confd, l);
! 1737: ((usb_config_descriptor_t *)buf)->bDescriptorType =
! 1738: value >> 8;
! 1739: buf = (char *)buf + l;
! 1740: len -= l;
! 1741: l = min(len, USB_INTERFACE_DESCRIPTOR_SIZE);
! 1742: totlen += l;
! 1743: memcpy(buf, &ehci_ifcd, l);
! 1744: buf = (char *)buf + l;
! 1745: len -= l;
! 1746: l = min(len, USB_ENDPOINT_DESCRIPTOR_SIZE);
! 1747: totlen += l;
! 1748: memcpy(buf, &ehci_endpd, l);
! 1749: break;
! 1750: case UDESC_STRING:
! 1751: if (len == 0)
! 1752: break;
! 1753: *(u_int8_t *)buf = 0;
! 1754: totlen = 1;
! 1755: switch (value & 0xff) {
! 1756: case 0: /* Language table */
! 1757: totlen = ehci_str(buf, len, "\001");
! 1758: break;
! 1759: case 1: /* Vendor */
! 1760: totlen = ehci_str(buf, len, sc->sc_vendor);
! 1761: break;
! 1762: case 2: /* Product */
! 1763: totlen = ehci_str(buf, len, "EHCI root hub");
! 1764: break;
! 1765: }
! 1766: break;
! 1767: default:
! 1768: err = USBD_IOERROR;
! 1769: goto ret;
! 1770: }
! 1771: break;
! 1772: case C(UR_GET_INTERFACE, UT_READ_INTERFACE):
! 1773: if (len > 0) {
! 1774: *(u_int8_t *)buf = 0;
! 1775: totlen = 1;
! 1776: }
! 1777: break;
! 1778: case C(UR_GET_STATUS, UT_READ_DEVICE):
! 1779: if (len > 1) {
! 1780: USETW(((usb_status_t *)buf)->wStatus,UDS_SELF_POWERED);
! 1781: totlen = 2;
! 1782: }
! 1783: break;
! 1784: case C(UR_GET_STATUS, UT_READ_INTERFACE):
! 1785: case C(UR_GET_STATUS, UT_READ_ENDPOINT):
! 1786: if (len > 1) {
! 1787: USETW(((usb_status_t *)buf)->wStatus, 0);
! 1788: totlen = 2;
! 1789: }
! 1790: break;
! 1791: case C(UR_SET_ADDRESS, UT_WRITE_DEVICE):
! 1792: if (value >= USB_MAX_DEVICES) {
! 1793: err = USBD_IOERROR;
! 1794: goto ret;
! 1795: }
! 1796: sc->sc_addr = value;
! 1797: break;
! 1798: case C(UR_SET_CONFIG, UT_WRITE_DEVICE):
! 1799: if (value != 0 && value != 1) {
! 1800: err = USBD_IOERROR;
! 1801: goto ret;
! 1802: }
! 1803: sc->sc_conf = value;
! 1804: break;
! 1805: case C(UR_SET_DESCRIPTOR, UT_WRITE_DEVICE):
! 1806: break;
! 1807: case C(UR_SET_FEATURE, UT_WRITE_DEVICE):
! 1808: case C(UR_SET_FEATURE, UT_WRITE_INTERFACE):
! 1809: case C(UR_SET_FEATURE, UT_WRITE_ENDPOINT):
! 1810: err = USBD_IOERROR;
! 1811: goto ret;
! 1812: case C(UR_SET_INTERFACE, UT_WRITE_INTERFACE):
! 1813: break;
! 1814: case C(UR_SYNCH_FRAME, UT_WRITE_ENDPOINT):
! 1815: break;
! 1816: /* Hub requests */
! 1817: case C(UR_CLEAR_FEATURE, UT_WRITE_CLASS_DEVICE):
! 1818: break;
! 1819: case C(UR_CLEAR_FEATURE, UT_WRITE_CLASS_OTHER):
! 1820: DPRINTFN(8, ("ehci_root_ctrl_start: UR_CLEAR_PORT_FEATURE "
! 1821: "port=%d feature=%d\n", index, value));
! 1822: if (index < 1 || index > sc->sc_noport) {
! 1823: err = USBD_IOERROR;
! 1824: goto ret;
! 1825: }
! 1826: port = EHCI_PORTSC(index);
! 1827: v = EOREAD4(sc, port) &~ EHCI_PS_CLEAR;
! 1828: switch(value) {
! 1829: case UHF_PORT_ENABLE:
! 1830: EOWRITE4(sc, port, v &~ EHCI_PS_PE);
! 1831: break;
! 1832: case UHF_PORT_SUSPEND:
! 1833: EOWRITE4(sc, port, v &~ EHCI_PS_SUSP);
! 1834: break;
! 1835: case UHF_PORT_POWER:
! 1836: EOWRITE4(sc, port, v &~ EHCI_PS_PP);
! 1837: break;
! 1838: case UHF_PORT_TEST:
! 1839: DPRINTFN(2,("ehci_root_ctrl_start: "
! 1840: "clear port test %d\n", index));
! 1841: break;
! 1842: case UHF_PORT_INDICATOR:
! 1843: DPRINTFN(2,("ehci_root_ctrl_start: "
! 1844: "clear port index %d\n", index));
! 1845: EOWRITE4(sc, port, v &~ EHCI_PS_PIC);
! 1846: break;
! 1847: case UHF_C_PORT_CONNECTION:
! 1848: EOWRITE4(sc, port, v | EHCI_PS_CSC);
! 1849: break;
! 1850: case UHF_C_PORT_ENABLE:
! 1851: EOWRITE4(sc, port, v | EHCI_PS_PEC);
! 1852: break;
! 1853: case UHF_C_PORT_SUSPEND:
! 1854: /* how? */
! 1855: break;
! 1856: case UHF_C_PORT_OVER_CURRENT:
! 1857: EOWRITE4(sc, port, v | EHCI_PS_OCC);
! 1858: break;
! 1859: case UHF_C_PORT_RESET:
! 1860: sc->sc_isreset = 0;
! 1861: break;
! 1862: default:
! 1863: err = USBD_IOERROR;
! 1864: goto ret;
! 1865: }
! 1866: #if 0
! 1867: switch(value) {
! 1868: case UHF_C_PORT_CONNECTION:
! 1869: case UHF_C_PORT_ENABLE:
! 1870: case UHF_C_PORT_SUSPEND:
! 1871: case UHF_C_PORT_OVER_CURRENT:
! 1872: case UHF_C_PORT_RESET:
! 1873: /* Enable RHSC interrupt if condition is cleared. */
! 1874: if ((OREAD4(sc, port) >> 16) == 0)
! 1875: ehci_pcd_able(sc, 1);
! 1876: break;
! 1877: default:
! 1878: break;
! 1879: }
! 1880: #endif
! 1881: break;
! 1882: case C(UR_GET_DESCRIPTOR, UT_READ_CLASS_DEVICE):
! 1883: if ((value & 0xff) != 0) {
! 1884: err = USBD_IOERROR;
! 1885: goto ret;
! 1886: }
! 1887: hubd = ehci_hubd;
! 1888: hubd.bNbrPorts = sc->sc_noport;
! 1889: v = EOREAD4(sc, EHCI_HCSPARAMS);
! 1890: USETW(hubd.wHubCharacteristics,
! 1891: EHCI_HCS_PPC(v) ? UHD_PWR_INDIVIDUAL : UHD_PWR_NO_SWITCH |
! 1892: EHCI_HCS_P_INDICATOR(EREAD4(sc, EHCI_HCSPARAMS))
! 1893: ? UHD_PORT_IND : 0);
! 1894: hubd.bPwrOn2PwrGood = 200; /* XXX can't find out? */
! 1895: for (i = 0, l = sc->sc_noport; l > 0; i++, l -= 8, v >>= 8)
! 1896: hubd.DeviceRemovable[i++] = 0; /* XXX can't find out? */
! 1897: hubd.bDescLength = USB_HUB_DESCRIPTOR_SIZE + i;
! 1898: l = min(len, hubd.bDescLength);
! 1899: totlen = l;
! 1900: memcpy(buf, &hubd, l);
! 1901: break;
! 1902: case C(UR_GET_STATUS, UT_READ_CLASS_DEVICE):
! 1903: if (len != 4) {
! 1904: err = USBD_IOERROR;
! 1905: goto ret;
! 1906: }
! 1907: memset(buf, 0, len); /* ? XXX */
! 1908: totlen = len;
! 1909: break;
! 1910: case C(UR_GET_STATUS, UT_READ_CLASS_OTHER):
! 1911: DPRINTFN(8,("ehci_root_ctrl_start: get port status i=%d\n",
! 1912: index));
! 1913: if (index < 1 || index > sc->sc_noport) {
! 1914: err = USBD_IOERROR;
! 1915: goto ret;
! 1916: }
! 1917: if (len != 4) {
! 1918: err = USBD_IOERROR;
! 1919: goto ret;
! 1920: }
! 1921: v = EOREAD4(sc, EHCI_PORTSC(index));
! 1922: DPRINTFN(8,("ehci_root_ctrl_start: port status=0x%04x\n", v));
! 1923: i = UPS_HIGH_SPEED;
! 1924: if (v & EHCI_PS_CS) i |= UPS_CURRENT_CONNECT_STATUS;
! 1925: if (v & EHCI_PS_PE) i |= UPS_PORT_ENABLED;
! 1926: if (v & EHCI_PS_SUSP) i |= UPS_SUSPEND;
! 1927: if (v & EHCI_PS_OCA) i |= UPS_OVERCURRENT_INDICATOR;
! 1928: if (v & EHCI_PS_PR) i |= UPS_RESET;
! 1929: if (v & EHCI_PS_PP) i |= UPS_PORT_POWER;
! 1930: USETW(ps.wPortStatus, i);
! 1931: i = 0;
! 1932: if (v & EHCI_PS_CSC) i |= UPS_C_CONNECT_STATUS;
! 1933: if (v & EHCI_PS_PEC) i |= UPS_C_PORT_ENABLED;
! 1934: if (v & EHCI_PS_OCC) i |= UPS_C_OVERCURRENT_INDICATOR;
! 1935: if (sc->sc_isreset) i |= UPS_C_PORT_RESET;
! 1936: USETW(ps.wPortChange, i);
! 1937: l = min(len, sizeof(ps));
! 1938: memcpy(buf, &ps, l);
! 1939: totlen = l;
! 1940: break;
! 1941: case C(UR_SET_DESCRIPTOR, UT_WRITE_CLASS_DEVICE):
! 1942: err = USBD_IOERROR;
! 1943: goto ret;
! 1944: case C(UR_SET_FEATURE, UT_WRITE_CLASS_DEVICE):
! 1945: break;
! 1946: case C(UR_SET_FEATURE, UT_WRITE_CLASS_OTHER):
! 1947: if (index < 1 || index > sc->sc_noport) {
! 1948: err = USBD_IOERROR;
! 1949: goto ret;
! 1950: }
! 1951: port = EHCI_PORTSC(index);
! 1952: v = EOREAD4(sc, port) &~ EHCI_PS_CLEAR;
! 1953: switch(value) {
! 1954: case UHF_PORT_ENABLE:
! 1955: EOWRITE4(sc, port, v | EHCI_PS_PE);
! 1956: break;
! 1957: case UHF_PORT_SUSPEND:
! 1958: EOWRITE4(sc, port, v | EHCI_PS_SUSP);
! 1959: break;
! 1960: case UHF_PORT_RESET:
! 1961: DPRINTFN(5,("ehci_root_ctrl_start: reset port %d\n",
! 1962: index));
! 1963: if (EHCI_PS_IS_LOWSPEED(v)) {
! 1964: /* Low speed device, give up ownership. */
! 1965: ehci_disown(sc, index, 1);
! 1966: break;
! 1967: }
! 1968: /* Start reset sequence. */
! 1969: v &= ~ (EHCI_PS_PE | EHCI_PS_PR);
! 1970: EOWRITE4(sc, port, v | EHCI_PS_PR);
! 1971: /* Wait for reset to complete. */
! 1972: usb_delay_ms(&sc->sc_bus, USB_PORT_ROOT_RESET_DELAY);
! 1973: if (sc->sc_dying) {
! 1974: err = USBD_IOERROR;
! 1975: goto ret;
! 1976: }
! 1977: /* Terminate reset sequence. */
! 1978: EOWRITE4(sc, port, v);
! 1979: /* Wait for HC to complete reset. */
! 1980: usb_delay_ms(&sc->sc_bus, EHCI_PORT_RESET_COMPLETE);
! 1981: if (sc->sc_dying) {
! 1982: err = USBD_IOERROR;
! 1983: goto ret;
! 1984: }
! 1985: v = EOREAD4(sc, port);
! 1986: DPRINTF(("ehci after reset, status=0x%08x\n", v));
! 1987: if (v & EHCI_PS_PR) {
! 1988: printf("%s: port reset timeout\n",
! 1989: sc->sc_bus.bdev.dv_xname);
! 1990: return (USBD_TIMEOUT);
! 1991: }
! 1992: if (!(v & EHCI_PS_PE)) {
! 1993: /* Not a high speed device, give up ownership.*/
! 1994: ehci_disown(sc, index, 0);
! 1995: break;
! 1996: }
! 1997: sc->sc_isreset = 1;
! 1998: DPRINTF(("ehci port %d reset, status = 0x%08x\n",
! 1999: index, v));
! 2000: break;
! 2001: case UHF_PORT_POWER:
! 2002: DPRINTFN(2,("ehci_root_ctrl_start: "
! 2003: "set port power %d\n", index));
! 2004: EOWRITE4(sc, port, v | EHCI_PS_PP);
! 2005: break;
! 2006: case UHF_PORT_TEST:
! 2007: DPRINTFN(2,("ehci_root_ctrl_start: "
! 2008: "set port test %d\n", index));
! 2009: break;
! 2010: case UHF_PORT_INDICATOR:
! 2011: DPRINTFN(2,("ehci_root_ctrl_start: "
! 2012: "set port ind %d\n", index));
! 2013: EOWRITE4(sc, port, v | EHCI_PS_PIC);
! 2014: break;
! 2015: default:
! 2016: err = USBD_IOERROR;
! 2017: goto ret;
! 2018: }
! 2019: break;
! 2020: case C(UR_CLEAR_TT_BUFFER, UT_WRITE_CLASS_OTHER):
! 2021: case C(UR_RESET_TT, UT_WRITE_CLASS_OTHER):
! 2022: case C(UR_GET_TT_STATE, UT_READ_CLASS_OTHER):
! 2023: case C(UR_STOP_TT, UT_WRITE_CLASS_OTHER):
! 2024: break;
! 2025: default:
! 2026: err = USBD_IOERROR;
! 2027: goto ret;
! 2028: }
! 2029: xfer->actlen = totlen;
! 2030: err = USBD_NORMAL_COMPLETION;
! 2031: ret:
! 2032: xfer->status = err;
! 2033: s = splusb();
! 2034: usb_transfer_complete(xfer);
! 2035: splx(s);
! 2036: return (USBD_IN_PROGRESS);
! 2037: }
! 2038:
! 2039: void
! 2040: ehci_disown(ehci_softc_t *sc, int index, int lowspeed)
! 2041: {
! 2042: int port;
! 2043: u_int32_t v;
! 2044:
! 2045: DPRINTF(("ehci_disown: index=%d lowspeed=%d\n", index, lowspeed));
! 2046:
! 2047: port = EHCI_PORTSC(index);
! 2048: v = EOREAD4(sc, port) &~ EHCI_PS_CLEAR;
! 2049: EOWRITE4(sc, port, v | EHCI_PS_PO);
! 2050: }
! 2051:
! 2052: /* Abort a root control request. */
! 2053: void
! 2054: ehci_root_ctrl_abort(usbd_xfer_handle xfer)
! 2055: {
! 2056: /* Nothing to do, all transfers are synchronous. */
! 2057: }
! 2058:
! 2059: /* Close the root pipe. */
! 2060: void
! 2061: ehci_root_ctrl_close(usbd_pipe_handle pipe)
! 2062: {
! 2063: DPRINTF(("ehci_root_ctrl_close\n"));
! 2064: /* Nothing to do. */
! 2065: }
! 2066:
! 2067: void
! 2068: ehci_root_intr_done(usbd_xfer_handle xfer)
! 2069: {
! 2070: }
! 2071:
! 2072: usbd_status
! 2073: ehci_root_intr_transfer(usbd_xfer_handle xfer)
! 2074: {
! 2075: usbd_status err;
! 2076:
! 2077: /* Insert last in queue. */
! 2078: err = usb_insert_transfer(xfer);
! 2079: if (err)
! 2080: return (err);
! 2081:
! 2082: /* Pipe isn't running, start first */
! 2083: return (ehci_root_intr_start(SIMPLEQ_FIRST(&xfer->pipe->queue)));
! 2084: }
! 2085:
! 2086: usbd_status
! 2087: ehci_root_intr_start(usbd_xfer_handle xfer)
! 2088: {
! 2089: usbd_pipe_handle pipe = xfer->pipe;
! 2090: ehci_softc_t *sc = (ehci_softc_t *)pipe->device->bus;
! 2091:
! 2092: if (sc->sc_dying)
! 2093: return (USBD_IOERROR);
! 2094:
! 2095: sc->sc_intrxfer = xfer;
! 2096:
! 2097: return (USBD_IN_PROGRESS);
! 2098: }
! 2099:
! 2100: /* Abort a root interrupt request. */
! 2101: void
! 2102: ehci_root_intr_abort(usbd_xfer_handle xfer)
! 2103: {
! 2104: int s;
! 2105:
! 2106: if (xfer->pipe->intrxfer == xfer) {
! 2107: DPRINTF(("ehci_root_intr_abort: remove\n"));
! 2108: xfer->pipe->intrxfer = NULL;
! 2109: }
! 2110: xfer->status = USBD_CANCELLED;
! 2111: s = splusb();
! 2112: usb_transfer_complete(xfer);
! 2113: splx(s);
! 2114: }
! 2115:
! 2116: /* Close the root pipe. */
! 2117: void
! 2118: ehci_root_intr_close(usbd_pipe_handle pipe)
! 2119: {
! 2120: ehci_softc_t *sc = (ehci_softc_t *)pipe->device->bus;
! 2121:
! 2122: DPRINTF(("ehci_root_intr_close\n"));
! 2123:
! 2124: sc->sc_intrxfer = NULL;
! 2125: }
! 2126:
! 2127: void
! 2128: ehci_root_ctrl_done(usbd_xfer_handle xfer)
! 2129: {
! 2130: }
! 2131:
! 2132: /************************/
! 2133:
! 2134: ehci_soft_qh_t *
! 2135: ehci_alloc_sqh(ehci_softc_t *sc)
! 2136: {
! 2137: ehci_soft_qh_t *sqh;
! 2138: usbd_status err;
! 2139: int i, offs;
! 2140: usb_dma_t dma;
! 2141:
! 2142: if (sc->sc_freeqhs == NULL) {
! 2143: DPRINTFN(2, ("ehci_alloc_sqh: allocating chunk\n"));
! 2144: err = usb_allocmem(&sc->sc_bus, EHCI_SQH_SIZE * EHCI_SQH_CHUNK,
! 2145: EHCI_PAGE_SIZE, &dma);
! 2146: #ifdef EHCI_DEBUG
! 2147: if (err)
! 2148: printf("ehci_alloc_sqh: usb_allocmem()=%d\n", err);
! 2149: #endif
! 2150: if (err)
! 2151: return (NULL);
! 2152: for(i = 0; i < EHCI_SQH_CHUNK; i++) {
! 2153: offs = i * EHCI_SQH_SIZE;
! 2154: sqh = KERNADDR(&dma, offs);
! 2155: sqh->physaddr = DMAADDR(&dma, offs);
! 2156: sqh->next = sc->sc_freeqhs;
! 2157: sc->sc_freeqhs = sqh;
! 2158: }
! 2159: }
! 2160: sqh = sc->sc_freeqhs;
! 2161: sc->sc_freeqhs = sqh->next;
! 2162: memset(&sqh->qh, 0, sizeof(ehci_qh_t));
! 2163: sqh->next = NULL;
! 2164: sqh->prev = NULL;
! 2165: return (sqh);
! 2166: }
! 2167:
! 2168: void
! 2169: ehci_free_sqh(ehci_softc_t *sc, ehci_soft_qh_t *sqh)
! 2170: {
! 2171: sqh->next = sc->sc_freeqhs;
! 2172: sc->sc_freeqhs = sqh;
! 2173: }
! 2174:
! 2175: ehci_soft_qtd_t *
! 2176: ehci_alloc_sqtd(ehci_softc_t *sc)
! 2177: {
! 2178: ehci_soft_qtd_t *sqtd;
! 2179: usbd_status err;
! 2180: int i, offs;
! 2181: usb_dma_t dma;
! 2182: int s;
! 2183:
! 2184: if (sc->sc_freeqtds == NULL) {
! 2185: DPRINTFN(2, ("ehci_alloc_sqtd: allocating chunk\n"));
! 2186: err = usb_allocmem(&sc->sc_bus, EHCI_SQTD_SIZE*EHCI_SQTD_CHUNK,
! 2187: EHCI_PAGE_SIZE, &dma);
! 2188: #ifdef EHCI_DEBUG
! 2189: if (err)
! 2190: printf("ehci_alloc_sqtd: usb_allocmem()=%d\n", err);
! 2191: #endif
! 2192: if (err)
! 2193: return (NULL);
! 2194: s = splusb();
! 2195: for(i = 0; i < EHCI_SQTD_CHUNK; i++) {
! 2196: offs = i * EHCI_SQTD_SIZE;
! 2197: sqtd = KERNADDR(&dma, offs);
! 2198: sqtd->physaddr = DMAADDR(&dma, offs);
! 2199: sqtd->nextqtd = sc->sc_freeqtds;
! 2200: sc->sc_freeqtds = sqtd;
! 2201: }
! 2202: splx(s);
! 2203: }
! 2204:
! 2205: s = splusb();
! 2206: sqtd = sc->sc_freeqtds;
! 2207: sc->sc_freeqtds = sqtd->nextqtd;
! 2208: memset(&sqtd->qtd, 0, sizeof(ehci_qtd_t));
! 2209: sqtd->nextqtd = NULL;
! 2210: sqtd->xfer = NULL;
! 2211: splx(s);
! 2212:
! 2213: return (sqtd);
! 2214: }
! 2215:
! 2216: void
! 2217: ehci_free_sqtd(ehci_softc_t *sc, ehci_soft_qtd_t *sqtd)
! 2218: {
! 2219: int s;
! 2220:
! 2221: s = splusb();
! 2222: sqtd->nextqtd = sc->sc_freeqtds;
! 2223: sc->sc_freeqtds = sqtd;
! 2224: splx(s);
! 2225: }
! 2226:
! 2227: usbd_status
! 2228: ehci_alloc_sqtd_chain(struct ehci_pipe *epipe, ehci_softc_t *sc, int alen,
! 2229: int rd, usbd_xfer_handle xfer, ehci_soft_qtd_t **sp, ehci_soft_qtd_t **ep)
! 2230: {
! 2231: ehci_soft_qtd_t *next, *cur;
! 2232: ehci_physaddr_t dataphys, dataphyspage, dataphyslastpage, nextphys;
! 2233: u_int32_t qtdstatus;
! 2234: int len, curlen, mps;
! 2235: int i, iscontrol, forceshort;
! 2236: usb_dma_t *dma = &xfer->dmabuf;
! 2237:
! 2238: DPRINTFN(alen<4*4096,("ehci_alloc_sqtd_chain: start len=%d\n", alen));
! 2239:
! 2240: len = alen;
! 2241: iscontrol = (epipe->pipe.endpoint->edesc->bmAttributes & UE_XFERTYPE) ==
! 2242: UE_CONTROL;
! 2243:
! 2244: dataphys = DMAADDR(dma, 0);
! 2245: dataphyslastpage = EHCI_PAGE(dataphys + len - 1);
! 2246: qtdstatus = EHCI_QTD_ACTIVE |
! 2247: EHCI_QTD_SET_PID(rd ? EHCI_QTD_PID_IN : EHCI_QTD_PID_OUT) |
! 2248: EHCI_QTD_SET_CERR(3); /* IOC and BYTES set below */
! 2249: mps = UGETW(epipe->pipe.endpoint->edesc->wMaxPacketSize);
! 2250: forceshort = ((xfer->flags & USBD_FORCE_SHORT_XFER) || len == 0) &&
! 2251: len % mps == 0;
! 2252: /*
! 2253: * The control transfer data stage always starts with a toggle of 1.
! 2254: * For other transfers we let the hardware track the toggle state.
! 2255: */
! 2256: if (iscontrol)
! 2257: qtdstatus |= EHCI_QTD_SET_TOGGLE(1);
! 2258:
! 2259: cur = ehci_alloc_sqtd(sc);
! 2260: *sp = cur;
! 2261: if (cur == NULL)
! 2262: goto nomem;
! 2263: for (;;) {
! 2264: dataphyspage = EHCI_PAGE(dataphys);
! 2265: /* The EHCI hardware can handle at most 5 pages. */
! 2266: if (dataphyslastpage - dataphyspage <
! 2267: EHCI_QTD_NBUFFERS * EHCI_PAGE_SIZE) {
! 2268: /* we can handle it in this QTD */
! 2269: curlen = len;
! 2270: } else {
! 2271: /* must use multiple TDs, fill as much as possible. */
! 2272: curlen = EHCI_QTD_NBUFFERS * EHCI_PAGE_SIZE -
! 2273: EHCI_PAGE_OFFSET(dataphys);
! 2274: #ifdef DIAGNOSTIC
! 2275: if (curlen > len) {
! 2276: printf("ehci_alloc_sqtd_chain: curlen=0x%x "
! 2277: "len=0x%x offs=0x%x\n", curlen, len,
! 2278: EHCI_PAGE_OFFSET(dataphys));
! 2279: printf("lastpage=0x%x page=0x%x phys=0x%x\n",
! 2280: dataphyslastpage, dataphyspage, dataphys);
! 2281: curlen = len;
! 2282: }
! 2283: #endif
! 2284: /* the length must be a multiple of the max size */
! 2285: curlen -= curlen % mps;
! 2286: DPRINTFN(1,("ehci_alloc_sqtd_chain: multiple QTDs, "
! 2287: "curlen=%d\n", curlen));
! 2288: #ifdef DIAGNOSTIC
! 2289: if (curlen == 0)
! 2290: panic("ehci_alloc_std: curlen == 0");
! 2291: #endif
! 2292: }
! 2293: DPRINTFN(4,("ehci_alloc_sqtd_chain: dataphys=0x%08x "
! 2294: "dataphyslastpage=0x%08x len=%d curlen=%d\n",
! 2295: dataphys, dataphyslastpage, len, curlen));
! 2296: len -= curlen;
! 2297:
! 2298: /*
! 2299: * Allocate another transfer if there's more data left,
! 2300: * or if force last short transfer flag is set and we're
! 2301: * allocating a multiple of the max packet size.
! 2302: */
! 2303: if (len != 0 || forceshort) {
! 2304: next = ehci_alloc_sqtd(sc);
! 2305: if (next == NULL)
! 2306: goto nomem;
! 2307: nextphys = htole32(next->physaddr);
! 2308: } else {
! 2309: next = NULL;
! 2310: nextphys = EHCI_NULL;
! 2311: }
! 2312:
! 2313: for (i = 0; i * EHCI_PAGE_SIZE <
! 2314: curlen + EHCI_PAGE_OFFSET(dataphys); i++) {
! 2315: ehci_physaddr_t a = dataphys + i * EHCI_PAGE_SIZE;
! 2316: if (i != 0) /* use offset only in first buffer */
! 2317: a = EHCI_PAGE(a);
! 2318: cur->qtd.qtd_buffer[i] = htole32(a);
! 2319: cur->qtd.qtd_buffer_hi[i] = 0;
! 2320: #ifdef DIAGNOSTIC
! 2321: if (i >= EHCI_QTD_NBUFFERS) {
! 2322: printf("ehci_alloc_sqtd_chain: i=%d\n", i);
! 2323: goto nomem;
! 2324: }
! 2325: #endif
! 2326: }
! 2327: cur->nextqtd = next;
! 2328: cur->qtd.qtd_next = cur->qtd.qtd_altnext = nextphys;
! 2329: cur->qtd.qtd_status = htole32(qtdstatus |
! 2330: EHCI_QTD_SET_BYTES(curlen));
! 2331: cur->xfer = xfer;
! 2332: cur->len = curlen;
! 2333: DPRINTFN(10,("ehci_alloc_sqtd_chain: cbp=0x%08x end=0x%08x\n",
! 2334: dataphys, dataphys + curlen));
! 2335: DPRINTFN(10,("ehci_alloc_sqtd_chain: curlen=%d\n", curlen));
! 2336: if (iscontrol) {
! 2337: /*
! 2338: * adjust the toggle based on the number of packets
! 2339: * in this qtd
! 2340: */
! 2341: if ((((curlen + mps - 1) / mps) & 1) || curlen == 0)
! 2342: qtdstatus ^= EHCI_QTD_TOGGLE_MASK;
! 2343: }
! 2344: if (len == 0) {
! 2345: if (! forceshort)
! 2346: break;
! 2347: forceshort = 0;
! 2348: }
! 2349: DPRINTFN(10,("ehci_alloc_sqtd_chain: extend chain\n"));
! 2350: dataphys += curlen;
! 2351: cur = next;
! 2352: }
! 2353: cur->qtd.qtd_status |= htole32(EHCI_QTD_IOC);
! 2354: *ep = cur;
! 2355:
! 2356: DPRINTFN(10,("ehci_alloc_sqtd_chain: return sqtd=%p sqtdend=%p\n",
! 2357: *sp, *ep));
! 2358:
! 2359: return (USBD_NORMAL_COMPLETION);
! 2360:
! 2361: nomem:
! 2362: /* XXX free chain */
! 2363: DPRINTFN(-1,("ehci_alloc_sqtd_chain: no memory\n"));
! 2364: return (USBD_NOMEM);
! 2365: }
! 2366:
! 2367: void
! 2368: ehci_free_sqtd_chain(ehci_softc_t *sc, ehci_soft_qtd_t *sqtd,
! 2369: ehci_soft_qtd_t *sqtdend)
! 2370: {
! 2371: ehci_soft_qtd_t *p;
! 2372: int i;
! 2373:
! 2374: DPRINTFN(10,("ehci_free_sqtd_chain: sqtd=%p sqtdend=%p\n",
! 2375: sqtd, sqtdend));
! 2376:
! 2377: for (i = 0; sqtd != sqtdend; sqtd = p, i++) {
! 2378: p = sqtd->nextqtd;
! 2379: ehci_free_sqtd(sc, sqtd);
! 2380: }
! 2381: }
! 2382:
! 2383: /****************/
! 2384:
! 2385: /*
! 2386: * Close a reqular pipe.
! 2387: * Assumes that there are no pending transactions.
! 2388: */
! 2389: void
! 2390: ehci_close_pipe(usbd_pipe_handle pipe, ehci_soft_qh_t *head)
! 2391: {
! 2392: struct ehci_pipe *epipe = (struct ehci_pipe *)pipe;
! 2393: ehci_softc_t *sc = (ehci_softc_t *)pipe->device->bus;
! 2394: ehci_soft_qh_t *sqh = epipe->sqh;
! 2395: int s;
! 2396:
! 2397: s = splusb();
! 2398: ehci_rem_qh(sc, sqh, head);
! 2399: splx(s);
! 2400: pipe->endpoint->savedtoggle =
! 2401: EHCI_QTD_GET_TOGGLE(letoh32(sqh->qh.qh_qtd.qtd_status));
! 2402: ehci_free_sqh(sc, epipe->sqh);
! 2403: }
! 2404:
! 2405: /*
! 2406: * Abort a device request.
! 2407: * If this routine is called at splusb() it guarantees that the request
! 2408: * will be removed from the hardware scheduling and that the callback
! 2409: * for it will be called with USBD_CANCELLED status.
! 2410: * It's impossible to guarantee that the requested transfer will not
! 2411: * have happened since the hardware runs concurrently.
! 2412: * If the transaction has already happened we rely on the ordinary
! 2413: * interrupt processing to process it.
! 2414: */
! 2415: void
! 2416: ehci_abort_xfer(usbd_xfer_handle xfer, usbd_status status)
! 2417: {
! 2418: #define exfer EXFER(xfer)
! 2419: struct ehci_pipe *epipe = (struct ehci_pipe *)xfer->pipe;
! 2420: ehci_softc_t *sc = (ehci_softc_t *)epipe->pipe.device->bus;
! 2421: ehci_soft_qh_t *sqh = epipe->sqh;
! 2422: ehci_soft_qtd_t *sqtd, *snext, **psqtd;
! 2423: ehci_physaddr_t cur, us, next;
! 2424: int s;
! 2425: int hit;
! 2426: ehci_soft_qh_t *psqh;
! 2427:
! 2428: DPRINTF(("ehci_abort_xfer: xfer=%p pipe=%p\n", xfer, epipe));
! 2429:
! 2430: if (sc->sc_dying) {
! 2431: /* If we're dying, just do the software part. */
! 2432: s = splusb();
! 2433: xfer->status = status; /* make software ignore it */
! 2434: timeout_del(&xfer->timeout_handle);
! 2435: usb_rem_task(epipe->pipe.device, &exfer->abort_task);
! 2436: usb_transfer_complete(xfer);
! 2437: splx(s);
! 2438: return;
! 2439: }
! 2440:
! 2441: if (xfer->device->bus->intr_context || !curproc)
! 2442: panic("ehci_abort_xfer: not in process context");
! 2443:
! 2444: /*
! 2445: * If an abort is already in progress then just wait for it to
! 2446: * complete and return.
! 2447: */
! 2448: if (exfer->ehci_xfer_flags & EHCI_XFER_ABORTING) {
! 2449: DPRINTFN(2, ("ehci_abort_xfer: already aborting\n"));
! 2450: /* No need to wait if we're aborting from a timeout. */
! 2451: if (status == USBD_TIMEOUT)
! 2452: return;
! 2453: /* Override the status which might be USBD_TIMEOUT. */
! 2454: xfer->status = status;
! 2455: DPRINTFN(2, ("ehci_abort_xfer: waiting for abort to finish\n"));
! 2456: exfer->ehci_xfer_flags |= EHCI_XFER_ABORTWAIT;
! 2457: while (exfer->ehci_xfer_flags & EHCI_XFER_ABORTING)
! 2458: tsleep(&exfer->ehci_xfer_flags, PZERO, "ehciaw", 0);
! 2459: return;
! 2460: }
! 2461:
! 2462: /*
! 2463: * Step 1: Make interrupt routine and timeouts ignore xfer.
! 2464: */
! 2465: s = splusb();
! 2466: exfer->ehci_xfer_flags |= EHCI_XFER_ABORTING;
! 2467: xfer->status = status; /* make software ignore it */
! 2468: timeout_del(&xfer->timeout_handle);
! 2469: usb_rem_task(epipe->pipe.device, &exfer->abort_task);
! 2470: splx(s);
! 2471:
! 2472: /*
! 2473: * Step 2: Wait until we know hardware has finished any possible
! 2474: * use of the xfer. We do this by removing the entire
! 2475: * queue from the async schedule and waiting for the doorbell.
! 2476: * Nothing else should be touching the queue now.
! 2477: */
! 2478: psqh = sqh->prev;
! 2479: ehci_rem_qh(sc, sqh, psqh);
! 2480:
! 2481: /*
! 2482: * Step 3: Deactivate all of the qTDs that we will be removing,
! 2483: * otherwise the queue head may go active again. The EHCI spec
! 2484: * suggests we should perform the deactivation before removing the
! 2485: * queue head from the schedule, however the VT6202 (at least) only
! 2486: * behaves correctly when we deactivate them afterwards.
! 2487: */
! 2488: for (sqtd = exfer->sqtdstart; ; sqtd = sqtd->nextqtd) {
! 2489: sqtd->qtd.qtd_status = htole32(EHCI_QTD_HALTED);
! 2490: if (sqtd == exfer->sqtdend)
! 2491: break;
! 2492: }
! 2493: ehci_sync_hc(sc);
! 2494:
! 2495: /*
! 2496: * Step 4: make sure the soft interrupt routine
! 2497: * has run. This should remove any completed items off the queue.
! 2498: * The hardware has no reference to completed items (TDs).
! 2499: * It's safe to remove them at any time.
! 2500: * use of the xfer. Also make sure the soft interrupt routine
! 2501: * has run.
! 2502: */
! 2503: s = splusb();
! 2504: #ifdef __HAVE_GENERIC_SOFT_INTERRUPTS
! 2505: sc->sc_softwake = 1;
! 2506: #endif /* __HAVE_GENERIC_SOFT_INTERRUPTS */
! 2507: usb_schedsoftintr(&sc->sc_bus);
! 2508: #ifdef __HAVE_GENERIC_SOFT_INTERRUPTS
! 2509: tsleep(&sc->sc_softwake, PZERO, "ehciab", 0);
! 2510: #endif /* __HAVE_GENERIC_SOFT_INTERRUPTS */
! 2511:
! 2512: /*
! 2513: * Step 5: Remove any vestiges of the xfer from the hardware.
! 2514: * The complication here is that the hardware may have executed
! 2515: * into or even beyond the xfer we're trying to abort.
! 2516: * So as we're scanning the TDs of this xfer we check if
! 2517: * the hardware points to any of them.
! 2518: *
! 2519: * first we need to see if there are any transfers
! 2520: * on this queue before the xfer we are aborting.. we need
! 2521: * to update any pointers that point to us to point past
! 2522: * the aborting xfer. (If there is something past us).
! 2523: * Hardware and software.
! 2524: */
! 2525: cur = EHCI_LINK_ADDR(letoh32(sqh->qh.qh_curqtd));
! 2526: hit = 0;
! 2527:
! 2528: /* If they initially point here. */
! 2529: us = exfer->sqtdstart->physaddr;
! 2530:
! 2531: /* We will change them to point here */
! 2532: snext = exfer->sqtdend->nextqtd;
! 2533: next = snext ? snext->physaddr : EHCI_NULL;
! 2534:
! 2535: /*
! 2536: * Now loop through any qTDs before us and keep track of the pointer
! 2537: * that points to us for the end.
! 2538: */
! 2539: psqtd = &sqh->sqtd;
! 2540: sqtd = sqh->sqtd;
! 2541: while (sqtd && sqtd != exfer->sqtdstart) {
! 2542: hit |= (cur == sqtd->physaddr);
! 2543: if (EHCI_LINK_ADDR(letoh32(sqtd->qtd.qtd_next)) == us)
! 2544: sqtd->qtd.qtd_next = next;
! 2545: if (EHCI_LINK_ADDR(letoh32(sqtd->qtd.qtd_altnext)) == us)
! 2546: sqtd->qtd.qtd_altnext = next;
! 2547: psqtd = &sqtd->nextqtd;
! 2548: sqtd = sqtd->nextqtd;
! 2549: }
! 2550: /* make the software pointer bypass us too */
! 2551: *psqtd = exfer->sqtdend->nextqtd;
! 2552:
! 2553: /*
! 2554: * If we already saw the active one then we are pretty much done.
! 2555: * We've done all the relinking we need to do.
! 2556: */
! 2557: if (!hit) {
! 2558:
! 2559: /*
! 2560: * Now reinitialise the QH to point to the next qTD
! 2561: * (if there is one). We only need to do this if
! 2562: * it was previously pointing to us.
! 2563: * XXX Not quite sure what to do about the data toggle.
! 2564: */
! 2565: sqtd = exfer->sqtdstart;
! 2566: for (sqtd = exfer->sqtdstart; ; sqtd = sqtd->nextqtd) {
! 2567: if (cur == sqtd->physaddr) {
! 2568: hit++;
! 2569: }
! 2570: if (sqtd == exfer->sqtdend)
! 2571: break;
! 2572: }
! 2573: sqtd = sqtd->nextqtd;
! 2574: /*
! 2575: * Only need to alter the QH if it was pointing at a qTD
! 2576: * that we are removing.
! 2577: */
! 2578: if (hit) {
! 2579: if (snext) {
! 2580: ehci_set_qh_qtd(sqh, snext);
! 2581: } else {
! 2582:
! 2583: sqh->qh.qh_curqtd = 0; /* unlink qTDs */
! 2584: sqh->qh.qh_qtd.qtd_status = 0;
! 2585: sqh->qh.qh_qtd.qtd_next =
! 2586: sqh->qh.qh_qtd.qtd_altnext = EHCI_NULL;
! 2587: DPRINTFN(1,("ehci_abort_xfer: no hit\n"));
! 2588: }
! 2589: }
! 2590: }
! 2591: ehci_add_qh(sqh, psqh);
! 2592:
! 2593: /*
! 2594: * Step 6: Execute callback.
! 2595: */
! 2596: #ifdef DIAGNOSTIC
! 2597: exfer->isdone = 1;
! 2598: #endif
! 2599: /* Do the wakeup first to avoid touching the xfer after the callback. */
! 2600: exfer->ehci_xfer_flags &= ~EHCI_XFER_ABORTING;
! 2601: if (exfer->ehci_xfer_flags & EHCI_XFER_ABORTWAIT) {
! 2602: exfer->ehci_xfer_flags &= ~EHCI_XFER_ABORTWAIT;
! 2603: wakeup(&exfer->ehci_xfer_flags);
! 2604: }
! 2605: usb_transfer_complete(xfer);
! 2606:
! 2607: splx(s);
! 2608: #undef exfer
! 2609: }
! 2610:
! 2611: void
! 2612: ehci_timeout(void *addr)
! 2613: {
! 2614: struct ehci_xfer *exfer = addr;
! 2615: struct ehci_pipe *epipe = (struct ehci_pipe *)exfer->xfer.pipe;
! 2616: ehci_softc_t *sc = (ehci_softc_t *)epipe->pipe.device->bus;
! 2617:
! 2618: DPRINTF(("ehci_timeout: exfer=%p\n", exfer));
! 2619: #ifdef USB_DEBUG
! 2620: if (ehcidebug > 1)
! 2621: usbd_dump_pipe(exfer->xfer.pipe);
! 2622: #endif
! 2623:
! 2624: if (sc->sc_dying) {
! 2625: ehci_abort_xfer(&exfer->xfer, USBD_TIMEOUT);
! 2626: return;
! 2627: }
! 2628:
! 2629: /* Execute the abort in a process context. */
! 2630: usb_add_task(exfer->xfer.pipe->device, &exfer->abort_task);
! 2631: }
! 2632:
! 2633: void
! 2634: ehci_timeout_task(void *addr)
! 2635: {
! 2636: usbd_xfer_handle xfer = addr;
! 2637: int s;
! 2638:
! 2639: DPRINTF(("ehci_timeout_task: xfer=%p\n", xfer));
! 2640:
! 2641: s = splusb();
! 2642: ehci_abort_xfer(xfer, USBD_TIMEOUT);
! 2643: splx(s);
! 2644: }
! 2645:
! 2646: /*
! 2647: * Some EHCI chips from VIA seem to trigger interrupts before writing back the
! 2648: * qTD status, or miss signalling occasionally under heavy load. If the host
! 2649: * machine is too fast, we we can miss transaction completion - when we scan
! 2650: * the active list the transaction still seems to be active. This generally
! 2651: * exhibits itself as a umass stall that never recovers.
! 2652: *
! 2653: * We work around this behaviour by setting up this callback after any softintr
! 2654: * that completes with transactions still pending, giving us another chance to
! 2655: * check for completion after the writeback has taken place.
! 2656: */
! 2657: void
! 2658: ehci_intrlist_timeout(void *arg)
! 2659: {
! 2660: ehci_softc_t *sc = arg;
! 2661: int s = splusb();
! 2662:
! 2663: DPRINTFN(1, ("ehci_intrlist_timeout\n"));
! 2664: usb_schedsoftintr(&sc->sc_bus);
! 2665:
! 2666: splx(s);
! 2667: }
! 2668:
! 2669: /************************/
! 2670:
! 2671: usbd_status
! 2672: ehci_device_ctrl_transfer(usbd_xfer_handle xfer)
! 2673: {
! 2674: usbd_status err;
! 2675:
! 2676: /* Insert last in queue. */
! 2677: err = usb_insert_transfer(xfer);
! 2678: if (err)
! 2679: return (err);
! 2680:
! 2681: /* Pipe isn't running, start first */
! 2682: return (ehci_device_ctrl_start(SIMPLEQ_FIRST(&xfer->pipe->queue)));
! 2683: }
! 2684:
! 2685: usbd_status
! 2686: ehci_device_ctrl_start(usbd_xfer_handle xfer)
! 2687: {
! 2688: ehci_softc_t *sc = (ehci_softc_t *)xfer->pipe->device->bus;
! 2689: usbd_status err;
! 2690:
! 2691: if (sc->sc_dying)
! 2692: return (USBD_IOERROR);
! 2693:
! 2694: #ifdef DIAGNOSTIC
! 2695: if (!(xfer->rqflags & URQ_REQUEST)) {
! 2696: /* XXX panic */
! 2697: printf("ehci_device_ctrl_transfer: not a request\n");
! 2698: return (USBD_INVAL);
! 2699: }
! 2700: #endif
! 2701:
! 2702: err = ehci_device_request(xfer);
! 2703: if (err)
! 2704: return (err);
! 2705:
! 2706: if (sc->sc_bus.use_polling)
! 2707: ehci_waitintr(sc, xfer);
! 2708: return (USBD_IN_PROGRESS);
! 2709: }
! 2710:
! 2711: void
! 2712: ehci_device_ctrl_done(usbd_xfer_handle xfer)
! 2713: {
! 2714: struct ehci_xfer *ex = EXFER(xfer);
! 2715: ehci_softc_t *sc = (ehci_softc_t *)xfer->pipe->device->bus;
! 2716: /*struct ehci_pipe *epipe = (struct ehci_pipe *)xfer->pipe;*/
! 2717:
! 2718: DPRINTFN(10,("ehci_ctrl_done: xfer=%p\n", xfer));
! 2719:
! 2720: #ifdef DIAGNOSTIC
! 2721: if (!(xfer->rqflags & URQ_REQUEST)) {
! 2722: panic("ehci_ctrl_done: not a request");
! 2723: }
! 2724: #endif
! 2725:
! 2726: if (xfer->status != USBD_NOMEM && ehci_active_intr_list(ex)) {
! 2727: ehci_del_intr_list(ex); /* remove from active list */
! 2728: ehci_free_sqtd_chain(sc, ex->sqtdstart, NULL);
! 2729: }
! 2730:
! 2731: DPRINTFN(5, ("ehci_ctrl_done: length=%d\n", xfer->actlen));
! 2732: }
! 2733:
! 2734: /* Abort a device control request. */
! 2735: void
! 2736: ehci_device_ctrl_abort(usbd_xfer_handle xfer)
! 2737: {
! 2738: DPRINTF(("ehci_device_ctrl_abort: xfer=%p\n", xfer));
! 2739: ehci_abort_xfer(xfer, USBD_CANCELLED);
! 2740: }
! 2741:
! 2742: /* Close a device control pipe. */
! 2743: void
! 2744: ehci_device_ctrl_close(usbd_pipe_handle pipe)
! 2745: {
! 2746: ehci_softc_t *sc = (ehci_softc_t *)pipe->device->bus;
! 2747: /*struct ehci_pipe *epipe = (struct ehci_pipe *)pipe;*/
! 2748:
! 2749: DPRINTF(("ehci_device_ctrl_close: pipe=%p\n", pipe));
! 2750: ehci_close_pipe(pipe, sc->sc_async_head);
! 2751: }
! 2752:
! 2753: usbd_status
! 2754: ehci_device_request(usbd_xfer_handle xfer)
! 2755: {
! 2756: #define exfer EXFER(xfer)
! 2757: struct ehci_pipe *epipe = (struct ehci_pipe *)xfer->pipe;
! 2758: usb_device_request_t *req = &xfer->request;
! 2759: usbd_device_handle dev = epipe->pipe.device;
! 2760: ehci_softc_t *sc = (ehci_softc_t *)dev->bus;
! 2761: int addr = dev->address;
! 2762: ehci_soft_qtd_t *setup, *stat, *next;
! 2763: ehci_soft_qh_t *sqh;
! 2764: int isread;
! 2765: int len;
! 2766: usbd_status err;
! 2767: int s;
! 2768:
! 2769: isread = req->bmRequestType & UT_READ;
! 2770: len = UGETW(req->wLength);
! 2771:
! 2772: DPRINTFN(3,("ehci_device_request: type=0x%02x, request=0x%02x, "
! 2773: "wValue=0x%04x, wIndex=0x%04x len=%d, addr=%d, endpt=%d\n",
! 2774: req->bmRequestType, req->bRequest, UGETW(req->wValue),
! 2775: UGETW(req->wIndex), len, addr,
! 2776: epipe->pipe.endpoint->edesc->bEndpointAddress));
! 2777:
! 2778: setup = ehci_alloc_sqtd(sc);
! 2779: if (setup == NULL) {
! 2780: err = USBD_NOMEM;
! 2781: goto bad1;
! 2782: }
! 2783: stat = ehci_alloc_sqtd(sc);
! 2784: if (stat == NULL) {
! 2785: err = USBD_NOMEM;
! 2786: goto bad2;
! 2787: }
! 2788:
! 2789: sqh = epipe->sqh;
! 2790: epipe->u.ctl.length = len;
! 2791:
! 2792: /* Update device address and length since they may have changed
! 2793: during the setup of the control pipe in usbd_new_device(). */
! 2794: /* XXX This only needs to be done once, but it's too early in open. */
! 2795: /* XXXX Should not touch ED here! */
! 2796: sqh->qh.qh_endp =
! 2797: (sqh->qh.qh_endp & htole32(~(EHCI_QH_ADDRMASK | EHCI_QH_MPLMASK))) |
! 2798: htole32(
! 2799: EHCI_QH_SET_ADDR(addr) |
! 2800: EHCI_QH_SET_MPL(UGETW(epipe->pipe.endpoint->edesc->wMaxPacketSize))
! 2801: );
! 2802:
! 2803: /* Set up data transaction */
! 2804: if (len != 0) {
! 2805: ehci_soft_qtd_t *end;
! 2806:
! 2807: err = ehci_alloc_sqtd_chain(epipe, sc, len, isread, xfer,
! 2808: &next, &end);
! 2809: if (err)
! 2810: goto bad3;
! 2811: end->qtd.qtd_status &= htole32(~EHCI_QTD_IOC);
! 2812: end->nextqtd = stat;
! 2813: end->qtd.qtd_next =
! 2814: end->qtd.qtd_altnext = htole32(stat->physaddr);
! 2815: } else {
! 2816: next = stat;
! 2817: }
! 2818:
! 2819: memcpy(KERNADDR(&epipe->u.ctl.reqdma, 0), req, sizeof(*req));
! 2820:
! 2821: /* Clear toggle */
! 2822: setup->qtd.qtd_status = htole32(
! 2823: EHCI_QTD_ACTIVE |
! 2824: EHCI_QTD_SET_PID(EHCI_QTD_PID_SETUP) |
! 2825: EHCI_QTD_SET_CERR(3) |
! 2826: EHCI_QTD_SET_TOGGLE(0) |
! 2827: EHCI_QTD_SET_BYTES(sizeof(*req)));
! 2828: setup->qtd.qtd_buffer[0] = htole32(DMAADDR(&epipe->u.ctl.reqdma, 0));
! 2829: setup->qtd.qtd_buffer_hi[0] = 0;
! 2830: setup->nextqtd = next;
! 2831: setup->qtd.qtd_next = setup->qtd.qtd_altnext = htole32(next->physaddr);
! 2832: setup->xfer = xfer;
! 2833: setup->len = sizeof(*req);
! 2834:
! 2835: stat->qtd.qtd_status = htole32(
! 2836: EHCI_QTD_ACTIVE |
! 2837: EHCI_QTD_SET_PID(isread ? EHCI_QTD_PID_OUT : EHCI_QTD_PID_IN) |
! 2838: EHCI_QTD_SET_CERR(3) |
! 2839: EHCI_QTD_SET_TOGGLE(1) |
! 2840: EHCI_QTD_IOC);
! 2841: stat->qtd.qtd_buffer[0] = 0; /* XXX not needed? */
! 2842: stat->qtd.qtd_buffer_hi[0] = 0; /* XXX not needed? */
! 2843: stat->nextqtd = NULL;
! 2844: stat->qtd.qtd_next = stat->qtd.qtd_altnext = EHCI_NULL;
! 2845: stat->xfer = xfer;
! 2846: stat->len = 0;
! 2847:
! 2848: #ifdef EHCI_DEBUG
! 2849: if (ehcidebug > 5) {
! 2850: DPRINTF(("ehci_device_request:\n"));
! 2851: ehci_dump_sqh(sqh);
! 2852: ehci_dump_sqtds(setup);
! 2853: }
! 2854: #endif
! 2855:
! 2856: exfer->sqtdstart = setup;
! 2857: exfer->sqtdend = stat;
! 2858: #ifdef DIAGNOSTIC
! 2859: if (!exfer->isdone) {
! 2860: printf("ehci_device_request: not done, exfer=%p\n", exfer);
! 2861: }
! 2862: exfer->isdone = 0;
! 2863: #endif
! 2864:
! 2865: /* Insert qTD in QH list. */
! 2866: s = splusb();
! 2867: ehci_set_qh_qtd(sqh, setup);
! 2868: if (xfer->timeout && !sc->sc_bus.use_polling) {
! 2869: timeout_del(&xfer->timeout_handle);
! 2870: timeout_set(&xfer->timeout_handle, ehci_timeout, xfer);
! 2871: timeout_add(&xfer->timeout_handle, mstohz(xfer->timeout));
! 2872: }
! 2873: ehci_add_intr_list(sc, exfer);
! 2874: xfer->status = USBD_IN_PROGRESS;
! 2875: splx(s);
! 2876:
! 2877: #ifdef EHCI_DEBUG
! 2878: if (ehcidebug > 10) {
! 2879: DPRINTF(("ehci_device_request: status=%x\n",
! 2880: EOREAD4(sc, EHCI_USBSTS)));
! 2881: delay(10000);
! 2882: ehci_dump_regs(sc);
! 2883: ehci_dump_sqh(sc->sc_async_head);
! 2884: ehci_dump_sqh(sqh);
! 2885: ehci_dump_sqtds(setup);
! 2886: }
! 2887: #endif
! 2888:
! 2889: return (USBD_NORMAL_COMPLETION);
! 2890:
! 2891: bad3:
! 2892: ehci_free_sqtd(sc, stat);
! 2893: bad2:
! 2894: ehci_free_sqtd(sc, setup);
! 2895: bad1:
! 2896: DPRINTFN(-1,("ehci_device_request: no memory\n"));
! 2897: xfer->status = err;
! 2898: usb_transfer_complete(xfer);
! 2899: return (err);
! 2900: #undef exfer
! 2901: }
! 2902:
! 2903: /************************/
! 2904:
! 2905: usbd_status
! 2906: ehci_device_bulk_transfer(usbd_xfer_handle xfer)
! 2907: {
! 2908: usbd_status err;
! 2909:
! 2910: /* Insert last in queue. */
! 2911: err = usb_insert_transfer(xfer);
! 2912: if (err)
! 2913: return (err);
! 2914:
! 2915: /* Pipe isn't running, start first */
! 2916: return (ehci_device_bulk_start(SIMPLEQ_FIRST(&xfer->pipe->queue)));
! 2917: }
! 2918:
! 2919: usbd_status
! 2920: ehci_device_bulk_start(usbd_xfer_handle xfer)
! 2921: {
! 2922: #define exfer EXFER(xfer)
! 2923: struct ehci_pipe *epipe = (struct ehci_pipe *)xfer->pipe;
! 2924: usbd_device_handle dev = epipe->pipe.device;
! 2925: ehci_softc_t *sc = (ehci_softc_t *)dev->bus;
! 2926: ehci_soft_qtd_t *data, *dataend;
! 2927: ehci_soft_qh_t *sqh;
! 2928: usbd_status err;
! 2929: int len, isread, endpt;
! 2930: int s;
! 2931:
! 2932: DPRINTFN(2, ("ehci_device_bulk_start: xfer=%p len=%d flags=%d\n",
! 2933: xfer, xfer->length, xfer->flags));
! 2934:
! 2935: if (sc->sc_dying)
! 2936: return (USBD_IOERROR);
! 2937:
! 2938: #ifdef DIAGNOSTIC
! 2939: if (xfer->rqflags & URQ_REQUEST)
! 2940: panic("ehci_device_bulk_start: a request");
! 2941: #endif
! 2942:
! 2943: len = xfer->length;
! 2944: endpt = epipe->pipe.endpoint->edesc->bEndpointAddress;
! 2945: isread = UE_GET_DIR(endpt) == UE_DIR_IN;
! 2946: sqh = epipe->sqh;
! 2947:
! 2948: epipe->u.bulk.length = len;
! 2949:
! 2950: err = ehci_alloc_sqtd_chain(epipe, sc, len, isread, xfer, &data,
! 2951: &dataend);
! 2952: if (err) {
! 2953: DPRINTFN(-1,("ehci_device_bulk_start: no memory\n"));
! 2954: xfer->status = err;
! 2955: usb_transfer_complete(xfer);
! 2956: return (err);
! 2957: }
! 2958:
! 2959: #ifdef EHCI_DEBUG
! 2960: if (ehcidebug > 5) {
! 2961: DPRINTF(("ehci_device_bulk_start: data(1)\n"));
! 2962: ehci_dump_sqh(sqh);
! 2963: ehci_dump_sqtds(data);
! 2964: }
! 2965: #endif
! 2966:
! 2967: /* Set up interrupt info. */
! 2968: exfer->sqtdstart = data;
! 2969: exfer->sqtdend = dataend;
! 2970: #ifdef DIAGNOSTIC
! 2971: if (!exfer->isdone) {
! 2972: printf("ehci_device_bulk_start: not done, ex=%p\n", exfer);
! 2973: }
! 2974: exfer->isdone = 0;
! 2975: #endif
! 2976:
! 2977: s = splusb();
! 2978: ehci_set_qh_qtd(sqh, data);
! 2979: if (xfer->timeout && !sc->sc_bus.use_polling) {
! 2980: timeout_del(&xfer->timeout_handle);
! 2981: timeout_set(&xfer->timeout_handle, ehci_timeout, xfer);
! 2982: timeout_add(&xfer->timeout_handle, mstohz(xfer->timeout));
! 2983: }
! 2984: ehci_add_intr_list(sc, exfer);
! 2985: xfer->status = USBD_IN_PROGRESS;
! 2986: splx(s);
! 2987:
! 2988: #ifdef EHCI_DEBUG
! 2989: if (ehcidebug > 10) {
! 2990: DPRINTF(("ehci_device_bulk_start: data(2)\n"));
! 2991: delay(10000);
! 2992: DPRINTF(("ehci_device_bulk_start: data(3)\n"));
! 2993: ehci_dump_regs(sc);
! 2994: #if 0
! 2995: printf("async_head:\n");
! 2996: ehci_dump_sqh(sc->sc_async_head);
! 2997: #endif
! 2998: printf("sqh:\n");
! 2999: ehci_dump_sqh(sqh);
! 3000: ehci_dump_sqtds(data);
! 3001: }
! 3002: #endif
! 3003:
! 3004: if (sc->sc_bus.use_polling)
! 3005: ehci_waitintr(sc, xfer);
! 3006:
! 3007: return (USBD_IN_PROGRESS);
! 3008: #undef exfer
! 3009: }
! 3010:
! 3011: void
! 3012: ehci_device_bulk_abort(usbd_xfer_handle xfer)
! 3013: {
! 3014: DPRINTF(("ehci_device_bulk_abort: xfer=%p\n", xfer));
! 3015: ehci_abort_xfer(xfer, USBD_CANCELLED);
! 3016: }
! 3017:
! 3018: /*
! 3019: * Close a device bulk pipe.
! 3020: */
! 3021: void
! 3022: ehci_device_bulk_close(usbd_pipe_handle pipe)
! 3023: {
! 3024: ehci_softc_t *sc = (ehci_softc_t *)pipe->device->bus;
! 3025:
! 3026: DPRINTF(("ehci_device_bulk_close: pipe=%p\n", pipe));
! 3027: ehci_close_pipe(pipe, sc->sc_async_head);
! 3028: }
! 3029:
! 3030: void
! 3031: ehci_device_bulk_done(usbd_xfer_handle xfer)
! 3032: {
! 3033: struct ehci_xfer *ex = EXFER(xfer);
! 3034: ehci_softc_t *sc = (ehci_softc_t *)xfer->pipe->device->bus;
! 3035: /*struct ehci_pipe *epipe = (struct ehci_pipe *)xfer->pipe;*/
! 3036:
! 3037: DPRINTFN(10,("ehci_bulk_done: xfer=%p, actlen=%d\n",
! 3038: xfer, xfer->actlen));
! 3039:
! 3040: if (xfer->status != USBD_NOMEM && ehci_active_intr_list(ex)) {
! 3041: ehci_del_intr_list(ex); /* remove from active list */
! 3042: ehci_free_sqtd_chain(sc, ex->sqtdstart, NULL);
! 3043: }
! 3044:
! 3045: DPRINTFN(5, ("ehci_bulk_done: length=%d\n", xfer->actlen));
! 3046: }
! 3047:
! 3048: /************************/
! 3049:
! 3050: usbd_status
! 3051: ehci_device_setintr(ehci_softc_t *sc, ehci_soft_qh_t *sqh, int ival)
! 3052: {
! 3053: struct ehci_soft_islot *isp;
! 3054: int islot, lev;
! 3055:
! 3056: /* Find a poll rate that is large enough. */
! 3057: for (lev = EHCI_IPOLLRATES - 1; lev > 0; lev--)
! 3058: if (EHCI_ILEV_IVAL(lev) <= ival)
! 3059: break;
! 3060:
! 3061: /* Pick an interrupt slot at the right level. */
! 3062: /* XXX could do better than picking at random */
! 3063: if (cold) {
! 3064: /* XXX prevent panics at boot by not using arc4random */
! 3065: sc->sc_rand = (sc->sc_rand + 192) % sc->sc_flsize;
! 3066: islot = EHCI_IQHIDX(lev, sc->sc_rand);
! 3067: } else
! 3068: islot = EHCI_IQHIDX(lev, arc4random());
! 3069:
! 3070: sqh->islot = islot;
! 3071: isp = &sc->sc_islots[islot];
! 3072: ehci_add_qh(sqh, isp->sqh);
! 3073:
! 3074: return (USBD_NORMAL_COMPLETION);
! 3075: }
! 3076:
! 3077: usbd_status
! 3078: ehci_device_intr_transfer(usbd_xfer_handle xfer)
! 3079: {
! 3080: usbd_status err;
! 3081:
! 3082: /* Insert last in queue. */
! 3083: err = usb_insert_transfer(xfer);
! 3084: if (err)
! 3085: return (err);
! 3086:
! 3087: /*
! 3088: * Pipe isn't running (otherwise err would be USBD_INPROG),
! 3089: * so start it first.
! 3090: */
! 3091: return (ehci_device_intr_start(SIMPLEQ_FIRST(&xfer->pipe->queue)));
! 3092: }
! 3093:
! 3094: usbd_status
! 3095: ehci_device_intr_start(usbd_xfer_handle xfer)
! 3096: {
! 3097: #define exfer EXFER(xfer)
! 3098: struct ehci_pipe *epipe = (struct ehci_pipe *)xfer->pipe;
! 3099: usbd_device_handle dev = xfer->pipe->device;
! 3100: ehci_softc_t *sc = (ehci_softc_t *)dev->bus;
! 3101: ehci_soft_qtd_t *data, *dataend;
! 3102: ehci_soft_qh_t *sqh;
! 3103: usbd_status err;
! 3104: int len, isread, endpt;
! 3105: int s;
! 3106:
! 3107: DPRINTFN(2, ("ehci_device_intr_start: xfer=%p len=%d flags=%d\n",
! 3108: xfer, xfer->length, xfer->flags));
! 3109:
! 3110: if (sc->sc_dying)
! 3111: return (USBD_IOERROR);
! 3112:
! 3113: #ifdef DIAGNOSTIC
! 3114: if (xfer->rqflags & URQ_REQUEST)
! 3115: panic("ehci_device_intr_start: a request");
! 3116: #endif
! 3117:
! 3118: len = xfer->length;
! 3119: endpt = epipe->pipe.endpoint->edesc->bEndpointAddress;
! 3120: isread = UE_GET_DIR(endpt) == UE_DIR_IN;
! 3121: sqh = epipe->sqh;
! 3122:
! 3123: epipe->u.intr.length = len;
! 3124:
! 3125: err = ehci_alloc_sqtd_chain(epipe, sc, len, isread, xfer, &data,
! 3126: &dataend);
! 3127: if (err) {
! 3128: DPRINTFN(-1, ("ehci_device_intr_start: no memory\n"));
! 3129: xfer->status = err;
! 3130: usb_transfer_complete(xfer);
! 3131: return (err);
! 3132: }
! 3133:
! 3134: #ifdef EHCI_DEBUG
! 3135: if (ehcidebug > 5) {
! 3136: DPRINTF(("ehci_device_intr_start: data(1)\n"));
! 3137: ehci_dump_sqh(sqh);
! 3138: ehci_dump_sqtds(data);
! 3139: }
! 3140: #endif
! 3141:
! 3142: /* Set up interrupt info. */
! 3143: exfer->sqtdstart = data;
! 3144: exfer->sqtdend = dataend;
! 3145: #ifdef DIAGNOSTIC
! 3146: if (!exfer->isdone)
! 3147: printf("ehci_device_intr_start: not done, ex=%p\n", exfer);
! 3148: exfer->isdone = 0;
! 3149: #endif
! 3150:
! 3151: s = splusb();
! 3152: ehci_set_qh_qtd(sqh, data);
! 3153: if (xfer->timeout && !sc->sc_bus.use_polling) {
! 3154: timeout_del(&xfer->timeout_handle);
! 3155: timeout_set(&xfer->timeout_handle, ehci_timeout, xfer);
! 3156: timeout_add(&xfer->timeout_handle, mstohz(xfer->timeout));
! 3157: }
! 3158: ehci_add_intr_list(sc, exfer);
! 3159: xfer->status = USBD_IN_PROGRESS;
! 3160: splx(s);
! 3161:
! 3162: #ifdef EHCI_DEBUG
! 3163: if (ehcidebug > 10) {
! 3164: DPRINTF(("ehci_device_intr_start: data(2)\n"));
! 3165: delay(10000);
! 3166: DPRINTF(("ehci_device_intr_start: data(3)\n"));
! 3167: ehci_dump_regs(sc);
! 3168: printf("sqh:\n");
! 3169: ehci_dump_sqh(sqh);
! 3170: ehci_dump_sqtds(data);
! 3171: }
! 3172: #endif
! 3173:
! 3174: if (sc->sc_bus.use_polling)
! 3175: ehci_waitintr(sc, xfer);
! 3176:
! 3177: return (USBD_IN_PROGRESS);
! 3178: #undef exfer
! 3179: }
! 3180:
! 3181: void
! 3182: ehci_device_intr_abort(usbd_xfer_handle xfer)
! 3183: {
! 3184: DPRINTFN(1, ("ehci_device_intr_abort: xfer=%p\n", xfer));
! 3185: if (xfer->pipe->intrxfer == xfer) {
! 3186: DPRINTFN(1, ("ehci_device_intr_abort: remove\n"));
! 3187: xfer->pipe->intrxfer = NULL;
! 3188: }
! 3189: ehci_abort_xfer(xfer, USBD_CANCELLED);
! 3190: }
! 3191:
! 3192: void
! 3193: ehci_device_intr_close(usbd_pipe_handle pipe)
! 3194: {
! 3195: ehci_softc_t *sc = (ehci_softc_t *)pipe->device->bus;
! 3196: struct ehci_pipe *epipe = (struct ehci_pipe *)pipe;
! 3197: struct ehci_soft_islot *isp;
! 3198:
! 3199: isp = &sc->sc_islots[epipe->sqh->islot];
! 3200: ehci_close_pipe(pipe, isp->sqh);
! 3201: }
! 3202:
! 3203: void
! 3204: ehci_device_intr_done(usbd_xfer_handle xfer)
! 3205: {
! 3206: #define exfer EXFER(xfer)
! 3207: struct ehci_xfer *ex = EXFER(xfer);
! 3208: ehci_softc_t *sc = (ehci_softc_t *)xfer->pipe->device->bus;
! 3209: struct ehci_pipe *epipe = (struct ehci_pipe *)xfer->pipe;
! 3210: ehci_soft_qtd_t *data, *dataend;
! 3211: ehci_soft_qh_t *sqh;
! 3212: usbd_status err;
! 3213: int len, isread, endpt, s;
! 3214:
! 3215: DPRINTFN(10, ("ehci_device_intr_done: xfer=%p, actlen=%d\n",
! 3216: xfer, xfer->actlen));
! 3217:
! 3218: if (xfer->pipe->repeat) {
! 3219: ehci_free_sqtd_chain(sc, ex->sqtdstart, NULL);
! 3220:
! 3221: len = epipe->u.intr.length;
! 3222: xfer->length = len;
! 3223: endpt = epipe->pipe.endpoint->edesc->bEndpointAddress;
! 3224: isread = UE_GET_DIR(endpt) == UE_DIR_IN;
! 3225: sqh = epipe->sqh;
! 3226:
! 3227: err = ehci_alloc_sqtd_chain(epipe, sc, len, isread, xfer,
! 3228: &data, &dataend);
! 3229: if (err) {
! 3230: DPRINTFN(-1, ("ehci_device_intr_done: no memory\n"));
! 3231: xfer->status = err;
! 3232: return;
! 3233: }
! 3234:
! 3235: /* Set up interrupt info. */
! 3236: exfer->sqtdstart = data;
! 3237: exfer->sqtdend = dataend;
! 3238: #ifdef DIAGNOSTIC
! 3239: if (!exfer->isdone) {
! 3240: printf("ehci_device_intr_done: not done, ex=%p\n",
! 3241: exfer);
! 3242: }
! 3243: exfer->isdone = 0;
! 3244: #endif
! 3245:
! 3246: s = splusb();
! 3247: ehci_set_qh_qtd(sqh, data);
! 3248: if (xfer->timeout && !sc->sc_bus.use_polling) {
! 3249: timeout_del(&xfer->timeout_handle);
! 3250: timeout_set(&xfer->timeout_handle, ehci_timeout, xfer);
! 3251: timeout_add(&xfer->timeout_handle,
! 3252: mstohz(xfer->timeout));
! 3253: }
! 3254: splx(s);
! 3255:
! 3256: xfer->status = USBD_IN_PROGRESS;
! 3257: } else if (xfer->status != USBD_NOMEM && ehci_active_intr_list(ex)) {
! 3258: ehci_del_intr_list(ex); /* remove from active list */
! 3259: ehci_free_sqtd_chain(sc, ex->sqtdstart, NULL);
! 3260: }
! 3261: #undef exfer
! 3262: }
! 3263:
! 3264: /************************/
! 3265:
! 3266: usbd_status ehci_device_isoc_transfer(usbd_xfer_handle xfer) { return USBD_IOERROR; }
! 3267: usbd_status ehci_device_isoc_start(usbd_xfer_handle xfer) { return USBD_IOERROR; }
! 3268: void ehci_device_isoc_abort(usbd_xfer_handle xfer) { }
! 3269: void ehci_device_isoc_close(usbd_pipe_handle pipe) { }
! 3270: void ehci_device_isoc_done(usbd_xfer_handle xfer) { }
CVSweb