1246122Shselasky/* $FreeBSD$ */ 2184610Salfred/*- 3184610Salfred * Copyright (c) 2008 Hans Petter Selasky. All rights reserved. 4184610Salfred * Copyright (c) 1998 The NetBSD Foundation, Inc. All rights reserved. 5184610Salfred * Copyright (c) 1998 Lennart Augustsson. All rights reserved. 6184610Salfred * 7184610Salfred * Redistribution and use in source and binary forms, with or without 8184610Salfred * modification, are permitted provided that the following conditions 9184610Salfred * are met: 10184610Salfred * 1. Redistributions of source code must retain the above copyright 11184610Salfred * notice, this list of conditions and the following disclaimer. 12184610Salfred * 2. Redistributions in binary form must reproduce the above copyright 13184610Salfred * notice, this list of conditions and the following disclaimer in the 14184610Salfred * documentation and/or other materials provided with the distribution. 15184610Salfred * 16184610Salfred * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 17184610Salfred * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 18184610Salfred * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 19184610Salfred * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 20184610Salfred * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 21184610Salfred * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 22184610Salfred * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 23184610Salfred * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 24184610Salfred * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 25184610Salfred * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 26184610Salfred * SUCH DAMAGE. 27184610Salfred */ 28184610Salfred 29184610Salfred/* 30184610Salfred * USB Open Host Controller driver. 31184610Salfred * 32184610Salfred * OHCI spec: http://www.compaq.com/productinfo/development/openhci.html 33190754Sthompsa * USB spec: http://www.usb.org/developers/docs/usbspec.zip 34184610Salfred */ 35184610Salfred 36246122Shselasky#ifdef USB_GLOBAL_INCLUDE_FILE 37246122Shselasky#include USB_GLOBAL_INCLUDE_FILE 38246122Shselasky#else 39194677Sthompsa#include <sys/stdint.h> 40194677Sthompsa#include <sys/stddef.h> 41194677Sthompsa#include <sys/param.h> 42194677Sthompsa#include <sys/queue.h> 43194677Sthompsa#include <sys/types.h> 44194677Sthompsa#include <sys/systm.h> 45194677Sthompsa#include <sys/kernel.h> 46194677Sthompsa#include <sys/bus.h> 47194677Sthompsa#include <sys/module.h> 48194677Sthompsa#include <sys/lock.h> 49194677Sthompsa#include <sys/mutex.h> 50194677Sthompsa#include <sys/condvar.h> 51194677Sthompsa#include <sys/sysctl.h> 52194677Sthompsa#include <sys/sx.h> 53194677Sthompsa#include <sys/unistd.h> 54194677Sthompsa#include <sys/callout.h> 55194677Sthompsa#include <sys/malloc.h> 56194677Sthompsa#include <sys/priv.h> 57194677Sthompsa 58188942Sthompsa#include <dev/usb/usb.h> 59194677Sthompsa#include <dev/usb/usbdi.h> 60184610Salfred 61184610Salfred#define USB_DEBUG_VAR ohcidebug 62184610Salfred 63188942Sthompsa#include <dev/usb/usb_core.h> 64188942Sthompsa#include <dev/usb/usb_debug.h> 65188942Sthompsa#include <dev/usb/usb_busdma.h> 66188942Sthompsa#include <dev/usb/usb_process.h> 67188942Sthompsa#include <dev/usb/usb_transfer.h> 68188942Sthompsa#include <dev/usb/usb_device.h> 69188942Sthompsa#include <dev/usb/usb_hub.h> 70188942Sthompsa#include <dev/usb/usb_util.h> 71184610Salfred 72188942Sthompsa#include <dev/usb/usb_controller.h> 73188942Sthompsa#include <dev/usb/usb_bus.h> 74246122Shselasky#endif /* USB_GLOBAL_INCLUDE_FILE */ 75246122Shselasky 76188942Sthompsa#include <dev/usb/controller/ohci.h> 77198151Sthompsa#include <dev/usb/controller/ohcireg.h> 78184610Salfred 79190181Sthompsa#define OHCI_BUS2SC(bus) \ 80190181Sthompsa ((ohci_softc_t *)(((uint8_t *)(bus)) - \ 81190181Sthompsa ((uint8_t *)&(((ohci_softc_t *)0)->sc_bus)))) 82184610Salfred 83194677Sthompsa#ifdef USB_DEBUG 84184610Salfredstatic int ohcidebug = 0; 85184610Salfred 86227309Sedstatic SYSCTL_NODE(_hw_usb, OID_AUTO, ohci, CTLFLAG_RW, 0, "USB ohci"); 87242126ShselaskySYSCTL_INT(_hw_usb_ohci, OID_AUTO, debug, CTLFLAG_RW | CTLFLAG_TUN, 88184610Salfred &ohcidebug, 0, "ohci debug level"); 89199675SthompsaTUNABLE_INT("hw.usb.ohci.debug", &ohcidebug); 90199675Sthompsa 91184610Salfredstatic void ohci_dumpregs(ohci_softc_t *); 92184610Salfredstatic void ohci_dump_tds(ohci_td_t *); 93184610Salfredstatic uint8_t ohci_dump_td(ohci_td_t *); 94184610Salfredstatic void ohci_dump_ed(ohci_ed_t *); 95184610Salfredstatic uint8_t ohci_dump_itd(ohci_itd_t *); 96184610Salfredstatic void ohci_dump_itds(ohci_itd_t *); 97184610Salfred 98184610Salfred#endif 99184610Salfred 100184610Salfred#define OBARR(sc) bus_space_barrier((sc)->sc_io_tag, (sc)->sc_io_hdl, 0, (sc)->sc_io_size, \ 101184610Salfred BUS_SPACE_BARRIER_READ|BUS_SPACE_BARRIER_WRITE) 102184610Salfred#define OWRITE1(sc, r, x) \ 103184610Salfred do { OBARR(sc); bus_space_write_1((sc)->sc_io_tag, (sc)->sc_io_hdl, (r), (x)); } while (0) 104184610Salfred#define OWRITE2(sc, r, x) \ 105184610Salfred do { OBARR(sc); bus_space_write_2((sc)->sc_io_tag, (sc)->sc_io_hdl, (r), (x)); } while (0) 106184610Salfred#define OWRITE4(sc, r, x) \ 107184610Salfred do { OBARR(sc); bus_space_write_4((sc)->sc_io_tag, (sc)->sc_io_hdl, (r), (x)); } while (0) 108184610Salfred#define OREAD1(sc, r) (OBARR(sc), bus_space_read_1((sc)->sc_io_tag, (sc)->sc_io_hdl, (r))) 109184610Salfred#define OREAD2(sc, r) (OBARR(sc), bus_space_read_2((sc)->sc_io_tag, (sc)->sc_io_hdl, (r))) 110184610Salfred#define OREAD4(sc, r) (OBARR(sc), bus_space_read_4((sc)->sc_io_tag, (sc)->sc_io_hdl, (r))) 111184610Salfred 112184610Salfred#define OHCI_INTR_ENDPT 1 113184610Salfred 114192984Sthompsaextern struct usb_bus_methods ohci_bus_methods; 115192984Sthompsaextern struct usb_pipe_methods ohci_device_bulk_methods; 116192984Sthompsaextern struct usb_pipe_methods ohci_device_ctrl_methods; 117192984Sthompsaextern struct usb_pipe_methods ohci_device_intr_methods; 118192984Sthompsaextern struct usb_pipe_methods ohci_device_isoc_methods; 119184610Salfred 120192984Sthompsastatic void ohci_do_poll(struct usb_bus *bus); 121193045Sthompsastatic void ohci_device_done(struct usb_xfer *xfer, usb_error_t error); 122184610Salfredstatic void ohci_timeout(void *arg); 123192984Sthompsastatic uint8_t ohci_check_transfer(struct usb_xfer *xfer); 124190735Sthompsastatic void ohci_root_intr(ohci_softc_t *sc); 125184610Salfred 126184610Salfredstruct ohci_std_temp { 127192984Sthompsa struct usb_page_cache *pc; 128184610Salfred ohci_td_t *td; 129184610Salfred ohci_td_t *td_next; 130184610Salfred uint32_t average; 131184610Salfred uint32_t td_flags; 132184610Salfred uint32_t len; 133184610Salfred uint16_t max_frame_size; 134184610Salfred uint8_t shortpkt; 135184610Salfred uint8_t setup_alt_next; 136190183Sthompsa uint8_t last_frame; 137184610Salfred}; 138184610Salfred 139184610Salfredstatic struct ohci_hcca * 140184610Salfredohci_get_hcca(ohci_softc_t *sc) 141184610Salfred{ 142194228Sthompsa usb_pc_cpu_invalidate(&sc->sc_hw.hcca_pc); 143184610Salfred return (sc->sc_hcca_p); 144184610Salfred} 145184610Salfred 146184610Salfredvoid 147193045Sthompsaohci_iterate_hw_softc(struct usb_bus *bus, usb_bus_mem_sub_cb_t *cb) 148184610Salfred{ 149184610Salfred struct ohci_softc *sc = OHCI_BUS2SC(bus); 150184610Salfred uint32_t i; 151184610Salfred 152184610Salfred cb(bus, &sc->sc_hw.hcca_pc, &sc->sc_hw.hcca_pg, 153184610Salfred sizeof(ohci_hcca_t), OHCI_HCCA_ALIGN); 154184610Salfred 155184610Salfred cb(bus, &sc->sc_hw.ctrl_start_pc, &sc->sc_hw.ctrl_start_pg, 156184610Salfred sizeof(ohci_ed_t), OHCI_ED_ALIGN); 157184610Salfred 158184610Salfred cb(bus, &sc->sc_hw.bulk_start_pc, &sc->sc_hw.bulk_start_pg, 159184610Salfred sizeof(ohci_ed_t), OHCI_ED_ALIGN); 160184610Salfred 161184610Salfred cb(bus, &sc->sc_hw.isoc_start_pc, &sc->sc_hw.isoc_start_pg, 162184610Salfred sizeof(ohci_ed_t), OHCI_ED_ALIGN); 163184610Salfred 164184610Salfred for (i = 0; i != OHCI_NO_EDS; i++) { 165184610Salfred cb(bus, sc->sc_hw.intr_start_pc + i, sc->sc_hw.intr_start_pg + i, 166184610Salfred sizeof(ohci_ed_t), OHCI_ED_ALIGN); 167184610Salfred } 168184610Salfred} 169184610Salfred 170193045Sthompsastatic usb_error_t 171228483Shselaskyohci_controller_init(ohci_softc_t *sc, int do_suspend) 172184610Salfred{ 173192984Sthompsa struct usb_page_search buf_res; 174184610Salfred uint32_t i; 175184610Salfred uint32_t ctl; 176184610Salfred uint32_t ival; 177184610Salfred uint32_t hcr; 178184610Salfred uint32_t fm; 179184610Salfred uint32_t per; 180184610Salfred uint32_t desca; 181184610Salfred 182198501Sthompsa /* Determine in what context we are running. */ 183198501Sthompsa ctl = OREAD4(sc, OHCI_CONTROL); 184198501Sthompsa if (ctl & OHCI_IR) { 185198501Sthompsa /* SMM active, request change */ 186198501Sthompsa DPRINTF("SMM active, request owner change\n"); 187198501Sthompsa OWRITE4(sc, OHCI_COMMAND_STATUS, OHCI_OCR); 188198501Sthompsa for (i = 0; (i < 100) && (ctl & OHCI_IR); i++) { 189198501Sthompsa usb_pause_mtx(NULL, hz / 1000); 190198501Sthompsa ctl = OREAD4(sc, OHCI_CONTROL); 191198501Sthompsa } 192198501Sthompsa if (ctl & OHCI_IR) { 193198501Sthompsa device_printf(sc->sc_bus.bdev, 194198501Sthompsa "SMM does not respond, resetting\n"); 195198501Sthompsa OWRITE4(sc, OHCI_CONTROL, OHCI_HCFS_RESET); 196198501Sthompsa goto reset; 197198501Sthompsa } 198198501Sthompsa } else { 199198501Sthompsa DPRINTF("cold started\n"); 200198501Sthompsareset: 201198501Sthompsa /* controller was cold started */ 202198501Sthompsa usb_pause_mtx(NULL, 203198501Sthompsa USB_MS_TO_TICKS(USB_BUS_RESET_DELAY)); 204198501Sthompsa } 205198501Sthompsa 206184610Salfred /* 207184610Salfred * This reset should not be necessary according to the OHCI spec, but 208184610Salfred * without it some controllers do not start. 209184610Salfred */ 210184610Salfred DPRINTF("%s: resetting\n", device_get_nameunit(sc->sc_bus.bdev)); 211184610Salfred OWRITE4(sc, OHCI_CONTROL, OHCI_HCFS_RESET); 212184610Salfred 213194228Sthompsa usb_pause_mtx(NULL, 214188409Sthompsa USB_MS_TO_TICKS(USB_BUS_RESET_DELAY)); 215184610Salfred 216184610Salfred /* we now own the host controller and the bus has been reset */ 217184610Salfred ival = OHCI_GET_IVAL(OREAD4(sc, OHCI_FM_INTERVAL)); 218184610Salfred 219184610Salfred OWRITE4(sc, OHCI_COMMAND_STATUS, OHCI_HCR); /* Reset HC */ 220184610Salfred /* nominal time for a reset is 10 us */ 221184610Salfred for (i = 0; i < 10; i++) { 222184610Salfred DELAY(10); 223184610Salfred hcr = OREAD4(sc, OHCI_COMMAND_STATUS) & OHCI_HCR; 224184610Salfred if (!hcr) { 225184610Salfred break; 226184610Salfred } 227184610Salfred } 228184610Salfred if (hcr) { 229184610Salfred device_printf(sc->sc_bus.bdev, "reset timeout\n"); 230184610Salfred return (USB_ERR_IOERROR); 231184610Salfred } 232194677Sthompsa#ifdef USB_DEBUG 233184610Salfred if (ohcidebug > 15) { 234184610Salfred ohci_dumpregs(sc); 235184610Salfred } 236184610Salfred#endif 237184610Salfred 238228483Shselasky if (do_suspend) { 239228483Shselasky OWRITE4(sc, OHCI_CONTROL, OHCI_HCFS_SUSPEND); 240228483Shselasky return (USB_ERR_NORMAL_COMPLETION); 241228483Shselasky } 242228483Shselasky 243184610Salfred /* The controller is now in SUSPEND state, we have 2ms to finish. */ 244184610Salfred 245184610Salfred /* set up HC registers */ 246194228Sthompsa usbd_get_page(&sc->sc_hw.hcca_pc, 0, &buf_res); 247184610Salfred OWRITE4(sc, OHCI_HCCA, buf_res.physaddr); 248184610Salfred 249194228Sthompsa usbd_get_page(&sc->sc_hw.ctrl_start_pc, 0, &buf_res); 250184610Salfred OWRITE4(sc, OHCI_CONTROL_HEAD_ED, buf_res.physaddr); 251184610Salfred 252194228Sthompsa usbd_get_page(&sc->sc_hw.bulk_start_pc, 0, &buf_res); 253184610Salfred OWRITE4(sc, OHCI_BULK_HEAD_ED, buf_res.physaddr); 254184610Salfred 255184610Salfred /* disable all interrupts and then switch on all desired interrupts */ 256184610Salfred OWRITE4(sc, OHCI_INTERRUPT_DISABLE, OHCI_ALL_INTRS); 257184610Salfred OWRITE4(sc, OHCI_INTERRUPT_ENABLE, sc->sc_eintrs | OHCI_MIE); 258184610Salfred /* switch on desired functional features */ 259184610Salfred ctl = OREAD4(sc, OHCI_CONTROL); 260184610Salfred ctl &= ~(OHCI_CBSR_MASK | OHCI_LES | OHCI_HCFS_MASK | OHCI_IR); 261184610Salfred ctl |= OHCI_PLE | OHCI_IE | OHCI_CLE | OHCI_BLE | 262184610Salfred OHCI_RATIO_1_4 | OHCI_HCFS_OPERATIONAL; 263184610Salfred /* And finally start it! */ 264184610Salfred OWRITE4(sc, OHCI_CONTROL, ctl); 265184610Salfred 266184610Salfred /* 267184610Salfred * The controller is now OPERATIONAL. Set a some final 268184610Salfred * registers that should be set earlier, but that the 269184610Salfred * controller ignores when in the SUSPEND state. 270184610Salfred */ 271184610Salfred fm = (OREAD4(sc, OHCI_FM_INTERVAL) & OHCI_FIT) ^ OHCI_FIT; 272184610Salfred fm |= OHCI_FSMPS(ival) | ival; 273184610Salfred OWRITE4(sc, OHCI_FM_INTERVAL, fm); 274184610Salfred per = OHCI_PERIODIC(ival); /* 90% periodic */ 275184610Salfred OWRITE4(sc, OHCI_PERIODIC_START, per); 276184610Salfred 277184610Salfred /* Fiddle the No OverCurrent Protection bit to avoid chip bug. */ 278184610Salfred desca = OREAD4(sc, OHCI_RH_DESCRIPTOR_A); 279184610Salfred OWRITE4(sc, OHCI_RH_DESCRIPTOR_A, desca | OHCI_NOCP); 280184610Salfred OWRITE4(sc, OHCI_RH_STATUS, OHCI_LPSC); /* Enable port power */ 281194228Sthompsa usb_pause_mtx(NULL, 282188409Sthompsa USB_MS_TO_TICKS(OHCI_ENABLE_POWER_DELAY)); 283184610Salfred OWRITE4(sc, OHCI_RH_DESCRIPTOR_A, desca); 284184610Salfred 285184610Salfred /* 286184610Salfred * The AMD756 requires a delay before re-reading the register, 287184610Salfred * otherwise it will occasionally report 0 ports. 288184610Salfred */ 289184610Salfred sc->sc_noport = 0; 290184610Salfred for (i = 0; (i < 10) && (sc->sc_noport == 0); i++) { 291194228Sthompsa usb_pause_mtx(NULL, 292188409Sthompsa USB_MS_TO_TICKS(OHCI_READ_DESC_DELAY)); 293184610Salfred sc->sc_noport = OHCI_GET_NDP(OREAD4(sc, OHCI_RH_DESCRIPTOR_A)); 294184610Salfred } 295184610Salfred 296194677Sthompsa#ifdef USB_DEBUG 297184610Salfred if (ohcidebug > 5) { 298184610Salfred ohci_dumpregs(sc); 299184610Salfred } 300184610Salfred#endif 301184610Salfred return (USB_ERR_NORMAL_COMPLETION); 302184610Salfred} 303184610Salfred 304184610Salfredstatic struct ohci_ed * 305192984Sthompsaohci_init_ed(struct usb_page_cache *pc) 306184610Salfred{ 307192984Sthompsa struct usb_page_search buf_res; 308184610Salfred struct ohci_ed *ed; 309184610Salfred 310194228Sthompsa usbd_get_page(pc, 0, &buf_res); 311184610Salfred 312184610Salfred ed = buf_res.buffer; 313184610Salfred 314184610Salfred ed->ed_self = htole32(buf_res.physaddr); 315184610Salfred ed->ed_flags = htole32(OHCI_ED_SKIP); 316184610Salfred ed->page_cache = pc; 317184610Salfred 318184610Salfred return (ed); 319184610Salfred} 320184610Salfred 321193045Sthompsausb_error_t 322184610Salfredohci_init(ohci_softc_t *sc) 323184610Salfred{ 324192984Sthompsa struct usb_page_search buf_res; 325184610Salfred uint16_t i; 326184610Salfred uint16_t bit; 327184610Salfred uint16_t x; 328184610Salfred uint16_t y; 329184610Salfred 330184610Salfred DPRINTF("start\n"); 331184610Salfred 332184610Salfred sc->sc_eintrs = OHCI_NORMAL_INTRS; 333184610Salfred 334184610Salfred /* 335184610Salfred * Setup all ED's 336184610Salfred */ 337184610Salfred 338184610Salfred sc->sc_ctrl_p_last = 339184610Salfred ohci_init_ed(&sc->sc_hw.ctrl_start_pc); 340184610Salfred 341184610Salfred sc->sc_bulk_p_last = 342184610Salfred ohci_init_ed(&sc->sc_hw.bulk_start_pc); 343184610Salfred 344184610Salfred sc->sc_isoc_p_last = 345184610Salfred ohci_init_ed(&sc->sc_hw.isoc_start_pc); 346184610Salfred 347184610Salfred for (i = 0; i != OHCI_NO_EDS; i++) { 348184610Salfred sc->sc_intr_p_last[i] = 349184610Salfred ohci_init_ed(sc->sc_hw.intr_start_pc + i); 350184610Salfred } 351184610Salfred 352184610Salfred /* 353184610Salfred * the QHs are arranged to give poll intervals that are 354184610Salfred * powers of 2 times 1ms 355184610Salfred */ 356184610Salfred bit = OHCI_NO_EDS / 2; 357184610Salfred while (bit) { 358184610Salfred x = bit; 359184610Salfred while (x & bit) { 360184610Salfred ohci_ed_t *ed_x; 361184610Salfred ohci_ed_t *ed_y; 362184610Salfred 363184610Salfred y = (x ^ bit) | (bit / 2); 364184610Salfred 365184610Salfred /* 366184610Salfred * the next QH has half the poll interval 367184610Salfred */ 368184610Salfred ed_x = sc->sc_intr_p_last[x]; 369184610Salfred ed_y = sc->sc_intr_p_last[y]; 370184610Salfred 371184610Salfred ed_x->next = NULL; 372184610Salfred ed_x->ed_next = ed_y->ed_self; 373184610Salfred 374184610Salfred x++; 375184610Salfred } 376184610Salfred bit >>= 1; 377184610Salfred } 378184610Salfred 379184610Salfred if (1) { 380184610Salfred 381184610Salfred ohci_ed_t *ed_int; 382184610Salfred ohci_ed_t *ed_isc; 383184610Salfred 384184610Salfred ed_int = sc->sc_intr_p_last[0]; 385184610Salfred ed_isc = sc->sc_isoc_p_last; 386184610Salfred 387184610Salfred /* the last (1ms) QH */ 388184610Salfred ed_int->next = ed_isc; 389184610Salfred ed_int->ed_next = ed_isc->ed_self; 390184610Salfred } 391194228Sthompsa usbd_get_page(&sc->sc_hw.hcca_pc, 0, &buf_res); 392184610Salfred 393184610Salfred sc->sc_hcca_p = buf_res.buffer; 394184610Salfred 395184610Salfred /* 396184610Salfred * Fill HCCA interrupt table. The bit reversal is to get 397184610Salfred * the tree set up properly to spread the interrupts. 398184610Salfred */ 399184610Salfred for (i = 0; i != OHCI_NO_INTRS; i++) { 400184610Salfred sc->sc_hcca_p->hcca_interrupt_table[i] = 401184610Salfred sc->sc_intr_p_last[i | (OHCI_NO_EDS / 2)]->ed_self; 402184610Salfred } 403184610Salfred /* flush all cache into memory */ 404184610Salfred 405194228Sthompsa usb_bus_mem_flush_all(&sc->sc_bus, &ohci_iterate_hw_softc); 406184610Salfred 407184610Salfred /* set up the bus struct */ 408184610Salfred sc->sc_bus.methods = &ohci_bus_methods; 409184610Salfred 410194228Sthompsa usb_callout_init_mtx(&sc->sc_tmo_rhsc, &sc->sc_bus.bus_mtx, 0); 411184610Salfred 412194677Sthompsa#ifdef USB_DEBUG 413184610Salfred if (ohcidebug > 15) { 414184610Salfred for (i = 0; i != OHCI_NO_EDS; i++) { 415184610Salfred printf("ed#%d ", i); 416184610Salfred ohci_dump_ed(sc->sc_intr_p_last[i]); 417184610Salfred } 418184610Salfred printf("iso "); 419184610Salfred ohci_dump_ed(sc->sc_isoc_p_last); 420184610Salfred } 421184610Salfred#endif 422184610Salfred 423184610Salfred sc->sc_bus.usbrev = USB_REV_1_0; 424184610Salfred 425228483Shselasky if (ohci_controller_init(sc, 0) != 0) 426184610Salfred return (USB_ERR_INVAL); 427228483Shselasky 428228483Shselasky /* catch any lost interrupts */ 429228483Shselasky ohci_do_poll(&sc->sc_bus); 430228483Shselasky return (USB_ERR_NORMAL_COMPLETION); 431184610Salfred} 432184610Salfred 433184610Salfred/* 434184610Salfred * shut down the controller when the system is going down 435184610Salfred */ 436184610Salfredvoid 437184610Salfredohci_detach(struct ohci_softc *sc) 438184610Salfred{ 439184824Sthompsa USB_BUS_LOCK(&sc->sc_bus); 440184610Salfred 441194228Sthompsa usb_callout_stop(&sc->sc_tmo_rhsc); 442184610Salfred 443184610Salfred OWRITE4(sc, OHCI_INTERRUPT_DISABLE, OHCI_ALL_INTRS); 444184610Salfred OWRITE4(sc, OHCI_CONTROL, OHCI_HCFS_RESET); 445184610Salfred 446188409Sthompsa USB_BUS_UNLOCK(&sc->sc_bus); 447188409Sthompsa 448184610Salfred /* XXX let stray task complete */ 449194228Sthompsa usb_pause_mtx(NULL, hz / 20); 450184610Salfred 451194228Sthompsa usb_callout_drain(&sc->sc_tmo_rhsc); 452184610Salfred} 453184610Salfred 454228483Shselaskystatic void 455184610Salfredohci_suspend(ohci_softc_t *sc) 456184610Salfred{ 457228483Shselasky DPRINTF("\n"); 458184610Salfred 459194677Sthompsa#ifdef USB_DEBUG 460228483Shselasky if (ohcidebug > 2) 461184610Salfred ohci_dumpregs(sc); 462184610Salfred#endif 463184610Salfred 464228483Shselasky /* reset HC and leave it suspended */ 465228483Shselasky ohci_controller_init(sc, 1); 466184610Salfred} 467184610Salfred 468228483Shselaskystatic void 469184610Salfredohci_resume(ohci_softc_t *sc) 470184610Salfred{ 471228483Shselasky DPRINTF("\n"); 472184610Salfred 473194677Sthompsa#ifdef USB_DEBUG 474228483Shselasky if (ohcidebug > 2) 475184610Salfred ohci_dumpregs(sc); 476184610Salfred#endif 477228483Shselasky 478184610Salfred /* some broken BIOSes never initialize the Controller chip */ 479228483Shselasky ohci_controller_init(sc, 0); 480184610Salfred 481184610Salfred /* catch any lost interrupts */ 482184610Salfred ohci_do_poll(&sc->sc_bus); 483184610Salfred} 484184610Salfred 485194677Sthompsa#ifdef USB_DEBUG 486184610Salfredstatic void 487184610Salfredohci_dumpregs(ohci_softc_t *sc) 488184610Salfred{ 489184610Salfred struct ohci_hcca *hcca; 490184610Salfred 491184610Salfred DPRINTF("ohci_dumpregs: rev=0x%08x control=0x%08x command=0x%08x\n", 492184610Salfred OREAD4(sc, OHCI_REVISION), 493184610Salfred OREAD4(sc, OHCI_CONTROL), 494184610Salfred OREAD4(sc, OHCI_COMMAND_STATUS)); 495184610Salfred DPRINTF(" intrstat=0x%08x intre=0x%08x intrd=0x%08x\n", 496184610Salfred OREAD4(sc, OHCI_INTERRUPT_STATUS), 497184610Salfred OREAD4(sc, OHCI_INTERRUPT_ENABLE), 498184610Salfred OREAD4(sc, OHCI_INTERRUPT_DISABLE)); 499184610Salfred DPRINTF(" hcca=0x%08x percur=0x%08x ctrlhd=0x%08x\n", 500184610Salfred OREAD4(sc, OHCI_HCCA), 501184610Salfred OREAD4(sc, OHCI_PERIOD_CURRENT_ED), 502184610Salfred OREAD4(sc, OHCI_CONTROL_HEAD_ED)); 503184610Salfred DPRINTF(" ctrlcur=0x%08x bulkhd=0x%08x bulkcur=0x%08x\n", 504184610Salfred OREAD4(sc, OHCI_CONTROL_CURRENT_ED), 505184610Salfred OREAD4(sc, OHCI_BULK_HEAD_ED), 506184610Salfred OREAD4(sc, OHCI_BULK_CURRENT_ED)); 507184610Salfred DPRINTF(" done=0x%08x fmival=0x%08x fmrem=0x%08x\n", 508184610Salfred OREAD4(sc, OHCI_DONE_HEAD), 509184610Salfred OREAD4(sc, OHCI_FM_INTERVAL), 510184610Salfred OREAD4(sc, OHCI_FM_REMAINING)); 511184610Salfred DPRINTF(" fmnum=0x%08x perst=0x%08x lsthrs=0x%08x\n", 512184610Salfred OREAD4(sc, OHCI_FM_NUMBER), 513184610Salfred OREAD4(sc, OHCI_PERIODIC_START), 514184610Salfred OREAD4(sc, OHCI_LS_THRESHOLD)); 515184610Salfred DPRINTF(" desca=0x%08x descb=0x%08x stat=0x%08x\n", 516184610Salfred OREAD4(sc, OHCI_RH_DESCRIPTOR_A), 517184610Salfred OREAD4(sc, OHCI_RH_DESCRIPTOR_B), 518184610Salfred OREAD4(sc, OHCI_RH_STATUS)); 519184610Salfred DPRINTF(" port1=0x%08x port2=0x%08x\n", 520184610Salfred OREAD4(sc, OHCI_RH_PORT_STATUS(1)), 521184610Salfred OREAD4(sc, OHCI_RH_PORT_STATUS(2))); 522184610Salfred 523184610Salfred hcca = ohci_get_hcca(sc); 524184610Salfred 525184610Salfred DPRINTF(" HCCA: frame_number=0x%04x done_head=0x%08x\n", 526184610Salfred le32toh(hcca->hcca_frame_number), 527184610Salfred le32toh(hcca->hcca_done_head)); 528184610Salfred} 529184610Salfredstatic void 530184610Salfredohci_dump_tds(ohci_td_t *std) 531184610Salfred{ 532184610Salfred for (; std; std = std->obj_next) { 533184610Salfred if (ohci_dump_td(std)) { 534184610Salfred break; 535184610Salfred } 536184610Salfred } 537184610Salfred} 538184610Salfred 539184610Salfredstatic uint8_t 540184610Salfredohci_dump_td(ohci_td_t *std) 541184610Salfred{ 542184610Salfred uint32_t td_flags; 543184610Salfred uint8_t temp; 544184610Salfred 545194228Sthompsa usb_pc_cpu_invalidate(std->page_cache); 546184610Salfred 547184610Salfred td_flags = le32toh(std->td_flags); 548184610Salfred temp = (std->td_next == 0); 549184610Salfred 550184610Salfred printf("TD(%p) at 0x%08x: %s%s%s%s%s delay=%d ec=%d " 551184610Salfred "cc=%d\ncbp=0x%08x next=0x%08x be=0x%08x\n", 552184610Salfred std, le32toh(std->td_self), 553184610Salfred (td_flags & OHCI_TD_R) ? "-R" : "", 554184610Salfred (td_flags & OHCI_TD_OUT) ? "-OUT" : "", 555184610Salfred (td_flags & OHCI_TD_IN) ? "-IN" : "", 556184610Salfred ((td_flags & OHCI_TD_TOGGLE_MASK) == OHCI_TD_TOGGLE_1) ? "-TOG1" : "", 557184610Salfred ((td_flags & OHCI_TD_TOGGLE_MASK) == OHCI_TD_TOGGLE_0) ? "-TOG0" : "", 558184610Salfred OHCI_TD_GET_DI(td_flags), 559184610Salfred OHCI_TD_GET_EC(td_flags), 560184610Salfred OHCI_TD_GET_CC(td_flags), 561184610Salfred le32toh(std->td_cbp), 562184610Salfred le32toh(std->td_next), 563184610Salfred le32toh(std->td_be)); 564184610Salfred 565184610Salfred return (temp); 566184610Salfred} 567184610Salfred 568184610Salfredstatic uint8_t 569184610Salfredohci_dump_itd(ohci_itd_t *sitd) 570184610Salfred{ 571184610Salfred uint32_t itd_flags; 572184610Salfred uint16_t i; 573184610Salfred uint8_t temp; 574184610Salfred 575194228Sthompsa usb_pc_cpu_invalidate(sitd->page_cache); 576184610Salfred 577184610Salfred itd_flags = le32toh(sitd->itd_flags); 578184610Salfred temp = (sitd->itd_next == 0); 579184610Salfred 580184610Salfred printf("ITD(%p) at 0x%08x: sf=%d di=%d fc=%d cc=%d\n" 581184610Salfred "bp0=0x%08x next=0x%08x be=0x%08x\n", 582184610Salfred sitd, le32toh(sitd->itd_self), 583184610Salfred OHCI_ITD_GET_SF(itd_flags), 584184610Salfred OHCI_ITD_GET_DI(itd_flags), 585184610Salfred OHCI_ITD_GET_FC(itd_flags), 586184610Salfred OHCI_ITD_GET_CC(itd_flags), 587184610Salfred le32toh(sitd->itd_bp0), 588184610Salfred le32toh(sitd->itd_next), 589184610Salfred le32toh(sitd->itd_be)); 590184610Salfred for (i = 0; i < OHCI_ITD_NOFFSET; i++) { 591184610Salfred printf("offs[%d]=0x%04x ", i, 592184610Salfred (uint32_t)le16toh(sitd->itd_offset[i])); 593184610Salfred } 594184610Salfred printf("\n"); 595184610Salfred 596184610Salfred return (temp); 597184610Salfred} 598184610Salfred 599184610Salfredstatic void 600184610Salfredohci_dump_itds(ohci_itd_t *sitd) 601184610Salfred{ 602184610Salfred for (; sitd; sitd = sitd->obj_next) { 603184610Salfred if (ohci_dump_itd(sitd)) { 604184610Salfred break; 605184610Salfred } 606184610Salfred } 607184610Salfred} 608184610Salfred 609184610Salfredstatic void 610184610Salfredohci_dump_ed(ohci_ed_t *sed) 611184610Salfred{ 612184610Salfred uint32_t ed_flags; 613184610Salfred uint32_t ed_headp; 614184610Salfred 615194228Sthompsa usb_pc_cpu_invalidate(sed->page_cache); 616184610Salfred 617184610Salfred ed_flags = le32toh(sed->ed_flags); 618184610Salfred ed_headp = le32toh(sed->ed_headp); 619184610Salfred 620184610Salfred printf("ED(%p) at 0x%08x: addr=%d endpt=%d maxp=%d flags=%s%s%s%s%s\n" 621184610Salfred "tailp=0x%08x headflags=%s%s headp=0x%08x nexted=0x%08x\n", 622184610Salfred sed, le32toh(sed->ed_self), 623184610Salfred OHCI_ED_GET_FA(ed_flags), 624184610Salfred OHCI_ED_GET_EN(ed_flags), 625184610Salfred OHCI_ED_GET_MAXP(ed_flags), 626184610Salfred (ed_flags & OHCI_ED_DIR_OUT) ? "-OUT" : "", 627184610Salfred (ed_flags & OHCI_ED_DIR_IN) ? "-IN" : "", 628184610Salfred (ed_flags & OHCI_ED_SPEED) ? "-LOWSPEED" : "", 629184610Salfred (ed_flags & OHCI_ED_SKIP) ? "-SKIP" : "", 630184610Salfred (ed_flags & OHCI_ED_FORMAT_ISO) ? "-ISO" : "", 631184610Salfred le32toh(sed->ed_tailp), 632184610Salfred (ed_headp & OHCI_HALTED) ? "-HALTED" : "", 633184610Salfred (ed_headp & OHCI_TOGGLECARRY) ? "-CARRY" : "", 634184610Salfred le32toh(sed->ed_headp), 635184610Salfred le32toh(sed->ed_next)); 636184610Salfred} 637184610Salfred 638184610Salfred#endif 639184610Salfred 640184610Salfredstatic void 641192984Sthompsaohci_transfer_intr_enqueue(struct usb_xfer *xfer) 642184610Salfred{ 643184610Salfred /* check for early completion */ 644184610Salfred if (ohci_check_transfer(xfer)) { 645184610Salfred return; 646184610Salfred } 647184610Salfred /* put transfer on interrupt queue */ 648194228Sthompsa usbd_transfer_enqueue(&xfer->xroot->bus->intr_q, xfer); 649184610Salfred 650184610Salfred /* start timeout, if any */ 651184610Salfred if (xfer->timeout != 0) { 652194228Sthompsa usbd_transfer_timeout_ms(xfer, &ohci_timeout, xfer->timeout); 653184610Salfred } 654184610Salfred} 655184610Salfred 656186730Salfred#define OHCI_APPEND_QH(sed,last) (last) = _ohci_append_qh(sed,last) 657184610Salfredstatic ohci_ed_t * 658186730Salfred_ohci_append_qh(ohci_ed_t *sed, ohci_ed_t *last) 659184610Salfred{ 660184610Salfred DPRINTFN(11, "%p to %p\n", sed, last); 661184610Salfred 662186730Salfred if (sed->prev != NULL) { 663186730Salfred /* should not happen */ 664186730Salfred DPRINTFN(0, "ED already linked!\n"); 665186730Salfred return (last); 666186730Salfred } 667184824Sthompsa /* (sc->sc_bus.bus_mtx) must be locked */ 668184610Salfred 669184610Salfred sed->next = last->next; 670184610Salfred sed->ed_next = last->ed_next; 671184610Salfred sed->ed_tailp = 0; 672184610Salfred 673184610Salfred sed->prev = last; 674184610Salfred 675194228Sthompsa usb_pc_cpu_flush(sed->page_cache); 676184610Salfred 677184610Salfred /* 678184610Salfred * the last->next->prev is never followed: sed->next->prev = sed; 679184610Salfred */ 680184610Salfred 681184610Salfred last->next = sed; 682184610Salfred last->ed_next = sed->ed_self; 683184610Salfred 684194228Sthompsa usb_pc_cpu_flush(last->page_cache); 685184610Salfred 686184610Salfred return (sed); 687184610Salfred} 688184610Salfred 689184610Salfred#define OHCI_REMOVE_QH(sed,last) (last) = _ohci_remove_qh(sed,last) 690184610Salfredstatic ohci_ed_t * 691184610Salfred_ohci_remove_qh(ohci_ed_t *sed, ohci_ed_t *last) 692184610Salfred{ 693184610Salfred DPRINTFN(11, "%p from %p\n", sed, last); 694184610Salfred 695184824Sthompsa /* (sc->sc_bus.bus_mtx) must be locked */ 696184610Salfred 697184610Salfred /* only remove if not removed from a queue */ 698184610Salfred if (sed->prev) { 699184610Salfred 700184610Salfred sed->prev->next = sed->next; 701184610Salfred sed->prev->ed_next = sed->ed_next; 702184610Salfred 703194228Sthompsa usb_pc_cpu_flush(sed->prev->page_cache); 704184610Salfred 705184610Salfred if (sed->next) { 706184610Salfred sed->next->prev = sed->prev; 707194228Sthompsa usb_pc_cpu_flush(sed->next->page_cache); 708184610Salfred } 709184610Salfred last = ((last == sed) ? sed->prev : last); 710184610Salfred 711184610Salfred sed->prev = 0; 712184610Salfred 713194228Sthompsa usb_pc_cpu_flush(sed->page_cache); 714184610Salfred } 715184610Salfred return (last); 716184610Salfred} 717184610Salfred 718184610Salfredstatic void 719192984Sthompsaohci_isoc_done(struct usb_xfer *xfer) 720184610Salfred{ 721184610Salfred uint8_t nframes; 722184610Salfred uint32_t *plen = xfer->frlengths; 723184610Salfred volatile uint16_t *olen; 724184610Salfred uint16_t len = 0; 725184610Salfred ohci_itd_t *td = xfer->td_transfer_first; 726184610Salfred 727184610Salfred while (1) { 728184610Salfred if (td == NULL) { 729184610Salfred panic("%s:%d: out of TD's\n", 730184610Salfred __FUNCTION__, __LINE__); 731184610Salfred } 732194677Sthompsa#ifdef USB_DEBUG 733184610Salfred if (ohcidebug > 5) { 734184610Salfred DPRINTF("isoc TD\n"); 735184610Salfred ohci_dump_itd(td); 736184610Salfred } 737184610Salfred#endif 738194228Sthompsa usb_pc_cpu_invalidate(td->page_cache); 739184610Salfred 740184610Salfred nframes = td->frames; 741184610Salfred olen = &td->itd_offset[0]; 742184610Salfred 743184610Salfred if (nframes > 8) { 744184610Salfred nframes = 8; 745184610Salfred } 746184610Salfred while (nframes--) { 747184610Salfred len = le16toh(*olen); 748184610Salfred 749184610Salfred if ((len >> 12) == OHCI_CC_NOT_ACCESSED) { 750184610Salfred len = 0; 751184610Salfred } else { 752184610Salfred len &= ((1 << 12) - 1); 753184610Salfred } 754184610Salfred 755184610Salfred if (len > *plen) { 756184610Salfred len = 0;/* invalid length */ 757184610Salfred } 758184610Salfred *plen = len; 759184610Salfred plen++; 760184610Salfred olen++; 761184610Salfred } 762184610Salfred 763184610Salfred if (((void *)td) == xfer->td_transfer_last) { 764184610Salfred break; 765184610Salfred } 766184610Salfred td = td->obj_next; 767184610Salfred } 768184610Salfred 769184610Salfred xfer->aframes = xfer->nframes; 770184610Salfred ohci_device_done(xfer, USB_ERR_NORMAL_COMPLETION); 771184610Salfred} 772184610Salfred 773194677Sthompsa#ifdef USB_DEBUG 774184610Salfredstatic const char *const 775184610Salfred ohci_cc_strs[] = 776184610Salfred{ 777184610Salfred "NO_ERROR", 778184610Salfred "CRC", 779184610Salfred "BIT_STUFFING", 780184610Salfred "DATA_TOGGLE_MISMATCH", 781184610Salfred 782184610Salfred "STALL", 783184610Salfred "DEVICE_NOT_RESPONDING", 784184610Salfred "PID_CHECK_FAILURE", 785184610Salfred "UNEXPECTED_PID", 786184610Salfred 787184610Salfred "DATA_OVERRUN", 788184610Salfred "DATA_UNDERRUN", 789184610Salfred "BUFFER_OVERRUN", 790184610Salfred "BUFFER_UNDERRUN", 791184610Salfred 792184610Salfred "reserved", 793184610Salfred "reserved", 794184610Salfred "NOT_ACCESSED", 795184610Salfred "NOT_ACCESSED" 796184610Salfred}; 797184610Salfred 798184610Salfred#endif 799184610Salfred 800193045Sthompsastatic usb_error_t 801192984Sthompsaohci_non_isoc_done_sub(struct usb_xfer *xfer) 802184610Salfred{ 803184610Salfred ohci_td_t *td; 804184610Salfred ohci_td_t *td_alt_next; 805184610Salfred uint32_t temp; 806184610Salfred uint32_t phy_start; 807184610Salfred uint32_t phy_end; 808184610Salfred uint32_t td_flags; 809184610Salfred uint16_t cc; 810184610Salfred 811184610Salfred td = xfer->td_transfer_cache; 812184610Salfred td_alt_next = td->alt_next; 813184610Salfred td_flags = 0; 814184610Salfred 815188409Sthompsa if (xfer->aframes != xfer->nframes) { 816194677Sthompsa usbd_xfer_set_frame_len(xfer, xfer->aframes, 0); 817188409Sthompsa } 818184610Salfred while (1) { 819184610Salfred 820194228Sthompsa usb_pc_cpu_invalidate(td->page_cache); 821184610Salfred phy_start = le32toh(td->td_cbp); 822184610Salfred td_flags = le32toh(td->td_flags); 823184610Salfred cc = OHCI_TD_GET_CC(td_flags); 824184610Salfred 825184610Salfred if (phy_start) { 826184610Salfred /* 827184610Salfred * short transfer - compute the number of remaining 828184610Salfred * bytes in the hardware buffer: 829184610Salfred */ 830184610Salfred phy_end = le32toh(td->td_be); 831184610Salfred temp = (OHCI_PAGE(phy_start ^ phy_end) ? 832184610Salfred (OHCI_PAGE_SIZE + 1) : 0x0001); 833184610Salfred temp += OHCI_PAGE_OFFSET(phy_end); 834184610Salfred temp -= OHCI_PAGE_OFFSET(phy_start); 835184610Salfred 836184610Salfred if (temp > td->len) { 837184610Salfred /* guard against corruption */ 838184610Salfred cc = OHCI_CC_STALL; 839184610Salfred } else if (xfer->aframes != xfer->nframes) { 840184610Salfred /* 841188409Sthompsa * Sum up total transfer length 842188409Sthompsa * in "frlengths[]": 843184610Salfred */ 844188409Sthompsa xfer->frlengths[xfer->aframes] += td->len - temp; 845184610Salfred } 846188409Sthompsa } else { 847188409Sthompsa if (xfer->aframes != xfer->nframes) { 848188409Sthompsa /* transfer was complete */ 849188409Sthompsa xfer->frlengths[xfer->aframes] += td->len; 850188409Sthompsa } 851184610Salfred } 852184610Salfred /* Check for last transfer */ 853184610Salfred if (((void *)td) == xfer->td_transfer_last) { 854184610Salfred td = NULL; 855184610Salfred break; 856184610Salfred } 857184610Salfred /* Check transfer status */ 858184610Salfred if (cc) { 859184610Salfred /* the transfer is finished */ 860184610Salfred td = NULL; 861184610Salfred break; 862184610Salfred } 863184610Salfred /* Check for short transfer */ 864184610Salfred if (phy_start) { 865184610Salfred if (xfer->flags_int.short_frames_ok) { 866184610Salfred /* follow alt next */ 867184610Salfred td = td->alt_next; 868184610Salfred } else { 869184610Salfred /* the transfer is finished */ 870184610Salfred td = NULL; 871184610Salfred } 872184610Salfred break; 873184610Salfred } 874184610Salfred td = td->obj_next; 875184610Salfred 876184610Salfred if (td->alt_next != td_alt_next) { 877184610Salfred /* this USB frame is complete */ 878184610Salfred break; 879184610Salfred } 880184610Salfred } 881184610Salfred 882184610Salfred /* update transfer cache */ 883184610Salfred 884184610Salfred xfer->td_transfer_cache = td; 885184610Salfred 886184610Salfred DPRINTFN(16, "error cc=%d (%s)\n", 887184610Salfred cc, ohci_cc_strs[cc]); 888184610Salfred 889184610Salfred return ((cc == 0) ? USB_ERR_NORMAL_COMPLETION : 890184610Salfred (cc == OHCI_CC_STALL) ? USB_ERR_STALLED : USB_ERR_IOERROR); 891184610Salfred} 892184610Salfred 893184610Salfredstatic void 894192984Sthompsaohci_non_isoc_done(struct usb_xfer *xfer) 895184610Salfred{ 896193045Sthompsa usb_error_t err = 0; 897184610Salfred 898193644Sthompsa DPRINTFN(13, "xfer=%p endpoint=%p transfer done\n", 899193644Sthompsa xfer, xfer->endpoint); 900184610Salfred 901194677Sthompsa#ifdef USB_DEBUG 902184610Salfred if (ohcidebug > 10) { 903184610Salfred ohci_dump_tds(xfer->td_transfer_first); 904184610Salfred } 905184610Salfred#endif 906184610Salfred 907184610Salfred /* reset scanner */ 908184610Salfred 909184610Salfred xfer->td_transfer_cache = xfer->td_transfer_first; 910184610Salfred 911184610Salfred if (xfer->flags_int.control_xfr) { 912184610Salfred 913184610Salfred if (xfer->flags_int.control_hdr) { 914184610Salfred 915184610Salfred err = ohci_non_isoc_done_sub(xfer); 916184610Salfred } 917184610Salfred xfer->aframes = 1; 918184610Salfred 919184610Salfred if (xfer->td_transfer_cache == NULL) { 920184610Salfred goto done; 921184610Salfred } 922184610Salfred } 923184610Salfred while (xfer->aframes != xfer->nframes) { 924184610Salfred 925184610Salfred err = ohci_non_isoc_done_sub(xfer); 926184610Salfred xfer->aframes++; 927184610Salfred 928184610Salfred if (xfer->td_transfer_cache == NULL) { 929184610Salfred goto done; 930184610Salfred } 931184610Salfred } 932184610Salfred 933184610Salfred if (xfer->flags_int.control_xfr && 934184610Salfred !xfer->flags_int.control_act) { 935184610Salfred 936184610Salfred err = ohci_non_isoc_done_sub(xfer); 937184610Salfred } 938184610Salfreddone: 939184610Salfred ohci_device_done(xfer, err); 940184610Salfred} 941184610Salfred 942184610Salfred/*------------------------------------------------------------------------* 943184610Salfred * ohci_check_transfer_sub 944184610Salfred *------------------------------------------------------------------------*/ 945184610Salfredstatic void 946192984Sthompsaohci_check_transfer_sub(struct usb_xfer *xfer) 947184610Salfred{ 948184610Salfred ohci_td_t *td; 949184610Salfred ohci_ed_t *ed; 950184610Salfred uint32_t phy_start; 951184610Salfred uint32_t td_flags; 952184610Salfred uint32_t td_next; 953184610Salfred uint16_t cc; 954184610Salfred 955184610Salfred td = xfer->td_transfer_cache; 956184610Salfred 957184610Salfred while (1) { 958184610Salfred 959194228Sthompsa usb_pc_cpu_invalidate(td->page_cache); 960184610Salfred phy_start = le32toh(td->td_cbp); 961184610Salfred td_flags = le32toh(td->td_flags); 962184610Salfred td_next = le32toh(td->td_next); 963184610Salfred 964184610Salfred /* Check for last transfer */ 965184610Salfred if (((void *)td) == xfer->td_transfer_last) { 966184610Salfred /* the transfer is finished */ 967184610Salfred td = NULL; 968184610Salfred break; 969184610Salfred } 970184610Salfred /* Check transfer status */ 971184610Salfred cc = OHCI_TD_GET_CC(td_flags); 972184610Salfred if (cc) { 973184610Salfred /* the transfer is finished */ 974184610Salfred td = NULL; 975184610Salfred break; 976184610Salfred } 977184610Salfred /* 978184610Salfred * Check if we reached the last packet 979184610Salfred * or if there is a short packet: 980184610Salfred */ 981184610Salfred 982184610Salfred if (((td_next & (~0xF)) == OHCI_TD_NEXT_END) || phy_start) { 983184610Salfred /* follow alt next */ 984184610Salfred td = td->alt_next; 985184610Salfred break; 986184610Salfred } 987184610Salfred td = td->obj_next; 988184610Salfred } 989184610Salfred 990184610Salfred /* update transfer cache */ 991184610Salfred 992184610Salfred xfer->td_transfer_cache = td; 993184610Salfred 994184610Salfred if (td) { 995184610Salfred 996184610Salfred ed = xfer->qh_start[xfer->flags_int.curr_dma_set]; 997184610Salfred 998184610Salfred ed->ed_headp = td->td_self; 999194228Sthompsa usb_pc_cpu_flush(ed->page_cache); 1000184610Salfred 1001184610Salfred DPRINTFN(13, "xfer=%p following alt next\n", xfer); 1002190183Sthompsa 1003190183Sthompsa /* 1004190183Sthompsa * Make sure that the OHCI re-scans the schedule by 1005190183Sthompsa * writing the BLF and CLF bits: 1006190183Sthompsa */ 1007190183Sthompsa 1008191824Sthompsa if (xfer->xroot->udev->flags.self_suspended) { 1009190183Sthompsa /* nothing to do */ 1010193644Sthompsa } else if (xfer->endpoint->methods == &ohci_device_bulk_methods) { 1011190183Sthompsa ohci_softc_t *sc = OHCI_BUS2SC(xfer->xroot->bus); 1012190183Sthompsa 1013190183Sthompsa OWRITE4(sc, OHCI_COMMAND_STATUS, OHCI_BLF); 1014193644Sthompsa } else if (xfer->endpoint->methods == &ohci_device_ctrl_methods) { 1015190183Sthompsa ohci_softc_t *sc = OHCI_BUS2SC(xfer->xroot->bus); 1016190183Sthompsa 1017190183Sthompsa OWRITE4(sc, OHCI_COMMAND_STATUS, OHCI_CLF); 1018190183Sthompsa } 1019184610Salfred } 1020184610Salfred} 1021184610Salfred 1022184610Salfred/*------------------------------------------------------------------------* 1023184610Salfred * ohci_check_transfer 1024184610Salfred * 1025184610Salfred * Return values: 1026184610Salfred * 0: USB transfer is not finished 1027184610Salfred * Else: USB transfer is finished 1028184610Salfred *------------------------------------------------------------------------*/ 1029184610Salfredstatic uint8_t 1030192984Sthompsaohci_check_transfer(struct usb_xfer *xfer) 1031184610Salfred{ 1032184610Salfred ohci_ed_t *ed; 1033184610Salfred uint32_t ed_headp; 1034184610Salfred uint32_t ed_tailp; 1035184610Salfred 1036184610Salfred DPRINTFN(13, "xfer=%p checking transfer\n", xfer); 1037184610Salfred 1038184610Salfred ed = xfer->qh_start[xfer->flags_int.curr_dma_set]; 1039184610Salfred 1040194228Sthompsa usb_pc_cpu_invalidate(ed->page_cache); 1041184610Salfred ed_headp = le32toh(ed->ed_headp); 1042184610Salfred ed_tailp = le32toh(ed->ed_tailp); 1043184610Salfred 1044190183Sthompsa if ((ed_headp & OHCI_HALTED) || 1045184610Salfred (((ed_headp ^ ed_tailp) & (~0xF)) == 0)) { 1046193644Sthompsa if (xfer->endpoint->methods == &ohci_device_isoc_methods) { 1047184610Salfred /* isochronous transfer */ 1048184610Salfred ohci_isoc_done(xfer); 1049184610Salfred } else { 1050184610Salfred if (xfer->flags_int.short_frames_ok) { 1051184610Salfred ohci_check_transfer_sub(xfer); 1052184610Salfred if (xfer->td_transfer_cache) { 1053184610Salfred /* not finished yet */ 1054184610Salfred return (0); 1055184610Salfred } 1056184610Salfred } 1057184610Salfred /* store data-toggle */ 1058184610Salfred if (ed_headp & OHCI_TOGGLECARRY) { 1059193644Sthompsa xfer->endpoint->toggle_next = 1; 1060184610Salfred } else { 1061193644Sthompsa xfer->endpoint->toggle_next = 0; 1062184610Salfred } 1063184610Salfred 1064184610Salfred /* non-isochronous transfer */ 1065184610Salfred ohci_non_isoc_done(xfer); 1066184610Salfred } 1067184610Salfred return (1); 1068184610Salfred } 1069184610Salfred DPRINTFN(13, "xfer=%p is still active\n", xfer); 1070184610Salfred return (0); 1071184610Salfred} 1072184610Salfred 1073184610Salfredstatic void 1074184610Salfredohci_rhsc_enable(ohci_softc_t *sc) 1075184610Salfred{ 1076184610Salfred DPRINTFN(5, "\n"); 1077184610Salfred 1078184824Sthompsa USB_BUS_LOCK_ASSERT(&sc->sc_bus, MA_OWNED); 1079184610Salfred 1080184610Salfred sc->sc_eintrs |= OHCI_RHSC; 1081184610Salfred OWRITE4(sc, OHCI_INTERRUPT_ENABLE, OHCI_RHSC); 1082184610Salfred 1083184610Salfred /* acknowledge any RHSC interrupt */ 1084184610Salfred OWRITE4(sc, OHCI_INTERRUPT_STATUS, OHCI_RHSC); 1085184610Salfred 1086190735Sthompsa ohci_root_intr(sc); 1087184610Salfred} 1088184610Salfred 1089184610Salfredstatic void 1090184610Salfredohci_interrupt_poll(ohci_softc_t *sc) 1091184610Salfred{ 1092192984Sthompsa struct usb_xfer *xfer; 1093184610Salfred 1094184610Salfredrepeat: 1095184610Salfred TAILQ_FOREACH(xfer, &sc->sc_bus.intr_q.head, wait_entry) { 1096184610Salfred /* 1097184610Salfred * check if transfer is transferred 1098184610Salfred */ 1099184610Salfred if (ohci_check_transfer(xfer)) { 1100184610Salfred /* queue has been modified */ 1101184610Salfred goto repeat; 1102184610Salfred } 1103184610Salfred } 1104184610Salfred} 1105184610Salfred 1106184610Salfred/*------------------------------------------------------------------------* 1107184610Salfred * ohci_interrupt - OHCI interrupt handler 1108184610Salfred * 1109184610Salfred * NOTE: Do not access "sc->sc_bus.bdev" inside the interrupt handler, 1110184610Salfred * hence the interrupt handler will be setup before "sc->sc_bus.bdev" 1111184610Salfred * is present ! 1112184610Salfred *------------------------------------------------------------------------*/ 1113184610Salfredvoid 1114184610Salfredohci_interrupt(ohci_softc_t *sc) 1115184610Salfred{ 1116184610Salfred struct ohci_hcca *hcca; 1117184610Salfred uint32_t status; 1118184610Salfred uint32_t done; 1119184610Salfred 1120184824Sthompsa USB_BUS_LOCK(&sc->sc_bus); 1121184610Salfred 1122184610Salfred hcca = ohci_get_hcca(sc); 1123184610Salfred 1124184610Salfred DPRINTFN(16, "real interrupt\n"); 1125184610Salfred 1126194677Sthompsa#ifdef USB_DEBUG 1127184610Salfred if (ohcidebug > 15) { 1128184610Salfred ohci_dumpregs(sc); 1129184610Salfred } 1130184610Salfred#endif 1131184610Salfred 1132184610Salfred done = le32toh(hcca->hcca_done_head); 1133184610Salfred 1134184610Salfred /* 1135184610Salfred * The LSb of done is used to inform the HC Driver that an interrupt 1136184610Salfred * condition exists for both the Done list and for another event 1137184610Salfred * recorded in HcInterruptStatus. On an interrupt from the HC, the 1138184610Salfred * HC Driver checks the HccaDoneHead Value. If this value is 0, then 1139184610Salfred * the interrupt was caused by other than the HccaDoneHead update 1140184610Salfred * and the HcInterruptStatus register needs to be accessed to 1141184610Salfred * determine that exact interrupt cause. If HccaDoneHead is nonzero, 1142184610Salfred * then a Done list update interrupt is indicated and if the LSb of 1143184610Salfred * done is nonzero, then an additional interrupt event is indicated 1144184610Salfred * and HcInterruptStatus should be checked to determine its cause. 1145184610Salfred */ 1146184610Salfred if (done != 0) { 1147184610Salfred status = 0; 1148184610Salfred 1149184610Salfred if (done & ~OHCI_DONE_INTRS) { 1150184610Salfred status |= OHCI_WDH; 1151184610Salfred } 1152184610Salfred if (done & OHCI_DONE_INTRS) { 1153184610Salfred status |= OREAD4(sc, OHCI_INTERRUPT_STATUS); 1154184610Salfred } 1155184610Salfred hcca->hcca_done_head = 0; 1156184610Salfred 1157194228Sthompsa usb_pc_cpu_flush(&sc->sc_hw.hcca_pc); 1158184610Salfred } else { 1159184610Salfred status = OREAD4(sc, OHCI_INTERRUPT_STATUS) & ~OHCI_WDH; 1160184610Salfred } 1161184610Salfred 1162184610Salfred status &= ~OHCI_MIE; 1163184610Salfred if (status == 0) { 1164184610Salfred /* 1165184610Salfred * nothing to be done (PCI shared 1166184610Salfred * interrupt) 1167184610Salfred */ 1168184610Salfred goto done; 1169184610Salfred } 1170184610Salfred OWRITE4(sc, OHCI_INTERRUPT_STATUS, status); /* Acknowledge */ 1171184610Salfred 1172184610Salfred status &= sc->sc_eintrs; 1173184610Salfred if (status == 0) { 1174184610Salfred goto done; 1175184610Salfred } 1176184610Salfred if (status & (OHCI_SO | OHCI_RD | OHCI_UE | OHCI_RHSC)) { 1177184610Salfred#if 0 1178184610Salfred if (status & OHCI_SO) { 1179184610Salfred /* XXX do what */ 1180184610Salfred } 1181184610Salfred#endif 1182184610Salfred if (status & OHCI_RD) { 1183184610Salfred printf("%s: resume detect\n", __FUNCTION__); 1184184610Salfred /* XXX process resume detect */ 1185184610Salfred } 1186184610Salfred if (status & OHCI_UE) { 1187184610Salfred printf("%s: unrecoverable error, " 1188184610Salfred "controller halted\n", __FUNCTION__); 1189184610Salfred OWRITE4(sc, OHCI_CONTROL, OHCI_HCFS_RESET); 1190184610Salfred /* XXX what else */ 1191184610Salfred } 1192184610Salfred if (status & OHCI_RHSC) { 1193184610Salfred /* 1194184610Salfred * Disable RHSC interrupt for now, because it will be 1195184610Salfred * on until the port has been reset. 1196184610Salfred */ 1197184610Salfred sc->sc_eintrs &= ~OHCI_RHSC; 1198184610Salfred OWRITE4(sc, OHCI_INTERRUPT_DISABLE, OHCI_RHSC); 1199184610Salfred 1200190735Sthompsa ohci_root_intr(sc); 1201184610Salfred 1202184610Salfred /* do not allow RHSC interrupts > 1 per second */ 1203194228Sthompsa usb_callout_reset(&sc->sc_tmo_rhsc, hz, 1204184610Salfred (void *)&ohci_rhsc_enable, sc); 1205184610Salfred } 1206184610Salfred } 1207184610Salfred status &= ~(OHCI_RHSC | OHCI_WDH | OHCI_SO); 1208184610Salfred if (status != 0) { 1209184610Salfred /* Block unprocessed interrupts. XXX */ 1210184610Salfred OWRITE4(sc, OHCI_INTERRUPT_DISABLE, status); 1211184610Salfred sc->sc_eintrs &= ~status; 1212184610Salfred printf("%s: blocking intrs 0x%x\n", 1213184610Salfred __FUNCTION__, status); 1214184610Salfred } 1215184610Salfred /* poll all the USB transfers */ 1216184610Salfred ohci_interrupt_poll(sc); 1217184610Salfred 1218184610Salfreddone: 1219184824Sthompsa USB_BUS_UNLOCK(&sc->sc_bus); 1220184610Salfred} 1221184610Salfred 1222184610Salfred/* 1223184610Salfred * called when a request does not complete 1224184610Salfred */ 1225184610Salfredstatic void 1226184610Salfredohci_timeout(void *arg) 1227184610Salfred{ 1228192984Sthompsa struct usb_xfer *xfer = arg; 1229184610Salfred 1230184610Salfred DPRINTF("xfer=%p\n", xfer); 1231184610Salfred 1232187173Sthompsa USB_BUS_LOCK_ASSERT(xfer->xroot->bus, MA_OWNED); 1233184610Salfred 1234184610Salfred /* transfer is transferred */ 1235184610Salfred ohci_device_done(xfer, USB_ERR_TIMEOUT); 1236184610Salfred} 1237184610Salfred 1238184610Salfredstatic void 1239192984Sthompsaohci_do_poll(struct usb_bus *bus) 1240184610Salfred{ 1241184610Salfred struct ohci_softc *sc = OHCI_BUS2SC(bus); 1242184610Salfred 1243184824Sthompsa USB_BUS_LOCK(&sc->sc_bus); 1244184610Salfred ohci_interrupt_poll(sc); 1245184824Sthompsa USB_BUS_UNLOCK(&sc->sc_bus); 1246184610Salfred} 1247184610Salfred 1248184610Salfredstatic void 1249184610Salfredohci_setup_standard_chain_sub(struct ohci_std_temp *temp) 1250184610Salfred{ 1251192984Sthompsa struct usb_page_search buf_res; 1252184610Salfred ohci_td_t *td; 1253184610Salfred ohci_td_t *td_next; 1254184610Salfred ohci_td_t *td_alt_next; 1255184610Salfred uint32_t buf_offset; 1256184610Salfred uint32_t average; 1257184610Salfred uint32_t len_old; 1258184610Salfred uint8_t shortpkt_old; 1259184610Salfred uint8_t precompute; 1260184610Salfred 1261184610Salfred td_alt_next = NULL; 1262184610Salfred buf_offset = 0; 1263184610Salfred shortpkt_old = temp->shortpkt; 1264184610Salfred len_old = temp->len; 1265184610Salfred precompute = 1; 1266184610Salfred 1267184610Salfred /* software is used to detect short incoming transfers */ 1268184610Salfred 1269184610Salfred if ((temp->td_flags & htole32(OHCI_TD_DP_MASK)) == htole32(OHCI_TD_IN)) { 1270184610Salfred temp->td_flags |= htole32(OHCI_TD_R); 1271184610Salfred } else { 1272184610Salfred temp->td_flags &= ~htole32(OHCI_TD_R); 1273184610Salfred } 1274184610Salfred 1275184610Salfredrestart: 1276184610Salfred 1277184610Salfred td = temp->td; 1278184610Salfred td_next = temp->td_next; 1279184610Salfred 1280184610Salfred while (1) { 1281184610Salfred 1282184610Salfred if (temp->len == 0) { 1283184610Salfred 1284184610Salfred if (temp->shortpkt) { 1285184610Salfred break; 1286184610Salfred } 1287184610Salfred /* send a Zero Length Packet, ZLP, last */ 1288184610Salfred 1289184610Salfred temp->shortpkt = 1; 1290184610Salfred average = 0; 1291184610Salfred 1292184610Salfred } else { 1293184610Salfred 1294184610Salfred average = temp->average; 1295184610Salfred 1296184610Salfred if (temp->len < average) { 1297184610Salfred if (temp->len % temp->max_frame_size) { 1298184610Salfred temp->shortpkt = 1; 1299184610Salfred } 1300184610Salfred average = temp->len; 1301184610Salfred } 1302184610Salfred } 1303184610Salfred 1304184610Salfred if (td_next == NULL) { 1305184610Salfred panic("%s: out of OHCI transfer descriptors!", __FUNCTION__); 1306184610Salfred } 1307184610Salfred /* get next TD */ 1308184610Salfred 1309184610Salfred td = td_next; 1310184610Salfred td_next = td->obj_next; 1311184610Salfred 1312184610Salfred /* check if we are pre-computing */ 1313184610Salfred 1314184610Salfred if (precompute) { 1315184610Salfred 1316184610Salfred /* update remaining length */ 1317184610Salfred 1318184610Salfred temp->len -= average; 1319184610Salfred 1320184610Salfred continue; 1321184610Salfred } 1322184610Salfred /* fill out current TD */ 1323184610Salfred td->td_flags = temp->td_flags; 1324184610Salfred 1325184610Salfred /* the next TD uses TOGGLE_CARRY */ 1326184610Salfred temp->td_flags &= ~htole32(OHCI_TD_TOGGLE_MASK); 1327184610Salfred 1328184610Salfred if (average == 0) { 1329190471Sthompsa /* 1330190471Sthompsa * The buffer start and end phys addresses should be 1331190471Sthompsa * 0x0 for a zero length packet. 1332190471Sthompsa */ 1333184610Salfred td->td_cbp = 0; 1334190471Sthompsa td->td_be = 0; 1335184610Salfred td->len = 0; 1336184610Salfred 1337184610Salfred } else { 1338184610Salfred 1339194228Sthompsa usbd_get_page(temp->pc, buf_offset, &buf_res); 1340184610Salfred td->td_cbp = htole32(buf_res.physaddr); 1341184610Salfred buf_offset += (average - 1); 1342184610Salfred 1343194228Sthompsa usbd_get_page(temp->pc, buf_offset, &buf_res); 1344184610Salfred td->td_be = htole32(buf_res.physaddr); 1345184610Salfred buf_offset++; 1346184610Salfred 1347184610Salfred td->len = average; 1348184610Salfred 1349184610Salfred /* update remaining length */ 1350184610Salfred 1351184610Salfred temp->len -= average; 1352184610Salfred } 1353184610Salfred 1354184610Salfred if ((td_next == td_alt_next) && temp->setup_alt_next) { 1355184610Salfred /* we need to receive these frames one by one ! */ 1356184610Salfred td->td_flags &= htole32(~OHCI_TD_INTR_MASK); 1357184610Salfred td->td_flags |= htole32(OHCI_TD_SET_DI(1)); 1358184610Salfred td->td_next = htole32(OHCI_TD_NEXT_END); 1359184610Salfred } else { 1360184610Salfred if (td_next) { 1361184610Salfred /* link the current TD with the next one */ 1362184610Salfred td->td_next = td_next->td_self; 1363184610Salfred } 1364184610Salfred } 1365184610Salfred 1366184610Salfred td->alt_next = td_alt_next; 1367184610Salfred 1368194228Sthompsa usb_pc_cpu_flush(td->page_cache); 1369184610Salfred } 1370184610Salfred 1371184610Salfred if (precompute) { 1372184610Salfred precompute = 0; 1373184610Salfred 1374184610Salfred /* setup alt next pointer, if any */ 1375190183Sthompsa if (temp->last_frame) { 1376190183Sthompsa /* no alternate next */ 1377190183Sthompsa td_alt_next = NULL; 1378184610Salfred } else { 1379184610Salfred /* we use this field internally */ 1380184610Salfred td_alt_next = td_next; 1381184610Salfred } 1382184610Salfred 1383184610Salfred /* restore */ 1384184610Salfred temp->shortpkt = shortpkt_old; 1385184610Salfred temp->len = len_old; 1386184610Salfred goto restart; 1387184610Salfred } 1388184610Salfred temp->td = td; 1389184610Salfred temp->td_next = td_next; 1390184610Salfred} 1391184610Salfred 1392184610Salfredstatic void 1393192984Sthompsaohci_setup_standard_chain(struct usb_xfer *xfer, ohci_ed_t **ed_last) 1394184610Salfred{ 1395184610Salfred struct ohci_std_temp temp; 1396192984Sthompsa struct usb_pipe_methods *methods; 1397184610Salfred ohci_ed_t *ed; 1398184610Salfred ohci_td_t *td; 1399184610Salfred uint32_t ed_flags; 1400184610Salfred uint32_t x; 1401184610Salfred 1402184610Salfred DPRINTFN(9, "addr=%d endpt=%d sumlen=%d speed=%d\n", 1403193644Sthompsa xfer->address, UE_GET_ADDR(xfer->endpointno), 1404194228Sthompsa xfer->sumlen, usbd_get_speed(xfer->xroot->udev)); 1405184610Salfred 1406190181Sthompsa temp.average = xfer->max_hc_frame_size; 1407184610Salfred temp.max_frame_size = xfer->max_frame_size; 1408184610Salfred 1409184610Salfred /* toggle the DMA set we are using */ 1410184610Salfred xfer->flags_int.curr_dma_set ^= 1; 1411184610Salfred 1412184610Salfred /* get next DMA set */ 1413184610Salfred td = xfer->td_start[xfer->flags_int.curr_dma_set]; 1414184610Salfred 1415184610Salfred xfer->td_transfer_first = td; 1416184610Salfred xfer->td_transfer_cache = td; 1417184610Salfred 1418184610Salfred temp.td = NULL; 1419184610Salfred temp.td_next = td; 1420190183Sthompsa temp.last_frame = 0; 1421184610Salfred temp.setup_alt_next = xfer->flags_int.short_frames_ok; 1422184610Salfred 1423193644Sthompsa methods = xfer->endpoint->methods; 1424184610Salfred 1425184610Salfred /* check if we should prepend a setup message */ 1426184610Salfred 1427184610Salfred if (xfer->flags_int.control_xfr) { 1428184610Salfred if (xfer->flags_int.control_hdr) { 1429184610Salfred 1430184610Salfred temp.td_flags = htole32(OHCI_TD_SETUP | OHCI_TD_NOCC | 1431184610Salfred OHCI_TD_TOGGLE_0 | OHCI_TD_NOINTR); 1432184610Salfred 1433184610Salfred temp.len = xfer->frlengths[0]; 1434184610Salfred temp.pc = xfer->frbuffers + 0; 1435184610Salfred temp.shortpkt = temp.len ? 1 : 0; 1436190183Sthompsa /* check for last frame */ 1437190183Sthompsa if (xfer->nframes == 1) { 1438190183Sthompsa /* no STATUS stage yet, SETUP is last */ 1439190183Sthompsa if (xfer->flags_int.control_act) { 1440190183Sthompsa temp.last_frame = 1; 1441190183Sthompsa temp.setup_alt_next = 0; 1442190183Sthompsa } 1443190183Sthompsa } 1444184610Salfred ohci_setup_standard_chain_sub(&temp); 1445184610Salfred 1446184610Salfred /* 1447184610Salfred * XXX assume that the setup message is 1448184610Salfred * contained within one USB packet: 1449184610Salfred */ 1450193644Sthompsa xfer->endpoint->toggle_next = 1; 1451184610Salfred } 1452184610Salfred x = 1; 1453184610Salfred } else { 1454184610Salfred x = 0; 1455184610Salfred } 1456184610Salfred temp.td_flags = htole32(OHCI_TD_NOCC | OHCI_TD_NOINTR); 1457184610Salfred 1458184610Salfred /* set data toggle */ 1459184610Salfred 1460193644Sthompsa if (xfer->endpoint->toggle_next) { 1461184610Salfred temp.td_flags |= htole32(OHCI_TD_TOGGLE_1); 1462184610Salfred } else { 1463184610Salfred temp.td_flags |= htole32(OHCI_TD_TOGGLE_0); 1464184610Salfred } 1465184610Salfred 1466184610Salfred /* set endpoint direction */ 1467184610Salfred 1468193644Sthompsa if (UE_GET_DIR(xfer->endpointno) == UE_DIR_IN) { 1469184610Salfred temp.td_flags |= htole32(OHCI_TD_IN); 1470184610Salfred } else { 1471184610Salfred temp.td_flags |= htole32(OHCI_TD_OUT); 1472184610Salfred } 1473184610Salfred 1474184610Salfred while (x != xfer->nframes) { 1475184610Salfred 1476184610Salfred /* DATA0 / DATA1 message */ 1477184610Salfred 1478184610Salfred temp.len = xfer->frlengths[x]; 1479184610Salfred temp.pc = xfer->frbuffers + x; 1480184610Salfred 1481184610Salfred x++; 1482184610Salfred 1483184610Salfred if (x == xfer->nframes) { 1484190183Sthompsa if (xfer->flags_int.control_xfr) { 1485190183Sthompsa /* no STATUS stage yet, DATA is last */ 1486190183Sthompsa if (xfer->flags_int.control_act) { 1487190183Sthompsa temp.last_frame = 1; 1488190183Sthompsa temp.setup_alt_next = 0; 1489190183Sthompsa } 1490190183Sthompsa } else { 1491190183Sthompsa temp.last_frame = 1; 1492190183Sthompsa temp.setup_alt_next = 0; 1493190183Sthompsa } 1494184610Salfred } 1495184610Salfred if (temp.len == 0) { 1496184610Salfred 1497184610Salfred /* make sure that we send an USB packet */ 1498184610Salfred 1499184610Salfred temp.shortpkt = 0; 1500184610Salfred 1501184610Salfred } else { 1502184610Salfred 1503184610Salfred /* regular data transfer */ 1504184610Salfred 1505184610Salfred temp.shortpkt = (xfer->flags.force_short_xfer) ? 0 : 1; 1506184610Salfred } 1507184610Salfred 1508184610Salfred ohci_setup_standard_chain_sub(&temp); 1509184610Salfred } 1510184610Salfred 1511184610Salfred /* check if we should append a status stage */ 1512184610Salfred 1513184610Salfred if (xfer->flags_int.control_xfr && 1514184610Salfred !xfer->flags_int.control_act) { 1515184610Salfred 1516184610Salfred /* 1517184610Salfred * Send a DATA1 message and invert the current endpoint 1518184610Salfred * direction. 1519184610Salfred */ 1520184610Salfred 1521184610Salfred /* set endpoint direction and data toggle */ 1522184610Salfred 1523193644Sthompsa if (UE_GET_DIR(xfer->endpointno) == UE_DIR_IN) { 1524184610Salfred temp.td_flags = htole32(OHCI_TD_OUT | 1525184610Salfred OHCI_TD_NOCC | OHCI_TD_TOGGLE_1 | OHCI_TD_SET_DI(1)); 1526184610Salfred } else { 1527184610Salfred temp.td_flags = htole32(OHCI_TD_IN | 1528184610Salfred OHCI_TD_NOCC | OHCI_TD_TOGGLE_1 | OHCI_TD_SET_DI(1)); 1529184610Salfred } 1530184610Salfred 1531184610Salfred temp.len = 0; 1532184610Salfred temp.pc = NULL; 1533184610Salfred temp.shortpkt = 0; 1534190183Sthompsa temp.last_frame = 1; 1535190183Sthompsa temp.setup_alt_next = 0; 1536184610Salfred 1537184610Salfred ohci_setup_standard_chain_sub(&temp); 1538184610Salfred } 1539184610Salfred td = temp.td; 1540184610Salfred 1541190183Sthompsa /* Ensure that last TD is terminating: */ 1542184610Salfred td->td_next = htole32(OHCI_TD_NEXT_END); 1543184610Salfred td->td_flags &= ~htole32(OHCI_TD_INTR_MASK); 1544184610Salfred td->td_flags |= htole32(OHCI_TD_SET_DI(1)); 1545184610Salfred 1546194228Sthompsa usb_pc_cpu_flush(td->page_cache); 1547184610Salfred 1548184610Salfred /* must have at least one frame! */ 1549184610Salfred 1550184610Salfred xfer->td_transfer_last = td; 1551184610Salfred 1552194677Sthompsa#ifdef USB_DEBUG 1553184610Salfred if (ohcidebug > 8) { 1554184610Salfred DPRINTF("nexttog=%d; data before transfer:\n", 1555193644Sthompsa xfer->endpoint->toggle_next); 1556184610Salfred ohci_dump_tds(xfer->td_transfer_first); 1557184610Salfred } 1558184610Salfred#endif 1559184610Salfred 1560184610Salfred ed = xfer->qh_start[xfer->flags_int.curr_dma_set]; 1561184610Salfred 1562184610Salfred ed_flags = (OHCI_ED_SET_FA(xfer->address) | 1563193644Sthompsa OHCI_ED_SET_EN(UE_GET_ADDR(xfer->endpointno)) | 1564184610Salfred OHCI_ED_SET_MAXP(xfer->max_frame_size)); 1565184610Salfred 1566184610Salfred ed_flags |= (OHCI_ED_FORMAT_GEN | OHCI_ED_DIR_TD); 1567184610Salfred 1568187173Sthompsa if (xfer->xroot->udev->speed == USB_SPEED_LOW) { 1569184610Salfred ed_flags |= OHCI_ED_SPEED; 1570184610Salfred } 1571184610Salfred ed->ed_flags = htole32(ed_flags); 1572184610Salfred 1573184610Salfred td = xfer->td_transfer_first; 1574184610Salfred 1575186730Salfred ed->ed_headp = td->td_self; 1576184610Salfred 1577191824Sthompsa if (xfer->xroot->udev->flags.self_suspended == 0) { 1578187167Sthompsa /* the append function will flush the endpoint descriptor */ 1579186730Salfred OHCI_APPEND_QH(ed, *ed_last); 1580184610Salfred 1581186730Salfred if (methods == &ohci_device_bulk_methods) { 1582187173Sthompsa ohci_softc_t *sc = OHCI_BUS2SC(xfer->xroot->bus); 1583184610Salfred 1584186730Salfred OWRITE4(sc, OHCI_COMMAND_STATUS, OHCI_BLF); 1585186730Salfred } 1586186730Salfred if (methods == &ohci_device_ctrl_methods) { 1587187173Sthompsa ohci_softc_t *sc = OHCI_BUS2SC(xfer->xroot->bus); 1588186730Salfred 1589186730Salfred OWRITE4(sc, OHCI_COMMAND_STATUS, OHCI_CLF); 1590186730Salfred } 1591186730Salfred } else { 1592194228Sthompsa usb_pc_cpu_flush(ed->page_cache); 1593184610Salfred } 1594184610Salfred} 1595184610Salfred 1596184610Salfredstatic void 1597190735Sthompsaohci_root_intr(ohci_softc_t *sc) 1598184610Salfred{ 1599184610Salfred uint32_t hstatus; 1600184610Salfred uint16_t i; 1601184610Salfred uint16_t m; 1602184610Salfred 1603184824Sthompsa USB_BUS_LOCK_ASSERT(&sc->sc_bus, MA_OWNED); 1604184610Salfred 1605184610Salfred /* clear any old interrupt data */ 1606190735Sthompsa memset(sc->sc_hub_idata, 0, sizeof(sc->sc_hub_idata)); 1607184610Salfred 1608184610Salfred hstatus = OREAD4(sc, OHCI_RH_STATUS); 1609190735Sthompsa DPRINTF("sc=%p hstatus=0x%08x\n", 1610190735Sthompsa sc, hstatus); 1611184610Salfred 1612184610Salfred /* set bits */ 1613184610Salfred m = (sc->sc_noport + 1); 1614184610Salfred if (m > (8 * sizeof(sc->sc_hub_idata))) { 1615184610Salfred m = (8 * sizeof(sc->sc_hub_idata)); 1616184610Salfred } 1617184610Salfred for (i = 1; i < m; i++) { 1618184610Salfred /* pick out CHANGE bits from the status register */ 1619184610Salfred if (OREAD4(sc, OHCI_RH_PORT_STATUS(i)) >> 16) { 1620184610Salfred sc->sc_hub_idata[i / 8] |= 1 << (i % 8); 1621184610Salfred DPRINTF("port %d changed\n", i); 1622184610Salfred } 1623184610Salfred } 1624190735Sthompsa 1625190735Sthompsa uhub_root_intr(&sc->sc_bus, sc->sc_hub_idata, 1626190735Sthompsa sizeof(sc->sc_hub_idata)); 1627184610Salfred} 1628184610Salfred 1629184610Salfred/* NOTE: "done" can be run two times in a row, 1630184610Salfred * from close and from interrupt 1631184610Salfred */ 1632184610Salfredstatic void 1633193045Sthompsaohci_device_done(struct usb_xfer *xfer, usb_error_t error) 1634184610Salfred{ 1635193644Sthompsa struct usb_pipe_methods *methods = xfer->endpoint->methods; 1636187173Sthompsa ohci_softc_t *sc = OHCI_BUS2SC(xfer->xroot->bus); 1637184610Salfred ohci_ed_t *ed; 1638184610Salfred 1639184824Sthompsa USB_BUS_LOCK_ASSERT(&sc->sc_bus, MA_OWNED); 1640184610Salfred 1641184610Salfred 1642193644Sthompsa DPRINTFN(2, "xfer=%p, endpoint=%p, error=%d\n", 1643193644Sthompsa xfer, xfer->endpoint, error); 1644184610Salfred 1645184610Salfred ed = xfer->qh_start[xfer->flags_int.curr_dma_set]; 1646184610Salfred if (ed) { 1647194228Sthompsa usb_pc_cpu_invalidate(ed->page_cache); 1648184610Salfred } 1649184610Salfred if (methods == &ohci_device_bulk_methods) { 1650184610Salfred OHCI_REMOVE_QH(ed, sc->sc_bulk_p_last); 1651184610Salfred } 1652184610Salfred if (methods == &ohci_device_ctrl_methods) { 1653184610Salfred OHCI_REMOVE_QH(ed, sc->sc_ctrl_p_last); 1654184610Salfred } 1655184610Salfred if (methods == &ohci_device_intr_methods) { 1656184610Salfred OHCI_REMOVE_QH(ed, sc->sc_intr_p_last[xfer->qh_pos]); 1657184610Salfred } 1658184610Salfred if (methods == &ohci_device_isoc_methods) { 1659184610Salfred OHCI_REMOVE_QH(ed, sc->sc_isoc_p_last); 1660184610Salfred } 1661184610Salfred xfer->td_transfer_first = NULL; 1662184610Salfred xfer->td_transfer_last = NULL; 1663184610Salfred 1664184610Salfred /* dequeue transfer and start next transfer */ 1665194228Sthompsa usbd_transfer_done(xfer, error); 1666184610Salfred} 1667184610Salfred 1668184610Salfred/*------------------------------------------------------------------------* 1669184610Salfred * ohci bulk support 1670184610Salfred *------------------------------------------------------------------------*/ 1671184610Salfredstatic void 1672192984Sthompsaohci_device_bulk_open(struct usb_xfer *xfer) 1673184610Salfred{ 1674184610Salfred return; 1675184610Salfred} 1676184610Salfred 1677184610Salfredstatic void 1678192984Sthompsaohci_device_bulk_close(struct usb_xfer *xfer) 1679184610Salfred{ 1680184610Salfred ohci_device_done(xfer, USB_ERR_CANCELLED); 1681184610Salfred} 1682184610Salfred 1683184610Salfredstatic void 1684192984Sthompsaohci_device_bulk_enter(struct usb_xfer *xfer) 1685184610Salfred{ 1686184610Salfred return; 1687184610Salfred} 1688184610Salfred 1689184610Salfredstatic void 1690192984Sthompsaohci_device_bulk_start(struct usb_xfer *xfer) 1691184610Salfred{ 1692187173Sthompsa ohci_softc_t *sc = OHCI_BUS2SC(xfer->xroot->bus); 1693184610Salfred 1694184610Salfred /* setup TD's and QH */ 1695184610Salfred ohci_setup_standard_chain(xfer, &sc->sc_bulk_p_last); 1696184610Salfred 1697184610Salfred /* put transfer on interrupt queue */ 1698184610Salfred ohci_transfer_intr_enqueue(xfer); 1699184610Salfred} 1700184610Salfred 1701192984Sthompsastruct usb_pipe_methods ohci_device_bulk_methods = 1702184610Salfred{ 1703184610Salfred .open = ohci_device_bulk_open, 1704184610Salfred .close = ohci_device_bulk_close, 1705184610Salfred .enter = ohci_device_bulk_enter, 1706184610Salfred .start = ohci_device_bulk_start, 1707184610Salfred}; 1708184610Salfred 1709184610Salfred/*------------------------------------------------------------------------* 1710184610Salfred * ohci control support 1711184610Salfred *------------------------------------------------------------------------*/ 1712184610Salfredstatic void 1713192984Sthompsaohci_device_ctrl_open(struct usb_xfer *xfer) 1714184610Salfred{ 1715184610Salfred return; 1716184610Salfred} 1717184610Salfred 1718184610Salfredstatic void 1719192984Sthompsaohci_device_ctrl_close(struct usb_xfer *xfer) 1720184610Salfred{ 1721184610Salfred ohci_device_done(xfer, USB_ERR_CANCELLED); 1722184610Salfred} 1723184610Salfred 1724184610Salfredstatic void 1725192984Sthompsaohci_device_ctrl_enter(struct usb_xfer *xfer) 1726184610Salfred{ 1727184610Salfred return; 1728184610Salfred} 1729184610Salfred 1730184610Salfredstatic void 1731192984Sthompsaohci_device_ctrl_start(struct usb_xfer *xfer) 1732184610Salfred{ 1733187173Sthompsa ohci_softc_t *sc = OHCI_BUS2SC(xfer->xroot->bus); 1734184610Salfred 1735184610Salfred /* setup TD's and QH */ 1736184610Salfred ohci_setup_standard_chain(xfer, &sc->sc_ctrl_p_last); 1737184610Salfred 1738184610Salfred /* put transfer on interrupt queue */ 1739184610Salfred ohci_transfer_intr_enqueue(xfer); 1740184610Salfred} 1741184610Salfred 1742192984Sthompsastruct usb_pipe_methods ohci_device_ctrl_methods = 1743184610Salfred{ 1744184610Salfred .open = ohci_device_ctrl_open, 1745184610Salfred .close = ohci_device_ctrl_close, 1746184610Salfred .enter = ohci_device_ctrl_enter, 1747184610Salfred .start = ohci_device_ctrl_start, 1748184610Salfred}; 1749184610Salfred 1750184610Salfred/*------------------------------------------------------------------------* 1751184610Salfred * ohci interrupt support 1752184610Salfred *------------------------------------------------------------------------*/ 1753184610Salfredstatic void 1754192984Sthompsaohci_device_intr_open(struct usb_xfer *xfer) 1755184610Salfred{ 1756187173Sthompsa ohci_softc_t *sc = OHCI_BUS2SC(xfer->xroot->bus); 1757184610Salfred uint16_t best; 1758184610Salfred uint16_t bit; 1759184610Salfred uint16_t x; 1760184610Salfred 1761184610Salfred best = 0; 1762184610Salfred bit = OHCI_NO_EDS / 2; 1763184610Salfred while (bit) { 1764184610Salfred if (xfer->interval >= bit) { 1765184610Salfred x = bit; 1766184610Salfred best = bit; 1767184610Salfred while (x & bit) { 1768184610Salfred if (sc->sc_intr_stat[x] < 1769184610Salfred sc->sc_intr_stat[best]) { 1770184610Salfred best = x; 1771184610Salfred } 1772184610Salfred x++; 1773184610Salfred } 1774184610Salfred break; 1775184610Salfred } 1776184610Salfred bit >>= 1; 1777184610Salfred } 1778184610Salfred 1779184610Salfred sc->sc_intr_stat[best]++; 1780184610Salfred xfer->qh_pos = best; 1781184610Salfred 1782184610Salfred DPRINTFN(3, "best=%d interval=%d\n", 1783184610Salfred best, xfer->interval); 1784184610Salfred} 1785184610Salfred 1786184610Salfredstatic void 1787192984Sthompsaohci_device_intr_close(struct usb_xfer *xfer) 1788184610Salfred{ 1789187173Sthompsa ohci_softc_t *sc = OHCI_BUS2SC(xfer->xroot->bus); 1790184610Salfred 1791184610Salfred sc->sc_intr_stat[xfer->qh_pos]--; 1792184610Salfred 1793184610Salfred ohci_device_done(xfer, USB_ERR_CANCELLED); 1794184610Salfred} 1795184610Salfred 1796184610Salfredstatic void 1797192984Sthompsaohci_device_intr_enter(struct usb_xfer *xfer) 1798184610Salfred{ 1799184610Salfred return; 1800184610Salfred} 1801184610Salfred 1802184610Salfredstatic void 1803192984Sthompsaohci_device_intr_start(struct usb_xfer *xfer) 1804184610Salfred{ 1805187173Sthompsa ohci_softc_t *sc = OHCI_BUS2SC(xfer->xroot->bus); 1806184610Salfred 1807184610Salfred /* setup TD's and QH */ 1808184610Salfred ohci_setup_standard_chain(xfer, &sc->sc_intr_p_last[xfer->qh_pos]); 1809184610Salfred 1810184610Salfred /* put transfer on interrupt queue */ 1811184610Salfred ohci_transfer_intr_enqueue(xfer); 1812184610Salfred} 1813184610Salfred 1814192984Sthompsastruct usb_pipe_methods ohci_device_intr_methods = 1815184610Salfred{ 1816184610Salfred .open = ohci_device_intr_open, 1817184610Salfred .close = ohci_device_intr_close, 1818184610Salfred .enter = ohci_device_intr_enter, 1819184610Salfred .start = ohci_device_intr_start, 1820184610Salfred}; 1821184610Salfred 1822184610Salfred/*------------------------------------------------------------------------* 1823184610Salfred * ohci isochronous support 1824184610Salfred *------------------------------------------------------------------------*/ 1825184610Salfredstatic void 1826192984Sthompsaohci_device_isoc_open(struct usb_xfer *xfer) 1827184610Salfred{ 1828184610Salfred return; 1829184610Salfred} 1830184610Salfred 1831184610Salfredstatic void 1832192984Sthompsaohci_device_isoc_close(struct usb_xfer *xfer) 1833184610Salfred{ 1834184610Salfred /**/ 1835184610Salfred ohci_device_done(xfer, USB_ERR_CANCELLED); 1836184610Salfred} 1837184610Salfred 1838184610Salfredstatic void 1839192984Sthompsaohci_device_isoc_enter(struct usb_xfer *xfer) 1840184610Salfred{ 1841192984Sthompsa struct usb_page_search buf_res; 1842187173Sthompsa ohci_softc_t *sc = OHCI_BUS2SC(xfer->xroot->bus); 1843184610Salfred struct ohci_hcca *hcca; 1844184610Salfred uint32_t buf_offset; 1845184610Salfred uint32_t nframes; 1846184610Salfred uint32_t ed_flags; 1847184610Salfred uint32_t *plen; 1848184610Salfred uint16_t itd_offset[OHCI_ITD_NOFFSET]; 1849184610Salfred uint16_t length; 1850184610Salfred uint8_t ncur; 1851184610Salfred ohci_itd_t *td; 1852184610Salfred ohci_itd_t *td_last = NULL; 1853184610Salfred ohci_ed_t *ed; 1854184610Salfred 1855184610Salfred hcca = ohci_get_hcca(sc); 1856184610Salfred 1857184610Salfred nframes = le32toh(hcca->hcca_frame_number); 1858184610Salfred 1859184610Salfred DPRINTFN(6, "xfer=%p isoc_next=%u nframes=%u hcca_fn=%u\n", 1860193644Sthompsa xfer, xfer->endpoint->isoc_next, xfer->nframes, nframes); 1861184610Salfred 1862193644Sthompsa if ((xfer->endpoint->is_synced == 0) || 1863193644Sthompsa (((nframes - xfer->endpoint->isoc_next) & 0xFFFF) < xfer->nframes) || 1864193644Sthompsa (((xfer->endpoint->isoc_next - nframes) & 0xFFFF) >= 128)) { 1865184610Salfred /* 1866184610Salfred * If there is data underflow or the pipe queue is empty we 1867184610Salfred * schedule the transfer a few frames ahead of the current 1868184610Salfred * frame position. Else two isochronous transfers might 1869184610Salfred * overlap. 1870184610Salfred */ 1871193644Sthompsa xfer->endpoint->isoc_next = (nframes + 3) & 0xFFFF; 1872193644Sthompsa xfer->endpoint->is_synced = 1; 1873193644Sthompsa DPRINTFN(3, "start next=%d\n", xfer->endpoint->isoc_next); 1874184610Salfred } 1875184610Salfred /* 1876184610Salfred * compute how many milliseconds the insertion is ahead of the 1877184610Salfred * current frame position: 1878184610Salfred */ 1879193644Sthompsa buf_offset = ((xfer->endpoint->isoc_next - nframes) & 0xFFFF); 1880184610Salfred 1881184610Salfred /* 1882184610Salfred * pre-compute when the isochronous transfer will be finished: 1883184610Salfred */ 1884184610Salfred xfer->isoc_time_complete = 1885194228Sthompsa (usb_isoc_time_expand(&sc->sc_bus, nframes) + buf_offset + 1886184610Salfred xfer->nframes); 1887184610Salfred 1888184610Salfred /* get the real number of frames */ 1889184610Salfred 1890184610Salfred nframes = xfer->nframes; 1891184610Salfred 1892184610Salfred buf_offset = 0; 1893184610Salfred 1894184610Salfred plen = xfer->frlengths; 1895184610Salfred 1896184610Salfred /* toggle the DMA set we are using */ 1897184610Salfred xfer->flags_int.curr_dma_set ^= 1; 1898184610Salfred 1899184610Salfred /* get next DMA set */ 1900184610Salfred td = xfer->td_start[xfer->flags_int.curr_dma_set]; 1901184610Salfred 1902184610Salfred xfer->td_transfer_first = td; 1903184610Salfred 1904184610Salfred ncur = 0; 1905184610Salfred length = 0; 1906184610Salfred 1907184610Salfred while (nframes--) { 1908184610Salfred if (td == NULL) { 1909184610Salfred panic("%s:%d: out of TD's\n", 1910184610Salfred __FUNCTION__, __LINE__); 1911184610Salfred } 1912184610Salfred itd_offset[ncur] = length; 1913184610Salfred buf_offset += *plen; 1914184610Salfred length += *plen; 1915184610Salfred plen++; 1916184610Salfred ncur++; 1917184610Salfred 1918184610Salfred if ( /* check if the ITD is full */ 1919184610Salfred (ncur == OHCI_ITD_NOFFSET) || 1920184610Salfred /* check if we have put more than 4K into the ITD */ 1921184610Salfred (length & 0xF000) || 1922184610Salfred /* check if it is the last frame */ 1923184610Salfred (nframes == 0)) { 1924184610Salfred 1925184610Salfred /* fill current ITD */ 1926184610Salfred td->itd_flags = htole32( 1927184610Salfred OHCI_ITD_NOCC | 1928193644Sthompsa OHCI_ITD_SET_SF(xfer->endpoint->isoc_next) | 1929184610Salfred OHCI_ITD_NOINTR | 1930184610Salfred OHCI_ITD_SET_FC(ncur)); 1931184610Salfred 1932184610Salfred td->frames = ncur; 1933193644Sthompsa xfer->endpoint->isoc_next += ncur; 1934184610Salfred 1935184610Salfred if (length == 0) { 1936184610Salfred /* all zero */ 1937184610Salfred td->itd_bp0 = 0; 1938184610Salfred td->itd_be = ~0; 1939184610Salfred 1940184610Salfred while (ncur--) { 1941184610Salfred td->itd_offset[ncur] = 1942184610Salfred htole16(OHCI_ITD_MK_OFFS(0)); 1943184610Salfred } 1944184610Salfred } else { 1945194228Sthompsa usbd_get_page(xfer->frbuffers, buf_offset - length, &buf_res); 1946184610Salfred length = OHCI_PAGE_MASK(buf_res.physaddr); 1947184610Salfred buf_res.physaddr = 1948184610Salfred OHCI_PAGE(buf_res.physaddr); 1949184610Salfred td->itd_bp0 = htole32(buf_res.physaddr); 1950194228Sthompsa usbd_get_page(xfer->frbuffers, buf_offset - 1, &buf_res); 1951184610Salfred td->itd_be = htole32(buf_res.physaddr); 1952184610Salfred 1953184610Salfred while (ncur--) { 1954184610Salfred itd_offset[ncur] += length; 1955184610Salfred itd_offset[ncur] = 1956184610Salfred OHCI_ITD_MK_OFFS(itd_offset[ncur]); 1957184610Salfred td->itd_offset[ncur] = 1958184610Salfred htole16(itd_offset[ncur]); 1959184610Salfred } 1960184610Salfred } 1961184610Salfred ncur = 0; 1962184610Salfred length = 0; 1963184610Salfred td_last = td; 1964184610Salfred td = td->obj_next; 1965184610Salfred 1966184610Salfred if (td) { 1967184610Salfred /* link the last TD with the next one */ 1968184610Salfred td_last->itd_next = td->itd_self; 1969184610Salfred } 1970194228Sthompsa usb_pc_cpu_flush(td_last->page_cache); 1971184610Salfred } 1972184610Salfred } 1973184610Salfred 1974184610Salfred /* update the last TD */ 1975184610Salfred td_last->itd_flags &= ~htole32(OHCI_ITD_NOINTR); 1976184610Salfred td_last->itd_flags |= htole32(OHCI_ITD_SET_DI(0)); 1977184610Salfred td_last->itd_next = 0; 1978184610Salfred 1979194228Sthompsa usb_pc_cpu_flush(td_last->page_cache); 1980184610Salfred 1981184610Salfred xfer->td_transfer_last = td_last; 1982184610Salfred 1983194677Sthompsa#ifdef USB_DEBUG 1984184610Salfred if (ohcidebug > 8) { 1985184610Salfred DPRINTF("data before transfer:\n"); 1986184610Salfred ohci_dump_itds(xfer->td_transfer_first); 1987184610Salfred } 1988184610Salfred#endif 1989184610Salfred ed = xfer->qh_start[xfer->flags_int.curr_dma_set]; 1990184610Salfred 1991193644Sthompsa if (UE_GET_DIR(xfer->endpointno) == UE_DIR_IN) 1992184610Salfred ed_flags = (OHCI_ED_DIR_IN | OHCI_ED_FORMAT_ISO); 1993184610Salfred else 1994184610Salfred ed_flags = (OHCI_ED_DIR_OUT | OHCI_ED_FORMAT_ISO); 1995184610Salfred 1996184610Salfred ed_flags |= (OHCI_ED_SET_FA(xfer->address) | 1997193644Sthompsa OHCI_ED_SET_EN(UE_GET_ADDR(xfer->endpointno)) | 1998184610Salfred OHCI_ED_SET_MAXP(xfer->max_frame_size)); 1999184610Salfred 2000187173Sthompsa if (xfer->xroot->udev->speed == USB_SPEED_LOW) { 2001184610Salfred ed_flags |= OHCI_ED_SPEED; 2002184610Salfred } 2003184610Salfred ed->ed_flags = htole32(ed_flags); 2004184610Salfred 2005184610Salfred td = xfer->td_transfer_first; 2006184610Salfred 2007186730Salfred ed->ed_headp = td->itd_self; 2008186730Salfred 2009186730Salfred /* isochronous transfers are not affected by suspend / resume */ 2010187167Sthompsa /* the append function will flush the endpoint descriptor */ 2011186730Salfred 2012186730Salfred OHCI_APPEND_QH(ed, sc->sc_isoc_p_last); 2013184610Salfred} 2014184610Salfred 2015184610Salfredstatic void 2016192984Sthompsaohci_device_isoc_start(struct usb_xfer *xfer) 2017184610Salfred{ 2018184610Salfred /* put transfer on interrupt queue */ 2019184610Salfred ohci_transfer_intr_enqueue(xfer); 2020184610Salfred} 2021184610Salfred 2022192984Sthompsastruct usb_pipe_methods ohci_device_isoc_methods = 2023184610Salfred{ 2024184610Salfred .open = ohci_device_isoc_open, 2025184610Salfred .close = ohci_device_isoc_close, 2026184610Salfred .enter = ohci_device_isoc_enter, 2027184610Salfred .start = ohci_device_isoc_start, 2028184610Salfred}; 2029184610Salfred 2030184610Salfred/*------------------------------------------------------------------------* 2031184610Salfred * ohci root control support 2032184610Salfred *------------------------------------------------------------------------* 2033190735Sthompsa * Simulate a hardware hub by handling all the necessary requests. 2034184610Salfred *------------------------------------------------------------------------*/ 2035184610Salfred 2036184610Salfredstatic const 2037192984Sthompsastruct usb_device_descriptor ohci_devd = 2038184610Salfred{ 2039192984Sthompsa sizeof(struct usb_device_descriptor), 2040184610Salfred UDESC_DEVICE, /* type */ 2041184610Salfred {0x00, 0x01}, /* USB version */ 2042184610Salfred UDCLASS_HUB, /* class */ 2043184610Salfred UDSUBCLASS_HUB, /* subclass */ 2044184610Salfred UDPROTO_FSHUB, /* protocol */ 2045184610Salfred 64, /* max packet */ 2046184610Salfred {0}, {0}, {0x00, 0x01}, /* device id */ 2047184610Salfred 1, 2, 0, /* string indicies */ 2048184610Salfred 1 /* # of configurations */ 2049184610Salfred}; 2050184610Salfred 2051184610Salfredstatic const 2052184610Salfredstruct ohci_config_desc ohci_confd = 2053184610Salfred{ 2054184610Salfred .confd = { 2055192984Sthompsa .bLength = sizeof(struct usb_config_descriptor), 2056184610Salfred .bDescriptorType = UDESC_CONFIG, 2057184610Salfred .wTotalLength[0] = sizeof(ohci_confd), 2058184610Salfred .bNumInterface = 1, 2059184610Salfred .bConfigurationValue = 1, 2060184610Salfred .iConfiguration = 0, 2061184610Salfred .bmAttributes = UC_SELF_POWERED, 2062184610Salfred .bMaxPower = 0, /* max power */ 2063184610Salfred }, 2064184610Salfred .ifcd = { 2065192984Sthompsa .bLength = sizeof(struct usb_interface_descriptor), 2066184610Salfred .bDescriptorType = UDESC_INTERFACE, 2067184610Salfred .bNumEndpoints = 1, 2068184610Salfred .bInterfaceClass = UICLASS_HUB, 2069184610Salfred .bInterfaceSubClass = UISUBCLASS_HUB, 2070213802Shselasky .bInterfaceProtocol = 0, 2071184610Salfred }, 2072184610Salfred .endpd = { 2073192984Sthompsa .bLength = sizeof(struct usb_endpoint_descriptor), 2074184610Salfred .bDescriptorType = UDESC_ENDPOINT, 2075184610Salfred .bEndpointAddress = UE_DIR_IN | OHCI_INTR_ENDPT, 2076184610Salfred .bmAttributes = UE_INTERRUPT, 2077184610Salfred .wMaxPacketSize[0] = 32,/* max packet (255 ports) */ 2078184610Salfred .bInterval = 255, 2079184610Salfred }, 2080184610Salfred}; 2081184610Salfred 2082184610Salfredstatic const 2083192984Sthompsastruct usb_hub_descriptor ohci_hubd = 2084184610Salfred{ 2085233774Shselasky .bDescLength = 0, /* dynamic length */ 2086233774Shselasky .bDescriptorType = UDESC_HUB, 2087184610Salfred}; 2088184610Salfred 2089193045Sthompsastatic usb_error_t 2090192984Sthompsaohci_roothub_exec(struct usb_device *udev, 2091192984Sthompsa struct usb_device_request *req, const void **pptr, uint16_t *plength) 2092184610Salfred{ 2093191402Sthompsa ohci_softc_t *sc = OHCI_BUS2SC(udev->bus); 2094191402Sthompsa const void *ptr; 2095191402Sthompsa const char *str_ptr; 2096184610Salfred uint32_t port; 2097184610Salfred uint32_t v; 2098191402Sthompsa uint16_t len; 2099184610Salfred uint16_t value; 2100184610Salfred uint16_t index; 2101184610Salfred uint8_t l; 2102193045Sthompsa usb_error_t err; 2103184610Salfred 2104184824Sthompsa USB_BUS_LOCK_ASSERT(&sc->sc_bus, MA_OWNED); 2105184610Salfred 2106184610Salfred /* buffer reset */ 2107191402Sthompsa ptr = (const void *)&sc->sc_hub_desc.temp; 2108191402Sthompsa len = 0; 2109191402Sthompsa err = 0; 2110184610Salfred 2111191402Sthompsa value = UGETW(req->wValue); 2112191402Sthompsa index = UGETW(req->wIndex); 2113184610Salfred 2114184610Salfred DPRINTFN(3, "type=0x%02x request=0x%02x wLen=0x%04x " 2115184610Salfred "wValue=0x%04x wIndex=0x%04x\n", 2116191402Sthompsa req->bmRequestType, req->bRequest, 2117191402Sthompsa UGETW(req->wLength), value, index); 2118184610Salfred 2119184610Salfred#define C(x,y) ((x) | ((y) << 8)) 2120191402Sthompsa switch (C(req->bRequest, req->bmRequestType)) { 2121184610Salfred case C(UR_CLEAR_FEATURE, UT_WRITE_DEVICE): 2122184610Salfred case C(UR_CLEAR_FEATURE, UT_WRITE_INTERFACE): 2123184610Salfred case C(UR_CLEAR_FEATURE, UT_WRITE_ENDPOINT): 2124184610Salfred /* 2125184610Salfred * DEVICE_REMOTE_WAKEUP and ENDPOINT_HALT are no-ops 2126184610Salfred * for the integrated root hub. 2127184610Salfred */ 2128184610Salfred break; 2129184610Salfred case C(UR_GET_CONFIG, UT_READ_DEVICE): 2130191402Sthompsa len = 1; 2131184610Salfred sc->sc_hub_desc.temp[0] = sc->sc_conf; 2132184610Salfred break; 2133184610Salfred case C(UR_GET_DESCRIPTOR, UT_READ_DEVICE): 2134184610Salfred switch (value >> 8) { 2135184610Salfred case UDESC_DEVICE: 2136184610Salfred if ((value & 0xff) != 0) { 2137191402Sthompsa err = USB_ERR_IOERROR; 2138184610Salfred goto done; 2139184610Salfred } 2140191402Sthompsa len = sizeof(ohci_devd); 2141191402Sthompsa ptr = (const void *)&ohci_devd; 2142184610Salfred break; 2143184610Salfred 2144184610Salfred case UDESC_CONFIG: 2145184610Salfred if ((value & 0xff) != 0) { 2146191402Sthompsa err = USB_ERR_IOERROR; 2147184610Salfred goto done; 2148184610Salfred } 2149191402Sthompsa len = sizeof(ohci_confd); 2150191402Sthompsa ptr = (const void *)&ohci_confd; 2151184610Salfred break; 2152184610Salfred 2153184610Salfred case UDESC_STRING: 2154184610Salfred switch (value & 0xff) { 2155184610Salfred case 0: /* Language table */ 2156191402Sthompsa str_ptr = "\001"; 2157184610Salfred break; 2158184610Salfred 2159184610Salfred case 1: /* Vendor */ 2160191402Sthompsa str_ptr = sc->sc_vendor; 2161184610Salfred break; 2162184610Salfred 2163184610Salfred case 2: /* Product */ 2164191402Sthompsa str_ptr = "OHCI root HUB"; 2165184610Salfred break; 2166184610Salfred 2167184610Salfred default: 2168191402Sthompsa str_ptr = ""; 2169184610Salfred break; 2170184610Salfred } 2171184610Salfred 2172194228Sthompsa len = usb_make_str_desc( 2173191402Sthompsa sc->sc_hub_desc.temp, 2174184610Salfred sizeof(sc->sc_hub_desc.temp), 2175191402Sthompsa str_ptr); 2176184610Salfred break; 2177184610Salfred 2178184610Salfred default: 2179191402Sthompsa err = USB_ERR_IOERROR; 2180184610Salfred goto done; 2181184610Salfred } 2182184610Salfred break; 2183184610Salfred case C(UR_GET_INTERFACE, UT_READ_INTERFACE): 2184191402Sthompsa len = 1; 2185184610Salfred sc->sc_hub_desc.temp[0] = 0; 2186184610Salfred break; 2187184610Salfred case C(UR_GET_STATUS, UT_READ_DEVICE): 2188191402Sthompsa len = 2; 2189184610Salfred USETW(sc->sc_hub_desc.stat.wStatus, UDS_SELF_POWERED); 2190184610Salfred break; 2191184610Salfred case C(UR_GET_STATUS, UT_READ_INTERFACE): 2192184610Salfred case C(UR_GET_STATUS, UT_READ_ENDPOINT): 2193191402Sthompsa len = 2; 2194184610Salfred USETW(sc->sc_hub_desc.stat.wStatus, 0); 2195184610Salfred break; 2196184610Salfred case C(UR_SET_ADDRESS, UT_WRITE_DEVICE): 2197190174Sthompsa if (value >= OHCI_MAX_DEVICES) { 2198191402Sthompsa err = USB_ERR_IOERROR; 2199184610Salfred goto done; 2200184610Salfred } 2201184610Salfred sc->sc_addr = value; 2202184610Salfred break; 2203184610Salfred case C(UR_SET_CONFIG, UT_WRITE_DEVICE): 2204184610Salfred if ((value != 0) && (value != 1)) { 2205191402Sthompsa err = USB_ERR_IOERROR; 2206184610Salfred goto done; 2207184610Salfred } 2208184610Salfred sc->sc_conf = value; 2209184610Salfred break; 2210184610Salfred case C(UR_SET_DESCRIPTOR, UT_WRITE_DEVICE): 2211184610Salfred break; 2212184610Salfred case C(UR_SET_FEATURE, UT_WRITE_DEVICE): 2213184610Salfred case C(UR_SET_FEATURE, UT_WRITE_INTERFACE): 2214184610Salfred case C(UR_SET_FEATURE, UT_WRITE_ENDPOINT): 2215191402Sthompsa err = USB_ERR_IOERROR; 2216184610Salfred goto done; 2217184610Salfred case C(UR_SET_INTERFACE, UT_WRITE_INTERFACE): 2218184610Salfred break; 2219184610Salfred case C(UR_SYNCH_FRAME, UT_WRITE_ENDPOINT): 2220184610Salfred break; 2221184610Salfred /* Hub requests */ 2222184610Salfred case C(UR_CLEAR_FEATURE, UT_WRITE_CLASS_DEVICE): 2223184610Salfred break; 2224184610Salfred case C(UR_CLEAR_FEATURE, UT_WRITE_CLASS_OTHER): 2225184610Salfred DPRINTFN(9, "UR_CLEAR_PORT_FEATURE " 2226184610Salfred "port=%d feature=%d\n", 2227184610Salfred index, value); 2228184610Salfred if ((index < 1) || 2229184610Salfred (index > sc->sc_noport)) { 2230191402Sthompsa err = USB_ERR_IOERROR; 2231184610Salfred goto done; 2232184610Salfred } 2233184610Salfred port = OHCI_RH_PORT_STATUS(index); 2234184610Salfred switch (value) { 2235184610Salfred case UHF_PORT_ENABLE: 2236184610Salfred OWRITE4(sc, port, UPS_CURRENT_CONNECT_STATUS); 2237184610Salfred break; 2238184610Salfred case UHF_PORT_SUSPEND: 2239184610Salfred OWRITE4(sc, port, UPS_OVERCURRENT_INDICATOR); 2240184610Salfred break; 2241184610Salfred case UHF_PORT_POWER: 2242184610Salfred /* Yes, writing to the LOW_SPEED bit clears power. */ 2243184610Salfred OWRITE4(sc, port, UPS_LOW_SPEED); 2244184610Salfred break; 2245184610Salfred case UHF_C_PORT_CONNECTION: 2246184610Salfred OWRITE4(sc, port, UPS_C_CONNECT_STATUS << 16); 2247184610Salfred break; 2248184610Salfred case UHF_C_PORT_ENABLE: 2249184610Salfred OWRITE4(sc, port, UPS_C_PORT_ENABLED << 16); 2250184610Salfred break; 2251184610Salfred case UHF_C_PORT_SUSPEND: 2252184610Salfred OWRITE4(sc, port, UPS_C_SUSPEND << 16); 2253184610Salfred break; 2254184610Salfred case UHF_C_PORT_OVER_CURRENT: 2255184610Salfred OWRITE4(sc, port, UPS_C_OVERCURRENT_INDICATOR << 16); 2256184610Salfred break; 2257184610Salfred case UHF_C_PORT_RESET: 2258184610Salfred OWRITE4(sc, port, UPS_C_PORT_RESET << 16); 2259184610Salfred break; 2260184610Salfred default: 2261191402Sthompsa err = USB_ERR_IOERROR; 2262184610Salfred goto done; 2263184610Salfred } 2264184610Salfred switch (value) { 2265184610Salfred case UHF_C_PORT_CONNECTION: 2266184610Salfred case UHF_C_PORT_ENABLE: 2267184610Salfred case UHF_C_PORT_SUSPEND: 2268184610Salfred case UHF_C_PORT_OVER_CURRENT: 2269184610Salfred case UHF_C_PORT_RESET: 2270184610Salfred /* enable RHSC interrupt if condition is cleared. */ 2271186454Sthompsa if ((OREAD4(sc, port) >> 16) == 0) 2272184610Salfred ohci_rhsc_enable(sc); 2273184610Salfred break; 2274184610Salfred default: 2275184610Salfred break; 2276184610Salfred } 2277184610Salfred break; 2278184610Salfred case C(UR_GET_DESCRIPTOR, UT_READ_CLASS_DEVICE): 2279184610Salfred if ((value & 0xff) != 0) { 2280191402Sthompsa err = USB_ERR_IOERROR; 2281184610Salfred goto done; 2282184610Salfred } 2283184610Salfred v = OREAD4(sc, OHCI_RH_DESCRIPTOR_A); 2284184610Salfred 2285184610Salfred sc->sc_hub_desc.hubd = ohci_hubd; 2286184610Salfred sc->sc_hub_desc.hubd.bNbrPorts = sc->sc_noport; 2287184610Salfred USETW(sc->sc_hub_desc.hubd.wHubCharacteristics, 2288184610Salfred (v & OHCI_NPS ? UHD_PWR_NO_SWITCH : 2289184610Salfred v & OHCI_PSM ? UHD_PWR_GANGED : UHD_PWR_INDIVIDUAL) 2290184610Salfred /* XXX overcurrent */ 2291184610Salfred ); 2292184610Salfred sc->sc_hub_desc.hubd.bPwrOn2PwrGood = OHCI_GET_POTPGT(v); 2293184610Salfred v = OREAD4(sc, OHCI_RH_DESCRIPTOR_B); 2294184610Salfred 2295184610Salfred for (l = 0; l < sc->sc_noport; l++) { 2296184610Salfred if (v & 1) { 2297184610Salfred sc->sc_hub_desc.hubd.DeviceRemovable[l / 8] |= (1 << (l % 8)); 2298184610Salfred } 2299184610Salfred v >>= 1; 2300184610Salfred } 2301184610Salfred sc->sc_hub_desc.hubd.bDescLength = 2302184610Salfred 8 + ((sc->sc_noport + 7) / 8); 2303191402Sthompsa len = sc->sc_hub_desc.hubd.bDescLength; 2304184610Salfred break; 2305184610Salfred 2306184610Salfred case C(UR_GET_STATUS, UT_READ_CLASS_DEVICE): 2307191402Sthompsa len = 16; 2308227461Shselasky memset(sc->sc_hub_desc.temp, 0, 16); 2309184610Salfred break; 2310184610Salfred case C(UR_GET_STATUS, UT_READ_CLASS_OTHER): 2311184610Salfred DPRINTFN(9, "get port status i=%d\n", 2312184610Salfred index); 2313184610Salfred if ((index < 1) || 2314184610Salfred (index > sc->sc_noport)) { 2315191402Sthompsa err = USB_ERR_IOERROR; 2316184610Salfred goto done; 2317184610Salfred } 2318184610Salfred v = OREAD4(sc, OHCI_RH_PORT_STATUS(index)); 2319184610Salfred DPRINTFN(9, "port status=0x%04x\n", v); 2320241082Shselasky v &= ~UPS_PORT_MODE_DEVICE; /* force host mode */ 2321184610Salfred USETW(sc->sc_hub_desc.ps.wPortStatus, v); 2322184610Salfred USETW(sc->sc_hub_desc.ps.wPortChange, v >> 16); 2323191402Sthompsa len = sizeof(sc->sc_hub_desc.ps); 2324184610Salfred break; 2325184610Salfred case C(UR_SET_DESCRIPTOR, UT_WRITE_CLASS_DEVICE): 2326191402Sthompsa err = USB_ERR_IOERROR; 2327184610Salfred goto done; 2328184610Salfred case C(UR_SET_FEATURE, UT_WRITE_CLASS_DEVICE): 2329184610Salfred break; 2330184610Salfred case C(UR_SET_FEATURE, UT_WRITE_CLASS_OTHER): 2331184610Salfred if ((index < 1) || 2332184610Salfred (index > sc->sc_noport)) { 2333191402Sthompsa err = USB_ERR_IOERROR; 2334184610Salfred goto done; 2335184610Salfred } 2336184610Salfred port = OHCI_RH_PORT_STATUS(index); 2337184610Salfred switch (value) { 2338184610Salfred case UHF_PORT_ENABLE: 2339184610Salfred OWRITE4(sc, port, UPS_PORT_ENABLED); 2340184610Salfred break; 2341184610Salfred case UHF_PORT_SUSPEND: 2342184610Salfred OWRITE4(sc, port, UPS_SUSPEND); 2343184610Salfred break; 2344184610Salfred case UHF_PORT_RESET: 2345184610Salfred DPRINTFN(6, "reset port %d\n", index); 2346184610Salfred OWRITE4(sc, port, UPS_RESET); 2347184610Salfred for (v = 0;; v++) { 2348184610Salfred if (v < 12) { 2349194228Sthompsa usb_pause_mtx(&sc->sc_bus.bus_mtx, 2350241987Shselasky USB_MS_TO_TICKS(usb_port_root_reset_delay)); 2351184610Salfred 2352184610Salfred if ((OREAD4(sc, port) & UPS_RESET) == 0) { 2353184610Salfred break; 2354184610Salfred } 2355184610Salfred } else { 2356191402Sthompsa err = USB_ERR_TIMEOUT; 2357184610Salfred goto done; 2358184610Salfred } 2359184610Salfred } 2360184610Salfred DPRINTFN(9, "ohci port %d reset, status = 0x%04x\n", 2361184610Salfred index, OREAD4(sc, port)); 2362184610Salfred break; 2363184610Salfred case UHF_PORT_POWER: 2364184610Salfred DPRINTFN(3, "set port power %d\n", index); 2365184610Salfred OWRITE4(sc, port, UPS_PORT_POWER); 2366184610Salfred break; 2367184610Salfred default: 2368191402Sthompsa err = USB_ERR_IOERROR; 2369184610Salfred goto done; 2370184610Salfred } 2371184610Salfred break; 2372184610Salfred default: 2373191402Sthompsa err = USB_ERR_IOERROR; 2374184610Salfred goto done; 2375184610Salfred } 2376184610Salfreddone: 2377191402Sthompsa *plength = len; 2378191402Sthompsa *pptr = ptr; 2379191402Sthompsa return (err); 2380184610Salfred} 2381184610Salfred 2382184610Salfredstatic void 2383192984Sthompsaohci_xfer_setup(struct usb_setup_params *parm) 2384184610Salfred{ 2385192984Sthompsa struct usb_page_search page_info; 2386192984Sthompsa struct usb_page_cache *pc; 2387184610Salfred ohci_softc_t *sc; 2388192984Sthompsa struct usb_xfer *xfer; 2389184610Salfred void *last_obj; 2390184610Salfred uint32_t ntd; 2391184610Salfred uint32_t nitd; 2392184610Salfred uint32_t nqh; 2393184610Salfred uint32_t n; 2394184610Salfred 2395184610Salfred sc = OHCI_BUS2SC(parm->udev->bus); 2396184610Salfred xfer = parm->curr_xfer; 2397184610Salfred 2398184610Salfred parm->hc_max_packet_size = 0x500; 2399184610Salfred parm->hc_max_packet_count = 1; 2400184610Salfred parm->hc_max_frame_size = OHCI_PAGE_SIZE; 2401184610Salfred 2402184610Salfred /* 2403184610Salfred * calculate ntd and nqh 2404184610Salfred */ 2405184610Salfred if (parm->methods == &ohci_device_ctrl_methods) { 2406184610Salfred xfer->flags_int.bdma_enable = 1; 2407184610Salfred 2408194228Sthompsa usbd_transfer_setup_sub(parm); 2409184610Salfred 2410184610Salfred nitd = 0; 2411184610Salfred ntd = ((2 * xfer->nframes) + 1 /* STATUS */ 2412190181Sthompsa + (xfer->max_data_length / xfer->max_hc_frame_size)); 2413184610Salfred nqh = 1; 2414184610Salfred 2415184610Salfred } else if (parm->methods == &ohci_device_bulk_methods) { 2416184610Salfred xfer->flags_int.bdma_enable = 1; 2417184610Salfred 2418194228Sthompsa usbd_transfer_setup_sub(parm); 2419184610Salfred 2420184610Salfred nitd = 0; 2421184610Salfred ntd = ((2 * xfer->nframes) 2422190181Sthompsa + (xfer->max_data_length / xfer->max_hc_frame_size)); 2423184610Salfred nqh = 1; 2424184610Salfred 2425184610Salfred } else if (parm->methods == &ohci_device_intr_methods) { 2426184610Salfred xfer->flags_int.bdma_enable = 1; 2427184610Salfred 2428194228Sthompsa usbd_transfer_setup_sub(parm); 2429184610Salfred 2430184610Salfred nitd = 0; 2431184610Salfred ntd = ((2 * xfer->nframes) 2432190181Sthompsa + (xfer->max_data_length / xfer->max_hc_frame_size)); 2433184610Salfred nqh = 1; 2434184610Salfred 2435184610Salfred } else if (parm->methods == &ohci_device_isoc_methods) { 2436184610Salfred xfer->flags_int.bdma_enable = 1; 2437184610Salfred 2438194228Sthompsa usbd_transfer_setup_sub(parm); 2439184610Salfred 2440184610Salfred nitd = ((xfer->max_data_length / OHCI_PAGE_SIZE) + 2441184610Salfred ((xfer->nframes + OHCI_ITD_NOFFSET - 1) / OHCI_ITD_NOFFSET) + 2442184610Salfred 1 /* EXTRA */ ); 2443184610Salfred ntd = 0; 2444184610Salfred nqh = 1; 2445184610Salfred 2446184610Salfred } else { 2447184610Salfred 2448194228Sthompsa usbd_transfer_setup_sub(parm); 2449184610Salfred 2450184610Salfred nitd = 0; 2451184610Salfred ntd = 0; 2452184610Salfred nqh = 0; 2453184610Salfred } 2454184610Salfred 2455184610Salfredalloc_dma_set: 2456184610Salfred 2457184610Salfred if (parm->err) { 2458184610Salfred return; 2459184610Salfred } 2460184610Salfred last_obj = NULL; 2461184610Salfred 2462194228Sthompsa if (usbd_transfer_setup_sub_malloc( 2463184610Salfred parm, &pc, sizeof(ohci_td_t), 2464184610Salfred OHCI_TD_ALIGN, ntd)) { 2465184610Salfred parm->err = USB_ERR_NOMEM; 2466184610Salfred return; 2467184610Salfred } 2468184610Salfred if (parm->buf) { 2469184610Salfred for (n = 0; n != ntd; n++) { 2470184610Salfred ohci_td_t *td; 2471184610Salfred 2472194228Sthompsa usbd_get_page(pc + n, 0, &page_info); 2473184610Salfred 2474184610Salfred td = page_info.buffer; 2475184610Salfred 2476184610Salfred /* init TD */ 2477184610Salfred td->td_self = htole32(page_info.physaddr); 2478184610Salfred td->obj_next = last_obj; 2479184610Salfred td->page_cache = pc + n; 2480184610Salfred 2481184610Salfred last_obj = td; 2482184610Salfred 2483194228Sthompsa usb_pc_cpu_flush(pc + n); 2484184610Salfred } 2485184610Salfred } 2486194228Sthompsa if (usbd_transfer_setup_sub_malloc( 2487184610Salfred parm, &pc, sizeof(ohci_itd_t), 2488184610Salfred OHCI_ITD_ALIGN, nitd)) { 2489184610Salfred parm->err = USB_ERR_NOMEM; 2490184610Salfred return; 2491184610Salfred } 2492184610Salfred if (parm->buf) { 2493184610Salfred for (n = 0; n != nitd; n++) { 2494184610Salfred ohci_itd_t *itd; 2495184610Salfred 2496194228Sthompsa usbd_get_page(pc + n, 0, &page_info); 2497184610Salfred 2498184610Salfred itd = page_info.buffer; 2499184610Salfred 2500184610Salfred /* init TD */ 2501184610Salfred itd->itd_self = htole32(page_info.physaddr); 2502184610Salfred itd->obj_next = last_obj; 2503184610Salfred itd->page_cache = pc + n; 2504184610Salfred 2505184610Salfred last_obj = itd; 2506184610Salfred 2507194228Sthompsa usb_pc_cpu_flush(pc + n); 2508184610Salfred } 2509184610Salfred } 2510184610Salfred xfer->td_start[xfer->flags_int.curr_dma_set] = last_obj; 2511184610Salfred 2512184610Salfred last_obj = NULL; 2513184610Salfred 2514194228Sthompsa if (usbd_transfer_setup_sub_malloc( 2515184610Salfred parm, &pc, sizeof(ohci_ed_t), 2516184610Salfred OHCI_ED_ALIGN, nqh)) { 2517184610Salfred parm->err = USB_ERR_NOMEM; 2518184610Salfred return; 2519184610Salfred } 2520184610Salfred if (parm->buf) { 2521184610Salfred for (n = 0; n != nqh; n++) { 2522184610Salfred ohci_ed_t *ed; 2523184610Salfred 2524194228Sthompsa usbd_get_page(pc + n, 0, &page_info); 2525184610Salfred 2526184610Salfred ed = page_info.buffer; 2527184610Salfred 2528184610Salfred /* init QH */ 2529184610Salfred ed->ed_self = htole32(page_info.physaddr); 2530184610Salfred ed->obj_next = last_obj; 2531184610Salfred ed->page_cache = pc + n; 2532184610Salfred 2533184610Salfred last_obj = ed; 2534184610Salfred 2535194228Sthompsa usb_pc_cpu_flush(pc + n); 2536184610Salfred } 2537184610Salfred } 2538184610Salfred xfer->qh_start[xfer->flags_int.curr_dma_set] = last_obj; 2539184610Salfred 2540184610Salfred if (!xfer->flags_int.curr_dma_set) { 2541184610Salfred xfer->flags_int.curr_dma_set = 1; 2542184610Salfred goto alloc_dma_set; 2543184610Salfred } 2544184610Salfred} 2545184610Salfred 2546184610Salfredstatic void 2547193644Sthompsaohci_ep_init(struct usb_device *udev, struct usb_endpoint_descriptor *edesc, 2548193644Sthompsa struct usb_endpoint *ep) 2549184610Salfred{ 2550184610Salfred ohci_softc_t *sc = OHCI_BUS2SC(udev->bus); 2551184610Salfred 2552193644Sthompsa DPRINTFN(2, "endpoint=%p, addr=%d, endpt=%d, mode=%d (%d)\n", 2553193644Sthompsa ep, udev->address, 2554192499Sthompsa edesc->bEndpointAddress, udev->flags.usb_mode, 2555184610Salfred sc->sc_addr); 2556184610Salfred 2557190735Sthompsa if (udev->device_index != sc->sc_addr) { 2558184610Salfred switch (edesc->bmAttributes & UE_XFERTYPE) { 2559184610Salfred case UE_CONTROL: 2560193644Sthompsa ep->methods = &ohci_device_ctrl_methods; 2561184610Salfred break; 2562184610Salfred case UE_INTERRUPT: 2563193644Sthompsa ep->methods = &ohci_device_intr_methods; 2564184610Salfred break; 2565184610Salfred case UE_ISOCHRONOUS: 2566184610Salfred if (udev->speed == USB_SPEED_FULL) { 2567193644Sthompsa ep->methods = &ohci_device_isoc_methods; 2568184610Salfred } 2569184610Salfred break; 2570184610Salfred case UE_BULK: 2571209443Sthompsa ep->methods = &ohci_device_bulk_methods; 2572184610Salfred break; 2573184610Salfred default: 2574184610Salfred /* do nothing */ 2575184610Salfred break; 2576184610Salfred } 2577184610Salfred } 2578184610Salfred} 2579184610Salfred 2580184610Salfredstatic void 2581192984Sthompsaohci_xfer_unsetup(struct usb_xfer *xfer) 2582184610Salfred{ 2583184610Salfred return; 2584184610Salfred} 2585184610Salfred 2586184610Salfredstatic void 2587212134Sthompsaohci_get_dma_delay(struct usb_device *udev, uint32_t *pus) 2588184610Salfred{ 2589184610Salfred /* 2590184610Salfred * Wait until hardware has finished any possible use of the 2591184610Salfred * transfer descriptor(s) and QH 2592184610Salfred */ 2593184610Salfred *pus = (1125); /* microseconds */ 2594184610Salfred} 2595184610Salfred 2596186730Salfredstatic void 2597192984Sthompsaohci_device_resume(struct usb_device *udev) 2598186730Salfred{ 2599186730Salfred struct ohci_softc *sc = OHCI_BUS2SC(udev->bus); 2600192984Sthompsa struct usb_xfer *xfer; 2601192984Sthompsa struct usb_pipe_methods *methods; 2602186730Salfred ohci_ed_t *ed; 2603186730Salfred 2604186730Salfred DPRINTF("\n"); 2605186730Salfred 2606186730Salfred USB_BUS_LOCK(udev->bus); 2607186730Salfred 2608186730Salfred TAILQ_FOREACH(xfer, &sc->sc_bus.intr_q.head, wait_entry) { 2609186730Salfred 2610187173Sthompsa if (xfer->xroot->udev == udev) { 2611186730Salfred 2612193644Sthompsa methods = xfer->endpoint->methods; 2613186730Salfred ed = xfer->qh_start[xfer->flags_int.curr_dma_set]; 2614186730Salfred 2615186730Salfred if (methods == &ohci_device_bulk_methods) { 2616186730Salfred OHCI_APPEND_QH(ed, sc->sc_bulk_p_last); 2617186730Salfred OWRITE4(sc, OHCI_COMMAND_STATUS, OHCI_BLF); 2618186730Salfred } 2619186730Salfred if (methods == &ohci_device_ctrl_methods) { 2620186730Salfred OHCI_APPEND_QH(ed, sc->sc_ctrl_p_last); 2621186730Salfred OWRITE4(sc, OHCI_COMMAND_STATUS, OHCI_CLF); 2622186730Salfred } 2623186730Salfred if (methods == &ohci_device_intr_methods) { 2624186730Salfred OHCI_APPEND_QH(ed, sc->sc_intr_p_last[xfer->qh_pos]); 2625186730Salfred } 2626186730Salfred } 2627186730Salfred } 2628186730Salfred 2629186730Salfred USB_BUS_UNLOCK(udev->bus); 2630186730Salfred 2631186730Salfred return; 2632186730Salfred} 2633186730Salfred 2634186730Salfredstatic void 2635192984Sthompsaohci_device_suspend(struct usb_device *udev) 2636186730Salfred{ 2637186730Salfred struct ohci_softc *sc = OHCI_BUS2SC(udev->bus); 2638192984Sthompsa struct usb_xfer *xfer; 2639192984Sthompsa struct usb_pipe_methods *methods; 2640186730Salfred ohci_ed_t *ed; 2641186730Salfred 2642186730Salfred DPRINTF("\n"); 2643186730Salfred 2644186730Salfred USB_BUS_LOCK(udev->bus); 2645186730Salfred 2646186730Salfred TAILQ_FOREACH(xfer, &sc->sc_bus.intr_q.head, wait_entry) { 2647186730Salfred 2648187173Sthompsa if (xfer->xroot->udev == udev) { 2649186730Salfred 2650193644Sthompsa methods = xfer->endpoint->methods; 2651186730Salfred ed = xfer->qh_start[xfer->flags_int.curr_dma_set]; 2652186730Salfred 2653186730Salfred if (methods == &ohci_device_bulk_methods) { 2654186730Salfred OHCI_REMOVE_QH(ed, sc->sc_bulk_p_last); 2655186730Salfred } 2656186730Salfred if (methods == &ohci_device_ctrl_methods) { 2657186730Salfred OHCI_REMOVE_QH(ed, sc->sc_ctrl_p_last); 2658186730Salfred } 2659186730Salfred if (methods == &ohci_device_intr_methods) { 2660186730Salfred OHCI_REMOVE_QH(ed, sc->sc_intr_p_last[xfer->qh_pos]); 2661186730Salfred } 2662186730Salfred } 2663186730Salfred } 2664186730Salfred 2665186730Salfred USB_BUS_UNLOCK(udev->bus); 2666186730Salfred 2667186730Salfred return; 2668186730Salfred} 2669186730Salfred 2670186730Salfredstatic void 2671228483Shselaskyohci_set_hw_power_sleep(struct usb_bus *bus, uint32_t state) 2672228483Shselasky{ 2673228483Shselasky struct ohci_softc *sc = OHCI_BUS2SC(bus); 2674228483Shselasky 2675228483Shselasky switch (state) { 2676228483Shselasky case USB_HW_POWER_SUSPEND: 2677228483Shselasky case USB_HW_POWER_SHUTDOWN: 2678228483Shselasky ohci_suspend(sc); 2679228483Shselasky break; 2680228483Shselasky case USB_HW_POWER_RESUME: 2681228483Shselasky ohci_resume(sc); 2682228483Shselasky break; 2683228483Shselasky default: 2684228483Shselasky break; 2685228483Shselasky } 2686228483Shselasky} 2687228483Shselasky 2688228483Shselaskystatic void 2689192984Sthompsaohci_set_hw_power(struct usb_bus *bus) 2690186730Salfred{ 2691186730Salfred struct ohci_softc *sc = OHCI_BUS2SC(bus); 2692186730Salfred uint32_t temp; 2693186730Salfred uint32_t flags; 2694186730Salfred 2695186730Salfred DPRINTF("\n"); 2696186730Salfred 2697186730Salfred USB_BUS_LOCK(bus); 2698186730Salfred 2699186730Salfred flags = bus->hw_power_state; 2700186730Salfred 2701186730Salfred temp = OREAD4(sc, OHCI_CONTROL); 2702186730Salfred temp &= ~(OHCI_PLE | OHCI_IE | OHCI_CLE | OHCI_BLE); 2703186730Salfred 2704186730Salfred if (flags & USB_HW_POWER_CONTROL) 2705186730Salfred temp |= OHCI_CLE; 2706186730Salfred 2707186730Salfred if (flags & USB_HW_POWER_BULK) 2708186730Salfred temp |= OHCI_BLE; 2709186730Salfred 2710186730Salfred if (flags & USB_HW_POWER_INTERRUPT) 2711186730Salfred temp |= OHCI_PLE; 2712186730Salfred 2713186730Salfred if (flags & USB_HW_POWER_ISOC) 2714186730Salfred temp |= OHCI_IE | OHCI_PLE; 2715186730Salfred 2716186730Salfred OWRITE4(sc, OHCI_CONTROL, temp); 2717186730Salfred 2718186730Salfred USB_BUS_UNLOCK(bus); 2719186730Salfred 2720186730Salfred return; 2721186730Salfred} 2722186730Salfred 2723192984Sthompsastruct usb_bus_methods ohci_bus_methods = 2724184610Salfred{ 2725193644Sthompsa .endpoint_init = ohci_ep_init, 2726184610Salfred .xfer_setup = ohci_xfer_setup, 2727184610Salfred .xfer_unsetup = ohci_xfer_unsetup, 2728184610Salfred .get_dma_delay = ohci_get_dma_delay, 2729186730Salfred .device_resume = ohci_device_resume, 2730186730Salfred .device_suspend = ohci_device_suspend, 2731186730Salfred .set_hw_power = ohci_set_hw_power, 2732228483Shselasky .set_hw_power_sleep = ohci_set_hw_power_sleep, 2733190735Sthompsa .roothub_exec = ohci_roothub_exec, 2734195960Salfred .xfer_poll = ohci_do_poll, 2735184610Salfred}; 2736