Annotation of sys/dev/usb/ohci.c, Revision 1.1
1.1 ! nbrk 1: /* $OpenBSD: ohci.c,v 1.84 2007/06/15 11:41:48 mbalmer Exp $ */
! 2: /* $NetBSD: ohci.c,v 1.139 2003/02/22 05:24:16 tsutsui Exp $ */
! 3: /* $FreeBSD: src/sys/dev/usb/ohci.c,v 1.22 1999/11/17 22:33:40 n_hibma Exp $ */
! 4:
! 5: /*
! 6: * Copyright (c) 1998 The NetBSD Foundation, Inc.
! 7: * All rights reserved.
! 8: *
! 9: * This code is derived from software contributed to The NetBSD Foundation
! 10: * by Lennart Augustsson (lennart@augustsson.net) at
! 11: * Carlstedt Research & Technology.
! 12: *
! 13: * Redistribution and use in source and binary forms, with or without
! 14: * modification, are permitted provided that the following conditions
! 15: * are met:
! 16: * 1. Redistributions of source code must retain the above copyright
! 17: * notice, this list of conditions and the following disclaimer.
! 18: * 2. Redistributions in binary form must reproduce the above copyright
! 19: * notice, this list of conditions and the following disclaimer in the
! 20: * documentation and/or other materials provided with the distribution.
! 21: * 3. All advertising materials mentioning features or use of this software
! 22: * must display the following acknowledgement:
! 23: * This product includes software developed by the NetBSD
! 24: * Foundation, Inc. and its contributors.
! 25: * 4. Neither the name of The NetBSD Foundation nor the names of its
! 26: * contributors may be used to endorse or promote products derived
! 27: * from this software without specific prior written permission.
! 28: *
! 29: * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
! 30: * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
! 31: * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
! 32: * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
! 33: * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
! 34: * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
! 35: * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
! 36: * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
! 37: * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
! 38: * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
! 39: * POSSIBILITY OF SUCH DAMAGE.
! 40: */
! 41:
! 42: /*
! 43: * USB Open Host Controller driver.
! 44: *
! 45: * OHCI spec: http://www.compaq.com/productinfo/development/openhci.html
! 46: * USB spec: http://www.usb.org/developers/docs/usbspec.zip
! 47: */
! 48:
! 49: #include <sys/param.h>
! 50: #include <sys/systm.h>
! 51: #include <sys/malloc.h>
! 52: #include <sys/kernel.h>
! 53: #include <sys/device.h>
! 54: #include <sys/selinfo.h>
! 55: #include <sys/proc.h>
! 56: #include <sys/queue.h>
! 57:
! 58: #include <machine/bus.h>
! 59: #include <machine/endian.h>
! 60:
! 61: #include <dev/usb/usb.h>
! 62: #include <dev/usb/usbdi.h>
! 63: #include <dev/usb/usbdivar.h>
! 64: #include <dev/usb/usb_mem.h>
! 65: #include <dev/usb/usb_quirks.h>
! 66:
! 67: #include <dev/usb/ohcireg.h>
! 68: #include <dev/usb/ohcivar.h>
! 69:
! 70: struct cfdriver ohci_cd = {
! 71: NULL, "ohci", DV_DULL
! 72: };
! 73:
! 74: #ifdef OHCI_DEBUG
! 75: #define DPRINTF(x) do { if (ohcidebug) printf x; } while (0)
! 76: #define DPRINTFN(n,x) do { if (ohcidebug>(n)) printf x; } while (0)
! 77: int ohcidebug = 0;
! 78: #define bitmask_snprintf(q,f,b,l) snprintf((b), (l), "%b", (q), (f))
! 79: #else
! 80: #define DPRINTF(x)
! 81: #define DPRINTFN(n,x)
! 82: #endif
! 83:
! 84: #define mstohz(ms) ((ms) * hz / 1000)
! 85:
! 86: /*
! 87: * The OHCI controller is little endian, so on big endian machines
! 88: * the data stored in memory needs to be swapped.
! 89: */
! 90:
! 91: struct ohci_pipe;
! 92:
! 93: ohci_soft_ed_t *ohci_alloc_sed(ohci_softc_t *);
! 94: void ohci_free_sed(ohci_softc_t *, ohci_soft_ed_t *);
! 95:
! 96: ohci_soft_td_t *ohci_alloc_std(ohci_softc_t *);
! 97: void ohci_free_std(ohci_softc_t *, ohci_soft_td_t *);
! 98:
! 99: ohci_soft_itd_t *ohci_alloc_sitd(ohci_softc_t *);
! 100: void ohci_free_sitd(ohci_softc_t *,ohci_soft_itd_t *);
! 101:
! 102: #if 0
! 103: void ohci_free_std_chain(ohci_softc_t *, ohci_soft_td_t *,
! 104: ohci_soft_td_t *);
! 105: #endif
! 106: usbd_status ohci_alloc_std_chain(struct ohci_pipe *,
! 107: ohci_softc_t *, int, int, usbd_xfer_handle,
! 108: ohci_soft_td_t *, ohci_soft_td_t **);
! 109:
! 110: void ohci_shutdown(void *v);
! 111: usbd_status ohci_open(usbd_pipe_handle);
! 112: void ohci_poll(struct usbd_bus *);
! 113: void ohci_softintr(void *);
! 114: void ohci_waitintr(ohci_softc_t *, usbd_xfer_handle);
! 115: void ohci_add_done(ohci_softc_t *, ohci_physaddr_t);
! 116: void ohci_rhsc(ohci_softc_t *, usbd_xfer_handle);
! 117:
! 118: usbd_status ohci_device_request(usbd_xfer_handle xfer);
! 119: void ohci_add_ed(ohci_soft_ed_t *, ohci_soft_ed_t *);
! 120: void ohci_rem_ed(ohci_soft_ed_t *, ohci_soft_ed_t *);
! 121: void ohci_hash_add_td(ohci_softc_t *, ohci_soft_td_t *);
! 122: void ohci_hash_rem_td(ohci_softc_t *, ohci_soft_td_t *);
! 123: ohci_soft_td_t *ohci_hash_find_td(ohci_softc_t *, ohci_physaddr_t);
! 124: void ohci_hash_add_itd(ohci_softc_t *, ohci_soft_itd_t *);
! 125: void ohci_hash_rem_itd(ohci_softc_t *, ohci_soft_itd_t *);
! 126: ohci_soft_itd_t *ohci_hash_find_itd(ohci_softc_t *, ohci_physaddr_t);
! 127:
! 128: usbd_status ohci_setup_isoc(usbd_pipe_handle pipe);
! 129: void ohci_device_isoc_enter(usbd_xfer_handle);
! 130:
! 131: usbd_status ohci_allocm(struct usbd_bus *, usb_dma_t *, u_int32_t);
! 132: void ohci_freem(struct usbd_bus *, usb_dma_t *);
! 133:
! 134: usbd_xfer_handle ohci_allocx(struct usbd_bus *);
! 135: void ohci_freex(struct usbd_bus *, usbd_xfer_handle);
! 136:
! 137: usbd_status ohci_root_ctrl_transfer(usbd_xfer_handle);
! 138: usbd_status ohci_root_ctrl_start(usbd_xfer_handle);
! 139: void ohci_root_ctrl_abort(usbd_xfer_handle);
! 140: void ohci_root_ctrl_close(usbd_pipe_handle);
! 141: void ohci_root_ctrl_done(usbd_xfer_handle);
! 142:
! 143: usbd_status ohci_root_intr_transfer(usbd_xfer_handle);
! 144: usbd_status ohci_root_intr_start(usbd_xfer_handle);
! 145: void ohci_root_intr_abort(usbd_xfer_handle);
! 146: void ohci_root_intr_close(usbd_pipe_handle);
! 147: void ohci_root_intr_done(usbd_xfer_handle);
! 148:
! 149: usbd_status ohci_device_ctrl_transfer(usbd_xfer_handle);
! 150: usbd_status ohci_device_ctrl_start(usbd_xfer_handle);
! 151: void ohci_device_ctrl_abort(usbd_xfer_handle);
! 152: void ohci_device_ctrl_close(usbd_pipe_handle);
! 153: void ohci_device_ctrl_done(usbd_xfer_handle);
! 154:
! 155: usbd_status ohci_device_bulk_transfer(usbd_xfer_handle);
! 156: usbd_status ohci_device_bulk_start(usbd_xfer_handle);
! 157: void ohci_device_bulk_abort(usbd_xfer_handle);
! 158: void ohci_device_bulk_close(usbd_pipe_handle);
! 159: void ohci_device_bulk_done(usbd_xfer_handle);
! 160:
! 161: usbd_status ohci_device_intr_transfer(usbd_xfer_handle);
! 162: usbd_status ohci_device_intr_start(usbd_xfer_handle);
! 163: void ohci_device_intr_abort(usbd_xfer_handle);
! 164: void ohci_device_intr_close(usbd_pipe_handle);
! 165: void ohci_device_intr_done(usbd_xfer_handle);
! 166:
! 167: usbd_status ohci_device_isoc_transfer(usbd_xfer_handle);
! 168: usbd_status ohci_device_isoc_start(usbd_xfer_handle);
! 169: void ohci_device_isoc_abort(usbd_xfer_handle);
! 170: void ohci_device_isoc_close(usbd_pipe_handle);
! 171: void ohci_device_isoc_done(usbd_xfer_handle);
! 172:
! 173: usbd_status ohci_device_setintr(ohci_softc_t *sc,
! 174: struct ohci_pipe *pipe, int ival);
! 175:
! 176: int ohci_str(usb_string_descriptor_t *, int, const char *);
! 177:
! 178: void ohci_timeout(void *);
! 179: void ohci_timeout_task(void *);
! 180: void ohci_rhsc_able(ohci_softc_t *, int);
! 181: void ohci_rhsc_enable(void *);
! 182:
! 183: void ohci_close_pipe(usbd_pipe_handle, ohci_soft_ed_t *);
! 184: void ohci_abort_xfer(usbd_xfer_handle, usbd_status);
! 185:
! 186: void ohci_device_clear_toggle(usbd_pipe_handle pipe);
! 187: void ohci_noop(usbd_pipe_handle pipe);
! 188:
! 189: #ifdef OHCI_DEBUG
! 190: void ohci_dumpregs(ohci_softc_t *);
! 191: void ohci_dump_tds(ohci_soft_td_t *);
! 192: void ohci_dump_td(ohci_soft_td_t *);
! 193: void ohci_dump_ed(ohci_soft_ed_t *);
! 194: void ohci_dump_itd(ohci_soft_itd_t *);
! 195: void ohci_dump_itds(ohci_soft_itd_t *);
! 196: #endif
! 197:
! 198: #define OBARR(sc) bus_space_barrier((sc)->iot, (sc)->ioh, 0, (sc)->sc_size, \
! 199: BUS_SPACE_BARRIER_READ|BUS_SPACE_BARRIER_WRITE)
! 200: #define OWRITE1(sc, r, x) \
! 201: do { OBARR(sc); bus_space_write_1((sc)->iot, (sc)->ioh, (r), (x)); } while (0)
! 202: #define OWRITE2(sc, r, x) \
! 203: do { OBARR(sc); bus_space_write_2((sc)->iot, (sc)->ioh, (r), (x)); } while (0)
! 204: #define OWRITE4(sc, r, x) \
! 205: do { OBARR(sc); bus_space_write_4((sc)->iot, (sc)->ioh, (r), (x)); } while (0)
! 206: #define OREAD1(sc, r) (OBARR(sc), bus_space_read_1((sc)->iot, (sc)->ioh, (r)))
! 207: #define OREAD2(sc, r) (OBARR(sc), bus_space_read_2((sc)->iot, (sc)->ioh, (r)))
! 208: #define OREAD4(sc, r) (OBARR(sc), bus_space_read_4((sc)->iot, (sc)->ioh, (r)))
! 209:
! 210: /* Reverse the bits in a value 0 .. 31 */
! 211: u_int8_t revbits[OHCI_NO_INTRS] =
! 212: { 0x00, 0x10, 0x08, 0x18, 0x04, 0x14, 0x0c, 0x1c,
! 213: 0x02, 0x12, 0x0a, 0x1a, 0x06, 0x16, 0x0e, 0x1e,
! 214: 0x01, 0x11, 0x09, 0x19, 0x05, 0x15, 0x0d, 0x1d,
! 215: 0x03, 0x13, 0x0b, 0x1b, 0x07, 0x17, 0x0f, 0x1f };
! 216:
! 217: struct ohci_pipe {
! 218: struct usbd_pipe pipe;
! 219: ohci_soft_ed_t *sed;
! 220: union {
! 221: ohci_soft_td_t *td;
! 222: ohci_soft_itd_t *itd;
! 223: } tail;
! 224: /* Info needed for different pipe kinds. */
! 225: union {
! 226: /* Control pipe */
! 227: struct {
! 228: usb_dma_t reqdma;
! 229: u_int length;
! 230: ohci_soft_td_t *setup, *data, *stat;
! 231: } ctl;
! 232: /* Interrupt pipe */
! 233: struct {
! 234: int nslots;
! 235: int pos;
! 236: } intr;
! 237: /* Bulk pipe */
! 238: struct {
! 239: u_int length;
! 240: int isread;
! 241: } bulk;
! 242: /* Iso pipe */
! 243: struct iso {
! 244: int next, inuse;
! 245: } iso;
! 246: } u;
! 247: };
! 248:
! 249: #define OHCI_INTR_ENDPT 1
! 250:
! 251: struct usbd_bus_methods ohci_bus_methods = {
! 252: ohci_open,
! 253: ohci_softintr,
! 254: ohci_poll,
! 255: ohci_allocm,
! 256: ohci_freem,
! 257: ohci_allocx,
! 258: ohci_freex,
! 259: };
! 260:
! 261: struct usbd_pipe_methods ohci_root_ctrl_methods = {
! 262: ohci_root_ctrl_transfer,
! 263: ohci_root_ctrl_start,
! 264: ohci_root_ctrl_abort,
! 265: ohci_root_ctrl_close,
! 266: ohci_noop,
! 267: ohci_root_ctrl_done,
! 268: };
! 269:
! 270: struct usbd_pipe_methods ohci_root_intr_methods = {
! 271: ohci_root_intr_transfer,
! 272: ohci_root_intr_start,
! 273: ohci_root_intr_abort,
! 274: ohci_root_intr_close,
! 275: ohci_noop,
! 276: ohci_root_intr_done,
! 277: };
! 278:
! 279: struct usbd_pipe_methods ohci_device_ctrl_methods = {
! 280: ohci_device_ctrl_transfer,
! 281: ohci_device_ctrl_start,
! 282: ohci_device_ctrl_abort,
! 283: ohci_device_ctrl_close,
! 284: ohci_noop,
! 285: ohci_device_ctrl_done,
! 286: };
! 287:
! 288: struct usbd_pipe_methods ohci_device_intr_methods = {
! 289: ohci_device_intr_transfer,
! 290: ohci_device_intr_start,
! 291: ohci_device_intr_abort,
! 292: ohci_device_intr_close,
! 293: ohci_device_clear_toggle,
! 294: ohci_device_intr_done,
! 295: };
! 296:
! 297: struct usbd_pipe_methods ohci_device_bulk_methods = {
! 298: ohci_device_bulk_transfer,
! 299: ohci_device_bulk_start,
! 300: ohci_device_bulk_abort,
! 301: ohci_device_bulk_close,
! 302: ohci_device_clear_toggle,
! 303: ohci_device_bulk_done,
! 304: };
! 305:
! 306: struct usbd_pipe_methods ohci_device_isoc_methods = {
! 307: ohci_device_isoc_transfer,
! 308: ohci_device_isoc_start,
! 309: ohci_device_isoc_abort,
! 310: ohci_device_isoc_close,
! 311: ohci_noop,
! 312: ohci_device_isoc_done,
! 313: };
! 314:
! 315: int
! 316: ohci_activate(struct device *self, enum devact act)
! 317: {
! 318: struct ohci_softc *sc = (struct ohci_softc *)self;
! 319: int rv = 0;
! 320:
! 321: switch (act) {
! 322: case DVACT_ACTIVATE:
! 323: break;
! 324:
! 325: case DVACT_DEACTIVATE:
! 326: if (sc->sc_child != NULL)
! 327: rv = config_deactivate(sc->sc_child);
! 328: sc->sc_dying = 1;
! 329: break;
! 330: }
! 331: return (rv);
! 332: }
! 333:
! 334: int
! 335: ohci_detach(struct ohci_softc *sc, int flags)
! 336: {
! 337: int rv = 0;
! 338:
! 339: if (sc->sc_child != NULL)
! 340: rv = config_detach(sc->sc_child, flags);
! 341:
! 342: if (rv != 0)
! 343: return (rv);
! 344:
! 345: timeout_del(&sc->sc_tmo_rhsc);
! 346:
! 347: if (sc->sc_shutdownhook != NULL)
! 348: shutdownhook_disestablish(sc->sc_shutdownhook);
! 349:
! 350: usb_delay_ms(&sc->sc_bus, 300); /* XXX let stray task complete */
! 351:
! 352: /* free data structures XXX */
! 353:
! 354: return (rv);
! 355: }
! 356:
! 357: ohci_soft_ed_t *
! 358: ohci_alloc_sed(ohci_softc_t *sc)
! 359: {
! 360: ohci_soft_ed_t *sed;
! 361: usbd_status err;
! 362: int i, offs;
! 363: usb_dma_t dma;
! 364:
! 365: if (sc->sc_freeeds == NULL) {
! 366: DPRINTFN(2, ("ohci_alloc_sed: allocating chunk\n"));
! 367: err = usb_allocmem(&sc->sc_bus, OHCI_SED_SIZE * OHCI_SED_CHUNK,
! 368: OHCI_ED_ALIGN, &dma);
! 369: if (err)
! 370: return (0);
! 371: for(i = 0; i < OHCI_SED_CHUNK; i++) {
! 372: offs = i * OHCI_SED_SIZE;
! 373: sed = KERNADDR(&dma, offs);
! 374: sed->physaddr = DMAADDR(&dma, offs);
! 375: sed->next = sc->sc_freeeds;
! 376: sc->sc_freeeds = sed;
! 377: }
! 378: }
! 379: sed = sc->sc_freeeds;
! 380: sc->sc_freeeds = sed->next;
! 381: memset(&sed->ed, 0, sizeof(ohci_ed_t));
! 382: sed->next = 0;
! 383: return (sed);
! 384: }
! 385:
! 386: void
! 387: ohci_free_sed(ohci_softc_t *sc, ohci_soft_ed_t *sed)
! 388: {
! 389: sed->next = sc->sc_freeeds;
! 390: sc->sc_freeeds = sed;
! 391: }
! 392:
! 393: ohci_soft_td_t *
! 394: ohci_alloc_std(ohci_softc_t *sc)
! 395: {
! 396: ohci_soft_td_t *std;
! 397: usbd_status err;
! 398: int i, offs;
! 399: usb_dma_t dma;
! 400: int s;
! 401:
! 402: if (sc->sc_freetds == NULL) {
! 403: DPRINTFN(2, ("ohci_alloc_std: allocating chunk\n"));
! 404: err = usb_allocmem(&sc->sc_bus, OHCI_STD_SIZE * OHCI_STD_CHUNK,
! 405: OHCI_TD_ALIGN, &dma);
! 406: if (err)
! 407: return (NULL);
! 408: s = splusb();
! 409: for(i = 0; i < OHCI_STD_CHUNK; i++) {
! 410: offs = i * OHCI_STD_SIZE;
! 411: std = KERNADDR(&dma, offs);
! 412: std->physaddr = DMAADDR(&dma, offs);
! 413: std->nexttd = sc->sc_freetds;
! 414: sc->sc_freetds = std;
! 415: }
! 416: splx(s);
! 417: }
! 418:
! 419: s = splusb();
! 420: std = sc->sc_freetds;
! 421: sc->sc_freetds = std->nexttd;
! 422: memset(&std->td, 0, sizeof(ohci_td_t));
! 423: std->nexttd = NULL;
! 424: std->xfer = NULL;
! 425: ohci_hash_add_td(sc, std);
! 426: splx(s);
! 427:
! 428: return (std);
! 429: }
! 430:
! 431: void
! 432: ohci_free_std(ohci_softc_t *sc, ohci_soft_td_t *std)
! 433: {
! 434: int s;
! 435:
! 436: s = splusb();
! 437: ohci_hash_rem_td(sc, std);
! 438: std->nexttd = sc->sc_freetds;
! 439: sc->sc_freetds = std;
! 440: splx(s);
! 441: }
! 442:
! 443: usbd_status
! 444: ohci_alloc_std_chain(struct ohci_pipe *opipe, ohci_softc_t *sc,
! 445: int alen, int rd, usbd_xfer_handle xfer,
! 446: ohci_soft_td_t *sp, ohci_soft_td_t **ep)
! 447: {
! 448: ohci_soft_td_t *next, *cur;
! 449: ohci_physaddr_t dataphys, dataphysend;
! 450: u_int32_t tdflags;
! 451: int len, curlen;
! 452: usb_dma_t *dma = &xfer->dmabuf;
! 453: u_int16_t flags = xfer->flags;
! 454:
! 455: DPRINTFN(alen < 4096,("ohci_alloc_std_chain: start len=%d\n", alen));
! 456:
! 457: len = alen;
! 458: cur = sp;
! 459: dataphys = DMAADDR(dma, 0);
! 460: dataphysend = OHCI_PAGE(dataphys + len - 1);
! 461: tdflags = htole32(
! 462: (rd ? OHCI_TD_IN : OHCI_TD_OUT) |
! 463: (flags & USBD_SHORT_XFER_OK ? OHCI_TD_R : 0) |
! 464: OHCI_TD_NOCC | OHCI_TD_TOGGLE_CARRY | OHCI_TD_NOINTR);
! 465:
! 466: for (;;) {
! 467: next = ohci_alloc_std(sc);
! 468: if (next == NULL)
! 469: goto nomem;
! 470:
! 471: /* The OHCI hardware can handle at most one page crossing. */
! 472: if (OHCI_PAGE(dataphys) == dataphysend ||
! 473: OHCI_PAGE(dataphys) + OHCI_PAGE_SIZE == dataphysend) {
! 474: /* we can handle it in this TD */
! 475: curlen = len;
! 476: } else {
! 477: /* must use multiple TDs, fill as much as possible. */
! 478: curlen = 2 * OHCI_PAGE_SIZE -
! 479: (dataphys & (OHCI_PAGE_SIZE-1));
! 480: /* the length must be a multiple of the max size */
! 481: curlen -= curlen % UGETW(opipe->pipe.endpoint->edesc->wMaxPacketSize);
! 482: #ifdef DIAGNOSTIC
! 483: if (curlen == 0)
! 484: panic("ohci_alloc_std: curlen == 0");
! 485: #endif
! 486: }
! 487: DPRINTFN(4,("ohci_alloc_std_chain: dataphys=0x%08x "
! 488: "dataphysend=0x%08x len=%d curlen=%d\n",
! 489: dataphys, dataphysend,
! 490: len, curlen));
! 491: len -= curlen;
! 492:
! 493: cur->td.td_flags = tdflags;
! 494: cur->td.td_cbp = htole32(dataphys);
! 495: cur->nexttd = next;
! 496: cur->td.td_nexttd = htole32(next->physaddr);
! 497: cur->td.td_be = htole32(dataphys + curlen - 1);
! 498: cur->len = curlen;
! 499: cur->flags = OHCI_ADD_LEN;
! 500: cur->xfer = xfer;
! 501: DPRINTFN(10,("ohci_alloc_std_chain: cbp=0x%08x be=0x%08x\n",
! 502: dataphys, dataphys + curlen - 1));
! 503: if (len == 0)
! 504: break;
! 505: DPRINTFN(10,("ohci_alloc_std_chain: extend chain\n"));
! 506: dataphys += curlen;
! 507: cur = next;
! 508: }
! 509: if (!rd && (flags & USBD_FORCE_SHORT_XFER) &&
! 510: alen % UGETW(opipe->pipe.endpoint->edesc->wMaxPacketSize) == 0) {
! 511: /* Force a 0 length transfer at the end. */
! 512:
! 513: cur = next;
! 514: next = ohci_alloc_std(sc);
! 515: if (next == NULL)
! 516: goto nomem;
! 517:
! 518: cur->td.td_flags = tdflags;
! 519: cur->td.td_cbp = 0; /* indicate 0 length packet */
! 520: cur->nexttd = next;
! 521: cur->td.td_nexttd = htole32(next->physaddr);
! 522: cur->td.td_be = ~0;
! 523: cur->len = 0;
! 524: cur->flags = 0;
! 525: cur->xfer = xfer;
! 526: DPRINTFN(2,("ohci_alloc_std_chain: add 0 xfer\n"));
! 527: }
! 528: *ep = cur;
! 529:
! 530: return (USBD_NORMAL_COMPLETION);
! 531:
! 532: nomem:
! 533: /* XXX free chain */
! 534: return (USBD_NOMEM);
! 535: }
! 536:
! 537: #if 0
! 538: void
! 539: ohci_free_std_chain(ohci_softc_t *sc, ohci_soft_td_t *std,
! 540: ohci_soft_td_t *stdend)
! 541: {
! 542: ohci_soft_td_t *p;
! 543:
! 544: for (; std != stdend; std = p) {
! 545: p = std->nexttd;
! 546: ohci_free_std(sc, std);
! 547: }
! 548: }
! 549: #endif
! 550:
! 551: ohci_soft_itd_t *
! 552: ohci_alloc_sitd(ohci_softc_t *sc)
! 553: {
! 554: ohci_soft_itd_t *sitd;
! 555: usbd_status err;
! 556: int i, s, offs;
! 557: usb_dma_t dma;
! 558:
! 559: if (sc->sc_freeitds == NULL) {
! 560: DPRINTFN(2, ("ohci_alloc_sitd: allocating chunk\n"));
! 561: err = usb_allocmem(&sc->sc_bus, OHCI_SITD_SIZE * OHCI_SITD_CHUNK,
! 562: OHCI_ITD_ALIGN, &dma);
! 563: if (err)
! 564: return (NULL);
! 565: s = splusb();
! 566: for(i = 0; i < OHCI_SITD_CHUNK; i++) {
! 567: offs = i * OHCI_SITD_SIZE;
! 568: sitd = KERNADDR(&dma, offs);
! 569: sitd->physaddr = DMAADDR(&dma, offs);
! 570: sitd->nextitd = sc->sc_freeitds;
! 571: sc->sc_freeitds = sitd;
! 572: }
! 573: splx(s);
! 574: }
! 575:
! 576: s = splusb();
! 577: sitd = sc->sc_freeitds;
! 578: sc->sc_freeitds = sitd->nextitd;
! 579: memset(&sitd->itd, 0, sizeof(ohci_itd_t));
! 580: sitd->nextitd = NULL;
! 581: sitd->xfer = NULL;
! 582: ohci_hash_add_itd(sc, sitd);
! 583: splx(s);
! 584:
! 585: #ifdef DIAGNOSTIC
! 586: sitd->isdone = 0;
! 587: #endif
! 588:
! 589: return (sitd);
! 590: }
! 591:
! 592: void
! 593: ohci_free_sitd(ohci_softc_t *sc, ohci_soft_itd_t *sitd)
! 594: {
! 595: int s;
! 596:
! 597: DPRINTFN(10,("ohci_free_sitd: sitd=%p\n", sitd));
! 598:
! 599: #ifdef DIAGNOSTIC
! 600: if (!sitd->isdone) {
! 601: panic("ohci_free_sitd: sitd=%p not done", sitd);
! 602: return;
! 603: }
! 604: /* Warn double free */
! 605: sitd->isdone = 0;
! 606: #endif
! 607:
! 608: s = splusb();
! 609: ohci_hash_rem_itd(sc, sitd);
! 610: sitd->nextitd = sc->sc_freeitds;
! 611: sc->sc_freeitds = sitd;
! 612: splx(s);
! 613: }
! 614:
! 615: usbd_status
! 616: ohci_checkrev(ohci_softc_t *sc)
! 617: {
! 618: u_int32_t rev;
! 619:
! 620: printf(",");
! 621: rev = OREAD4(sc, OHCI_REVISION);
! 622: printf(" version %d.%d%s\n", OHCI_REV_HI(rev), OHCI_REV_LO(rev),
! 623: OHCI_REV_LEGACY(rev) ? ", legacy support" : "");
! 624:
! 625: if (OHCI_REV_HI(rev) != 1 || OHCI_REV_LO(rev) != 0) {
! 626: printf("%s: unsupported OHCI revision\n",
! 627: sc->sc_bus.bdev.dv_xname);
! 628: sc->sc_bus.usbrev = USBREV_UNKNOWN;
! 629: return (USBD_INVAL);
! 630: }
! 631: sc->sc_bus.usbrev = USBREV_1_0;
! 632:
! 633: return (USBD_NORMAL_COMPLETION);
! 634: }
! 635:
! 636: usbd_status
! 637: ohci_handover(ohci_softc_t *sc)
! 638: {
! 639: u_int32_t s, ctl;
! 640: int i;
! 641:
! 642: ctl = OREAD4(sc, OHCI_CONTROL);
! 643: if (ctl & OHCI_IR) {
! 644: /* SMM active, request change */
! 645: DPRINTF(("ohci_handover: SMM active, request owner change\n"));
! 646: if ((sc->sc_intre & (OHCI_OC | OHCI_MIE)) ==
! 647: (OHCI_OC | OHCI_MIE))
! 648: OWRITE4(sc, OHCI_INTERRUPT_ENABLE, OHCI_MIE);
! 649: s = OREAD4(sc, OHCI_COMMAND_STATUS);
! 650: OWRITE4(sc, OHCI_COMMAND_STATUS, s | OHCI_OCR);
! 651: for (i = 0; i < 100 && (ctl & OHCI_IR); i++) {
! 652: usb_delay_ms(&sc->sc_bus, 1);
! 653: ctl = OREAD4(sc, OHCI_CONTROL);
! 654: }
! 655: OWRITE4(sc, OHCI_INTERRUPT_DISABLE, OHCI_MIE);
! 656: if (ctl & OHCI_IR) {
! 657: printf("%s: SMM does not respond, will reset\n",
! 658: sc->sc_bus.bdev.dv_xname);
! 659: }
! 660: }
! 661:
! 662: return (USBD_NORMAL_COMPLETION);
! 663: }
! 664:
! 665: usbd_status
! 666: ohci_init(ohci_softc_t *sc)
! 667: {
! 668: ohci_soft_ed_t *sed, *psed;
! 669: usbd_status err;
! 670: int i;
! 671: u_int32_t ctl, rwc, ival, hcr, fm, per, desca, descb;
! 672:
! 673: DPRINTF(("ohci_init: start\n"));
! 674:
! 675: for (i = 0; i < OHCI_HASH_SIZE; i++)
! 676: LIST_INIT(&sc->sc_hash_tds[i]);
! 677: for (i = 0; i < OHCI_HASH_SIZE; i++)
! 678: LIST_INIT(&sc->sc_hash_itds[i]);
! 679:
! 680: SIMPLEQ_INIT(&sc->sc_free_xfers);
! 681:
! 682: /* XXX determine alignment by R/W */
! 683: /* Allocate the HCCA area. */
! 684: err = usb_allocmem(&sc->sc_bus, OHCI_HCCA_SIZE,
! 685: OHCI_HCCA_ALIGN, &sc->sc_hccadma);
! 686: if (err)
! 687: return (err);
! 688: sc->sc_hcca = KERNADDR(&sc->sc_hccadma, 0);
! 689: memset(sc->sc_hcca, 0, OHCI_HCCA_SIZE);
! 690:
! 691: sc->sc_eintrs = OHCI_NORMAL_INTRS;
! 692:
! 693: /* Allocate dummy ED that starts the control list. */
! 694: sc->sc_ctrl_head = ohci_alloc_sed(sc);
! 695: if (sc->sc_ctrl_head == NULL) {
! 696: err = USBD_NOMEM;
! 697: goto bad1;
! 698: }
! 699: sc->sc_ctrl_head->ed.ed_flags |= htole32(OHCI_ED_SKIP);
! 700:
! 701: /* Allocate dummy ED that starts the bulk list. */
! 702: sc->sc_bulk_head = ohci_alloc_sed(sc);
! 703: if (sc->sc_bulk_head == NULL) {
! 704: err = USBD_NOMEM;
! 705: goto bad2;
! 706: }
! 707: sc->sc_bulk_head->ed.ed_flags |= htole32(OHCI_ED_SKIP);
! 708:
! 709: /* Allocate dummy ED that starts the isochronous list. */
! 710: sc->sc_isoc_head = ohci_alloc_sed(sc);
! 711: if (sc->sc_isoc_head == NULL) {
! 712: err = USBD_NOMEM;
! 713: goto bad3;
! 714: }
! 715: sc->sc_isoc_head->ed.ed_flags |= htole32(OHCI_ED_SKIP);
! 716:
! 717: /* Allocate all the dummy EDs that make up the interrupt tree. */
! 718: for (i = 0; i < OHCI_NO_EDS; i++) {
! 719: sed = ohci_alloc_sed(sc);
! 720: if (sed == NULL) {
! 721: while (--i >= 0)
! 722: ohci_free_sed(sc, sc->sc_eds[i]);
! 723: err = USBD_NOMEM;
! 724: goto bad4;
! 725: }
! 726: /* All ED fields are set to 0. */
! 727: sc->sc_eds[i] = sed;
! 728: sed->ed.ed_flags |= htole32(OHCI_ED_SKIP);
! 729: if (i != 0)
! 730: psed = sc->sc_eds[(i-1) / 2];
! 731: else
! 732: psed= sc->sc_isoc_head;
! 733: sed->next = psed;
! 734: sed->ed.ed_nexted = htole32(psed->physaddr);
! 735: }
! 736: /*
! 737: * Fill HCCA interrupt table. The bit reversal is to get
! 738: * the tree set up properly to spread the interrupts.
! 739: */
! 740: for (i = 0; i < OHCI_NO_INTRS; i++)
! 741: sc->sc_hcca->hcca_interrupt_table[revbits[i]] =
! 742: htole32(sc->sc_eds[OHCI_NO_EDS-OHCI_NO_INTRS+i]->physaddr);
! 743:
! 744: #ifdef OHCI_DEBUG
! 745: if (ohcidebug > 15) {
! 746: for (i = 0; i < OHCI_NO_EDS; i++) {
! 747: printf("ed#%d ", i);
! 748: ohci_dump_ed(sc->sc_eds[i]);
! 749: }
! 750: printf("iso ");
! 751: ohci_dump_ed(sc->sc_isoc_head);
! 752: }
! 753: #endif
! 754: /* Preserve values programmed by SMM/BIOS but lost over reset. */
! 755: ctl = OREAD4(sc, OHCI_CONTROL);
! 756: rwc = ctl & OHCI_RWC;
! 757: fm = OREAD4(sc, OHCI_FM_INTERVAL);
! 758: desca = OREAD4(sc, OHCI_RH_DESCRIPTOR_A);
! 759: descb = OREAD4(sc, OHCI_RH_DESCRIPTOR_B);
! 760:
! 761: /* Determine in what context we are running. */
! 762: if (ctl & OHCI_IR) {
! 763: OWRITE4(sc, OHCI_CONTROL, OHCI_HCFS_RESET | rwc);
! 764: goto reset;
! 765: #if 0
! 766: /* Don't bother trying to reuse the BIOS init, we'll reset it anyway. */
! 767: } else if ((ctl & OHCI_HCFS_MASK) != OHCI_HCFS_RESET) {
! 768: /* BIOS started controller. */
! 769: DPRINTF(("ohci_init: BIOS active\n"));
! 770: if ((ctl & OHCI_HCFS_MASK) != OHCI_HCFS_OPERATIONAL) {
! 771: OWRITE4(sc, OHCI_CONTROL, OHCI_HCFS_OPERATIONAL | rwc);
! 772: usb_delay_ms(&sc->sc_bus, USB_RESUME_DELAY);
! 773: }
! 774: #endif
! 775: } else {
! 776: DPRINTF(("ohci_init: cold started\n"));
! 777: reset:
! 778: /* Controller was cold started. */
! 779: usb_delay_ms(&sc->sc_bus, USB_BUS_RESET_DELAY);
! 780: }
! 781:
! 782: /*
! 783: * This reset should not be necessary according to the OHCI spec, but
! 784: * without it some controllers do not start.
! 785: */
! 786: DPRINTF(("%s: resetting\n", sc->sc_bus.bdev.dv_xname));
! 787: OWRITE4(sc, OHCI_CONTROL, OHCI_HCFS_RESET | rwc);
! 788: usb_delay_ms(&sc->sc_bus, USB_BUS_RESET_DELAY);
! 789:
! 790: /* We now own the host controller and the bus has been reset. */
! 791:
! 792: OWRITE4(sc, OHCI_COMMAND_STATUS, OHCI_HCR); /* Reset HC */
! 793: /* Nominal time for a reset is 10 us. */
! 794: for (i = 0; i < 10; i++) {
! 795: delay(10);
! 796: hcr = OREAD4(sc, OHCI_COMMAND_STATUS) & OHCI_HCR;
! 797: if (!hcr)
! 798: break;
! 799: }
! 800: if (hcr) {
! 801: printf("%s: reset timeout\n", sc->sc_bus.bdev.dv_xname);
! 802: err = USBD_IOERROR;
! 803: goto bad5;
! 804: }
! 805: #ifdef OHCI_DEBUG
! 806: if (ohcidebug > 15)
! 807: ohci_dumpregs(sc);
! 808: #endif
! 809:
! 810: /* The controller is now in SUSPEND state, we have 2ms to finish. */
! 811:
! 812: /* Set up HC registers. */
! 813: OWRITE4(sc, OHCI_HCCA, DMAADDR(&sc->sc_hccadma, 0));
! 814: OWRITE4(sc, OHCI_CONTROL_HEAD_ED, sc->sc_ctrl_head->physaddr);
! 815: OWRITE4(sc, OHCI_BULK_HEAD_ED, sc->sc_bulk_head->physaddr);
! 816: /* disable all interrupts and then switch on all desired interrupts */
! 817: OWRITE4(sc, OHCI_INTERRUPT_DISABLE, OHCI_ALL_INTRS);
! 818: /* switch on desired functional features */
! 819: ctl = OREAD4(sc, OHCI_CONTROL);
! 820: ctl &= ~(OHCI_CBSR_MASK | OHCI_LES | OHCI_HCFS_MASK | OHCI_IR);
! 821: ctl |= OHCI_PLE | OHCI_IE | OHCI_CLE | OHCI_BLE |
! 822: OHCI_RATIO_1_4 | OHCI_HCFS_OPERATIONAL | rwc;
! 823: /* And finally start it! */
! 824: OWRITE4(sc, OHCI_CONTROL, ctl);
! 825:
! 826: /*
! 827: * The controller is now OPERATIONAL. Set a some final
! 828: * registers that should be set earlier, but that the
! 829: * controller ignores when in the SUSPEND state.
! 830: */
! 831: ival = OHCI_GET_IVAL(fm);
! 832: fm = (OREAD4(sc, OHCI_FM_REMAINING) & OHCI_FIT) ^ OHCI_FIT;
! 833: fm |= OHCI_FSMPS(ival) | ival;
! 834: OWRITE4(sc, OHCI_FM_INTERVAL, fm);
! 835: per = OHCI_PERIODIC(ival); /* 90% periodic */
! 836: OWRITE4(sc, OHCI_PERIODIC_START, per);
! 837:
! 838: /* Fiddle the No OverCurrent Protection bit to avoid chip bug. */
! 839: OWRITE4(sc, OHCI_RH_DESCRIPTOR_A, desca | OHCI_NOCP);
! 840: OWRITE4(sc, OHCI_RH_STATUS, OHCI_LPSC); /* Enable port power */
! 841: usb_delay_ms(&sc->sc_bus, OHCI_ENABLE_POWER_DELAY);
! 842: OWRITE4(sc, OHCI_RH_DESCRIPTOR_A, desca);
! 843: OWRITE4(sc, OHCI_RH_DESCRIPTOR_B, descb);
! 844: usb_delay_ms(&sc->sc_bus, OHCI_GET_POTPGT(desca) * UHD_PWRON_FACTOR);
! 845:
! 846: /*
! 847: * The AMD756 requires a delay before re-reading the register,
! 848: * otherwise it will occasionally report 0 ports.
! 849: */
! 850: sc->sc_noport = 0;
! 851: for (i = 0; i < 10 && sc->sc_noport == 0; i++) {
! 852: usb_delay_ms(&sc->sc_bus, OHCI_READ_DESC_DELAY);
! 853: sc->sc_noport = OHCI_GET_NDP(OREAD4(sc, OHCI_RH_DESCRIPTOR_A));
! 854: }
! 855:
! 856: #ifdef OHCI_DEBUG
! 857: if (ohcidebug > 5)
! 858: ohci_dumpregs(sc);
! 859: #endif
! 860:
! 861: /* Set up the bus struct. */
! 862: sc->sc_bus.methods = &ohci_bus_methods;
! 863: sc->sc_bus.pipe_size = sizeof(struct ohci_pipe);
! 864:
! 865: sc->sc_control = sc->sc_intre = 0;
! 866: sc->sc_shutdownhook = shutdownhook_establish(ohci_shutdown, sc);
! 867:
! 868: timeout_set(&sc->sc_tmo_rhsc, NULL, NULL);
! 869:
! 870: /* Finally, turn on interrupts. */
! 871: DPRINTFN(1,("ohci_init: enabling\n"));
! 872: OWRITE4(sc, OHCI_INTERRUPT_ENABLE, sc->sc_eintrs | OHCI_MIE);
! 873:
! 874: return (USBD_NORMAL_COMPLETION);
! 875:
! 876: bad5:
! 877: for (i = 0; i < OHCI_NO_EDS; i++)
! 878: ohci_free_sed(sc, sc->sc_eds[i]);
! 879: bad4:
! 880: ohci_free_sed(sc, sc->sc_isoc_head);
! 881: bad3:
! 882: ohci_free_sed(sc, sc->sc_bulk_head);
! 883: bad2:
! 884: ohci_free_sed(sc, sc->sc_ctrl_head);
! 885: bad1:
! 886: usb_freemem(&sc->sc_bus, &sc->sc_hccadma);
! 887: return (err);
! 888: }
! 889:
! 890: usbd_status
! 891: ohci_allocm(struct usbd_bus *bus, usb_dma_t *dma, u_int32_t size)
! 892: {
! 893: struct ohci_softc *sc = (struct ohci_softc *)bus;
! 894:
! 895: return (usb_allocmem(&sc->sc_bus, size, 0, dma));
! 896: }
! 897:
! 898: void
! 899: ohci_freem(struct usbd_bus *bus, usb_dma_t *dma)
! 900: {
! 901: struct ohci_softc *sc = (struct ohci_softc *)bus;
! 902:
! 903: usb_freemem(&sc->sc_bus, dma);
! 904: }
! 905:
! 906: usbd_xfer_handle
! 907: ohci_allocx(struct usbd_bus *bus)
! 908: {
! 909: struct ohci_softc *sc = (struct ohci_softc *)bus;
! 910: usbd_xfer_handle xfer;
! 911:
! 912: xfer = SIMPLEQ_FIRST(&sc->sc_free_xfers);
! 913: if (xfer != NULL) {
! 914: SIMPLEQ_REMOVE_HEAD(&sc->sc_free_xfers, next);
! 915: #ifdef DIAGNOSTIC
! 916: if (xfer->busy_free != XFER_FREE) {
! 917: printf("ohci_allocx: xfer=%p not free, 0x%08x\n", xfer,
! 918: xfer->busy_free);
! 919: }
! 920: #endif
! 921: } else {
! 922: xfer = malloc(sizeof(struct ohci_xfer), M_USB, M_NOWAIT);
! 923: }
! 924: if (xfer != NULL) {
! 925: memset(xfer, 0, sizeof (struct ohci_xfer));
! 926: #ifdef DIAGNOSTIC
! 927: xfer->busy_free = XFER_BUSY;
! 928: #endif
! 929: }
! 930: return (xfer);
! 931: }
! 932:
! 933: void
! 934: ohci_freex(struct usbd_bus *bus, usbd_xfer_handle xfer)
! 935: {
! 936: struct ohci_softc *sc = (struct ohci_softc *)bus;
! 937:
! 938: #ifdef DIAGNOSTIC
! 939: if (xfer->busy_free != XFER_BUSY) {
! 940: printf("ohci_freex: xfer=%p not busy, 0x%08x\n", xfer,
! 941: xfer->busy_free);
! 942: return;
! 943: }
! 944: xfer->busy_free = XFER_FREE;
! 945: #endif
! 946: SIMPLEQ_INSERT_HEAD(&sc->sc_free_xfers, xfer, next);
! 947: }
! 948:
! 949: /*
! 950: * Shut down the controller when the system is going down.
! 951: */
! 952: void
! 953: ohci_shutdown(void *v)
! 954: {
! 955: ohci_softc_t *sc = v;
! 956:
! 957: DPRINTF(("ohci_shutdown: stopping the HC\n"));
! 958: OWRITE4(sc, OHCI_CONTROL, OHCI_HCFS_RESET);
! 959: }
! 960:
! 961: /*
! 962: * Handle suspend/resume.
! 963: *
! 964: * We need to switch to polling mode here, because this routine is
! 965: * called from an interrupt context. This is all right since we
! 966: * are almost suspended anyway.
! 967: */
! 968: void
! 969: ohci_power(int why, void *v)
! 970: {
! 971: ohci_softc_t *sc = v;
! 972: u_int32_t reg;
! 973: int s;
! 974:
! 975: #ifdef OHCI_DEBUG
! 976: DPRINTF(("ohci_power: sc=%p, why=%d\n", sc, why));
! 977: ohci_dumpregs(sc);
! 978: #endif
! 979:
! 980: s = splhardusb();
! 981: switch (why) {
! 982: case PWR_SUSPEND:
! 983: case PWR_STANDBY:
! 984: sc->sc_bus.use_polling++;
! 985: reg = OREAD4(sc, OHCI_CONTROL) & ~OHCI_HCFS_MASK;
! 986: if (sc->sc_control == 0) {
! 987: /*
! 988: * Preserve register values, in case that APM BIOS
! 989: * does not recover them.
! 990: */
! 991: sc->sc_control = reg;
! 992: sc->sc_intre = OREAD4(sc, OHCI_INTERRUPT_ENABLE);
! 993: sc->sc_ival = OHCI_GET_IVAL(OREAD4(sc,
! 994: OHCI_FM_INTERVAL));
! 995: }
! 996: reg |= OHCI_HCFS_SUSPEND;
! 997: OWRITE4(sc, OHCI_CONTROL, reg);
! 998: usb_delay_ms(&sc->sc_bus, USB_RESUME_WAIT);
! 999: sc->sc_bus.use_polling--;
! 1000: break;
! 1001: case PWR_RESUME:
! 1002: sc->sc_bus.use_polling++;
! 1003:
! 1004: /* Some broken BIOSes do not recover these values */
! 1005: OWRITE4(sc, OHCI_HCCA, DMAADDR(&sc->sc_hccadma, 0));
! 1006: OWRITE4(sc, OHCI_CONTROL_HEAD_ED, sc->sc_ctrl_head->physaddr);
! 1007: OWRITE4(sc, OHCI_BULK_HEAD_ED, sc->sc_bulk_head->physaddr);
! 1008: if (sc->sc_intre)
! 1009: OWRITE4(sc, OHCI_INTERRUPT_ENABLE,
! 1010: sc->sc_intre & (OHCI_ALL_INTRS | OHCI_MIE));
! 1011: if (sc->sc_control)
! 1012: reg = sc->sc_control;
! 1013: else
! 1014: reg = OREAD4(sc, OHCI_CONTROL);
! 1015: reg |= OHCI_HCFS_RESUME;
! 1016: OWRITE4(sc, OHCI_CONTROL, reg);
! 1017: usb_delay_ms(&sc->sc_bus, USB_RESUME_DELAY);
! 1018: reg = (reg & ~OHCI_HCFS_MASK) | OHCI_HCFS_OPERATIONAL;
! 1019: OWRITE4(sc, OHCI_CONTROL, reg);
! 1020:
! 1021: reg = (OREAD4(sc, OHCI_FM_REMAINING) & OHCI_FIT) ^ OHCI_FIT;
! 1022: reg |= OHCI_FSMPS(sc->sc_ival) | sc->sc_ival;
! 1023: OWRITE4(sc, OHCI_FM_INTERVAL, reg);
! 1024: OWRITE4(sc, OHCI_PERIODIC_START, OHCI_PERIODIC(sc->sc_ival));
! 1025:
! 1026: /* Fiddle the No OverCurrent Protection to avoid a chip bug */
! 1027: reg = OREAD4(sc, OHCI_RH_DESCRIPTOR_A);
! 1028: OWRITE4(sc, OHCI_RH_DESCRIPTOR_A, reg | OHCI_NOCP);
! 1029: OWRITE4(sc, OHCI_RH_STATUS, OHCI_LPSC); /* Enable port power */
! 1030: usb_delay_ms(&sc->sc_bus, OHCI_ENABLE_POWER_DELAY);
! 1031: OWRITE4(sc, OHCI_RH_DESCRIPTOR_A, reg);
! 1032:
! 1033: usb_delay_ms(&sc->sc_bus, USB_RESUME_RECOVERY);
! 1034: sc->sc_control = sc->sc_intre = sc->sc_ival = 0;
! 1035: sc->sc_bus.use_polling--;
! 1036: break;
! 1037: }
! 1038: splx(s);
! 1039: }
! 1040:
! 1041: #ifdef OHCI_DEBUG
! 1042: void
! 1043: ohci_dumpregs(ohci_softc_t *sc)
! 1044: {
! 1045: DPRINTF(("ohci_dumpregs: rev=0x%08x control=0x%08x command=0x%08x\n",
! 1046: OREAD4(sc, OHCI_REVISION),
! 1047: OREAD4(sc, OHCI_CONTROL),
! 1048: OREAD4(sc, OHCI_COMMAND_STATUS)));
! 1049: DPRINTF((" intrstat=0x%08x intre=0x%08x intrd=0x%08x\n",
! 1050: OREAD4(sc, OHCI_INTERRUPT_STATUS),
! 1051: OREAD4(sc, OHCI_INTERRUPT_ENABLE),
! 1052: OREAD4(sc, OHCI_INTERRUPT_DISABLE)));
! 1053: DPRINTF((" hcca=0x%08x percur=0x%08x ctrlhd=0x%08x\n",
! 1054: OREAD4(sc, OHCI_HCCA),
! 1055: OREAD4(sc, OHCI_PERIOD_CURRENT_ED),
! 1056: OREAD4(sc, OHCI_CONTROL_HEAD_ED)));
! 1057: DPRINTF((" ctrlcur=0x%08x bulkhd=0x%08x bulkcur=0x%08x\n",
! 1058: OREAD4(sc, OHCI_CONTROL_CURRENT_ED),
! 1059: OREAD4(sc, OHCI_BULK_HEAD_ED),
! 1060: OREAD4(sc, OHCI_BULK_CURRENT_ED)));
! 1061: DPRINTF((" done=0x%08x fmival=0x%08x fmrem=0x%08x\n",
! 1062: OREAD4(sc, OHCI_DONE_HEAD),
! 1063: OREAD4(sc, OHCI_FM_INTERVAL),
! 1064: OREAD4(sc, OHCI_FM_REMAINING)));
! 1065: DPRINTF((" fmnum=0x%08x perst=0x%08x lsthrs=0x%08x\n",
! 1066: OREAD4(sc, OHCI_FM_NUMBER),
! 1067: OREAD4(sc, OHCI_PERIODIC_START),
! 1068: OREAD4(sc, OHCI_LS_THRESHOLD)));
! 1069: DPRINTF((" desca=0x%08x descb=0x%08x stat=0x%08x\n",
! 1070: OREAD4(sc, OHCI_RH_DESCRIPTOR_A),
! 1071: OREAD4(sc, OHCI_RH_DESCRIPTOR_B),
! 1072: OREAD4(sc, OHCI_RH_STATUS)));
! 1073: DPRINTF((" port1=0x%08x port2=0x%08x\n",
! 1074: OREAD4(sc, OHCI_RH_PORT_STATUS(1)),
! 1075: OREAD4(sc, OHCI_RH_PORT_STATUS(2))));
! 1076: DPRINTF((" HCCA: frame_number=0x%04x done_head=0x%08x\n",
! 1077: letoh32(sc->sc_hcca->hcca_frame_number),
! 1078: letoh32(sc->sc_hcca->hcca_done_head)));
! 1079: }
! 1080: #endif
! 1081:
! 1082: int ohci_intr1(ohci_softc_t *);
! 1083:
! 1084: int
! 1085: ohci_intr(void *p)
! 1086: {
! 1087: ohci_softc_t *sc = p;
! 1088:
! 1089: if (sc == NULL || sc->sc_dying)
! 1090: return (0);
! 1091:
! 1092: /* If we get an interrupt while polling, then just ignore it. */
! 1093: if (!cold && sc->sc_bus.use_polling) {
! 1094: #ifdef DIAGNOSTIC
! 1095: static struct timeval ohci_intr_tv;
! 1096: if ((OREAD4(sc, OHCI_INTERRUPT_STATUS) & sc->sc_eintrs) &&
! 1097: usbd_ratecheck(&ohci_intr_tv))
! 1098: DPRINTFN(16,
! 1099: ("ohci_intr: ignored interrupt while polling\n"));
! 1100: #endif
! 1101: return (0);
! 1102: }
! 1103:
! 1104: return (ohci_intr1(sc));
! 1105: }
! 1106:
! 1107: int
! 1108: ohci_intr1(ohci_softc_t *sc)
! 1109: {
! 1110: u_int32_t intrs, eintrs;
! 1111: ohci_physaddr_t done;
! 1112:
! 1113: DPRINTFN(14,("ohci_intr1: enter\n"));
! 1114:
! 1115: /* In case the interrupt occurs before initialization has completed. */
! 1116: if (sc == NULL || sc->sc_hcca == NULL) {
! 1117: #ifdef DIAGNOSTIC
! 1118: printf("ohci_intr: sc->sc_hcca == NULL\n");
! 1119: #endif
! 1120: return (0);
! 1121: }
! 1122:
! 1123: intrs = 0;
! 1124: done = letoh32(sc->sc_hcca->hcca_done_head);
! 1125: if (done != 0) {
! 1126: if (done & ~OHCI_DONE_INTRS)
! 1127: intrs = OHCI_WDH;
! 1128: if (done & OHCI_DONE_INTRS)
! 1129: intrs |= OREAD4(sc, OHCI_INTERRUPT_STATUS);
! 1130: sc->sc_hcca->hcca_done_head = 0;
! 1131: } else {
! 1132: intrs = OREAD4(sc, OHCI_INTERRUPT_STATUS);
! 1133: /* If we've flushed out a WDH then reread */
! 1134: if (intrs & OHCI_WDH) {
! 1135: done = letoh32(sc->sc_hcca->hcca_done_head);
! 1136: sc->sc_hcca->hcca_done_head = 0;
! 1137: }
! 1138: }
! 1139:
! 1140: if (!intrs)
! 1141: return (0);
! 1142:
! 1143: intrs &= ~OHCI_MIE;
! 1144: OWRITE4(sc, OHCI_INTERRUPT_STATUS, intrs); /* Acknowledge */
! 1145: eintrs = intrs & sc->sc_eintrs;
! 1146: if (!eintrs)
! 1147: return (0);
! 1148:
! 1149: sc->sc_bus.intr_context++;
! 1150: sc->sc_bus.no_intrs++;
! 1151: DPRINTFN(7, ("ohci_intr: sc=%p intrs=0x%x(0x%x) eintrs=0x%x\n",
! 1152: sc, (u_int)intrs, OREAD4(sc, OHCI_INTERRUPT_STATUS),
! 1153: (u_int)eintrs));
! 1154:
! 1155: if (eintrs & OHCI_SO) {
! 1156: sc->sc_overrun_cnt++;
! 1157: if (usbd_ratecheck(&sc->sc_overrun_ntc)) {
! 1158: printf("%s: %u scheduling overruns\n",
! 1159: sc->sc_bus.bdev.dv_xname, sc->sc_overrun_cnt);
! 1160: sc->sc_overrun_cnt = 0;
! 1161: }
! 1162: /* XXX do what */
! 1163: eintrs &= ~OHCI_SO;
! 1164: }
! 1165: if (eintrs & OHCI_WDH) {
! 1166: ohci_add_done(sc, done &~ OHCI_DONE_INTRS);
! 1167: usb_schedsoftintr(&sc->sc_bus);
! 1168: eintrs &= ~OHCI_WDH;
! 1169: }
! 1170: if (eintrs & OHCI_RD) {
! 1171: printf("%s: resume detect\n", sc->sc_bus.bdev.dv_xname);
! 1172: /* XXX process resume detect */
! 1173: }
! 1174: if (eintrs & OHCI_UE) {
! 1175: printf("%s: unrecoverable error, controller halted\n",
! 1176: sc->sc_bus.bdev.dv_xname);
! 1177: OWRITE4(sc, OHCI_CONTROL, OHCI_HCFS_RESET);
! 1178: /* XXX what else */
! 1179: }
! 1180: if (eintrs & OHCI_RHSC) {
! 1181: ohci_rhsc(sc, sc->sc_intrxfer);
! 1182: /*
! 1183: * Disable RHSC interrupt for now, because it will be
! 1184: * on until the port has been reset.
! 1185: */
! 1186: ohci_rhsc_able(sc, 0);
! 1187: DPRINTFN(2, ("%s: rhsc interrupt disabled\n",
! 1188: sc->sc_bus.bdev.dv_xname));
! 1189:
! 1190: /* Do not allow RHSC interrupts > 1 per second */
! 1191: timeout_del(&sc->sc_tmo_rhsc);
! 1192: timeout_set(&sc->sc_tmo_rhsc, ohci_rhsc_enable, sc);
! 1193: timeout_add(&sc->sc_tmo_rhsc, hz);
! 1194: eintrs &= ~OHCI_RHSC;
! 1195: }
! 1196:
! 1197: sc->sc_bus.intr_context--;
! 1198:
! 1199: if (eintrs != 0) {
! 1200: /* Block unprocessed interrupts. XXX */
! 1201: OWRITE4(sc, OHCI_INTERRUPT_DISABLE, eintrs);
! 1202: sc->sc_eintrs &= ~eintrs;
! 1203: printf("%s: blocking intrs 0x%x\n",
! 1204: sc->sc_bus.bdev.dv_xname, eintrs);
! 1205: }
! 1206:
! 1207: return (1);
! 1208: }
! 1209:
! 1210: void
! 1211: ohci_rhsc_able(ohci_softc_t *sc, int on)
! 1212: {
! 1213: DPRINTFN(4, ("ohci_rhsc_able: on=%d\n", on));
! 1214: if (on) {
! 1215: sc->sc_eintrs |= OHCI_RHSC;
! 1216: OWRITE4(sc, OHCI_INTERRUPT_ENABLE, OHCI_RHSC);
! 1217: } else {
! 1218: sc->sc_eintrs &= ~OHCI_RHSC;
! 1219: OWRITE4(sc, OHCI_INTERRUPT_DISABLE, OHCI_RHSC);
! 1220: }
! 1221: }
! 1222:
! 1223: void
! 1224: ohci_rhsc_enable(void *v_sc)
! 1225: {
! 1226: ohci_softc_t *sc = v_sc;
! 1227: int s;
! 1228:
! 1229: s = splhardusb();
! 1230: ohci_rhsc(sc, sc->sc_intrxfer);
! 1231: DPRINTFN(2, ("%s: rhsc interrupt enabled\n",
! 1232: sc->sc_bus.bdev.dv_xname));
! 1233:
! 1234: ohci_rhsc_able(sc, 1);
! 1235: splx(s);
! 1236: }
! 1237:
! 1238: #ifdef OHCI_DEBUG
! 1239: char *ohci_cc_strs[] = {
! 1240: "NO_ERROR",
! 1241: "CRC",
! 1242: "BIT_STUFFING",
! 1243: "DATA_TOGGLE_MISMATCH",
! 1244: "STALL",
! 1245: "DEVICE_NOT_RESPONDING",
! 1246: "PID_CHECK_FAILURE",
! 1247: "UNEXPECTED_PID",
! 1248: "DATA_OVERRUN",
! 1249: "DATA_UNDERRUN",
! 1250: "BUFFER_OVERRUN",
! 1251: "BUFFER_UNDERRUN",
! 1252: "reserved",
! 1253: "reserved",
! 1254: "NOT_ACCESSED",
! 1255: "NOT_ACCESSED",
! 1256: };
! 1257: #endif
! 1258:
! 1259: void
! 1260: ohci_add_done(ohci_softc_t *sc, ohci_physaddr_t done)
! 1261: {
! 1262: ohci_soft_itd_t *sitd, *sidone, **ip;
! 1263: ohci_soft_td_t *std, *sdone, **p;
! 1264:
! 1265: /* Reverse the done list. */
! 1266: for (sdone = NULL, sidone = NULL; done != 0; ) {
! 1267: std = ohci_hash_find_td(sc, done);
! 1268: if (std != NULL) {
! 1269: std->dnext = sdone;
! 1270: done = letoh32(std->td.td_nexttd);
! 1271: sdone = std;
! 1272: DPRINTFN(10,("add TD %p\n", std));
! 1273: continue;
! 1274: }
! 1275: sitd = ohci_hash_find_itd(sc, done);
! 1276: if (sitd != NULL) {
! 1277: sitd->dnext = sidone;
! 1278: done = letoh32(sitd->itd.itd_nextitd);
! 1279: sidone = sitd;
! 1280: DPRINTFN(5,("add ITD %p\n", sitd));
! 1281: continue;
! 1282: }
! 1283: panic("ohci_add_done: addr 0x%08lx not found", (u_long)done);
! 1284: }
! 1285:
! 1286: /* sdone & sidone now hold the done lists. */
! 1287: /* Put them on the already processed lists. */
! 1288: for (p = &sc->sc_sdone; *p != NULL; p = &(*p)->dnext)
! 1289: ;
! 1290: *p = sdone;
! 1291: for (ip = &sc->sc_sidone; *ip != NULL; ip = &(*ip)->dnext)
! 1292: ;
! 1293: *ip = sidone;
! 1294: }
! 1295:
! 1296: void
! 1297: ohci_softintr(void *v)
! 1298: {
! 1299: ohci_softc_t *sc = v;
! 1300: ohci_soft_itd_t *sitd, *sidone, *sitdnext;
! 1301: ohci_soft_td_t *std, *sdone, *stdnext;
! 1302: usbd_xfer_handle xfer;
! 1303: struct ohci_pipe *opipe;
! 1304: int len, cc, s;
! 1305: int i, j, actlen, iframes, uedir;
! 1306:
! 1307: DPRINTFN(10,("ohci_softintr: enter\n"));
! 1308:
! 1309: sc->sc_bus.intr_context++;
! 1310:
! 1311: s = splhardusb();
! 1312: sdone = sc->sc_sdone;
! 1313: sc->sc_sdone = NULL;
! 1314: sidone = sc->sc_sidone;
! 1315: sc->sc_sidone = NULL;
! 1316: splx(s);
! 1317:
! 1318: DPRINTFN(10,("ohci_softintr: sdone=%p sidone=%p\n", sdone, sidone));
! 1319:
! 1320: #ifdef OHCI_DEBUG
! 1321: if (ohcidebug > 10) {
! 1322: DPRINTF(("ohci_process_done: TD done:\n"));
! 1323: ohci_dump_tds(sdone);
! 1324: }
! 1325: #endif
! 1326:
! 1327: for (std = sdone; std; std = stdnext) {
! 1328: xfer = std->xfer;
! 1329: stdnext = std->dnext;
! 1330: DPRINTFN(10, ("ohci_process_done: std=%p xfer=%p hcpriv=%p\n",
! 1331: std, xfer, xfer ? xfer->hcpriv : 0));
! 1332: if (xfer == NULL) {
! 1333: /*
! 1334: * xfer == NULL: There seems to be no xfer associated
! 1335: * with this TD. It is tailp that happened to end up on
! 1336: * the done queue.
! 1337: * Shouldn't happen, but some chips are broken(?).
! 1338: */
! 1339: continue;
! 1340: }
! 1341: if (xfer->status == USBD_CANCELLED ||
! 1342: xfer->status == USBD_TIMEOUT) {
! 1343: DPRINTF(("ohci_process_done: cancel/timeout %p\n",
! 1344: xfer));
! 1345: /* Handled by abort routine. */
! 1346: continue;
! 1347: }
! 1348: timeout_del(&xfer->timeout_handle);
! 1349:
! 1350: len = std->len;
! 1351: if (std->td.td_cbp != 0)
! 1352: len -= letoh32(std->td.td_be) -
! 1353: letoh32(std->td.td_cbp) + 1;
! 1354: DPRINTFN(10, ("ohci_process_done: len=%d, flags=0x%x\n", len,
! 1355: std->flags));
! 1356: if (std->flags & OHCI_ADD_LEN)
! 1357: xfer->actlen += len;
! 1358:
! 1359: cc = OHCI_TD_GET_CC(letoh32(std->td.td_flags));
! 1360: if (cc == OHCI_CC_NO_ERROR) {
! 1361: if (std->flags & OHCI_CALL_DONE) {
! 1362: xfer->status = USBD_NORMAL_COMPLETION;
! 1363: s = splusb();
! 1364: usb_transfer_complete(xfer);
! 1365: splx(s);
! 1366: }
! 1367: ohci_free_std(sc, std);
! 1368: } else {
! 1369: /*
! 1370: * Endpoint is halted. First unlink all the TDs
! 1371: * belonging to the failed transfer, and then restart
! 1372: * the endpoint.
! 1373: */
! 1374: ohci_soft_td_t *p, *n;
! 1375: opipe = (struct ohci_pipe *)xfer->pipe;
! 1376:
! 1377: DPRINTFN(15,("ohci_process_done: error cc=%d (%s)\n",
! 1378: OHCI_TD_GET_CC(letoh32(std->td.td_flags)),
! 1379: ohci_cc_strs[OHCI_TD_GET_CC(letoh32(std->td.td_flags))]));
! 1380:
! 1381: /* remove TDs */
! 1382: for (p = std; p->xfer == xfer; p = n) {
! 1383: n = p->nexttd;
! 1384: ohci_free_std(sc, p);
! 1385: }
! 1386:
! 1387: /* clear halt */
! 1388: opipe->sed->ed.ed_headp = htole32(p->physaddr);
! 1389: OWRITE4(sc, OHCI_COMMAND_STATUS, OHCI_CLF);
! 1390:
! 1391: if (cc == OHCI_CC_STALL)
! 1392: xfer->status = USBD_STALLED;
! 1393: else
! 1394: xfer->status = USBD_IOERROR;
! 1395: s = splusb();
! 1396: usb_transfer_complete(xfer);
! 1397: splx(s);
! 1398: }
! 1399: }
! 1400:
! 1401: #ifdef OHCI_DEBUG
! 1402: if (ohcidebug > 10) {
! 1403: DPRINTF(("ohci_softintr: ITD done:\n"));
! 1404: ohci_dump_itds(sidone);
! 1405: }
! 1406: #endif
! 1407:
! 1408: for (sitd = sidone; sitd != NULL; sitd = sitdnext) {
! 1409: xfer = sitd->xfer;
! 1410: sitdnext = sitd->dnext;
! 1411: DPRINTFN(1, ("ohci_process_done: sitd=%p xfer=%p hcpriv=%p\n",
! 1412: sitd, xfer, xfer ? xfer->hcpriv : 0));
! 1413: if (xfer == NULL)
! 1414: continue;
! 1415: if (xfer->status == USBD_CANCELLED ||
! 1416: xfer->status == USBD_TIMEOUT) {
! 1417: DPRINTF(("ohci_process_done: cancel/timeout %p\n",
! 1418: xfer));
! 1419: /* Handled by abort routine. */
! 1420: continue;
! 1421: }
! 1422: #ifdef DIAGNOSTIC
! 1423: if (sitd->isdone)
! 1424: printf("ohci_softintr: sitd=%p is done\n", sitd);
! 1425: sitd->isdone = 1;
! 1426: #endif
! 1427: if (sitd->flags & OHCI_CALL_DONE) {
! 1428: ohci_soft_itd_t *next;
! 1429:
! 1430: opipe = (struct ohci_pipe *)xfer->pipe;
! 1431: opipe->u.iso.inuse -= xfer->nframes;
! 1432: uedir = UE_GET_DIR(xfer->pipe->endpoint->edesc->
! 1433: bEndpointAddress);
! 1434: xfer->status = USBD_NORMAL_COMPLETION;
! 1435: actlen = 0;
! 1436: for (i = 0, sitd = xfer->hcpriv;;
! 1437: sitd = next) {
! 1438: next = sitd->nextitd;
! 1439: if (OHCI_ITD_GET_CC(letoh32(sitd->
! 1440: itd.itd_flags)) != OHCI_CC_NO_ERROR)
! 1441: xfer->status = USBD_IOERROR;
! 1442: /* For input, update frlengths with actual */
! 1443: /* XXX anything necessary for output? */
! 1444: if (uedir == UE_DIR_IN &&
! 1445: xfer->status == USBD_NORMAL_COMPLETION) {
! 1446: iframes = OHCI_ITD_GET_FC(letoh32(
! 1447: sitd->itd.itd_flags));
! 1448: for (j = 0; j < iframes; i++, j++) {
! 1449: len = letoh16(sitd->
! 1450: itd.itd_offset[j]);
! 1451: if ((OHCI_ITD_PSW_GET_CC(len) &
! 1452: OHCI_CC_NOT_ACCESSED_MASK)
! 1453: == OHCI_CC_NOT_ACCESSED)
! 1454: len = 0;
! 1455: else
! 1456: len = OHCI_ITD_PSW_LENGTH(len);
! 1457: xfer->frlengths[i] = len;
! 1458: actlen += len;
! 1459: }
! 1460: }
! 1461: if (sitd->flags & OHCI_CALL_DONE)
! 1462: break;
! 1463: ohci_free_sitd(sc, sitd);
! 1464: }
! 1465: ohci_free_sitd(sc, sitd);
! 1466: if (uedir == UE_DIR_IN &&
! 1467: xfer->status == USBD_NORMAL_COMPLETION)
! 1468: xfer->actlen = actlen;
! 1469: xfer->hcpriv = NULL;
! 1470:
! 1471: s = splusb();
! 1472: usb_transfer_complete(xfer);
! 1473: splx(s);
! 1474: }
! 1475: }
! 1476:
! 1477: #ifdef __HAVE_GENERIC_SOFT_INTERRUPTS
! 1478: if (sc->sc_softwake) {
! 1479: sc->sc_softwake = 0;
! 1480: wakeup(&sc->sc_softwake);
! 1481: }
! 1482: #endif /* __HAVE_GENERIC_SOFT_INTERRUPTS */
! 1483:
! 1484: sc->sc_bus.intr_context--;
! 1485: DPRINTFN(10,("ohci_softintr: done:\n"));
! 1486: }
! 1487:
! 1488: void
! 1489: ohci_device_ctrl_done(usbd_xfer_handle xfer)
! 1490: {
! 1491: DPRINTFN(10,("ohci_device_ctrl_done: xfer=%p\n", xfer));
! 1492:
! 1493: #ifdef DIAGNOSTIC
! 1494: if (!(xfer->rqflags & URQ_REQUEST)) {
! 1495: panic("ohci_device_ctrl_done: not a request");
! 1496: }
! 1497: #endif
! 1498: }
! 1499:
! 1500: void
! 1501: ohci_device_intr_done(usbd_xfer_handle xfer)
! 1502: {
! 1503: struct ohci_pipe *opipe = (struct ohci_pipe *)xfer->pipe;
! 1504: ohci_softc_t *sc = (ohci_softc_t *)opipe->pipe.device->bus;
! 1505: ohci_soft_ed_t *sed = opipe->sed;
! 1506: ohci_soft_td_t *data, *tail;
! 1507:
! 1508:
! 1509: DPRINTFN(10, ("ohci_device_intr_done: xfer=%p, actlen=%d\n", xfer,
! 1510: xfer->actlen));
! 1511:
! 1512: if (xfer->pipe->repeat) {
! 1513: data = opipe->tail.td;
! 1514: tail = ohci_alloc_std(sc); /* XXX should reuse TD */
! 1515: if (tail == NULL) {
! 1516: xfer->status = USBD_NOMEM;
! 1517: return;
! 1518: }
! 1519: tail->xfer = NULL;
! 1520:
! 1521: data->td.td_flags = htole32(
! 1522: OHCI_TD_IN | OHCI_TD_NOCC |
! 1523: OHCI_TD_SET_DI(1) | OHCI_TD_TOGGLE_CARRY);
! 1524: if (xfer->flags & USBD_SHORT_XFER_OK)
! 1525: data->td.td_flags |= htole32(OHCI_TD_R);
! 1526: data->td.td_cbp = htole32(DMAADDR(&xfer->dmabuf, 0));
! 1527: data->nexttd = tail;
! 1528: data->td.td_nexttd = htole32(tail->physaddr);
! 1529: data->td.td_be = htole32(letoh32(data->td.td_cbp) +
! 1530: xfer->length - 1);
! 1531: data->len = xfer->length;
! 1532: data->xfer = xfer;
! 1533: data->flags = OHCI_CALL_DONE | OHCI_ADD_LEN;
! 1534: xfer->hcpriv = data;
! 1535: xfer->actlen = 0;
! 1536:
! 1537: sed->ed.ed_tailp = htole32(tail->physaddr);
! 1538: opipe->tail.td = tail;
! 1539: }
! 1540: }
! 1541:
! 1542: void
! 1543: ohci_device_bulk_done(usbd_xfer_handle xfer)
! 1544: {
! 1545: DPRINTFN(10, ("ohci_device_bulk_done: xfer=%p, actlen=%d\n", xfer,
! 1546: xfer->actlen));
! 1547: }
! 1548:
! 1549: void
! 1550: ohci_rhsc(ohci_softc_t *sc, usbd_xfer_handle xfer)
! 1551: {
! 1552: usbd_pipe_handle pipe;
! 1553: u_char *p;
! 1554: int i, m;
! 1555: int hstatus;
! 1556:
! 1557: hstatus = OREAD4(sc, OHCI_RH_STATUS);
! 1558: DPRINTF(("ohci_rhsc: sc=%p xfer=%p hstatus=0x%08x\n",
! 1559: sc, xfer, hstatus));
! 1560:
! 1561: if (xfer == NULL) {
! 1562: /* Just ignore the change. */
! 1563: return;
! 1564: }
! 1565:
! 1566: pipe = xfer->pipe;
! 1567:
! 1568: p = KERNADDR(&xfer->dmabuf, 0);
! 1569: m = min(sc->sc_noport, xfer->length * 8 - 1);
! 1570: memset(p, 0, xfer->length);
! 1571: for (i = 1; i <= m; i++) {
! 1572: /* Pick out CHANGE bits from the status reg. */
! 1573: if (OREAD4(sc, OHCI_RH_PORT_STATUS(i)) >> 16)
! 1574: p[i/8] |= 1 << (i%8);
! 1575: }
! 1576: DPRINTF(("ohci_rhsc: change=0x%02x\n", *p));
! 1577: xfer->actlen = xfer->length;
! 1578: xfer->status = USBD_NORMAL_COMPLETION;
! 1579:
! 1580: usb_transfer_complete(xfer);
! 1581: }
! 1582:
! 1583: void
! 1584: ohci_root_intr_done(usbd_xfer_handle xfer)
! 1585: {
! 1586: }
! 1587:
! 1588: void
! 1589: ohci_root_ctrl_done(usbd_xfer_handle xfer)
! 1590: {
! 1591: }
! 1592:
! 1593: /*
! 1594: * Wait here until controller claims to have an interrupt.
! 1595: * Then call ohci_intr and return. Use timeout to avoid waiting
! 1596: * too long.
! 1597: */
! 1598: void
! 1599: ohci_waitintr(ohci_softc_t *sc, usbd_xfer_handle xfer)
! 1600: {
! 1601: int timo;
! 1602: u_int32_t intrs;
! 1603:
! 1604: xfer->status = USBD_IN_PROGRESS;
! 1605: for (timo = xfer->timeout; timo >= 0; timo--) {
! 1606: usb_delay_ms(&sc->sc_bus, 1);
! 1607: if (sc->sc_dying)
! 1608: break;
! 1609: intrs = OREAD4(sc, OHCI_INTERRUPT_STATUS) & sc->sc_eintrs;
! 1610: DPRINTFN(15,("ohci_waitintr: 0x%04x\n", intrs));
! 1611: #ifdef OHCI_DEBUG
! 1612: if (ohcidebug > 15)
! 1613: ohci_dumpregs(sc);
! 1614: #endif
! 1615: if (intrs) {
! 1616: ohci_intr1(sc);
! 1617: if (xfer->status != USBD_IN_PROGRESS)
! 1618: return;
! 1619: }
! 1620: }
! 1621:
! 1622: /* Timeout */
! 1623: DPRINTF(("ohci_waitintr: timeout\n"));
! 1624: xfer->status = USBD_TIMEOUT;
! 1625: usb_transfer_complete(xfer);
! 1626: /* XXX should free TD */
! 1627: }
! 1628:
! 1629: void
! 1630: ohci_poll(struct usbd_bus *bus)
! 1631: {
! 1632: ohci_softc_t *sc = (ohci_softc_t *)bus;
! 1633: #ifdef OHCI_DEBUG
! 1634: static int last;
! 1635: int new;
! 1636: new = OREAD4(sc, OHCI_INTERRUPT_STATUS);
! 1637: if (new != last) {
! 1638: DPRINTFN(10,("ohci_poll: intrs=0x%04x\n", new));
! 1639: last = new;
! 1640: }
! 1641: #endif
! 1642:
! 1643: if (OREAD4(sc, OHCI_INTERRUPT_STATUS) & sc->sc_eintrs)
! 1644: ohci_intr1(sc);
! 1645: }
! 1646:
! 1647: usbd_status
! 1648: ohci_device_request(usbd_xfer_handle xfer)
! 1649: {
! 1650: struct ohci_pipe *opipe = (struct ohci_pipe *)xfer->pipe;
! 1651: usb_device_request_t *req = &xfer->request;
! 1652: usbd_device_handle dev = opipe->pipe.device;
! 1653: ohci_softc_t *sc = (ohci_softc_t *)dev->bus;
! 1654: int addr = dev->address;
! 1655: ohci_soft_td_t *setup, *stat, *next, *tail;
! 1656: ohci_soft_ed_t *sed;
! 1657: int isread;
! 1658: int len;
! 1659: usbd_status err;
! 1660: int s;
! 1661:
! 1662: isread = req->bmRequestType & UT_READ;
! 1663: len = UGETW(req->wLength);
! 1664:
! 1665: DPRINTFN(3,("ohci_device_control type=0x%02x, request=0x%02x, "
! 1666: "wValue=0x%04x, wIndex=0x%04x len=%d, addr=%d, endpt=%d\n",
! 1667: req->bmRequestType, req->bRequest, UGETW(req->wValue),
! 1668: UGETW(req->wIndex), len, addr,
! 1669: opipe->pipe.endpoint->edesc->bEndpointAddress));
! 1670:
! 1671: setup = opipe->tail.td;
! 1672: stat = ohci_alloc_std(sc);
! 1673: if (stat == NULL) {
! 1674: err = USBD_NOMEM;
! 1675: goto bad1;
! 1676: }
! 1677: tail = ohci_alloc_std(sc);
! 1678: if (tail == NULL) {
! 1679: err = USBD_NOMEM;
! 1680: goto bad2;
! 1681: }
! 1682: tail->xfer = NULL;
! 1683:
! 1684: sed = opipe->sed;
! 1685: opipe->u.ctl.length = len;
! 1686:
! 1687: /* Update device address and length since they may have changed
! 1688: during the setup of the control pipe in usbd_new_device(). */
! 1689: /* XXX This only needs to be done once, but it's too early in open. */
! 1690: /* XXXX Should not touch ED here! */
! 1691: sed->ed.ed_flags = htole32(
! 1692: (letoh32(sed->ed.ed_flags) & ~(OHCI_ED_ADDRMASK | OHCI_ED_MAXPMASK)) |
! 1693: OHCI_ED_SET_FA(addr) |
! 1694: OHCI_ED_SET_MAXP(UGETW(opipe->pipe.endpoint->edesc->wMaxPacketSize)));
! 1695:
! 1696: next = stat;
! 1697:
! 1698: /* Set up data transaction */
! 1699: if (len != 0) {
! 1700: ohci_soft_td_t *std = stat;
! 1701:
! 1702: err = ohci_alloc_std_chain(opipe, sc, len, isread, xfer,
! 1703: std, &stat);
! 1704: stat = stat->nexttd; /* point at free TD */
! 1705: if (err)
! 1706: goto bad3;
! 1707: /* Start toggle at 1 and then use the carried toggle. */
! 1708: std->td.td_flags &= htole32(~OHCI_TD_TOGGLE_MASK);
! 1709: std->td.td_flags |= htole32(OHCI_TD_TOGGLE_1);
! 1710: }
! 1711:
! 1712: memcpy(KERNADDR(&opipe->u.ctl.reqdma, 0), req, sizeof *req);
! 1713:
! 1714: setup->td.td_flags = htole32(OHCI_TD_SETUP | OHCI_TD_NOCC |
! 1715: OHCI_TD_TOGGLE_0 | OHCI_TD_NOINTR);
! 1716: setup->td.td_cbp = htole32(DMAADDR(&opipe->u.ctl.reqdma, 0));
! 1717: setup->nexttd = next;
! 1718: setup->td.td_nexttd = htole32(next->physaddr);
! 1719: setup->td.td_be = htole32(letoh32(setup->td.td_cbp) + sizeof *req - 1);
! 1720: setup->len = 0;
! 1721: setup->xfer = xfer;
! 1722: setup->flags = 0;
! 1723: xfer->hcpriv = setup;
! 1724:
! 1725: stat->td.td_flags = htole32(
! 1726: (isread ? OHCI_TD_OUT : OHCI_TD_IN) |
! 1727: OHCI_TD_NOCC | OHCI_TD_TOGGLE_1 | OHCI_TD_SET_DI(1));
! 1728: stat->td.td_cbp = 0;
! 1729: stat->nexttd = tail;
! 1730: stat->td.td_nexttd = htole32(tail->physaddr);
! 1731: stat->td.td_be = 0;
! 1732: stat->flags = OHCI_CALL_DONE;
! 1733: stat->len = 0;
! 1734: stat->xfer = xfer;
! 1735:
! 1736: #ifdef OHCI_DEBUG
! 1737: if (ohcidebug > 5) {
! 1738: DPRINTF(("ohci_device_request:\n"));
! 1739: ohci_dump_ed(sed);
! 1740: ohci_dump_tds(setup);
! 1741: }
! 1742: #endif
! 1743:
! 1744: /* Insert ED in schedule */
! 1745: s = splusb();
! 1746: sed->ed.ed_tailp = htole32(tail->physaddr);
! 1747: opipe->tail.td = tail;
! 1748: OWRITE4(sc, OHCI_COMMAND_STATUS, OHCI_CLF);
! 1749: if (xfer->timeout && !sc->sc_bus.use_polling) {
! 1750: timeout_del(&xfer->timeout_handle);
! 1751: timeout_set(&xfer->timeout_handle, ohci_timeout, xfer);
! 1752: timeout_add(&xfer->timeout_handle, mstohz(xfer->timeout));
! 1753: }
! 1754: splx(s);
! 1755:
! 1756: #ifdef OHCI_DEBUG
! 1757: if (ohcidebug > 20) {
! 1758: delay(10000);
! 1759: DPRINTF(("ohci_device_request: status=%x\n",
! 1760: OREAD4(sc, OHCI_COMMAND_STATUS)));
! 1761: ohci_dumpregs(sc);
! 1762: printf("ctrl head:\n");
! 1763: ohci_dump_ed(sc->sc_ctrl_head);
! 1764: printf("sed:\n");
! 1765: ohci_dump_ed(sed);
! 1766: ohci_dump_tds(setup);
! 1767: }
! 1768: #endif
! 1769:
! 1770: return (USBD_NORMAL_COMPLETION);
! 1771:
! 1772: bad3:
! 1773: ohci_free_std(sc, tail);
! 1774: bad2:
! 1775: ohci_free_std(sc, stat);
! 1776: bad1:
! 1777: return (err);
! 1778: }
! 1779:
! 1780: /*
! 1781: * Add an ED to the schedule. Called at splusb().
! 1782: */
! 1783: void
! 1784: ohci_add_ed(ohci_soft_ed_t *sed, ohci_soft_ed_t *head)
! 1785: {
! 1786: DPRINTFN(8,("ohci_add_ed: sed=%p head=%p\n", sed, head));
! 1787:
! 1788: SPLUSBCHECK;
! 1789: sed->next = head->next;
! 1790: sed->ed.ed_nexted = head->ed.ed_nexted;
! 1791: head->next = sed;
! 1792: head->ed.ed_nexted = htole32(sed->physaddr);
! 1793: }
! 1794:
! 1795: /*
! 1796: * Remove an ED from the schedule. Called at splusb().
! 1797: */
! 1798: void
! 1799: ohci_rem_ed(ohci_soft_ed_t *sed, ohci_soft_ed_t *head)
! 1800: {
! 1801: ohci_soft_ed_t *p;
! 1802:
! 1803: SPLUSBCHECK;
! 1804:
! 1805: /* XXX */
! 1806: for (p = head; p != NULL && p->next != sed; p = p->next)
! 1807: ;
! 1808: if (p == NULL)
! 1809: panic("ohci_rem_ed: ED not found");
! 1810: p->next = sed->next;
! 1811: p->ed.ed_nexted = sed->ed.ed_nexted;
! 1812: }
! 1813:
! 1814: /*
! 1815: * When a transfer is completed the TD is added to the done queue by
! 1816: * the host controller. This queue is the processed by software.
! 1817: * Unfortunately the queue contains the physical address of the TD
! 1818: * and we have no simple way to translate this back to a kernel address.
! 1819: * To make the translation possible (and fast) we use a hash table of
! 1820: * TDs currently in the schedule. The physical address is used as the
! 1821: * hash value.
! 1822: */
! 1823:
! 1824: #define HASH(a) (((a) >> 4) % OHCI_HASH_SIZE)
! 1825: /* Called at splusb() */
! 1826: void
! 1827: ohci_hash_add_td(ohci_softc_t *sc, ohci_soft_td_t *std)
! 1828: {
! 1829: int h = HASH(std->physaddr);
! 1830:
! 1831: SPLUSBCHECK;
! 1832:
! 1833: LIST_INSERT_HEAD(&sc->sc_hash_tds[h], std, hnext);
! 1834: }
! 1835:
! 1836: /* Called at splusb() */
! 1837: void
! 1838: ohci_hash_rem_td(ohci_softc_t *sc, ohci_soft_td_t *std)
! 1839: {
! 1840: SPLUSBCHECK;
! 1841:
! 1842: LIST_REMOVE(std, hnext);
! 1843: }
! 1844:
! 1845: ohci_soft_td_t *
! 1846: ohci_hash_find_td(ohci_softc_t *sc, ohci_physaddr_t a)
! 1847: {
! 1848: int h = HASH(a);
! 1849: ohci_soft_td_t *std;
! 1850:
! 1851: for (std = LIST_FIRST(&sc->sc_hash_tds[h]);
! 1852: std != NULL;
! 1853: std = LIST_NEXT(std, hnext))
! 1854: if (std->physaddr == a)
! 1855: return (std);
! 1856: return (NULL);
! 1857: }
! 1858:
! 1859: /* Called at splusb() */
! 1860: void
! 1861: ohci_hash_add_itd(ohci_softc_t *sc, ohci_soft_itd_t *sitd)
! 1862: {
! 1863: int h = HASH(sitd->physaddr);
! 1864:
! 1865: SPLUSBCHECK;
! 1866:
! 1867: DPRINTFN(10,("ohci_hash_add_itd: sitd=%p physaddr=0x%08lx\n",
! 1868: sitd, (u_long)sitd->physaddr));
! 1869:
! 1870: LIST_INSERT_HEAD(&sc->sc_hash_itds[h], sitd, hnext);
! 1871: }
! 1872:
! 1873: /* Called at splusb() */
! 1874: void
! 1875: ohci_hash_rem_itd(ohci_softc_t *sc, ohci_soft_itd_t *sitd)
! 1876: {
! 1877: SPLUSBCHECK;
! 1878:
! 1879: DPRINTFN(10,("ohci_hash_rem_itd: sitd=%p physaddr=0x%08lx\n",
! 1880: sitd, (u_long)sitd->physaddr));
! 1881:
! 1882: LIST_REMOVE(sitd, hnext);
! 1883: }
! 1884:
! 1885: ohci_soft_itd_t *
! 1886: ohci_hash_find_itd(ohci_softc_t *sc, ohci_physaddr_t a)
! 1887: {
! 1888: int h = HASH(a);
! 1889: ohci_soft_itd_t *sitd;
! 1890:
! 1891: for (sitd = LIST_FIRST(&sc->sc_hash_itds[h]);
! 1892: sitd != NULL;
! 1893: sitd = LIST_NEXT(sitd, hnext))
! 1894: if (sitd->physaddr == a)
! 1895: return (sitd);
! 1896: return (NULL);
! 1897: }
! 1898:
! 1899: void
! 1900: ohci_timeout(void *addr)
! 1901: {
! 1902: struct ohci_xfer *oxfer = addr;
! 1903: struct ohci_pipe *opipe = (struct ohci_pipe *)oxfer->xfer.pipe;
! 1904: ohci_softc_t *sc = (ohci_softc_t *)opipe->pipe.device->bus;
! 1905:
! 1906: DPRINTF(("ohci_timeout: oxfer=%p\n", oxfer));
! 1907:
! 1908: if (sc->sc_dying) {
! 1909: ohci_abort_xfer(&oxfer->xfer, USBD_TIMEOUT);
! 1910: return;
! 1911: }
! 1912:
! 1913: /* Execute the abort in a process context. */
! 1914: usb_init_task(&oxfer->abort_task, ohci_timeout_task, addr);
! 1915: usb_add_task(oxfer->xfer.pipe->device, &oxfer->abort_task);
! 1916: }
! 1917:
! 1918: void
! 1919: ohci_timeout_task(void *addr)
! 1920: {
! 1921: usbd_xfer_handle xfer = addr;
! 1922: int s;
! 1923:
! 1924: DPRINTF(("ohci_timeout_task: xfer=%p\n", xfer));
! 1925:
! 1926: s = splusb();
! 1927: ohci_abort_xfer(xfer, USBD_TIMEOUT);
! 1928: splx(s);
! 1929: }
! 1930:
! 1931: #ifdef OHCI_DEBUG
! 1932: void
! 1933: ohci_dump_tds(ohci_soft_td_t *std)
! 1934: {
! 1935: for (; std; std = std->nexttd)
! 1936: ohci_dump_td(std);
! 1937: }
! 1938:
! 1939: void
! 1940: ohci_dump_td(ohci_soft_td_t *std)
! 1941: {
! 1942: char sbuf[128];
! 1943:
! 1944: bitmask_snprintf((u_int32_t)letoh32(std->td.td_flags),
! 1945: "\20\23R\24OUT\25IN\31TOG1\32SETTOGGLE",
! 1946: sbuf, sizeof(sbuf));
! 1947:
! 1948: printf("TD(%p) at %08lx: %s delay=%d ec=%d cc=%d\ncbp=0x%08lx "
! 1949: "nexttd=0x%08lx be=0x%08lx\n",
! 1950: std, (u_long)std->physaddr, sbuf,
! 1951: OHCI_TD_GET_DI(letoh32(std->td.td_flags)),
! 1952: OHCI_TD_GET_EC(letoh32(std->td.td_flags)),
! 1953: OHCI_TD_GET_CC(letoh32(std->td.td_flags)),
! 1954: (u_long)letoh32(std->td.td_cbp),
! 1955: (u_long)letoh32(std->td.td_nexttd),
! 1956: (u_long)letoh32(std->td.td_be));
! 1957: }
! 1958:
! 1959: void
! 1960: ohci_dump_itd(ohci_soft_itd_t *sitd)
! 1961: {
! 1962: int i;
! 1963:
! 1964: printf("ITD(%p) at %08lx: sf=%d di=%d fc=%d cc=%d\n"
! 1965: "bp0=0x%08lx next=0x%08lx be=0x%08lx\n",
! 1966: sitd, (u_long)sitd->physaddr,
! 1967: OHCI_ITD_GET_SF(letoh32(sitd->itd.itd_flags)),
! 1968: OHCI_ITD_GET_DI(letoh32(sitd->itd.itd_flags)),
! 1969: OHCI_ITD_GET_FC(letoh32(sitd->itd.itd_flags)),
! 1970: OHCI_ITD_GET_CC(letoh32(sitd->itd.itd_flags)),
! 1971: (u_long)letoh32(sitd->itd.itd_bp0),
! 1972: (u_long)letoh32(sitd->itd.itd_nextitd),
! 1973: (u_long)letoh32(sitd->itd.itd_be));
! 1974: for (i = 0; i < OHCI_ITD_NOFFSET; i++)
! 1975: printf("offs[%d]=0x%04x ", i,
! 1976: (u_int)letoh16(sitd->itd.itd_offset[i]));
! 1977: printf("\n");
! 1978: }
! 1979:
! 1980: void
! 1981: ohci_dump_itds(ohci_soft_itd_t *sitd)
! 1982: {
! 1983: for (; sitd; sitd = sitd->nextitd)
! 1984: ohci_dump_itd(sitd);
! 1985: }
! 1986:
! 1987: void
! 1988: ohci_dump_ed(ohci_soft_ed_t *sed)
! 1989: {
! 1990: char sbuf[128], sbuf2[128];
! 1991:
! 1992: bitmask_snprintf((u_int32_t)letoh32(sed->ed.ed_flags),
! 1993: "\20\14OUT\15IN\16LOWSPEED\17SKIP\20ISO",
! 1994: sbuf, sizeof(sbuf));
! 1995: bitmask_snprintf((u_int32_t)letoh32(sed->ed.ed_headp),
! 1996: "\20\1HALT\2CARRY", sbuf2, sizeof(sbuf2));
! 1997:
! 1998: printf("ED(%p) at 0x%08lx: addr=%d endpt=%d maxp=%d flags=%s\n"
! 1999: "tailp=0x%08lx headflags=%s headp=0x%08lx nexted=0x%08lx\n",
! 2000: sed, (u_long)sed->physaddr,
! 2001: OHCI_ED_GET_FA(letoh32(sed->ed.ed_flags)),
! 2002: OHCI_ED_GET_EN(letoh32(sed->ed.ed_flags)),
! 2003: OHCI_ED_GET_MAXP(letoh32(sed->ed.ed_flags)), sbuf,
! 2004: (u_long)letoh32(sed->ed.ed_tailp), sbuf2,
! 2005: (u_long)letoh32(sed->ed.ed_headp),
! 2006: (u_long)letoh32(sed->ed.ed_nexted));
! 2007: }
! 2008: #endif
! 2009:
! 2010: usbd_status
! 2011: ohci_open(usbd_pipe_handle pipe)
! 2012: {
! 2013: usbd_device_handle dev = pipe->device;
! 2014: ohci_softc_t *sc = (ohci_softc_t *)dev->bus;
! 2015: usb_endpoint_descriptor_t *ed = pipe->endpoint->edesc;
! 2016: struct ohci_pipe *opipe = (struct ohci_pipe *)pipe;
! 2017: u_int8_t addr = dev->address;
! 2018: u_int8_t xfertype = ed->bmAttributes & UE_XFERTYPE;
! 2019: ohci_soft_ed_t *sed;
! 2020: ohci_soft_td_t *std;
! 2021: ohci_soft_itd_t *sitd;
! 2022: ohci_physaddr_t tdphys;
! 2023: u_int32_t fmt;
! 2024: usbd_status err;
! 2025: int s;
! 2026: int ival;
! 2027:
! 2028: DPRINTFN(1, ("ohci_open: pipe=%p, addr=%d, endpt=%d (%d)\n",
! 2029: pipe, addr, ed->bEndpointAddress, sc->sc_addr));
! 2030:
! 2031: if (sc->sc_dying)
! 2032: return (USBD_IOERROR);
! 2033:
! 2034: std = NULL;
! 2035: sed = NULL;
! 2036:
! 2037: if (addr == sc->sc_addr) {
! 2038: switch (ed->bEndpointAddress) {
! 2039: case USB_CONTROL_ENDPOINT:
! 2040: pipe->methods = &ohci_root_ctrl_methods;
! 2041: break;
! 2042: case UE_DIR_IN | OHCI_INTR_ENDPT:
! 2043: pipe->methods = &ohci_root_intr_methods;
! 2044: break;
! 2045: default:
! 2046: return (USBD_INVAL);
! 2047: }
! 2048: } else {
! 2049: sed = ohci_alloc_sed(sc);
! 2050: if (sed == NULL)
! 2051: goto bad0;
! 2052: opipe->sed = sed;
! 2053: if (xfertype == UE_ISOCHRONOUS) {
! 2054: sitd = ohci_alloc_sitd(sc);
! 2055: if (sitd == NULL)
! 2056: goto bad1;
! 2057: opipe->tail.itd = sitd;
! 2058: tdphys = sitd->physaddr;
! 2059: fmt = OHCI_ED_FORMAT_ISO;
! 2060: if (UE_GET_DIR(ed->bEndpointAddress) == UE_DIR_IN)
! 2061: fmt |= OHCI_ED_DIR_IN;
! 2062: else
! 2063: fmt |= OHCI_ED_DIR_OUT;
! 2064: } else {
! 2065: std = ohci_alloc_std(sc);
! 2066: if (std == NULL)
! 2067: goto bad1;
! 2068: opipe->tail.td = std;
! 2069: tdphys = std->physaddr;
! 2070: fmt = OHCI_ED_FORMAT_GEN | OHCI_ED_DIR_TD;
! 2071: }
! 2072: sed->ed.ed_flags = htole32(
! 2073: OHCI_ED_SET_FA(addr) |
! 2074: OHCI_ED_SET_EN(UE_GET_ADDR(ed->bEndpointAddress)) |
! 2075: (dev->speed == USB_SPEED_LOW ? OHCI_ED_SPEED : 0) |
! 2076: fmt | OHCI_ED_SET_MAXP(UGETW(ed->wMaxPacketSize)));
! 2077: sed->ed.ed_headp = htole32(tdphys |
! 2078: (pipe->endpoint->savedtoggle ? OHCI_TOGGLECARRY : 0));
! 2079: sed->ed.ed_tailp = htole32(tdphys);
! 2080:
! 2081: switch (xfertype) {
! 2082: case UE_CONTROL:
! 2083: pipe->methods = &ohci_device_ctrl_methods;
! 2084: err = usb_allocmem(&sc->sc_bus,
! 2085: sizeof(usb_device_request_t),
! 2086: 0, &opipe->u.ctl.reqdma);
! 2087: if (err)
! 2088: goto bad;
! 2089: s = splusb();
! 2090: ohci_add_ed(sed, sc->sc_ctrl_head);
! 2091: splx(s);
! 2092: break;
! 2093: case UE_INTERRUPT:
! 2094: pipe->methods = &ohci_device_intr_methods;
! 2095: ival = pipe->interval;
! 2096: if (ival == USBD_DEFAULT_INTERVAL)
! 2097: ival = ed->bInterval;
! 2098: return (ohci_device_setintr(sc, opipe, ival));
! 2099: case UE_ISOCHRONOUS:
! 2100: pipe->methods = &ohci_device_isoc_methods;
! 2101: return (ohci_setup_isoc(pipe));
! 2102: case UE_BULK:
! 2103: pipe->methods = &ohci_device_bulk_methods;
! 2104: s = splusb();
! 2105: ohci_add_ed(sed, sc->sc_bulk_head);
! 2106: splx(s);
! 2107: break;
! 2108: }
! 2109: }
! 2110: return (USBD_NORMAL_COMPLETION);
! 2111:
! 2112: bad:
! 2113: if (std != NULL)
! 2114: ohci_free_std(sc, std);
! 2115: bad1:
! 2116: if (sed != NULL)
! 2117: ohci_free_sed(sc, sed);
! 2118: bad0:
! 2119: return (USBD_NOMEM);
! 2120:
! 2121: }
! 2122:
! 2123: /*
! 2124: * Close a reqular pipe.
! 2125: * Assumes that there are no pending transactions.
! 2126: */
! 2127: void
! 2128: ohci_close_pipe(usbd_pipe_handle pipe, ohci_soft_ed_t *head)
! 2129: {
! 2130: struct ohci_pipe *opipe = (struct ohci_pipe *)pipe;
! 2131: ohci_softc_t *sc = (ohci_softc_t *)pipe->device->bus;
! 2132: ohci_soft_ed_t *sed = opipe->sed;
! 2133: int s;
! 2134:
! 2135: s = splusb();
! 2136: #ifdef DIAGNOSTIC
! 2137: sed->ed.ed_flags |= htole32(OHCI_ED_SKIP);
! 2138: if ((letoh32(sed->ed.ed_tailp) & OHCI_HEADMASK) !=
! 2139: (letoh32(sed->ed.ed_headp) & OHCI_HEADMASK)) {
! 2140: ohci_soft_td_t *std;
! 2141: std = ohci_hash_find_td(sc, letoh32(sed->ed.ed_headp));
! 2142: printf("ohci_close_pipe: pipe not empty sed=%p hd=0x%x "
! 2143: "tl=0x%x pipe=%p, std=%p\n", sed,
! 2144: (int)letoh32(sed->ed.ed_headp),
! 2145: (int)letoh32(sed->ed.ed_tailp),
! 2146: pipe, std);
! 2147: #ifdef USB_DEBUG
! 2148: usbd_dump_pipe(&opipe->pipe);
! 2149: #endif
! 2150: #ifdef OHCI_DEBUG
! 2151: ohci_dump_ed(sed);
! 2152: if (std)
! 2153: ohci_dump_td(std);
! 2154: #endif
! 2155: usb_delay_ms(&sc->sc_bus, 2);
! 2156: if ((letoh32(sed->ed.ed_tailp) & OHCI_HEADMASK) !=
! 2157: (letoh32(sed->ed.ed_headp) & OHCI_HEADMASK))
! 2158: printf("ohci_close_pipe: pipe still not empty\n");
! 2159: }
! 2160: #endif
! 2161: ohci_rem_ed(sed, head);
! 2162: /* Make sure the host controller is not touching this ED */
! 2163: usb_delay_ms(&sc->sc_bus, 1);
! 2164: splx(s);
! 2165: pipe->endpoint->savedtoggle =
! 2166: (letoh32(sed->ed.ed_headp) & OHCI_TOGGLECARRY) ? 1 : 0;
! 2167: ohci_free_sed(sc, opipe->sed);
! 2168: }
! 2169:
! 2170: /*
! 2171: * Abort a device request.
! 2172: * If this routine is called at splusb() it guarantees that the request
! 2173: * will be removed from the hardware scheduling and that the callback
! 2174: * for it will be called with USBD_CANCELLED status.
! 2175: * It's impossible to guarantee that the requested transfer will not
! 2176: * have happened since the hardware runs concurrently.
! 2177: * If the transaction has already happened we rely on the ordinary
! 2178: * interrupt processing to process it.
! 2179: */
! 2180: void
! 2181: ohci_abort_xfer(usbd_xfer_handle xfer, usbd_status status)
! 2182: {
! 2183: struct ohci_pipe *opipe = (struct ohci_pipe *)xfer->pipe;
! 2184: ohci_softc_t *sc = (ohci_softc_t *)opipe->pipe.device->bus;
! 2185: ohci_soft_ed_t *sed = opipe->sed;
! 2186: ohci_soft_td_t *p, *n;
! 2187: ohci_physaddr_t headp;
! 2188: int s, hit;
! 2189:
! 2190: DPRINTF(("ohci_abort_xfer: xfer=%p pipe=%p sed=%p\n", xfer, opipe,
! 2191: sed));
! 2192:
! 2193: if (sc->sc_dying) {
! 2194: /* If we're dying, just do the software part. */
! 2195: s = splusb();
! 2196: xfer->status = status; /* make software ignore it */
! 2197: timeout_del(&xfer->timeout_handle);
! 2198: usb_transfer_complete(xfer);
! 2199: splx(s);
! 2200: return;
! 2201: }
! 2202:
! 2203: if (xfer->device->bus->intr_context || !curproc)
! 2204: panic("ohci_abort_xfer: not in process context");
! 2205:
! 2206: /*
! 2207: * Step 1: Make interrupt routine and hardware ignore xfer.
! 2208: */
! 2209: s = splusb();
! 2210: xfer->status = status; /* make software ignore it */
! 2211: timeout_del(&xfer->timeout_handle);
! 2212: splx(s);
! 2213: DPRINTFN(1,("ohci_abort_xfer: stop ed=%p\n", sed));
! 2214: sed->ed.ed_flags |= htole32(OHCI_ED_SKIP); /* force hardware skip */
! 2215:
! 2216: /*
! 2217: * Step 2: Wait until we know hardware has finished any possible
! 2218: * use of the xfer. Also make sure the soft interrupt routine
! 2219: * has run.
! 2220: */
! 2221: usb_delay_ms(opipe->pipe.device->bus, 20); /* Hardware finishes in 1ms */
! 2222: s = splusb();
! 2223: #ifdef __HAVE_GENERIC_SOFT_INTERRUPTS
! 2224: sc->sc_softwake = 1;
! 2225: #endif /* __HAVE_GENERIC_SOFT_INTERRUPTS */
! 2226: usb_schedsoftintr(&sc->sc_bus);
! 2227: #ifdef __HAVE_GENERIC_SOFT_INTERRUPTS
! 2228: tsleep(&sc->sc_softwake, PZERO, "ohciab", 0);
! 2229: #endif /* __HAVE_GENERIC_SOFT_INTERRUPTS */
! 2230: splx(s);
! 2231:
! 2232: /*
! 2233: * Step 3: Remove any vestiges of the xfer from the hardware.
! 2234: * The complication here is that the hardware may have executed
! 2235: * beyond the xfer we're trying to abort. So as we're scanning
! 2236: * the TDs of this xfer we check if the hardware points to
! 2237: * any of them.
! 2238: */
! 2239: s = splusb(); /* XXX why? */
! 2240: p = xfer->hcpriv;
! 2241: #ifdef DIAGNOSTIC
! 2242: if (p == NULL) {
! 2243: splx(s);
! 2244: printf("ohci_abort_xfer: hcpriv is NULL\n");
! 2245: return;
! 2246: }
! 2247: #endif
! 2248: #ifdef OHCI_DEBUG
! 2249: if (ohcidebug > 1) {
! 2250: DPRINTF(("ohci_abort_xfer: sed=\n"));
! 2251: ohci_dump_ed(sed);
! 2252: ohci_dump_tds(p);
! 2253: }
! 2254: #endif
! 2255: headp = letoh32(sed->ed.ed_headp) & OHCI_HEADMASK;
! 2256: hit = 0;
! 2257: for (; p->xfer == xfer; p = n) {
! 2258: hit |= headp == p->physaddr;
! 2259: n = p->nexttd;
! 2260: if (OHCI_TD_GET_CC(letoh32(p->td.td_flags)) ==
! 2261: OHCI_CC_NOT_ACCESSED)
! 2262: ohci_free_std(sc, p);
! 2263: }
! 2264: /* Zap headp register if hardware pointed inside the xfer. */
! 2265: if (hit) {
! 2266: DPRINTFN(1,("ohci_abort_xfer: set hd=0x%08x, tl=0x%08x\n",
! 2267: (int)p->physaddr, (int)letoh32(sed->ed.ed_tailp)));
! 2268: sed->ed.ed_headp = htole32(p->physaddr); /* unlink TDs */
! 2269: } else {
! 2270: DPRINTFN(1,("ohci_abort_xfer: no hit\n"));
! 2271: }
! 2272:
! 2273: /*
! 2274: * Step 4: Turn on hardware again.
! 2275: */
! 2276: sed->ed.ed_flags &= htole32(~OHCI_ED_SKIP); /* remove hardware skip */
! 2277:
! 2278: /*
! 2279: * Step 5: Execute callback.
! 2280: */
! 2281: usb_transfer_complete(xfer);
! 2282:
! 2283: splx(s);
! 2284: }
! 2285:
! 2286: /*
! 2287: * Data structures and routines to emulate the root hub.
! 2288: */
! 2289: usb_device_descriptor_t ohci_devd = {
! 2290: USB_DEVICE_DESCRIPTOR_SIZE,
! 2291: UDESC_DEVICE, /* type */
! 2292: {0x00, 0x01}, /* USB version */
! 2293: UDCLASS_HUB, /* class */
! 2294: UDSUBCLASS_HUB, /* subclass */
! 2295: UDPROTO_FSHUB,
! 2296: 64, /* max packet */
! 2297: {0},{0},{0x00,0x01}, /* device id */
! 2298: 1,2,0, /* string indices */
! 2299: 1 /* # of configurations */
! 2300: };
! 2301:
! 2302: usb_config_descriptor_t ohci_confd = {
! 2303: USB_CONFIG_DESCRIPTOR_SIZE,
! 2304: UDESC_CONFIG,
! 2305: {USB_CONFIG_DESCRIPTOR_SIZE +
! 2306: USB_INTERFACE_DESCRIPTOR_SIZE +
! 2307: USB_ENDPOINT_DESCRIPTOR_SIZE},
! 2308: 1,
! 2309: 1,
! 2310: 0,
! 2311: UC_SELF_POWERED,
! 2312: 0 /* max power */
! 2313: };
! 2314:
! 2315: usb_interface_descriptor_t ohci_ifcd = {
! 2316: USB_INTERFACE_DESCRIPTOR_SIZE,
! 2317: UDESC_INTERFACE,
! 2318: 0,
! 2319: 0,
! 2320: 1,
! 2321: UICLASS_HUB,
! 2322: UISUBCLASS_HUB,
! 2323: UIPROTO_FSHUB,
! 2324: 0
! 2325: };
! 2326:
! 2327: usb_endpoint_descriptor_t ohci_endpd = {
! 2328: USB_ENDPOINT_DESCRIPTOR_SIZE,
! 2329: UDESC_ENDPOINT,
! 2330: UE_DIR_IN | OHCI_INTR_ENDPT,
! 2331: UE_INTERRUPT,
! 2332: {8, 0}, /* max packet */
! 2333: 255
! 2334: };
! 2335:
! 2336: usb_hub_descriptor_t ohci_hubd = {
! 2337: USB_HUB_DESCRIPTOR_SIZE,
! 2338: UDESC_HUB,
! 2339: 0,
! 2340: {0,0},
! 2341: 0,
! 2342: 0,
! 2343: {0},
! 2344: };
! 2345:
! 2346: int
! 2347: ohci_str(usb_string_descriptor_t *p, int l, const char *s)
! 2348: {
! 2349: int i;
! 2350:
! 2351: if (l == 0)
! 2352: return (0);
! 2353: p->bLength = 2 * strlen(s) + 2;
! 2354: if (l == 1)
! 2355: return (1);
! 2356: p->bDescriptorType = UDESC_STRING;
! 2357: l -= 2;
! 2358: for (i = 0; s[i] && l > 1; i++, l -= 2)
! 2359: USETW2(p->bString[i], 0, s[i]);
! 2360: return (2*i+2);
! 2361: }
! 2362:
! 2363: /*
! 2364: * Simulate a hardware hub by handling all the necessary requests.
! 2365: */
! 2366: usbd_status
! 2367: ohci_root_ctrl_transfer(usbd_xfer_handle xfer)
! 2368: {
! 2369: usbd_status err;
! 2370:
! 2371: /* Insert last in queue. */
! 2372: err = usb_insert_transfer(xfer);
! 2373: if (err)
! 2374: return (err);
! 2375:
! 2376: /* Pipe isn't running, start first */
! 2377: return (ohci_root_ctrl_start(SIMPLEQ_FIRST(&xfer->pipe->queue)));
! 2378: }
! 2379:
! 2380: usbd_status
! 2381: ohci_root_ctrl_start(usbd_xfer_handle xfer)
! 2382: {
! 2383: ohci_softc_t *sc = (ohci_softc_t *)xfer->pipe->device->bus;
! 2384: usb_device_request_t *req;
! 2385: void *buf = NULL;
! 2386: int port, i;
! 2387: int s, len, value, index, l, totlen = 0;
! 2388: usb_port_status_t ps;
! 2389: usb_hub_descriptor_t hubd;
! 2390: usbd_status err;
! 2391: u_int32_t v;
! 2392:
! 2393: if (sc->sc_dying)
! 2394: return (USBD_IOERROR);
! 2395:
! 2396: #ifdef DIAGNOSTIC
! 2397: if (!(xfer->rqflags & URQ_REQUEST))
! 2398: /* XXX panic */
! 2399: return (USBD_INVAL);
! 2400: #endif
! 2401: req = &xfer->request;
! 2402:
! 2403: DPRINTFN(4,("ohci_root_ctrl_control type=0x%02x request=%02x\n",
! 2404: req->bmRequestType, req->bRequest));
! 2405:
! 2406: len = UGETW(req->wLength);
! 2407: value = UGETW(req->wValue);
! 2408: index = UGETW(req->wIndex);
! 2409:
! 2410: if (len != 0)
! 2411: buf = KERNADDR(&xfer->dmabuf, 0);
! 2412:
! 2413: #define C(x,y) ((x) | ((y) << 8))
! 2414: switch(C(req->bRequest, req->bmRequestType)) {
! 2415: case C(UR_CLEAR_FEATURE, UT_WRITE_DEVICE):
! 2416: case C(UR_CLEAR_FEATURE, UT_WRITE_INTERFACE):
! 2417: case C(UR_CLEAR_FEATURE, UT_WRITE_ENDPOINT):
! 2418: /*
! 2419: * DEVICE_REMOTE_WAKEUP and ENDPOINT_HALT are no-ops
! 2420: * for the integrated root hub.
! 2421: */
! 2422: break;
! 2423: case C(UR_GET_CONFIG, UT_READ_DEVICE):
! 2424: if (len > 0) {
! 2425: *(u_int8_t *)buf = sc->sc_conf;
! 2426: totlen = 1;
! 2427: }
! 2428: break;
! 2429: case C(UR_GET_DESCRIPTOR, UT_READ_DEVICE):
! 2430: DPRINTFN(8,("ohci_root_ctrl_control wValue=0x%04x\n", value));
! 2431: switch(value >> 8) {
! 2432: case UDESC_DEVICE:
! 2433: if ((value & 0xff) != 0) {
! 2434: err = USBD_IOERROR;
! 2435: goto ret;
! 2436: }
! 2437: totlen = l = min(len, USB_DEVICE_DESCRIPTOR_SIZE);
! 2438: USETW(ohci_devd.idVendor, sc->sc_id_vendor);
! 2439: memcpy(buf, &ohci_devd, l);
! 2440: break;
! 2441: case UDESC_CONFIG:
! 2442: if ((value & 0xff) != 0) {
! 2443: err = USBD_IOERROR;
! 2444: goto ret;
! 2445: }
! 2446: totlen = l = min(len, USB_CONFIG_DESCRIPTOR_SIZE);
! 2447: memcpy(buf, &ohci_confd, l);
! 2448: buf = (char *)buf + l;
! 2449: len -= l;
! 2450: l = min(len, USB_INTERFACE_DESCRIPTOR_SIZE);
! 2451: totlen += l;
! 2452: memcpy(buf, &ohci_ifcd, l);
! 2453: buf = (char *)buf + l;
! 2454: len -= l;
! 2455: l = min(len, USB_ENDPOINT_DESCRIPTOR_SIZE);
! 2456: totlen += l;
! 2457: memcpy(buf, &ohci_endpd, l);
! 2458: break;
! 2459: case UDESC_STRING:
! 2460: if (len == 0)
! 2461: break;
! 2462: *(u_int8_t *)buf = 0;
! 2463: totlen = 1;
! 2464: switch (value & 0xff) {
! 2465: case 0: /* Language table */
! 2466: totlen = ohci_str(buf, len, "\001");
! 2467: break;
! 2468: case 1: /* Vendor */
! 2469: totlen = ohci_str(buf, len, sc->sc_vendor);
! 2470: break;
! 2471: case 2: /* Product */
! 2472: totlen = ohci_str(buf, len, "OHCI root hub");
! 2473: break;
! 2474: }
! 2475: break;
! 2476: default:
! 2477: err = USBD_IOERROR;
! 2478: goto ret;
! 2479: }
! 2480: break;
! 2481: case C(UR_GET_INTERFACE, UT_READ_INTERFACE):
! 2482: if (len > 0) {
! 2483: *(u_int8_t *)buf = 0;
! 2484: totlen = 1;
! 2485: }
! 2486: break;
! 2487: case C(UR_GET_STATUS, UT_READ_DEVICE):
! 2488: if (len > 1) {
! 2489: USETW(((usb_status_t *)buf)->wStatus,UDS_SELF_POWERED);
! 2490: totlen = 2;
! 2491: }
! 2492: break;
! 2493: case C(UR_GET_STATUS, UT_READ_INTERFACE):
! 2494: case C(UR_GET_STATUS, UT_READ_ENDPOINT):
! 2495: if (len > 1) {
! 2496: USETW(((usb_status_t *)buf)->wStatus, 0);
! 2497: totlen = 2;
! 2498: }
! 2499: break;
! 2500: case C(UR_SET_ADDRESS, UT_WRITE_DEVICE):
! 2501: if (value >= USB_MAX_DEVICES) {
! 2502: err = USBD_IOERROR;
! 2503: goto ret;
! 2504: }
! 2505: sc->sc_addr = value;
! 2506: break;
! 2507: case C(UR_SET_CONFIG, UT_WRITE_DEVICE):
! 2508: if (value != 0 && value != 1) {
! 2509: err = USBD_IOERROR;
! 2510: goto ret;
! 2511: }
! 2512: sc->sc_conf = value;
! 2513: break;
! 2514: case C(UR_SET_DESCRIPTOR, UT_WRITE_DEVICE):
! 2515: break;
! 2516: case C(UR_SET_FEATURE, UT_WRITE_DEVICE):
! 2517: case C(UR_SET_FEATURE, UT_WRITE_INTERFACE):
! 2518: case C(UR_SET_FEATURE, UT_WRITE_ENDPOINT):
! 2519: err = USBD_IOERROR;
! 2520: goto ret;
! 2521: case C(UR_SET_INTERFACE, UT_WRITE_INTERFACE):
! 2522: break;
! 2523: case C(UR_SYNCH_FRAME, UT_WRITE_ENDPOINT):
! 2524: break;
! 2525: /* Hub requests */
! 2526: case C(UR_CLEAR_FEATURE, UT_WRITE_CLASS_DEVICE):
! 2527: break;
! 2528: case C(UR_CLEAR_FEATURE, UT_WRITE_CLASS_OTHER):
! 2529: DPRINTFN(8, ("ohci_root_ctrl_control: UR_CLEAR_PORT_FEATURE "
! 2530: "port=%d feature=%d\n",
! 2531: index, value));
! 2532: if (index < 1 || index > sc->sc_noport) {
! 2533: err = USBD_IOERROR;
! 2534: goto ret;
! 2535: }
! 2536: port = OHCI_RH_PORT_STATUS(index);
! 2537: switch(value) {
! 2538: case UHF_PORT_ENABLE:
! 2539: OWRITE4(sc, port, UPS_CURRENT_CONNECT_STATUS);
! 2540: break;
! 2541: case UHF_PORT_SUSPEND:
! 2542: OWRITE4(sc, port, UPS_OVERCURRENT_INDICATOR);
! 2543: break;
! 2544: case UHF_PORT_POWER:
! 2545: /* Yes, writing to the LOW_SPEED bit clears power. */
! 2546: OWRITE4(sc, port, UPS_LOW_SPEED);
! 2547: break;
! 2548: case UHF_C_PORT_CONNECTION:
! 2549: OWRITE4(sc, port, UPS_C_CONNECT_STATUS << 16);
! 2550: break;
! 2551: case UHF_C_PORT_ENABLE:
! 2552: OWRITE4(sc, port, UPS_C_PORT_ENABLED << 16);
! 2553: break;
! 2554: case UHF_C_PORT_SUSPEND:
! 2555: OWRITE4(sc, port, UPS_C_SUSPEND << 16);
! 2556: break;
! 2557: case UHF_C_PORT_OVER_CURRENT:
! 2558: OWRITE4(sc, port, UPS_C_OVERCURRENT_INDICATOR << 16);
! 2559: break;
! 2560: case UHF_C_PORT_RESET:
! 2561: OWRITE4(sc, port, UPS_C_PORT_RESET << 16);
! 2562: break;
! 2563: default:
! 2564: err = USBD_IOERROR;
! 2565: goto ret;
! 2566: }
! 2567: switch(value) {
! 2568: case UHF_C_PORT_CONNECTION:
! 2569: case UHF_C_PORT_ENABLE:
! 2570: case UHF_C_PORT_SUSPEND:
! 2571: case UHF_C_PORT_OVER_CURRENT:
! 2572: case UHF_C_PORT_RESET:
! 2573: /* Enable RHSC interrupt if condition is cleared. */
! 2574: if ((OREAD4(sc, port) >> 16) == 0)
! 2575: ohci_rhsc_able(sc, 1);
! 2576: break;
! 2577: default:
! 2578: break;
! 2579: }
! 2580: break;
! 2581: case C(UR_GET_DESCRIPTOR, UT_READ_CLASS_DEVICE):
! 2582: if ((value & 0xff) != 0) {
! 2583: err = USBD_IOERROR;
! 2584: goto ret;
! 2585: }
! 2586: v = OREAD4(sc, OHCI_RH_DESCRIPTOR_A);
! 2587: hubd = ohci_hubd;
! 2588: hubd.bNbrPorts = sc->sc_noport;
! 2589: USETW(hubd.wHubCharacteristics,
! 2590: (v & OHCI_NPS ? UHD_PWR_NO_SWITCH :
! 2591: v & OHCI_PSM ? UHD_PWR_GANGED : UHD_PWR_INDIVIDUAL)
! 2592: /* XXX overcurrent */
! 2593: );
! 2594: hubd.bPwrOn2PwrGood = OHCI_GET_POTPGT(v);
! 2595: v = OREAD4(sc, OHCI_RH_DESCRIPTOR_B);
! 2596: for (i = 0, l = sc->sc_noport; l > 0; i++, l -= 8, v >>= 8)
! 2597: hubd.DeviceRemovable[i++] = (u_int8_t)v;
! 2598: hubd.bDescLength = USB_HUB_DESCRIPTOR_SIZE + i;
! 2599: l = min(len, hubd.bDescLength);
! 2600: totlen = l;
! 2601: memcpy(buf, &hubd, l);
! 2602: break;
! 2603: case C(UR_GET_STATUS, UT_READ_CLASS_DEVICE):
! 2604: if (len != 4) {
! 2605: err = USBD_IOERROR;
! 2606: goto ret;
! 2607: }
! 2608: memset(buf, 0, len); /* ? XXX */
! 2609: totlen = len;
! 2610: break;
! 2611: case C(UR_GET_STATUS, UT_READ_CLASS_OTHER):
! 2612: DPRINTFN(8,("ohci_root_ctrl_transfer: get port status i=%d\n",
! 2613: index));
! 2614: if (index < 1 || index > sc->sc_noport) {
! 2615: err = USBD_IOERROR;
! 2616: goto ret;
! 2617: }
! 2618: if (len != 4) {
! 2619: err = USBD_IOERROR;
! 2620: goto ret;
! 2621: }
! 2622: v = OREAD4(sc, OHCI_RH_PORT_STATUS(index));
! 2623: DPRINTFN(8,("ohci_root_ctrl_transfer: port status=0x%04x\n",
! 2624: v));
! 2625: USETW(ps.wPortStatus, v);
! 2626: USETW(ps.wPortChange, v >> 16);
! 2627: l = min(len, sizeof ps);
! 2628: memcpy(buf, &ps, l);
! 2629: totlen = l;
! 2630: break;
! 2631: case C(UR_SET_DESCRIPTOR, UT_WRITE_CLASS_DEVICE):
! 2632: err = USBD_IOERROR;
! 2633: goto ret;
! 2634: case C(UR_SET_FEATURE, UT_WRITE_CLASS_DEVICE):
! 2635: break;
! 2636: case C(UR_SET_FEATURE, UT_WRITE_CLASS_OTHER):
! 2637: if (index < 1 || index > sc->sc_noport) {
! 2638: err = USBD_IOERROR;
! 2639: goto ret;
! 2640: }
! 2641: port = OHCI_RH_PORT_STATUS(index);
! 2642: switch(value) {
! 2643: case UHF_PORT_ENABLE:
! 2644: OWRITE4(sc, port, UPS_PORT_ENABLED);
! 2645: break;
! 2646: case UHF_PORT_SUSPEND:
! 2647: OWRITE4(sc, port, UPS_SUSPEND);
! 2648: break;
! 2649: case UHF_PORT_RESET:
! 2650: DPRINTFN(5,("ohci_root_ctrl_transfer: reset port %d\n",
! 2651: index));
! 2652: OWRITE4(sc, port, UPS_RESET);
! 2653: for (i = 0; i < 5; i++) {
! 2654: usb_delay_ms(&sc->sc_bus,
! 2655: USB_PORT_ROOT_RESET_DELAY);
! 2656: if (sc->sc_dying) {
! 2657: err = USBD_IOERROR;
! 2658: goto ret;
! 2659: }
! 2660: if ((OREAD4(sc, port) & UPS_RESET) == 0)
! 2661: break;
! 2662: }
! 2663: DPRINTFN(8,("ohci port %d reset, status = 0x%04x\n",
! 2664: index, OREAD4(sc, port)));
! 2665: break;
! 2666: case UHF_PORT_POWER:
! 2667: DPRINTFN(2,("ohci_root_ctrl_transfer: set port power "
! 2668: "%d\n", index));
! 2669: OWRITE4(sc, port, UPS_PORT_POWER);
! 2670: break;
! 2671: default:
! 2672: err = USBD_IOERROR;
! 2673: goto ret;
! 2674: }
! 2675: break;
! 2676: default:
! 2677: err = USBD_IOERROR;
! 2678: goto ret;
! 2679: }
! 2680: xfer->actlen = totlen;
! 2681: err = USBD_NORMAL_COMPLETION;
! 2682: ret:
! 2683: xfer->status = err;
! 2684: s = splusb();
! 2685: usb_transfer_complete(xfer);
! 2686: splx(s);
! 2687: return (USBD_IN_PROGRESS);
! 2688: }
! 2689:
! 2690: /* Abort a root control request. */
! 2691: void
! 2692: ohci_root_ctrl_abort(usbd_xfer_handle xfer)
! 2693: {
! 2694: /* Nothing to do, all transfers are synchronous. */
! 2695: }
! 2696:
! 2697: /* Close the root pipe. */
! 2698: void
! 2699: ohci_root_ctrl_close(usbd_pipe_handle pipe)
! 2700: {
! 2701: DPRINTF(("ohci_root_ctrl_close\n"));
! 2702: /* Nothing to do. */
! 2703: }
! 2704:
! 2705: usbd_status
! 2706: ohci_root_intr_transfer(usbd_xfer_handle xfer)
! 2707: {
! 2708: usbd_status err;
! 2709:
! 2710: /* Insert last in queue. */
! 2711: err = usb_insert_transfer(xfer);
! 2712: if (err)
! 2713: return (err);
! 2714:
! 2715: /* Pipe isn't running, start first */
! 2716: return (ohci_root_intr_start(SIMPLEQ_FIRST(&xfer->pipe->queue)));
! 2717: }
! 2718:
! 2719: usbd_status
! 2720: ohci_root_intr_start(usbd_xfer_handle xfer)
! 2721: {
! 2722: usbd_pipe_handle pipe = xfer->pipe;
! 2723: ohci_softc_t *sc = (ohci_softc_t *)pipe->device->bus;
! 2724:
! 2725: if (sc->sc_dying)
! 2726: return (USBD_IOERROR);
! 2727:
! 2728: sc->sc_intrxfer = xfer;
! 2729:
! 2730: return (USBD_IN_PROGRESS);
! 2731: }
! 2732:
! 2733: /* Abort a root interrupt request. */
! 2734: void
! 2735: ohci_root_intr_abort(usbd_xfer_handle xfer)
! 2736: {
! 2737: int s;
! 2738:
! 2739: if (xfer->pipe->intrxfer == xfer) {
! 2740: DPRINTF(("ohci_root_intr_abort: remove\n"));
! 2741: xfer->pipe->intrxfer = NULL;
! 2742: }
! 2743: xfer->status = USBD_CANCELLED;
! 2744: s = splusb();
! 2745: usb_transfer_complete(xfer);
! 2746: splx(s);
! 2747: }
! 2748:
! 2749: /* Close the root pipe. */
! 2750: void
! 2751: ohci_root_intr_close(usbd_pipe_handle pipe)
! 2752: {
! 2753: ohci_softc_t *sc = (ohci_softc_t *)pipe->device->bus;
! 2754:
! 2755: DPRINTF(("ohci_root_intr_close\n"));
! 2756:
! 2757: sc->sc_intrxfer = NULL;
! 2758: }
! 2759:
! 2760: /************************/
! 2761:
! 2762: usbd_status
! 2763: ohci_device_ctrl_transfer(usbd_xfer_handle xfer)
! 2764: {
! 2765: usbd_status err;
! 2766:
! 2767: /* Insert last in queue. */
! 2768: err = usb_insert_transfer(xfer);
! 2769: if (err)
! 2770: return (err);
! 2771:
! 2772: /* Pipe isn't running, start first */
! 2773: return (ohci_device_ctrl_start(SIMPLEQ_FIRST(&xfer->pipe->queue)));
! 2774: }
! 2775:
! 2776: usbd_status
! 2777: ohci_device_ctrl_start(usbd_xfer_handle xfer)
! 2778: {
! 2779: ohci_softc_t *sc = (ohci_softc_t *)xfer->pipe->device->bus;
! 2780: usbd_status err;
! 2781:
! 2782: if (sc->sc_dying)
! 2783: return (USBD_IOERROR);
! 2784:
! 2785: #ifdef DIAGNOSTIC
! 2786: if (!(xfer->rqflags & URQ_REQUEST)) {
! 2787: /* XXX panic */
! 2788: printf("ohci_device_ctrl_transfer: not a request\n");
! 2789: return (USBD_INVAL);
! 2790: }
! 2791: #endif
! 2792:
! 2793: err = ohci_device_request(xfer);
! 2794: if (err)
! 2795: return (err);
! 2796:
! 2797: if (sc->sc_bus.use_polling)
! 2798: ohci_waitintr(sc, xfer);
! 2799:
! 2800: return (USBD_IN_PROGRESS);
! 2801: }
! 2802:
! 2803: /* Abort a device control request. */
! 2804: void
! 2805: ohci_device_ctrl_abort(usbd_xfer_handle xfer)
! 2806: {
! 2807: DPRINTF(("ohci_device_ctrl_abort: xfer=%p\n", xfer));
! 2808: ohci_abort_xfer(xfer, USBD_CANCELLED);
! 2809: }
! 2810:
! 2811: /* Close a device control pipe. */
! 2812: void
! 2813: ohci_device_ctrl_close(usbd_pipe_handle pipe)
! 2814: {
! 2815: struct ohci_pipe *opipe = (struct ohci_pipe *)pipe;
! 2816: ohci_softc_t *sc = (ohci_softc_t *)pipe->device->bus;
! 2817:
! 2818: DPRINTF(("ohci_device_ctrl_close: pipe=%p\n", pipe));
! 2819: ohci_close_pipe(pipe, sc->sc_ctrl_head);
! 2820: ohci_free_std(sc, opipe->tail.td);
! 2821: }
! 2822:
! 2823: /************************/
! 2824:
! 2825: void
! 2826: ohci_device_clear_toggle(usbd_pipe_handle pipe)
! 2827: {
! 2828: struct ohci_pipe *opipe = (struct ohci_pipe *)pipe;
! 2829:
! 2830: opipe->sed->ed.ed_headp &= htole32(~OHCI_TOGGLECARRY);
! 2831: }
! 2832:
! 2833: void
! 2834: ohci_noop(usbd_pipe_handle pipe)
! 2835: {
! 2836: }
! 2837:
! 2838: usbd_status
! 2839: ohci_device_bulk_transfer(usbd_xfer_handle xfer)
! 2840: {
! 2841: usbd_status err;
! 2842:
! 2843: /* Insert last in queue. */
! 2844: err = usb_insert_transfer(xfer);
! 2845: if (err)
! 2846: return (err);
! 2847:
! 2848: /* Pipe isn't running, start first */
! 2849: return (ohci_device_bulk_start(SIMPLEQ_FIRST(&xfer->pipe->queue)));
! 2850: }
! 2851:
! 2852: usbd_status
! 2853: ohci_device_bulk_start(usbd_xfer_handle xfer)
! 2854: {
! 2855: struct ohci_pipe *opipe = (struct ohci_pipe *)xfer->pipe;
! 2856: usbd_device_handle dev = opipe->pipe.device;
! 2857: ohci_softc_t *sc = (ohci_softc_t *)dev->bus;
! 2858: int addr = dev->address;
! 2859: ohci_soft_td_t *data, *tail, *tdp;
! 2860: ohci_soft_ed_t *sed;
! 2861: int s, len, isread, endpt;
! 2862: usbd_status err;
! 2863:
! 2864: if (sc->sc_dying)
! 2865: return (USBD_IOERROR);
! 2866:
! 2867: #ifdef DIAGNOSTIC
! 2868: if (xfer->rqflags & URQ_REQUEST) {
! 2869: /* XXX panic */
! 2870: printf("ohci_device_bulk_start: a request\n");
! 2871: return (USBD_INVAL);
! 2872: }
! 2873: #endif
! 2874:
! 2875: len = xfer->length;
! 2876: endpt = xfer->pipe->endpoint->edesc->bEndpointAddress;
! 2877: isread = UE_GET_DIR(endpt) == UE_DIR_IN;
! 2878: sed = opipe->sed;
! 2879:
! 2880: DPRINTFN(4,("ohci_device_bulk_start: xfer=%p len=%d isread=%d "
! 2881: "flags=%d endpt=%d\n", xfer, len, isread, xfer->flags,
! 2882: endpt));
! 2883:
! 2884: opipe->u.bulk.isread = isread;
! 2885: opipe->u.bulk.length = len;
! 2886:
! 2887: /* Update device address */
! 2888: sed->ed.ed_flags = htole32(
! 2889: (letoh32(sed->ed.ed_flags) & ~OHCI_ED_ADDRMASK) |
! 2890: OHCI_ED_SET_FA(addr));
! 2891:
! 2892: /* Allocate a chain of new TDs (including a new tail). */
! 2893: data = opipe->tail.td;
! 2894: err = ohci_alloc_std_chain(opipe, sc, len, isread, xfer,
! 2895: data, &tail);
! 2896: /* We want interrupt at the end of the transfer. */
! 2897: tail->td.td_flags &= htole32(~OHCI_TD_INTR_MASK);
! 2898: tail->td.td_flags |= htole32(OHCI_TD_SET_DI(1));
! 2899: tail->flags |= OHCI_CALL_DONE;
! 2900: tail = tail->nexttd; /* point at sentinel */
! 2901: if (err)
! 2902: return (err);
! 2903:
! 2904: tail->xfer = NULL;
! 2905: xfer->hcpriv = data;
! 2906:
! 2907: DPRINTFN(4,("ohci_device_bulk_start: ed_flags=0x%08x td_flags=0x%08x "
! 2908: "td_cbp=0x%08x td_be=0x%08x\n",
! 2909: (int)letoh32(sed->ed.ed_flags),
! 2910: (int)letoh32(data->td.td_flags),
! 2911: (int)letoh32(data->td.td_cbp),
! 2912: (int)letoh32(data->td.td_be)));
! 2913:
! 2914: #ifdef OHCI_DEBUG
! 2915: if (ohcidebug > 5) {
! 2916: ohci_dump_ed(sed);
! 2917: ohci_dump_tds(data);
! 2918: }
! 2919: #endif
! 2920:
! 2921: /* Insert ED in schedule */
! 2922: s = splusb();
! 2923: for (tdp = data; tdp != tail; tdp = tdp->nexttd) {
! 2924: tdp->xfer = xfer;
! 2925: }
! 2926: sed->ed.ed_tailp = htole32(tail->physaddr);
! 2927: opipe->tail.td = tail;
! 2928: sed->ed.ed_flags &= htole32(~OHCI_ED_SKIP);
! 2929: OWRITE4(sc, OHCI_COMMAND_STATUS, OHCI_BLF);
! 2930: if (xfer->timeout && !sc->sc_bus.use_polling) {
! 2931: timeout_del(&xfer->timeout_handle);
! 2932: timeout_set(&xfer->timeout_handle, ohci_timeout, xfer);
! 2933: timeout_add(&xfer->timeout_handle, mstohz(xfer->timeout));
! 2934: }
! 2935:
! 2936: #if 0
! 2937: /* This goes wrong if we are too slow. */
! 2938: if (ohcidebug > 10) {
! 2939: delay(10000);
! 2940: DPRINTF(("ohci_device_intr_transfer: status=%x\n",
! 2941: OREAD4(sc, OHCI_COMMAND_STATUS)));
! 2942: ohci_dump_ed(sed);
! 2943: ohci_dump_tds(data);
! 2944: }
! 2945: #endif
! 2946:
! 2947: splx(s);
! 2948:
! 2949: if (sc->sc_bus.use_polling)
! 2950: ohci_waitintr(sc, xfer);
! 2951:
! 2952: return (USBD_IN_PROGRESS);
! 2953: }
! 2954:
! 2955: void
! 2956: ohci_device_bulk_abort(usbd_xfer_handle xfer)
! 2957: {
! 2958: DPRINTF(("ohci_device_bulk_abort: xfer=%p\n", xfer));
! 2959: ohci_abort_xfer(xfer, USBD_CANCELLED);
! 2960: }
! 2961:
! 2962: /*
! 2963: * Close a device bulk pipe.
! 2964: */
! 2965: void
! 2966: ohci_device_bulk_close(usbd_pipe_handle pipe)
! 2967: {
! 2968: struct ohci_pipe *opipe = (struct ohci_pipe *)pipe;
! 2969: ohci_softc_t *sc = (ohci_softc_t *)pipe->device->bus;
! 2970:
! 2971: DPRINTF(("ohci_device_bulk_close: pipe=%p\n", pipe));
! 2972: ohci_close_pipe(pipe, sc->sc_bulk_head);
! 2973: ohci_free_std(sc, opipe->tail.td);
! 2974: }
! 2975:
! 2976: /************************/
! 2977:
! 2978: usbd_status
! 2979: ohci_device_intr_transfer(usbd_xfer_handle xfer)
! 2980: {
! 2981: usbd_status err;
! 2982:
! 2983: /* Insert last in queue. */
! 2984: err = usb_insert_transfer(xfer);
! 2985: if (err)
! 2986: return (err);
! 2987:
! 2988: /* Pipe isn't running, start first */
! 2989: return (ohci_device_intr_start(SIMPLEQ_FIRST(&xfer->pipe->queue)));
! 2990: }
! 2991:
! 2992: usbd_status
! 2993: ohci_device_intr_start(usbd_xfer_handle xfer)
! 2994: {
! 2995: struct ohci_pipe *opipe = (struct ohci_pipe *)xfer->pipe;
! 2996: usbd_device_handle dev = opipe->pipe.device;
! 2997: ohci_softc_t *sc = (ohci_softc_t *)dev->bus;
! 2998: ohci_soft_ed_t *sed = opipe->sed;
! 2999: ohci_soft_td_t *data, *tail;
! 3000: int s, len, isread, endpt;
! 3001:
! 3002: if (sc->sc_dying)
! 3003: return (USBD_IOERROR);
! 3004:
! 3005: DPRINTFN(3, ("ohci_device_intr_transfer: xfer=%p len=%d "
! 3006: "flags=%d priv=%p\n",
! 3007: xfer, xfer->length, xfer->flags, xfer->priv));
! 3008:
! 3009: #ifdef DIAGNOSTIC
! 3010: if (xfer->rqflags & URQ_REQUEST)
! 3011: panic("ohci_device_intr_transfer: a request");
! 3012: #endif
! 3013:
! 3014: len = xfer->length;
! 3015: endpt = xfer->pipe->endpoint->edesc->bEndpointAddress;
! 3016: isread = UE_GET_DIR(endpt) == UE_DIR_IN;
! 3017:
! 3018: data = opipe->tail.td;
! 3019: tail = ohci_alloc_std(sc);
! 3020: if (tail == NULL)
! 3021: return (USBD_NOMEM);
! 3022: tail->xfer = NULL;
! 3023:
! 3024: data->td.td_flags = htole32(
! 3025: isread ? OHCI_TD_IN : OHCI_TD_OUT |
! 3026: OHCI_TD_NOCC |
! 3027: OHCI_TD_SET_DI(1) | OHCI_TD_TOGGLE_CARRY);
! 3028: if (xfer->flags & USBD_SHORT_XFER_OK)
! 3029: data->td.td_flags |= htole32(OHCI_TD_R);
! 3030: data->td.td_cbp = htole32(DMAADDR(&xfer->dmabuf, 0));
! 3031: data->nexttd = tail;
! 3032: data->td.td_nexttd = htole32(tail->physaddr);
! 3033: data->td.td_be = htole32(letoh32(data->td.td_cbp) + len - 1);
! 3034: data->len = len;
! 3035: data->xfer = xfer;
! 3036: data->flags = OHCI_CALL_DONE | OHCI_ADD_LEN;
! 3037: xfer->hcpriv = data;
! 3038:
! 3039: #ifdef OHCI_DEBUG
! 3040: if (ohcidebug > 5) {
! 3041: DPRINTF(("ohci_device_intr_transfer:\n"));
! 3042: ohci_dump_ed(sed);
! 3043: ohci_dump_tds(data);
! 3044: }
! 3045: #endif
! 3046:
! 3047: /* Insert ED in schedule */
! 3048: s = splusb();
! 3049: sed->ed.ed_tailp = htole32(tail->physaddr);
! 3050: opipe->tail.td = tail;
! 3051: sed->ed.ed_flags &= htole32(~OHCI_ED_SKIP);
! 3052:
! 3053: #if 0
! 3054: /*
! 3055: * This goes horribly wrong, printing thousands of descriptors,
! 3056: * because false references are followed due to the fact that the
! 3057: * TD is gone.
! 3058: */
! 3059: if (ohcidebug > 5) {
! 3060: usb_delay_ms(&sc->sc_bus, 5);
! 3061: DPRINTF(("ohci_device_intr_transfer: status=%x\n",
! 3062: OREAD4(sc, OHCI_COMMAND_STATUS)));
! 3063: ohci_dump_ed(sed);
! 3064: ohci_dump_tds(data);
! 3065: }
! 3066: #endif
! 3067: splx(s);
! 3068:
! 3069: return (USBD_IN_PROGRESS);
! 3070: }
! 3071:
! 3072: /* Abort a device control request. */
! 3073: void
! 3074: ohci_device_intr_abort(usbd_xfer_handle xfer)
! 3075: {
! 3076: if (xfer->pipe->intrxfer == xfer) {
! 3077: DPRINTF(("ohci_device_intr_abort: remove\n"));
! 3078: xfer->pipe->intrxfer = NULL;
! 3079: }
! 3080: ohci_abort_xfer(xfer, USBD_CANCELLED);
! 3081: }
! 3082:
! 3083: /* Close a device interrupt pipe. */
! 3084: void
! 3085: ohci_device_intr_close(usbd_pipe_handle pipe)
! 3086: {
! 3087: struct ohci_pipe *opipe = (struct ohci_pipe *)pipe;
! 3088: ohci_softc_t *sc = (ohci_softc_t *)pipe->device->bus;
! 3089: int nslots = opipe->u.intr.nslots;
! 3090: int pos = opipe->u.intr.pos;
! 3091: int j;
! 3092: ohci_soft_ed_t *p, *sed = opipe->sed;
! 3093: int s;
! 3094:
! 3095: DPRINTFN(1,("ohci_device_intr_close: pipe=%p nslots=%d pos=%d\n",
! 3096: pipe, nslots, pos));
! 3097: s = splusb();
! 3098: sed->ed.ed_flags |= htole32(OHCI_ED_SKIP);
! 3099: if ((letoh32(sed->ed.ed_tailp) & OHCI_HEADMASK) !=
! 3100: (letoh32(sed->ed.ed_headp) & OHCI_HEADMASK))
! 3101: usb_delay_ms(&sc->sc_bus, 2);
! 3102:
! 3103: for (p = sc->sc_eds[pos]; p && p->next != sed; p = p->next)
! 3104: ;
! 3105: #ifdef DIAGNOSTIC
! 3106: if (p == NULL)
! 3107: panic("ohci_device_intr_close: ED not found");
! 3108: #endif
! 3109: p->next = sed->next;
! 3110: p->ed.ed_nexted = sed->ed.ed_nexted;
! 3111: splx(s);
! 3112:
! 3113: for (j = 0; j < nslots; j++)
! 3114: --sc->sc_bws[(pos * nslots + j) % OHCI_NO_INTRS];
! 3115:
! 3116: ohci_free_std(sc, opipe->tail.td);
! 3117: ohci_free_sed(sc, opipe->sed);
! 3118: }
! 3119:
! 3120: usbd_status
! 3121: ohci_device_setintr(ohci_softc_t *sc, struct ohci_pipe *opipe, int ival)
! 3122: {
! 3123: int i, j, s, best;
! 3124: u_int npoll, slow, shigh, nslots;
! 3125: u_int bestbw, bw;
! 3126: ohci_soft_ed_t *hsed, *sed = opipe->sed;
! 3127:
! 3128: DPRINTFN(2, ("ohci_setintr: pipe=%p\n", opipe));
! 3129: if (ival == 0) {
! 3130: printf("ohci_setintr: 0 interval\n");
! 3131: return (USBD_INVAL);
! 3132: }
! 3133:
! 3134: npoll = OHCI_NO_INTRS;
! 3135: while (npoll > ival)
! 3136: npoll /= 2;
! 3137: DPRINTFN(2, ("ohci_setintr: ival=%d npoll=%d\n", ival, npoll));
! 3138:
! 3139: /*
! 3140: * We now know which level in the tree the ED must go into.
! 3141: * Figure out which slot has most bandwidth left over.
! 3142: * Slots to examine:
! 3143: * npoll
! 3144: * 1 0
! 3145: * 2 1 2
! 3146: * 4 3 4 5 6
! 3147: * 8 7 8 9 10 11 12 13 14
! 3148: * N (N-1) .. (N-1+N-1)
! 3149: */
! 3150: slow = npoll-1;
! 3151: shigh = slow + npoll;
! 3152: nslots = OHCI_NO_INTRS / npoll;
! 3153: for (best = i = slow, bestbw = ~0; i < shigh; i++) {
! 3154: bw = 0;
! 3155: for (j = 0; j < nslots; j++)
! 3156: bw += sc->sc_bws[(i * nslots + j) % OHCI_NO_INTRS];
! 3157: if (bw < bestbw) {
! 3158: best = i;
! 3159: bestbw = bw;
! 3160: }
! 3161: }
! 3162: DPRINTFN(2, ("ohci_setintr: best=%d(%d..%d) bestbw=%d\n",
! 3163: best, slow, shigh, bestbw));
! 3164:
! 3165: s = splusb();
! 3166: hsed = sc->sc_eds[best];
! 3167: sed->next = hsed->next;
! 3168: sed->ed.ed_nexted = hsed->ed.ed_nexted;
! 3169: hsed->next = sed;
! 3170: hsed->ed.ed_nexted = htole32(sed->physaddr);
! 3171: splx(s);
! 3172:
! 3173: for (j = 0; j < nslots; j++)
! 3174: ++sc->sc_bws[(best * nslots + j) % OHCI_NO_INTRS];
! 3175: opipe->u.intr.nslots = nslots;
! 3176: opipe->u.intr.pos = best;
! 3177:
! 3178: DPRINTFN(5, ("ohci_setintr: returns %p\n", opipe));
! 3179: return (USBD_NORMAL_COMPLETION);
! 3180: }
! 3181:
! 3182: /***********************/
! 3183:
! 3184: usbd_status
! 3185: ohci_device_isoc_transfer(usbd_xfer_handle xfer)
! 3186: {
! 3187: usbd_status err;
! 3188:
! 3189: DPRINTFN(5,("ohci_device_isoc_transfer: xfer=%p\n", xfer));
! 3190:
! 3191: /* Put it on our queue, */
! 3192: err = usb_insert_transfer(xfer);
! 3193:
! 3194: /* bail out on error, */
! 3195: if (err && err != USBD_IN_PROGRESS)
! 3196: return (err);
! 3197:
! 3198: /* XXX should check inuse here */
! 3199:
! 3200: /* insert into schedule, */
! 3201: ohci_device_isoc_enter(xfer);
! 3202:
! 3203: /* and start if the pipe wasn't running */
! 3204: if (!err)
! 3205: ohci_device_isoc_start(SIMPLEQ_FIRST(&xfer->pipe->queue));
! 3206:
! 3207: return (err);
! 3208: }
! 3209:
! 3210: void
! 3211: ohci_device_isoc_enter(usbd_xfer_handle xfer)
! 3212: {
! 3213: struct ohci_pipe *opipe = (struct ohci_pipe *)xfer->pipe;
! 3214: usbd_device_handle dev = opipe->pipe.device;
! 3215: ohci_softc_t *sc = (ohci_softc_t *)dev->bus;
! 3216: ohci_soft_ed_t *sed = opipe->sed;
! 3217: struct iso *iso = &opipe->u.iso;
! 3218: ohci_soft_itd_t *sitd, *nsitd;
! 3219: ohci_physaddr_t buf, offs, noffs, bp0;
! 3220: int i, ncur, nframes;
! 3221: int s;
! 3222:
! 3223: DPRINTFN(1,("ohci_device_isoc_enter: used=%d next=%d xfer=%p "
! 3224: "nframes=%d\n",
! 3225: iso->inuse, iso->next, xfer, xfer->nframes));
! 3226:
! 3227: if (sc->sc_dying)
! 3228: return;
! 3229:
! 3230: if (iso->next == -1) {
! 3231: /* Not in use yet, schedule it a few frames ahead. */
! 3232: iso->next = letoh32(sc->sc_hcca->hcca_frame_number) + 5;
! 3233: DPRINTFN(2,("ohci_device_isoc_enter: start next=%d\n",
! 3234: iso->next));
! 3235: }
! 3236:
! 3237: sitd = opipe->tail.itd;
! 3238: buf = DMAADDR(&xfer->dmabuf, 0);
! 3239: bp0 = OHCI_PAGE(buf);
! 3240: offs = OHCI_PAGE_OFFSET(buf);
! 3241: nframes = xfer->nframes;
! 3242: xfer->hcpriv = sitd;
! 3243: for (i = ncur = 0; i < nframes; i++, ncur++) {
! 3244: noffs = offs + xfer->frlengths[i];
! 3245: if (ncur == OHCI_ITD_NOFFSET || /* all offsets used */
! 3246: OHCI_PAGE(buf + noffs) > bp0 + OHCI_PAGE_SIZE) { /* too many page crossings */
! 3247:
! 3248: /* Allocate next ITD */
! 3249: nsitd = ohci_alloc_sitd(sc);
! 3250: if (nsitd == NULL) {
! 3251: /* XXX what now? */
! 3252: printf("%s: isoc TD alloc failed\n",
! 3253: sc->sc_bus.bdev.dv_xname);
! 3254: return;
! 3255: }
! 3256:
! 3257: /* Fill current ITD */
! 3258: sitd->itd.itd_flags = htole32(
! 3259: OHCI_ITD_NOCC |
! 3260: OHCI_ITD_SET_SF(iso->next) |
! 3261: OHCI_ITD_SET_DI(6) | /* delay intr a little */
! 3262: OHCI_ITD_SET_FC(ncur));
! 3263: sitd->itd.itd_bp0 = htole32(bp0);
! 3264: sitd->nextitd = nsitd;
! 3265: sitd->itd.itd_nextitd = htole32(nsitd->physaddr);
! 3266: sitd->itd.itd_be = htole32(bp0 + offs - 1);
! 3267: sitd->xfer = xfer;
! 3268: sitd->flags = 0;
! 3269:
! 3270: sitd = nsitd;
! 3271: iso->next = iso->next + ncur;
! 3272: bp0 = OHCI_PAGE(buf + offs);
! 3273: ncur = 0;
! 3274: }
! 3275: sitd->itd.itd_offset[ncur] = htole16(OHCI_ITD_MK_OFFS(offs));
! 3276: offs = noffs;
! 3277: }
! 3278: nsitd = ohci_alloc_sitd(sc);
! 3279: if (nsitd == NULL) {
! 3280: /* XXX what now? */
! 3281: printf("%s: isoc TD alloc failed\n",
! 3282: sc->sc_bus.bdev.dv_xname);
! 3283: return;
! 3284: }
! 3285: /* Fixup last used ITD */
! 3286: sitd->itd.itd_flags = htole32(
! 3287: OHCI_ITD_NOCC |
! 3288: OHCI_ITD_SET_SF(iso->next) |
! 3289: OHCI_ITD_SET_DI(0) |
! 3290: OHCI_ITD_SET_FC(ncur));
! 3291: sitd->itd.itd_bp0 = htole32(bp0);
! 3292: sitd->nextitd = nsitd;
! 3293: sitd->itd.itd_nextitd = htole32(nsitd->physaddr);
! 3294: sitd->itd.itd_be = htole32(bp0 + offs - 1);
! 3295: sitd->xfer = xfer;
! 3296: sitd->flags = OHCI_CALL_DONE;
! 3297:
! 3298: iso->next = iso->next + ncur;
! 3299: iso->inuse += nframes;
! 3300:
! 3301: xfer->actlen = offs; /* XXX pretend we did it all */
! 3302:
! 3303: xfer->status = USBD_IN_PROGRESS;
! 3304:
! 3305: #ifdef OHCI_DEBUG
! 3306: if (ohcidebug > 5) {
! 3307: DPRINTF(("ohci_device_isoc_enter: frame=%d\n",
! 3308: letoh32(sc->sc_hcca->hcca_frame_number)));
! 3309: ohci_dump_itds(xfer->hcpriv);
! 3310: ohci_dump_ed(sed);
! 3311: }
! 3312: #endif
! 3313:
! 3314: s = splusb();
! 3315: sed->ed.ed_tailp = htole32(nsitd->physaddr);
! 3316: opipe->tail.itd = nsitd;
! 3317: sed->ed.ed_flags &= htole32(~OHCI_ED_SKIP);
! 3318: splx(s);
! 3319:
! 3320: #ifdef OHCI_DEBUG
! 3321: if (ohcidebug > 5) {
! 3322: delay(150000);
! 3323: DPRINTF(("ohci_device_isoc_enter: after frame=%d\n",
! 3324: letoh32(sc->sc_hcca->hcca_frame_number)));
! 3325: ohci_dump_itds(xfer->hcpriv);
! 3326: ohci_dump_ed(sed);
! 3327: }
! 3328: #endif
! 3329: }
! 3330:
! 3331: usbd_status
! 3332: ohci_device_isoc_start(usbd_xfer_handle xfer)
! 3333: {
! 3334: struct ohci_pipe *opipe = (struct ohci_pipe *)xfer->pipe;
! 3335: ohci_softc_t *sc = (ohci_softc_t *)opipe->pipe.device->bus;
! 3336:
! 3337: DPRINTFN(5,("ohci_device_isoc_start: xfer=%p\n", xfer));
! 3338:
! 3339: if (sc->sc_dying)
! 3340: return (USBD_IOERROR);
! 3341:
! 3342: #ifdef DIAGNOSTIC
! 3343: if (xfer->status != USBD_IN_PROGRESS)
! 3344: printf("ohci_device_isoc_start: not in progress %p\n", xfer);
! 3345: #endif
! 3346:
! 3347: /* XXX anything to do? */
! 3348:
! 3349: return (USBD_IN_PROGRESS);
! 3350: }
! 3351:
! 3352: void
! 3353: ohci_device_isoc_abort(usbd_xfer_handle xfer)
! 3354: {
! 3355: struct ohci_pipe *opipe = (struct ohci_pipe *)xfer->pipe;
! 3356: ohci_softc_t *sc = (ohci_softc_t *)opipe->pipe.device->bus;
! 3357: ohci_soft_ed_t *sed;
! 3358: ohci_soft_itd_t *sitd;
! 3359: int s;
! 3360:
! 3361: s = splusb();
! 3362:
! 3363: DPRINTFN(1,("ohci_device_isoc_abort: xfer=%p\n", xfer));
! 3364:
! 3365: /* Transfer is already done. */
! 3366: if (xfer->status != USBD_NOT_STARTED &&
! 3367: xfer->status != USBD_IN_PROGRESS) {
! 3368: splx(s);
! 3369: printf("ohci_device_isoc_abort: early return\n");
! 3370: return;
! 3371: }
! 3372:
! 3373: /* Give xfer the requested abort code. */
! 3374: xfer->status = USBD_CANCELLED;
! 3375:
! 3376: sed = opipe->sed;
! 3377: sed->ed.ed_flags |= htole32(OHCI_ED_SKIP); /* force hardware skip */
! 3378:
! 3379: sitd = xfer->hcpriv;
! 3380: #ifdef DIAGNOSTIC
! 3381: if (sitd == NULL) {
! 3382: splx(s);
! 3383: printf("ohci_device_isoc_abort: hcpriv==0\n");
! 3384: return;
! 3385: }
! 3386: #endif
! 3387: for (; sitd->xfer == xfer; sitd = sitd->nextitd) {
! 3388: #ifdef DIAGNOSTIC
! 3389: DPRINTFN(1,("abort sets done sitd=%p\n", sitd));
! 3390: sitd->isdone = 1;
! 3391: #endif
! 3392: }
! 3393:
! 3394: splx(s);
! 3395:
! 3396: usb_delay_ms(&sc->sc_bus, OHCI_ITD_NOFFSET);
! 3397:
! 3398: s = splusb();
! 3399:
! 3400: /* Run callback. */
! 3401: usb_transfer_complete(xfer);
! 3402:
! 3403: sed->ed.ed_headp = htole32(sitd->physaddr); /* unlink TDs */
! 3404: sed->ed.ed_flags &= htole32(~OHCI_ED_SKIP); /* remove hardware skip */
! 3405:
! 3406: splx(s);
! 3407: }
! 3408:
! 3409: void
! 3410: ohci_device_isoc_done(usbd_xfer_handle xfer)
! 3411: {
! 3412: DPRINTFN(1,("ohci_device_isoc_done: xfer=%p\n", xfer));
! 3413: }
! 3414:
! 3415: usbd_status
! 3416: ohci_setup_isoc(usbd_pipe_handle pipe)
! 3417: {
! 3418: struct ohci_pipe *opipe = (struct ohci_pipe *)pipe;
! 3419: ohci_softc_t *sc = (ohci_softc_t *)pipe->device->bus;
! 3420: struct iso *iso = &opipe->u.iso;
! 3421: int s;
! 3422:
! 3423: iso->next = -1;
! 3424: iso->inuse = 0;
! 3425:
! 3426: s = splusb();
! 3427: ohci_add_ed(opipe->sed, sc->sc_isoc_head);
! 3428: splx(s);
! 3429:
! 3430: return (USBD_NORMAL_COMPLETION);
! 3431: }
! 3432:
! 3433: void
! 3434: ohci_device_isoc_close(usbd_pipe_handle pipe)
! 3435: {
! 3436: struct ohci_pipe *opipe = (struct ohci_pipe *)pipe;
! 3437: ohci_softc_t *sc = (ohci_softc_t *)pipe->device->bus;
! 3438:
! 3439: DPRINTF(("ohci_device_isoc_close: pipe=%p\n", pipe));
! 3440: ohci_close_pipe(pipe, sc->sc_isoc_head);
! 3441: #ifdef DIAGNOSTIC
! 3442: opipe->tail.itd->isdone = 1;
! 3443: #endif
! 3444: ohci_free_sitd(sc, opipe->tail.itd);
! 3445: }
CVSweb