ohci.c revision 186730
1184610Salfred/*- 2184610Salfred * Copyright (c) 2008 Hans Petter Selasky. All rights reserved. 3184610Salfred * Copyright (c) 1998 The NetBSD Foundation, Inc. All rights reserved. 4184610Salfred * Copyright (c) 1998 Lennart Augustsson. All rights reserved. 5184610Salfred * 6184610Salfred * Redistribution and use in source and binary forms, with or without 7184610Salfred * modification, are permitted provided that the following conditions 8184610Salfred * are met: 9184610Salfred * 1. Redistributions of source code must retain the above copyright 10184610Salfred * notice, this list of conditions and the following disclaimer. 11184610Salfred * 2. Redistributions in binary form must reproduce the above copyright 12184610Salfred * notice, this list of conditions and the following disclaimer in the 13184610Salfred * documentation and/or other materials provided with the distribution. 14184610Salfred * 15184610Salfred * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 16184610Salfred * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 17184610Salfred * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 18184610Salfred * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 19184610Salfred * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 20184610Salfred * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 21184610Salfred * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 22184610Salfred * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 23184610Salfred * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 24184610Salfred * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 25184610Salfred * SUCH DAMAGE. 26184610Salfred */ 27184610Salfred 28184610Salfred#include <sys/cdefs.h> 29184610Salfred__FBSDID("$FreeBSD: head/sys/dev/usb2/controller/ohci2.c 186730 2009-01-04 00:12:01Z alfred $"); 30184610Salfred 31184610Salfred/* 32184610Salfred * USB Open Host Controller driver. 33184610Salfred * 34184610Salfred * OHCI spec: http://www.compaq.com/productinfo/development/openhci.html 35184610Salfred * USB spec: http://www.usb.org/developers/docs/usbspec.zip 36184610Salfred */ 37184610Salfred 38184610Salfred#include <dev/usb2/include/usb2_standard.h> 39184610Salfred#include <dev/usb2/include/usb2_mfunc.h> 40184610Salfred#include <dev/usb2/include/usb2_error.h> 41184610Salfred#include <dev/usb2/include/usb2_defs.h> 42184610Salfred 43184610Salfred#define USB_DEBUG_VAR ohcidebug 44184610Salfred#define usb2_config_td_cc ohci_config_copy 45184610Salfred#define usb2_config_td_softc ohci_softc 46184610Salfred 47184610Salfred#include <dev/usb2/core/usb2_core.h> 48184610Salfred#include <dev/usb2/core/usb2_debug.h> 49184610Salfred#include <dev/usb2/core/usb2_busdma.h> 50184610Salfred#include <dev/usb2/core/usb2_process.h> 51184610Salfred#include <dev/usb2/core/usb2_config_td.h> 52184610Salfred#include <dev/usb2/core/usb2_sw_transfer.h> 53184610Salfred#include <dev/usb2/core/usb2_transfer.h> 54184610Salfred#include <dev/usb2/core/usb2_device.h> 55184610Salfred#include <dev/usb2/core/usb2_hub.h> 56184610Salfred#include <dev/usb2/core/usb2_util.h> 57184610Salfred 58184610Salfred#include <dev/usb2/controller/usb2_controller.h> 59184610Salfred#include <dev/usb2/controller/usb2_bus.h> 60184610Salfred#include <dev/usb2/controller/ohci2.h> 61184610Salfred 62184610Salfred#define OHCI_BUS2SC(bus) ((ohci_softc_t *)(((uint8_t *)(bus)) - \ 63184610Salfred USB_P2U(&(((ohci_softc_t *)0)->sc_bus)))) 64184610Salfred 65184610Salfred#if USB_DEBUG 66184610Salfredstatic int ohcidebug = 0; 67184610Salfred 68184610SalfredSYSCTL_NODE(_hw_usb2, OID_AUTO, ohci, CTLFLAG_RW, 0, "USB ohci"); 69184610SalfredSYSCTL_INT(_hw_usb2_ohci, OID_AUTO, debug, CTLFLAG_RW, 70184610Salfred &ohcidebug, 0, "ohci debug level"); 71184610Salfredstatic void ohci_dumpregs(ohci_softc_t *); 72184610Salfredstatic void ohci_dump_tds(ohci_td_t *); 73184610Salfredstatic uint8_t ohci_dump_td(ohci_td_t *); 74184610Salfredstatic void ohci_dump_ed(ohci_ed_t *); 75184610Salfredstatic uint8_t ohci_dump_itd(ohci_itd_t *); 76184610Salfredstatic void ohci_dump_itds(ohci_itd_t *); 77184610Salfred 78184610Salfred#endif 79184610Salfred 80184610Salfred#define OBARR(sc) bus_space_barrier((sc)->sc_io_tag, (sc)->sc_io_hdl, 0, (sc)->sc_io_size, \ 81184610Salfred BUS_SPACE_BARRIER_READ|BUS_SPACE_BARRIER_WRITE) 82184610Salfred#define OWRITE1(sc, r, x) \ 83184610Salfred do { OBARR(sc); bus_space_write_1((sc)->sc_io_tag, (sc)->sc_io_hdl, (r), (x)); } while (0) 84184610Salfred#define OWRITE2(sc, r, x) \ 85184610Salfred do { OBARR(sc); bus_space_write_2((sc)->sc_io_tag, (sc)->sc_io_hdl, (r), (x)); } while (0) 86184610Salfred#define OWRITE4(sc, r, x) \ 87184610Salfred do { OBARR(sc); bus_space_write_4((sc)->sc_io_tag, (sc)->sc_io_hdl, (r), (x)); } while (0) 88184610Salfred#define OREAD1(sc, r) (OBARR(sc), bus_space_read_1((sc)->sc_io_tag, (sc)->sc_io_hdl, (r))) 89184610Salfred#define OREAD2(sc, r) (OBARR(sc), bus_space_read_2((sc)->sc_io_tag, (sc)->sc_io_hdl, (r))) 90184610Salfred#define OREAD4(sc, r) (OBARR(sc), bus_space_read_4((sc)->sc_io_tag, (sc)->sc_io_hdl, (r))) 91184610Salfred 92184610Salfred#define OHCI_INTR_ENDPT 1 93184610Salfred 94184610Salfredextern struct usb2_bus_methods ohci_bus_methods; 95184610Salfredextern struct usb2_pipe_methods ohci_device_bulk_methods; 96184610Salfredextern struct usb2_pipe_methods ohci_device_ctrl_methods; 97184610Salfredextern struct usb2_pipe_methods ohci_device_intr_methods; 98184610Salfredextern struct usb2_pipe_methods ohci_device_isoc_methods; 99184610Salfredextern struct usb2_pipe_methods ohci_root_ctrl_methods; 100184610Salfredextern struct usb2_pipe_methods ohci_root_intr_methods; 101184610Salfred 102184610Salfredstatic usb2_config_td_command_t ohci_root_ctrl_task; 103184610Salfredstatic void ohci_root_ctrl_poll(struct ohci_softc *sc); 104184610Salfredstatic void ohci_do_poll(struct usb2_bus *bus); 105184610Salfredstatic void ohci_device_done(struct usb2_xfer *xfer, usb2_error_t error); 106184610Salfred 107184610Salfredstatic usb2_sw_transfer_func_t ohci_root_intr_done; 108184610Salfredstatic usb2_sw_transfer_func_t ohci_root_ctrl_done; 109184610Salfredstatic void ohci_timeout(void *arg); 110184610Salfredstatic uint8_t ohci_check_transfer(struct usb2_xfer *xfer); 111184610Salfred 112184610Salfredstruct ohci_std_temp { 113184610Salfred struct usb2_page_cache *pc; 114184610Salfred ohci_td_t *td; 115184610Salfred ohci_td_t *td_next; 116184610Salfred uint32_t average; 117184610Salfred uint32_t td_flags; 118184610Salfred uint32_t len; 119184610Salfred uint16_t max_frame_size; 120184610Salfred uint8_t shortpkt; 121184610Salfred uint8_t setup_alt_next; 122184610Salfred uint8_t short_frames_ok; 123184610Salfred}; 124184610Salfred 125184610Salfredstatic struct ohci_hcca * 126184610Salfredohci_get_hcca(ohci_softc_t *sc) 127184610Salfred{ 128184610Salfred usb2_pc_cpu_invalidate(&sc->sc_hw.hcca_pc); 129184610Salfred return (sc->sc_hcca_p); 130184610Salfred} 131184610Salfred 132184610Salfredvoid 133184610Salfredohci_iterate_hw_softc(struct usb2_bus *bus, usb2_bus_mem_sub_cb_t *cb) 134184610Salfred{ 135184610Salfred struct ohci_softc *sc = OHCI_BUS2SC(bus); 136184610Salfred uint32_t i; 137184610Salfred 138184610Salfred cb(bus, &sc->sc_hw.hcca_pc, &sc->sc_hw.hcca_pg, 139184610Salfred sizeof(ohci_hcca_t), OHCI_HCCA_ALIGN); 140184610Salfred 141184610Salfred cb(bus, &sc->sc_hw.ctrl_start_pc, &sc->sc_hw.ctrl_start_pg, 142184610Salfred sizeof(ohci_ed_t), OHCI_ED_ALIGN); 143184610Salfred 144184610Salfred cb(bus, &sc->sc_hw.bulk_start_pc, &sc->sc_hw.bulk_start_pg, 145184610Salfred sizeof(ohci_ed_t), OHCI_ED_ALIGN); 146184610Salfred 147184610Salfred cb(bus, &sc->sc_hw.isoc_start_pc, &sc->sc_hw.isoc_start_pg, 148184610Salfred sizeof(ohci_ed_t), OHCI_ED_ALIGN); 149184610Salfred 150184610Salfred for (i = 0; i != OHCI_NO_EDS; i++) { 151184610Salfred cb(bus, sc->sc_hw.intr_start_pc + i, sc->sc_hw.intr_start_pg + i, 152184610Salfred sizeof(ohci_ed_t), OHCI_ED_ALIGN); 153184610Salfred } 154184610Salfred} 155184610Salfred 156184610Salfredstatic usb2_error_t 157184610Salfredohci_controller_init(ohci_softc_t *sc) 158184610Salfred{ 159184610Salfred struct usb2_page_search buf_res; 160184610Salfred uint32_t i; 161184610Salfred uint32_t ctl; 162184610Salfred uint32_t ival; 163184610Salfred uint32_t hcr; 164184610Salfred uint32_t fm; 165184610Salfred uint32_t per; 166184610Salfred uint32_t desca; 167184610Salfred 168184610Salfred /* Determine in what context we are running. */ 169184610Salfred ctl = OREAD4(sc, OHCI_CONTROL); 170184610Salfred if (ctl & OHCI_IR) { 171184610Salfred /* SMM active, request change */ 172184610Salfred DPRINTF("SMM active, request owner change\n"); 173184610Salfred OWRITE4(sc, OHCI_COMMAND_STATUS, OHCI_OCR); 174184610Salfred for (i = 0; (i < 100) && (ctl & OHCI_IR); i++) { 175184824Sthompsa usb2_pause_mtx(&sc->sc_bus.bus_mtx, 1); 176184610Salfred ctl = OREAD4(sc, OHCI_CONTROL); 177184610Salfred } 178184610Salfred if (ctl & OHCI_IR) { 179184610Salfred device_printf(sc->sc_bus.bdev, 180184610Salfred "SMM does not respond, resetting\n"); 181184610Salfred OWRITE4(sc, OHCI_CONTROL, OHCI_HCFS_RESET); 182184610Salfred goto reset; 183184610Salfred } 184184610Salfred } else { 185184610Salfred DPRINTF("cold started\n"); 186184610Salfredreset: 187184610Salfred /* controller was cold started */ 188184824Sthompsa usb2_pause_mtx(&sc->sc_bus.bus_mtx, 189184610Salfred USB_BUS_RESET_DELAY); 190184610Salfred } 191184610Salfred 192184610Salfred /* 193184610Salfred * This reset should not be necessary according to the OHCI spec, but 194184610Salfred * without it some controllers do not start. 195184610Salfred */ 196184610Salfred DPRINTF("%s: resetting\n", device_get_nameunit(sc->sc_bus.bdev)); 197184610Salfred OWRITE4(sc, OHCI_CONTROL, OHCI_HCFS_RESET); 198184610Salfred 199184824Sthompsa usb2_pause_mtx(&sc->sc_bus.bus_mtx, 200184610Salfred USB_BUS_RESET_DELAY); 201184610Salfred 202184610Salfred /* we now own the host controller and the bus has been reset */ 203184610Salfred ival = OHCI_GET_IVAL(OREAD4(sc, OHCI_FM_INTERVAL)); 204184610Salfred 205184610Salfred OWRITE4(sc, OHCI_COMMAND_STATUS, OHCI_HCR); /* Reset HC */ 206184610Salfred /* nominal time for a reset is 10 us */ 207184610Salfred for (i = 0; i < 10; i++) { 208184610Salfred DELAY(10); 209184610Salfred hcr = OREAD4(sc, OHCI_COMMAND_STATUS) & OHCI_HCR; 210184610Salfred if (!hcr) { 211184610Salfred break; 212184610Salfred } 213184610Salfred } 214184610Salfred if (hcr) { 215184610Salfred device_printf(sc->sc_bus.bdev, "reset timeout\n"); 216184610Salfred return (USB_ERR_IOERROR); 217184610Salfred } 218184610Salfred#if USB_DEBUG 219184610Salfred if (ohcidebug > 15) { 220184610Salfred ohci_dumpregs(sc); 221184610Salfred } 222184610Salfred#endif 223184610Salfred 224184610Salfred /* The controller is now in SUSPEND state, we have 2ms to finish. */ 225184610Salfred 226184610Salfred /* set up HC registers */ 227184610Salfred usb2_get_page(&sc->sc_hw.hcca_pc, 0, &buf_res); 228184610Salfred OWRITE4(sc, OHCI_HCCA, buf_res.physaddr); 229184610Salfred 230184610Salfred usb2_get_page(&sc->sc_hw.ctrl_start_pc, 0, &buf_res); 231184610Salfred OWRITE4(sc, OHCI_CONTROL_HEAD_ED, buf_res.physaddr); 232184610Salfred 233184610Salfred usb2_get_page(&sc->sc_hw.bulk_start_pc, 0, &buf_res); 234184610Salfred OWRITE4(sc, OHCI_BULK_HEAD_ED, buf_res.physaddr); 235184610Salfred 236184610Salfred /* disable all interrupts and then switch on all desired interrupts */ 237184610Salfred OWRITE4(sc, OHCI_INTERRUPT_DISABLE, OHCI_ALL_INTRS); 238184610Salfred OWRITE4(sc, OHCI_INTERRUPT_ENABLE, sc->sc_eintrs | OHCI_MIE); 239184610Salfred /* switch on desired functional features */ 240184610Salfred ctl = OREAD4(sc, OHCI_CONTROL); 241184610Salfred ctl &= ~(OHCI_CBSR_MASK | OHCI_LES | OHCI_HCFS_MASK | OHCI_IR); 242184610Salfred ctl |= OHCI_PLE | OHCI_IE | OHCI_CLE | OHCI_BLE | 243184610Salfred OHCI_RATIO_1_4 | OHCI_HCFS_OPERATIONAL; 244184610Salfred /* And finally start it! */ 245184610Salfred OWRITE4(sc, OHCI_CONTROL, ctl); 246184610Salfred 247184610Salfred /* 248184610Salfred * The controller is now OPERATIONAL. Set a some final 249184610Salfred * registers that should be set earlier, but that the 250184610Salfred * controller ignores when in the SUSPEND state. 251184610Salfred */ 252184610Salfred fm = (OREAD4(sc, OHCI_FM_INTERVAL) & OHCI_FIT) ^ OHCI_FIT; 253184610Salfred fm |= OHCI_FSMPS(ival) | ival; 254184610Salfred OWRITE4(sc, OHCI_FM_INTERVAL, fm); 255184610Salfred per = OHCI_PERIODIC(ival); /* 90% periodic */ 256184610Salfred OWRITE4(sc, OHCI_PERIODIC_START, per); 257184610Salfred 258184610Salfred /* Fiddle the No OverCurrent Protection bit to avoid chip bug. */ 259184610Salfred desca = OREAD4(sc, OHCI_RH_DESCRIPTOR_A); 260184610Salfred OWRITE4(sc, OHCI_RH_DESCRIPTOR_A, desca | OHCI_NOCP); 261184610Salfred OWRITE4(sc, OHCI_RH_STATUS, OHCI_LPSC); /* Enable port power */ 262184824Sthompsa usb2_pause_mtx(&sc->sc_bus.bus_mtx, 263184610Salfred OHCI_ENABLE_POWER_DELAY); 264184610Salfred OWRITE4(sc, OHCI_RH_DESCRIPTOR_A, desca); 265184610Salfred 266184610Salfred /* 267184610Salfred * The AMD756 requires a delay before re-reading the register, 268184610Salfred * otherwise it will occasionally report 0 ports. 269184610Salfred */ 270184610Salfred sc->sc_noport = 0; 271184610Salfred for (i = 0; (i < 10) && (sc->sc_noport == 0); i++) { 272184824Sthompsa usb2_pause_mtx(&sc->sc_bus.bus_mtx, 273184610Salfred OHCI_READ_DESC_DELAY); 274184610Salfred sc->sc_noport = OHCI_GET_NDP(OREAD4(sc, OHCI_RH_DESCRIPTOR_A)); 275184610Salfred } 276184610Salfred 277184610Salfred#if USB_DEBUG 278184610Salfred if (ohcidebug > 5) { 279184610Salfred ohci_dumpregs(sc); 280184610Salfred } 281184610Salfred#endif 282184610Salfred return (USB_ERR_NORMAL_COMPLETION); 283184610Salfred} 284184610Salfred 285184610Salfredstatic struct ohci_ed * 286184610Salfredohci_init_ed(struct usb2_page_cache *pc) 287184610Salfred{ 288184610Salfred struct usb2_page_search buf_res; 289184610Salfred struct ohci_ed *ed; 290184610Salfred 291184610Salfred usb2_get_page(pc, 0, &buf_res); 292184610Salfred 293184610Salfred ed = buf_res.buffer; 294184610Salfred 295184610Salfred ed->ed_self = htole32(buf_res.physaddr); 296184610Salfred ed->ed_flags = htole32(OHCI_ED_SKIP); 297184610Salfred ed->page_cache = pc; 298184610Salfred 299184610Salfred return (ed); 300184610Salfred} 301184610Salfred 302184610Salfredusb2_error_t 303184610Salfredohci_init(ohci_softc_t *sc) 304184610Salfred{ 305184610Salfred struct usb2_page_search buf_res; 306184610Salfred uint16_t i; 307184610Salfred uint16_t bit; 308184610Salfred uint16_t x; 309184610Salfred uint16_t y; 310184610Salfred 311184824Sthompsa USB_BUS_LOCK(&sc->sc_bus); 312184610Salfred 313184610Salfred DPRINTF("start\n"); 314184610Salfred 315184610Salfred sc->sc_eintrs = OHCI_NORMAL_INTRS; 316184610Salfred 317184610Salfred /* 318184610Salfred * Setup all ED's 319184610Salfred */ 320184610Salfred 321184610Salfred sc->sc_ctrl_p_last = 322184610Salfred ohci_init_ed(&sc->sc_hw.ctrl_start_pc); 323184610Salfred 324184610Salfred sc->sc_bulk_p_last = 325184610Salfred ohci_init_ed(&sc->sc_hw.bulk_start_pc); 326184610Salfred 327184610Salfred sc->sc_isoc_p_last = 328184610Salfred ohci_init_ed(&sc->sc_hw.isoc_start_pc); 329184610Salfred 330184610Salfred for (i = 0; i != OHCI_NO_EDS; i++) { 331184610Salfred sc->sc_intr_p_last[i] = 332184610Salfred ohci_init_ed(sc->sc_hw.intr_start_pc + i); 333184610Salfred } 334184610Salfred 335184610Salfred /* 336184610Salfred * the QHs are arranged to give poll intervals that are 337184610Salfred * powers of 2 times 1ms 338184610Salfred */ 339184610Salfred bit = OHCI_NO_EDS / 2; 340184610Salfred while (bit) { 341184610Salfred x = bit; 342184610Salfred while (x & bit) { 343184610Salfred ohci_ed_t *ed_x; 344184610Salfred ohci_ed_t *ed_y; 345184610Salfred 346184610Salfred y = (x ^ bit) | (bit / 2); 347184610Salfred 348184610Salfred /* 349184610Salfred * the next QH has half the poll interval 350184610Salfred */ 351184610Salfred ed_x = sc->sc_intr_p_last[x]; 352184610Salfred ed_y = sc->sc_intr_p_last[y]; 353184610Salfred 354184610Salfred ed_x->next = NULL; 355184610Salfred ed_x->ed_next = ed_y->ed_self; 356184610Salfred 357184610Salfred x++; 358184610Salfred } 359184610Salfred bit >>= 1; 360184610Salfred } 361184610Salfred 362184610Salfred if (1) { 363184610Salfred 364184610Salfred ohci_ed_t *ed_int; 365184610Salfred ohci_ed_t *ed_isc; 366184610Salfred 367184610Salfred ed_int = sc->sc_intr_p_last[0]; 368184610Salfred ed_isc = sc->sc_isoc_p_last; 369184610Salfred 370184610Salfred /* the last (1ms) QH */ 371184610Salfred ed_int->next = ed_isc; 372184610Salfred ed_int->ed_next = ed_isc->ed_self; 373184610Salfred } 374184610Salfred usb2_get_page(&sc->sc_hw.hcca_pc, 0, &buf_res); 375184610Salfred 376184610Salfred sc->sc_hcca_p = buf_res.buffer; 377184610Salfred 378184610Salfred /* 379184610Salfred * Fill HCCA interrupt table. The bit reversal is to get 380184610Salfred * the tree set up properly to spread the interrupts. 381184610Salfred */ 382184610Salfred for (i = 0; i != OHCI_NO_INTRS; i++) { 383184610Salfred sc->sc_hcca_p->hcca_interrupt_table[i] = 384184610Salfred sc->sc_intr_p_last[i | (OHCI_NO_EDS / 2)]->ed_self; 385184610Salfred } 386184610Salfred /* flush all cache into memory */ 387184610Salfred 388184610Salfred usb2_bus_mem_flush_all(&sc->sc_bus, &ohci_iterate_hw_softc); 389184610Salfred 390184610Salfred /* set up the bus struct */ 391184610Salfred sc->sc_bus.methods = &ohci_bus_methods; 392184610Salfred 393186454Sthompsa usb2_callout_init_mtx(&sc->sc_tmo_rhsc, &sc->sc_bus.bus_mtx, 0); 394184610Salfred 395184610Salfred#if USB_DEBUG 396184610Salfred if (ohcidebug > 15) { 397184610Salfred for (i = 0; i != OHCI_NO_EDS; i++) { 398184610Salfred printf("ed#%d ", i); 399184610Salfred ohci_dump_ed(sc->sc_intr_p_last[i]); 400184610Salfred } 401184610Salfred printf("iso "); 402184610Salfred ohci_dump_ed(sc->sc_isoc_p_last); 403184610Salfred } 404184610Salfred#endif 405184610Salfred 406184610Salfred sc->sc_bus.usbrev = USB_REV_1_0; 407184610Salfred 408184610Salfred if (ohci_controller_init(sc)) { 409184824Sthompsa USB_BUS_UNLOCK(&sc->sc_bus); 410184610Salfred return (USB_ERR_INVAL); 411184610Salfred } else { 412184824Sthompsa USB_BUS_UNLOCK(&sc->sc_bus); 413184610Salfred /* catch any lost interrupts */ 414184610Salfred ohci_do_poll(&sc->sc_bus); 415184610Salfred return (USB_ERR_NORMAL_COMPLETION); 416184610Salfred } 417184610Salfred} 418184610Salfred 419184610Salfred/* 420184610Salfred * shut down the controller when the system is going down 421184610Salfred */ 422184610Salfredvoid 423184610Salfredohci_detach(struct ohci_softc *sc) 424184610Salfred{ 425184824Sthompsa USB_BUS_LOCK(&sc->sc_bus); 426184610Salfred 427184610Salfred usb2_callout_stop(&sc->sc_tmo_rhsc); 428184610Salfred 429184610Salfred OWRITE4(sc, OHCI_INTERRUPT_DISABLE, OHCI_ALL_INTRS); 430184610Salfred OWRITE4(sc, OHCI_CONTROL, OHCI_HCFS_RESET); 431184610Salfred 432184610Salfred /* XXX let stray task complete */ 433184824Sthompsa usb2_pause_mtx(&sc->sc_bus.bus_mtx, 50); 434184610Salfred 435184824Sthompsa USB_BUS_UNLOCK(&sc->sc_bus); 436184610Salfred 437184610Salfred usb2_callout_drain(&sc->sc_tmo_rhsc); 438184610Salfred} 439184610Salfred 440184610Salfred/* NOTE: suspend/resume is called from 441184610Salfred * interrupt context and cannot sleep! 442184610Salfred */ 443184610Salfredvoid 444184610Salfredohci_suspend(ohci_softc_t *sc) 445184610Salfred{ 446184610Salfred uint32_t ctl; 447184610Salfred 448184824Sthompsa USB_BUS_LOCK(&sc->sc_bus); 449184610Salfred 450184610Salfred#if USB_DEBUG 451184610Salfred DPRINTF("\n"); 452184610Salfred if (ohcidebug > 2) { 453184610Salfred ohci_dumpregs(sc); 454184610Salfred } 455184610Salfred#endif 456184610Salfred 457184610Salfred ctl = OREAD4(sc, OHCI_CONTROL) & ~OHCI_HCFS_MASK; 458184610Salfred if (sc->sc_control == 0) { 459184610Salfred /* 460184610Salfred * Preserve register values, in case that APM BIOS 461184610Salfred * does not recover them. 462184610Salfred */ 463184610Salfred sc->sc_control = ctl; 464184610Salfred sc->sc_intre = OREAD4(sc, OHCI_INTERRUPT_ENABLE); 465184610Salfred } 466184610Salfred ctl |= OHCI_HCFS_SUSPEND; 467184610Salfred OWRITE4(sc, OHCI_CONTROL, ctl); 468184610Salfred 469184824Sthompsa usb2_pause_mtx(&sc->sc_bus.bus_mtx, 470184610Salfred USB_RESUME_WAIT); 471184610Salfred 472184824Sthompsa USB_BUS_UNLOCK(&sc->sc_bus); 473184610Salfred} 474184610Salfred 475184610Salfredvoid 476184610Salfredohci_resume(ohci_softc_t *sc) 477184610Salfred{ 478184610Salfred uint32_t ctl; 479184610Salfred 480184824Sthompsa USB_BUS_LOCK(&sc->sc_bus); 481184610Salfred 482184610Salfred#if USB_DEBUG 483184610Salfred DPRINTF("\n"); 484184610Salfred if (ohcidebug > 2) { 485184610Salfred ohci_dumpregs(sc); 486184610Salfred } 487184610Salfred#endif 488184610Salfred /* some broken BIOSes never initialize the Controller chip */ 489184610Salfred ohci_controller_init(sc); 490184610Salfred 491184610Salfred if (sc->sc_intre) { 492184610Salfred OWRITE4(sc, OHCI_INTERRUPT_ENABLE, 493184610Salfred sc->sc_intre & (OHCI_ALL_INTRS | OHCI_MIE)); 494184610Salfred } 495184610Salfred if (sc->sc_control) 496184610Salfred ctl = sc->sc_control; 497184610Salfred else 498184610Salfred ctl = OREAD4(sc, OHCI_CONTROL); 499184610Salfred ctl |= OHCI_HCFS_RESUME; 500184610Salfred OWRITE4(sc, OHCI_CONTROL, ctl); 501184824Sthompsa usb2_pause_mtx(&sc->sc_bus.bus_mtx, USB_RESUME_DELAY); 502184610Salfred ctl = (ctl & ~OHCI_HCFS_MASK) | OHCI_HCFS_OPERATIONAL; 503184610Salfred OWRITE4(sc, OHCI_CONTROL, ctl); 504184824Sthompsa usb2_pause_mtx(&sc->sc_bus.bus_mtx, USB_RESUME_RECOVERY); 505184610Salfred sc->sc_control = sc->sc_intre = 0; 506184610Salfred 507184824Sthompsa USB_BUS_UNLOCK(&sc->sc_bus); 508184610Salfred 509184610Salfred /* catch any lost interrupts */ 510184610Salfred ohci_do_poll(&sc->sc_bus); 511184610Salfred} 512184610Salfred 513184610Salfred#if USB_DEBUG 514184610Salfredstatic void 515184610Salfredohci_dumpregs(ohci_softc_t *sc) 516184610Salfred{ 517184610Salfred struct ohci_hcca *hcca; 518184610Salfred 519184610Salfred DPRINTF("ohci_dumpregs: rev=0x%08x control=0x%08x command=0x%08x\n", 520184610Salfred OREAD4(sc, OHCI_REVISION), 521184610Salfred OREAD4(sc, OHCI_CONTROL), 522184610Salfred OREAD4(sc, OHCI_COMMAND_STATUS)); 523184610Salfred DPRINTF(" intrstat=0x%08x intre=0x%08x intrd=0x%08x\n", 524184610Salfred OREAD4(sc, OHCI_INTERRUPT_STATUS), 525184610Salfred OREAD4(sc, OHCI_INTERRUPT_ENABLE), 526184610Salfred OREAD4(sc, OHCI_INTERRUPT_DISABLE)); 527184610Salfred DPRINTF(" hcca=0x%08x percur=0x%08x ctrlhd=0x%08x\n", 528184610Salfred OREAD4(sc, OHCI_HCCA), 529184610Salfred OREAD4(sc, OHCI_PERIOD_CURRENT_ED), 530184610Salfred OREAD4(sc, OHCI_CONTROL_HEAD_ED)); 531184610Salfred DPRINTF(" ctrlcur=0x%08x bulkhd=0x%08x bulkcur=0x%08x\n", 532184610Salfred OREAD4(sc, OHCI_CONTROL_CURRENT_ED), 533184610Salfred OREAD4(sc, OHCI_BULK_HEAD_ED), 534184610Salfred OREAD4(sc, OHCI_BULK_CURRENT_ED)); 535184610Salfred DPRINTF(" done=0x%08x fmival=0x%08x fmrem=0x%08x\n", 536184610Salfred OREAD4(sc, OHCI_DONE_HEAD), 537184610Salfred OREAD4(sc, OHCI_FM_INTERVAL), 538184610Salfred OREAD4(sc, OHCI_FM_REMAINING)); 539184610Salfred DPRINTF(" fmnum=0x%08x perst=0x%08x lsthrs=0x%08x\n", 540184610Salfred OREAD4(sc, OHCI_FM_NUMBER), 541184610Salfred OREAD4(sc, OHCI_PERIODIC_START), 542184610Salfred OREAD4(sc, OHCI_LS_THRESHOLD)); 543184610Salfred DPRINTF(" desca=0x%08x descb=0x%08x stat=0x%08x\n", 544184610Salfred OREAD4(sc, OHCI_RH_DESCRIPTOR_A), 545184610Salfred OREAD4(sc, OHCI_RH_DESCRIPTOR_B), 546184610Salfred OREAD4(sc, OHCI_RH_STATUS)); 547184610Salfred DPRINTF(" port1=0x%08x port2=0x%08x\n", 548184610Salfred OREAD4(sc, OHCI_RH_PORT_STATUS(1)), 549184610Salfred OREAD4(sc, OHCI_RH_PORT_STATUS(2))); 550184610Salfred 551184610Salfred hcca = ohci_get_hcca(sc); 552184610Salfred 553184610Salfred DPRINTF(" HCCA: frame_number=0x%04x done_head=0x%08x\n", 554184610Salfred le32toh(hcca->hcca_frame_number), 555184610Salfred le32toh(hcca->hcca_done_head)); 556184610Salfred} 557184610Salfredstatic void 558184610Salfredohci_dump_tds(ohci_td_t *std) 559184610Salfred{ 560184610Salfred for (; std; std = std->obj_next) { 561184610Salfred if (ohci_dump_td(std)) { 562184610Salfred break; 563184610Salfred } 564184610Salfred } 565184610Salfred} 566184610Salfred 567184610Salfredstatic uint8_t 568184610Salfredohci_dump_td(ohci_td_t *std) 569184610Salfred{ 570184610Salfred uint32_t td_flags; 571184610Salfred uint8_t temp; 572184610Salfred 573184610Salfred usb2_pc_cpu_invalidate(std->page_cache); 574184610Salfred 575184610Salfred td_flags = le32toh(std->td_flags); 576184610Salfred temp = (std->td_next == 0); 577184610Salfred 578184610Salfred printf("TD(%p) at 0x%08x: %s%s%s%s%s delay=%d ec=%d " 579184610Salfred "cc=%d\ncbp=0x%08x next=0x%08x be=0x%08x\n", 580184610Salfred std, le32toh(std->td_self), 581184610Salfred (td_flags & OHCI_TD_R) ? "-R" : "", 582184610Salfred (td_flags & OHCI_TD_OUT) ? "-OUT" : "", 583184610Salfred (td_flags & OHCI_TD_IN) ? "-IN" : "", 584184610Salfred ((td_flags & OHCI_TD_TOGGLE_MASK) == OHCI_TD_TOGGLE_1) ? "-TOG1" : "", 585184610Salfred ((td_flags & OHCI_TD_TOGGLE_MASK) == OHCI_TD_TOGGLE_0) ? "-TOG0" : "", 586184610Salfred OHCI_TD_GET_DI(td_flags), 587184610Salfred OHCI_TD_GET_EC(td_flags), 588184610Salfred OHCI_TD_GET_CC(td_flags), 589184610Salfred le32toh(std->td_cbp), 590184610Salfred le32toh(std->td_next), 591184610Salfred le32toh(std->td_be)); 592184610Salfred 593184610Salfred return (temp); 594184610Salfred} 595184610Salfred 596184610Salfredstatic uint8_t 597184610Salfredohci_dump_itd(ohci_itd_t *sitd) 598184610Salfred{ 599184610Salfred uint32_t itd_flags; 600184610Salfred uint16_t i; 601184610Salfred uint8_t temp; 602184610Salfred 603184610Salfred usb2_pc_cpu_invalidate(sitd->page_cache); 604184610Salfred 605184610Salfred itd_flags = le32toh(sitd->itd_flags); 606184610Salfred temp = (sitd->itd_next == 0); 607184610Salfred 608184610Salfred printf("ITD(%p) at 0x%08x: sf=%d di=%d fc=%d cc=%d\n" 609184610Salfred "bp0=0x%08x next=0x%08x be=0x%08x\n", 610184610Salfred sitd, le32toh(sitd->itd_self), 611184610Salfred OHCI_ITD_GET_SF(itd_flags), 612184610Salfred OHCI_ITD_GET_DI(itd_flags), 613184610Salfred OHCI_ITD_GET_FC(itd_flags), 614184610Salfred OHCI_ITD_GET_CC(itd_flags), 615184610Salfred le32toh(sitd->itd_bp0), 616184610Salfred le32toh(sitd->itd_next), 617184610Salfred le32toh(sitd->itd_be)); 618184610Salfred for (i = 0; i < OHCI_ITD_NOFFSET; i++) { 619184610Salfred printf("offs[%d]=0x%04x ", i, 620184610Salfred (uint32_t)le16toh(sitd->itd_offset[i])); 621184610Salfred } 622184610Salfred printf("\n"); 623184610Salfred 624184610Salfred return (temp); 625184610Salfred} 626184610Salfred 627184610Salfredstatic void 628184610Salfredohci_dump_itds(ohci_itd_t *sitd) 629184610Salfred{ 630184610Salfred for (; sitd; sitd = sitd->obj_next) { 631184610Salfred if (ohci_dump_itd(sitd)) { 632184610Salfred break; 633184610Salfred } 634184610Salfred } 635184610Salfred} 636184610Salfred 637184610Salfredstatic void 638184610Salfredohci_dump_ed(ohci_ed_t *sed) 639184610Salfred{ 640184610Salfred uint32_t ed_flags; 641184610Salfred uint32_t ed_headp; 642184610Salfred 643184610Salfred usb2_pc_cpu_invalidate(sed->page_cache); 644184610Salfred 645184610Salfred ed_flags = le32toh(sed->ed_flags); 646184610Salfred ed_headp = le32toh(sed->ed_headp); 647184610Salfred 648184610Salfred printf("ED(%p) at 0x%08x: addr=%d endpt=%d maxp=%d flags=%s%s%s%s%s\n" 649184610Salfred "tailp=0x%08x headflags=%s%s headp=0x%08x nexted=0x%08x\n", 650184610Salfred sed, le32toh(sed->ed_self), 651184610Salfred OHCI_ED_GET_FA(ed_flags), 652184610Salfred OHCI_ED_GET_EN(ed_flags), 653184610Salfred OHCI_ED_GET_MAXP(ed_flags), 654184610Salfred (ed_flags & OHCI_ED_DIR_OUT) ? "-OUT" : "", 655184610Salfred (ed_flags & OHCI_ED_DIR_IN) ? "-IN" : "", 656184610Salfred (ed_flags & OHCI_ED_SPEED) ? "-LOWSPEED" : "", 657184610Salfred (ed_flags & OHCI_ED_SKIP) ? "-SKIP" : "", 658184610Salfred (ed_flags & OHCI_ED_FORMAT_ISO) ? "-ISO" : "", 659184610Salfred le32toh(sed->ed_tailp), 660184610Salfred (ed_headp & OHCI_HALTED) ? "-HALTED" : "", 661184610Salfred (ed_headp & OHCI_TOGGLECARRY) ? "-CARRY" : "", 662184610Salfred le32toh(sed->ed_headp), 663184610Salfred le32toh(sed->ed_next)); 664184610Salfred} 665184610Salfred 666184610Salfred#endif 667184610Salfred 668184610Salfredstatic void 669184610Salfredohci_transfer_intr_enqueue(struct usb2_xfer *xfer) 670184610Salfred{ 671184610Salfred /* check for early completion */ 672184610Salfred if (ohci_check_transfer(xfer)) { 673184610Salfred return; 674184610Salfred } 675184610Salfred /* put transfer on interrupt queue */ 676184610Salfred usb2_transfer_enqueue(&xfer->udev->bus->intr_q, xfer); 677184610Salfred 678184610Salfred /* start timeout, if any */ 679184610Salfred if (xfer->timeout != 0) { 680184610Salfred usb2_transfer_timeout_ms(xfer, &ohci_timeout, xfer->timeout); 681184610Salfred } 682184610Salfred} 683184610Salfred 684186730Salfred#define OHCI_APPEND_QH(sed,last) (last) = _ohci_append_qh(sed,last) 685184610Salfredstatic ohci_ed_t * 686186730Salfred_ohci_append_qh(ohci_ed_t *sed, ohci_ed_t *last) 687184610Salfred{ 688184610Salfred DPRINTFN(11, "%p to %p\n", sed, last); 689184610Salfred 690186730Salfred if (sed->prev != NULL) { 691186730Salfred /* should not happen */ 692186730Salfred DPRINTFN(0, "ED already linked!\n"); 693186730Salfred return (last); 694186730Salfred } 695184824Sthompsa /* (sc->sc_bus.bus_mtx) must be locked */ 696184610Salfred 697184610Salfred sed->next = last->next; 698184610Salfred sed->ed_next = last->ed_next; 699184610Salfred sed->ed_tailp = 0; 700184610Salfred 701184610Salfred sed->prev = last; 702184610Salfred 703184610Salfred usb2_pc_cpu_flush(sed->page_cache); 704184610Salfred 705184610Salfred /* 706184610Salfred * the last->next->prev is never followed: sed->next->prev = sed; 707184610Salfred */ 708184610Salfred 709184610Salfred last->next = sed; 710184610Salfred last->ed_next = sed->ed_self; 711184610Salfred 712184610Salfred usb2_pc_cpu_flush(last->page_cache); 713184610Salfred 714184610Salfred return (sed); 715184610Salfred} 716184610Salfred 717184610Salfred#define OHCI_REMOVE_QH(sed,last) (last) = _ohci_remove_qh(sed,last) 718184610Salfredstatic ohci_ed_t * 719184610Salfred_ohci_remove_qh(ohci_ed_t *sed, ohci_ed_t *last) 720184610Salfred{ 721184610Salfred DPRINTFN(11, "%p from %p\n", sed, last); 722184610Salfred 723184824Sthompsa /* (sc->sc_bus.bus_mtx) must be locked */ 724184610Salfred 725184610Salfred /* only remove if not removed from a queue */ 726184610Salfred if (sed->prev) { 727184610Salfred 728184610Salfred sed->prev->next = sed->next; 729184610Salfred sed->prev->ed_next = sed->ed_next; 730184610Salfred 731184610Salfred usb2_pc_cpu_flush(sed->prev->page_cache); 732184610Salfred 733184610Salfred if (sed->next) { 734184610Salfred sed->next->prev = sed->prev; 735184610Salfred usb2_pc_cpu_flush(sed->next->page_cache); 736184610Salfred } 737184610Salfred last = ((last == sed) ? sed->prev : last); 738184610Salfred 739184610Salfred sed->prev = 0; 740184610Salfred 741184610Salfred usb2_pc_cpu_flush(sed->page_cache); 742184610Salfred } 743184610Salfred return (last); 744184610Salfred} 745184610Salfred 746184610Salfredstatic void 747184610Salfredohci_isoc_done(struct usb2_xfer *xfer) 748184610Salfred{ 749184610Salfred uint8_t nframes; 750184610Salfred uint32_t *plen = xfer->frlengths; 751184610Salfred volatile uint16_t *olen; 752184610Salfred uint16_t len = 0; 753184610Salfred ohci_itd_t *td = xfer->td_transfer_first; 754184610Salfred 755184610Salfred while (1) { 756184610Salfred if (td == NULL) { 757184610Salfred panic("%s:%d: out of TD's\n", 758184610Salfred __FUNCTION__, __LINE__); 759184610Salfred } 760184610Salfred#if USB_DEBUG 761184610Salfred if (ohcidebug > 5) { 762184610Salfred DPRINTF("isoc TD\n"); 763184610Salfred ohci_dump_itd(td); 764184610Salfred } 765184610Salfred#endif 766184610Salfred usb2_pc_cpu_invalidate(td->page_cache); 767184610Salfred 768184610Salfred nframes = td->frames; 769184610Salfred olen = &td->itd_offset[0]; 770184610Salfred 771184610Salfred if (nframes > 8) { 772184610Salfred nframes = 8; 773184610Salfred } 774184610Salfred while (nframes--) { 775184610Salfred len = le16toh(*olen); 776184610Salfred 777184610Salfred if ((len >> 12) == OHCI_CC_NOT_ACCESSED) { 778184610Salfred len = 0; 779184610Salfred } else { 780184610Salfred len &= ((1 << 12) - 1); 781184610Salfred } 782184610Salfred 783184610Salfred if (len > *plen) { 784184610Salfred len = 0;/* invalid length */ 785184610Salfred } 786184610Salfred *plen = len; 787184610Salfred plen++; 788184610Salfred olen++; 789184610Salfred } 790184610Salfred 791184610Salfred if (((void *)td) == xfer->td_transfer_last) { 792184610Salfred break; 793184610Salfred } 794184610Salfred td = td->obj_next; 795184610Salfred } 796184610Salfred 797184610Salfred xfer->aframes = xfer->nframes; 798184610Salfred ohci_device_done(xfer, USB_ERR_NORMAL_COMPLETION); 799184610Salfred} 800184610Salfred 801184610Salfred#if USB_DEBUG 802184610Salfredstatic const char *const 803184610Salfred ohci_cc_strs[] = 804184610Salfred{ 805184610Salfred "NO_ERROR", 806184610Salfred "CRC", 807184610Salfred "BIT_STUFFING", 808184610Salfred "DATA_TOGGLE_MISMATCH", 809184610Salfred 810184610Salfred "STALL", 811184610Salfred "DEVICE_NOT_RESPONDING", 812184610Salfred "PID_CHECK_FAILURE", 813184610Salfred "UNEXPECTED_PID", 814184610Salfred 815184610Salfred "DATA_OVERRUN", 816184610Salfred "DATA_UNDERRUN", 817184610Salfred "BUFFER_OVERRUN", 818184610Salfred "BUFFER_UNDERRUN", 819184610Salfred 820184610Salfred "reserved", 821184610Salfred "reserved", 822184610Salfred "NOT_ACCESSED", 823184610Salfred "NOT_ACCESSED" 824184610Salfred}; 825184610Salfred 826184610Salfred#endif 827184610Salfred 828184610Salfredstatic usb2_error_t 829184610Salfredohci_non_isoc_done_sub(struct usb2_xfer *xfer) 830184610Salfred{ 831184610Salfred ohci_td_t *td; 832184610Salfred ohci_td_t *td_alt_next; 833184610Salfred uint32_t temp; 834184610Salfred uint32_t phy_start; 835184610Salfred uint32_t phy_end; 836184610Salfred uint32_t td_flags; 837184610Salfred uint16_t cc; 838184610Salfred 839184610Salfred td = xfer->td_transfer_cache; 840184610Salfred td_alt_next = td->alt_next; 841184610Salfred td_flags = 0; 842184610Salfred 843184610Salfred while (1) { 844184610Salfred 845184610Salfred usb2_pc_cpu_invalidate(td->page_cache); 846184610Salfred phy_start = le32toh(td->td_cbp); 847184610Salfred td_flags = le32toh(td->td_flags); 848184610Salfred cc = OHCI_TD_GET_CC(td_flags); 849184610Salfred 850184610Salfred if (phy_start) { 851184610Salfred /* 852184610Salfred * short transfer - compute the number of remaining 853184610Salfred * bytes in the hardware buffer: 854184610Salfred */ 855184610Salfred phy_end = le32toh(td->td_be); 856184610Salfred temp = (OHCI_PAGE(phy_start ^ phy_end) ? 857184610Salfred (OHCI_PAGE_SIZE + 1) : 0x0001); 858184610Salfred temp += OHCI_PAGE_OFFSET(phy_end); 859184610Salfred temp -= OHCI_PAGE_OFFSET(phy_start); 860184610Salfred 861184610Salfred if (temp > td->len) { 862184610Salfred /* guard against corruption */ 863184610Salfred cc = OHCI_CC_STALL; 864184610Salfred } else if (xfer->aframes != xfer->nframes) { 865184610Salfred /* 866184610Salfred * subtract remaining length from 867184610Salfred * "frlengths[]" 868184610Salfred */ 869184610Salfred xfer->frlengths[xfer->aframes] -= temp; 870184610Salfred } 871184610Salfred } 872184610Salfred /* Check for last transfer */ 873184610Salfred if (((void *)td) == xfer->td_transfer_last) { 874184610Salfred td = NULL; 875184610Salfred break; 876184610Salfred } 877184610Salfred /* Check transfer status */ 878184610Salfred if (cc) { 879184610Salfred /* the transfer is finished */ 880184610Salfred td = NULL; 881184610Salfred break; 882184610Salfred } 883184610Salfred /* Check for short transfer */ 884184610Salfred if (phy_start) { 885184610Salfred if (xfer->flags_int.short_frames_ok) { 886184610Salfred /* follow alt next */ 887184610Salfred td = td->alt_next; 888184610Salfred } else { 889184610Salfred /* the transfer is finished */ 890184610Salfred td = NULL; 891184610Salfred } 892184610Salfred break; 893184610Salfred } 894184610Salfred td = td->obj_next; 895184610Salfred 896184610Salfred if (td->alt_next != td_alt_next) { 897184610Salfred /* this USB frame is complete */ 898184610Salfred break; 899184610Salfred } 900184610Salfred } 901184610Salfred 902184610Salfred /* update transfer cache */ 903184610Salfred 904184610Salfred xfer->td_transfer_cache = td; 905184610Salfred 906184610Salfred DPRINTFN(16, "error cc=%d (%s)\n", 907184610Salfred cc, ohci_cc_strs[cc]); 908184610Salfred 909184610Salfred return ((cc == 0) ? USB_ERR_NORMAL_COMPLETION : 910184610Salfred (cc == OHCI_CC_STALL) ? USB_ERR_STALLED : USB_ERR_IOERROR); 911184610Salfred} 912184610Salfred 913184610Salfredstatic void 914184610Salfredohci_non_isoc_done(struct usb2_xfer *xfer) 915184610Salfred{ 916184610Salfred usb2_error_t err = 0; 917184610Salfred 918184610Salfred DPRINTFN(13, "xfer=%p pipe=%p transfer done\n", 919184610Salfred xfer, xfer->pipe); 920184610Salfred 921184610Salfred#if USB_DEBUG 922184610Salfred if (ohcidebug > 10) { 923184610Salfred ohci_dump_tds(xfer->td_transfer_first); 924184610Salfred } 925184610Salfred#endif 926184610Salfred 927184610Salfred /* reset scanner */ 928184610Salfred 929184610Salfred xfer->td_transfer_cache = xfer->td_transfer_first; 930184610Salfred 931184610Salfred if (xfer->flags_int.control_xfr) { 932184610Salfred 933184610Salfred if (xfer->flags_int.control_hdr) { 934184610Salfred 935184610Salfred err = ohci_non_isoc_done_sub(xfer); 936184610Salfred } 937184610Salfred xfer->aframes = 1; 938184610Salfred 939184610Salfred if (xfer->td_transfer_cache == NULL) { 940184610Salfred goto done; 941184610Salfred } 942184610Salfred } 943184610Salfred while (xfer->aframes != xfer->nframes) { 944184610Salfred 945184610Salfred err = ohci_non_isoc_done_sub(xfer); 946184610Salfred xfer->aframes++; 947184610Salfred 948184610Salfred if (xfer->td_transfer_cache == NULL) { 949184610Salfred goto done; 950184610Salfred } 951184610Salfred } 952184610Salfred 953184610Salfred if (xfer->flags_int.control_xfr && 954184610Salfred !xfer->flags_int.control_act) { 955184610Salfred 956184610Salfred err = ohci_non_isoc_done_sub(xfer); 957184610Salfred } 958184610Salfreddone: 959184610Salfred ohci_device_done(xfer, err); 960184610Salfred} 961184610Salfred 962184610Salfred/*------------------------------------------------------------------------* 963184610Salfred * ohci_check_transfer_sub 964184610Salfred *------------------------------------------------------------------------*/ 965184610Salfredstatic void 966184610Salfredohci_check_transfer_sub(struct usb2_xfer *xfer) 967184610Salfred{ 968184610Salfred ohci_td_t *td; 969184610Salfred ohci_ed_t *ed; 970184610Salfred uint32_t phy_start; 971184610Salfred uint32_t td_flags; 972184610Salfred uint32_t td_next; 973184610Salfred uint16_t cc; 974184610Salfred 975184610Salfred td = xfer->td_transfer_cache; 976184610Salfred 977184610Salfred while (1) { 978184610Salfred 979184610Salfred usb2_pc_cpu_invalidate(td->page_cache); 980184610Salfred phy_start = le32toh(td->td_cbp); 981184610Salfred td_flags = le32toh(td->td_flags); 982184610Salfred td_next = le32toh(td->td_next); 983184610Salfred 984184610Salfred /* Check for last transfer */ 985184610Salfred if (((void *)td) == xfer->td_transfer_last) { 986184610Salfred /* the transfer is finished */ 987184610Salfred td = NULL; 988184610Salfred break; 989184610Salfred } 990184610Salfred /* Check transfer status */ 991184610Salfred cc = OHCI_TD_GET_CC(td_flags); 992184610Salfred if (cc) { 993184610Salfred /* the transfer is finished */ 994184610Salfred td = NULL; 995184610Salfred break; 996184610Salfred } 997184610Salfred /* 998184610Salfred * Check if we reached the last packet 999184610Salfred * or if there is a short packet: 1000184610Salfred */ 1001184610Salfred 1002184610Salfred if (((td_next & (~0xF)) == OHCI_TD_NEXT_END) || phy_start) { 1003184610Salfred /* follow alt next */ 1004184610Salfred td = td->alt_next; 1005184610Salfred break; 1006184610Salfred } 1007184610Salfred td = td->obj_next; 1008184610Salfred } 1009184610Salfred 1010184610Salfred /* update transfer cache */ 1011184610Salfred 1012184610Salfred xfer->td_transfer_cache = td; 1013184610Salfred 1014184610Salfred if (td) { 1015184610Salfred 1016184610Salfred ed = xfer->qh_start[xfer->flags_int.curr_dma_set]; 1017184610Salfred 1018184610Salfred ed->ed_headp = td->td_self; 1019184610Salfred usb2_pc_cpu_flush(ed->page_cache); 1020184610Salfred 1021184610Salfred DPRINTFN(13, "xfer=%p following alt next\n", xfer); 1022184610Salfred } 1023184610Salfred} 1024184610Salfred 1025184610Salfred/*------------------------------------------------------------------------* 1026184610Salfred * ohci_check_transfer 1027184610Salfred * 1028184610Salfred * Return values: 1029184610Salfred * 0: USB transfer is not finished 1030184610Salfred * Else: USB transfer is finished 1031184610Salfred *------------------------------------------------------------------------*/ 1032184610Salfredstatic uint8_t 1033184610Salfredohci_check_transfer(struct usb2_xfer *xfer) 1034184610Salfred{ 1035184610Salfred ohci_ed_t *ed; 1036184610Salfred uint32_t ed_flags; 1037184610Salfred uint32_t ed_headp; 1038184610Salfred uint32_t ed_tailp; 1039184610Salfred 1040184610Salfred DPRINTFN(13, "xfer=%p checking transfer\n", xfer); 1041184610Salfred 1042184610Salfred ed = xfer->qh_start[xfer->flags_int.curr_dma_set]; 1043184610Salfred 1044184610Salfred usb2_pc_cpu_invalidate(ed->page_cache); 1045184610Salfred ed_flags = le32toh(ed->ed_flags); 1046184610Salfred ed_headp = le32toh(ed->ed_headp); 1047184610Salfred ed_tailp = le32toh(ed->ed_tailp); 1048184610Salfred 1049184610Salfred if ((ed_flags & OHCI_ED_SKIP) || 1050184610Salfred (ed_headp & OHCI_HALTED) || 1051184610Salfred (((ed_headp ^ ed_tailp) & (~0xF)) == 0)) { 1052184610Salfred if (xfer->pipe->methods == &ohci_device_isoc_methods) { 1053184610Salfred /* isochronous transfer */ 1054184610Salfred ohci_isoc_done(xfer); 1055184610Salfred } else { 1056184610Salfred if (xfer->flags_int.short_frames_ok) { 1057184610Salfred ohci_check_transfer_sub(xfer); 1058184610Salfred if (xfer->td_transfer_cache) { 1059184610Salfred /* not finished yet */ 1060184610Salfred return (0); 1061184610Salfred } 1062184610Salfred } 1063184610Salfred /* store data-toggle */ 1064184610Salfred if (ed_headp & OHCI_TOGGLECARRY) { 1065184610Salfred xfer->pipe->toggle_next = 1; 1066184610Salfred } else { 1067184610Salfred xfer->pipe->toggle_next = 0; 1068184610Salfred } 1069184610Salfred 1070184610Salfred /* non-isochronous transfer */ 1071184610Salfred ohci_non_isoc_done(xfer); 1072184610Salfred } 1073184610Salfred return (1); 1074184610Salfred } 1075184610Salfred DPRINTFN(13, "xfer=%p is still active\n", xfer); 1076184610Salfred return (0); 1077184610Salfred} 1078184610Salfred 1079184610Salfredstatic void 1080184610Salfredohci_rhsc_enable(ohci_softc_t *sc) 1081184610Salfred{ 1082184610Salfred DPRINTFN(5, "\n"); 1083184610Salfred 1084184824Sthompsa USB_BUS_LOCK_ASSERT(&sc->sc_bus, MA_OWNED); 1085184610Salfred 1086184610Salfred sc->sc_eintrs |= OHCI_RHSC; 1087184610Salfred OWRITE4(sc, OHCI_INTERRUPT_ENABLE, OHCI_RHSC); 1088184610Salfred 1089184610Salfred /* acknowledge any RHSC interrupt */ 1090184610Salfred OWRITE4(sc, OHCI_INTERRUPT_STATUS, OHCI_RHSC); 1091184610Salfred 1092184610Salfred usb2_sw_transfer(&sc->sc_root_intr, 1093184610Salfred &ohci_root_intr_done); 1094184610Salfred} 1095184610Salfred 1096184610Salfredstatic void 1097184610Salfredohci_interrupt_poll(ohci_softc_t *sc) 1098184610Salfred{ 1099184610Salfred struct usb2_xfer *xfer; 1100184610Salfred 1101184610Salfredrepeat: 1102184610Salfred TAILQ_FOREACH(xfer, &sc->sc_bus.intr_q.head, wait_entry) { 1103184610Salfred /* 1104184610Salfred * check if transfer is transferred 1105184610Salfred */ 1106184610Salfred if (ohci_check_transfer(xfer)) { 1107184610Salfred /* queue has been modified */ 1108184610Salfred goto repeat; 1109184610Salfred } 1110184610Salfred } 1111184610Salfred} 1112184610Salfred 1113184610Salfred/*------------------------------------------------------------------------* 1114184610Salfred * ohci_interrupt - OHCI interrupt handler 1115184610Salfred * 1116184610Salfred * NOTE: Do not access "sc->sc_bus.bdev" inside the interrupt handler, 1117184610Salfred * hence the interrupt handler will be setup before "sc->sc_bus.bdev" 1118184610Salfred * is present ! 1119184610Salfred *------------------------------------------------------------------------*/ 1120184610Salfredvoid 1121184610Salfredohci_interrupt(ohci_softc_t *sc) 1122184610Salfred{ 1123184610Salfred struct ohci_hcca *hcca; 1124184610Salfred uint32_t status; 1125184610Salfred uint32_t done; 1126184610Salfred 1127184824Sthompsa USB_BUS_LOCK(&sc->sc_bus); 1128184610Salfred 1129184610Salfred hcca = ohci_get_hcca(sc); 1130184610Salfred 1131184610Salfred DPRINTFN(16, "real interrupt\n"); 1132184610Salfred 1133184610Salfred#if USB_DEBUG 1134184610Salfred if (ohcidebug > 15) { 1135184610Salfred ohci_dumpregs(sc); 1136184610Salfred } 1137184610Salfred#endif 1138184610Salfred 1139184610Salfred done = le32toh(hcca->hcca_done_head); 1140184610Salfred 1141184610Salfred /* 1142184610Salfred * The LSb of done is used to inform the HC Driver that an interrupt 1143184610Salfred * condition exists for both the Done list and for another event 1144184610Salfred * recorded in HcInterruptStatus. On an interrupt from the HC, the 1145184610Salfred * HC Driver checks the HccaDoneHead Value. If this value is 0, then 1146184610Salfred * the interrupt was caused by other than the HccaDoneHead update 1147184610Salfred * and the HcInterruptStatus register needs to be accessed to 1148184610Salfred * determine that exact interrupt cause. If HccaDoneHead is nonzero, 1149184610Salfred * then a Done list update interrupt is indicated and if the LSb of 1150184610Salfred * done is nonzero, then an additional interrupt event is indicated 1151184610Salfred * and HcInterruptStatus should be checked to determine its cause. 1152184610Salfred */ 1153184610Salfred if (done != 0) { 1154184610Salfred status = 0; 1155184610Salfred 1156184610Salfred if (done & ~OHCI_DONE_INTRS) { 1157184610Salfred status |= OHCI_WDH; 1158184610Salfred } 1159184610Salfred if (done & OHCI_DONE_INTRS) { 1160184610Salfred status |= OREAD4(sc, OHCI_INTERRUPT_STATUS); 1161184610Salfred } 1162184610Salfred hcca->hcca_done_head = 0; 1163184610Salfred 1164184610Salfred usb2_pc_cpu_flush(&sc->sc_hw.hcca_pc); 1165184610Salfred } else { 1166184610Salfred status = OREAD4(sc, OHCI_INTERRUPT_STATUS) & ~OHCI_WDH; 1167184610Salfred } 1168184610Salfred 1169184610Salfred status &= ~OHCI_MIE; 1170184610Salfred if (status == 0) { 1171184610Salfred /* 1172184610Salfred * nothing to be done (PCI shared 1173184610Salfred * interrupt) 1174184610Salfred */ 1175184610Salfred goto done; 1176184610Salfred } 1177184610Salfred OWRITE4(sc, OHCI_INTERRUPT_STATUS, status); /* Acknowledge */ 1178184610Salfred 1179184610Salfred status &= sc->sc_eintrs; 1180184610Salfred if (status == 0) { 1181184610Salfred goto done; 1182184610Salfred } 1183184610Salfred if (status & (OHCI_SO | OHCI_RD | OHCI_UE | OHCI_RHSC)) { 1184184610Salfred#if 0 1185184610Salfred if (status & OHCI_SO) { 1186184610Salfred /* XXX do what */ 1187184610Salfred } 1188184610Salfred#endif 1189184610Salfred if (status & OHCI_RD) { 1190184610Salfred printf("%s: resume detect\n", __FUNCTION__); 1191184610Salfred /* XXX process resume detect */ 1192184610Salfred } 1193184610Salfred if (status & OHCI_UE) { 1194184610Salfred printf("%s: unrecoverable error, " 1195184610Salfred "controller halted\n", __FUNCTION__); 1196184610Salfred OWRITE4(sc, OHCI_CONTROL, OHCI_HCFS_RESET); 1197184610Salfred /* XXX what else */ 1198184610Salfred } 1199184610Salfred if (status & OHCI_RHSC) { 1200184610Salfred /* 1201184610Salfred * Disable RHSC interrupt for now, because it will be 1202184610Salfred * on until the port has been reset. 1203184610Salfred */ 1204184610Salfred sc->sc_eintrs &= ~OHCI_RHSC; 1205184610Salfred OWRITE4(sc, OHCI_INTERRUPT_DISABLE, OHCI_RHSC); 1206184610Salfred 1207184610Salfred usb2_sw_transfer(&sc->sc_root_intr, 1208184610Salfred &ohci_root_intr_done); 1209184610Salfred 1210184610Salfred /* do not allow RHSC interrupts > 1 per second */ 1211184610Salfred usb2_callout_reset(&sc->sc_tmo_rhsc, hz, 1212184610Salfred (void *)&ohci_rhsc_enable, sc); 1213184610Salfred } 1214184610Salfred } 1215184610Salfred status &= ~(OHCI_RHSC | OHCI_WDH | OHCI_SO); 1216184610Salfred if (status != 0) { 1217184610Salfred /* Block unprocessed interrupts. XXX */ 1218184610Salfred OWRITE4(sc, OHCI_INTERRUPT_DISABLE, status); 1219184610Salfred sc->sc_eintrs &= ~status; 1220184610Salfred printf("%s: blocking intrs 0x%x\n", 1221184610Salfred __FUNCTION__, status); 1222184610Salfred } 1223184610Salfred /* poll all the USB transfers */ 1224184610Salfred ohci_interrupt_poll(sc); 1225184610Salfred 1226184610Salfreddone: 1227184824Sthompsa USB_BUS_UNLOCK(&sc->sc_bus); 1228184610Salfred} 1229184610Salfred 1230184610Salfred/* 1231184610Salfred * called when a request does not complete 1232184610Salfred */ 1233184610Salfredstatic void 1234184610Salfredohci_timeout(void *arg) 1235184610Salfred{ 1236184610Salfred struct usb2_xfer *xfer = arg; 1237184610Salfred 1238184610Salfred DPRINTF("xfer=%p\n", xfer); 1239184610Salfred 1240186454Sthompsa USB_BUS_LOCK_ASSERT(xfer->udev->bus, MA_OWNED); 1241184610Salfred 1242184610Salfred /* transfer is transferred */ 1243184610Salfred ohci_device_done(xfer, USB_ERR_TIMEOUT); 1244184610Salfred} 1245184610Salfred 1246184610Salfredstatic void 1247184610Salfredohci_do_poll(struct usb2_bus *bus) 1248184610Salfred{ 1249184610Salfred struct ohci_softc *sc = OHCI_BUS2SC(bus); 1250184610Salfred 1251184824Sthompsa USB_BUS_LOCK(&sc->sc_bus); 1252184610Salfred ohci_interrupt_poll(sc); 1253184610Salfred ohci_root_ctrl_poll(sc); 1254184824Sthompsa USB_BUS_UNLOCK(&sc->sc_bus); 1255184610Salfred} 1256184610Salfred 1257184610Salfredstatic void 1258184610Salfredohci_setup_standard_chain_sub(struct ohci_std_temp *temp) 1259184610Salfred{ 1260184610Salfred struct usb2_page_search buf_res; 1261184610Salfred ohci_td_t *td; 1262184610Salfred ohci_td_t *td_next; 1263184610Salfred ohci_td_t *td_alt_next; 1264184610Salfred uint32_t buf_offset; 1265184610Salfred uint32_t average; 1266184610Salfred uint32_t len_old; 1267184610Salfred uint8_t shortpkt_old; 1268184610Salfred uint8_t precompute; 1269184610Salfred 1270184610Salfred td_alt_next = NULL; 1271184610Salfred buf_offset = 0; 1272184610Salfred shortpkt_old = temp->shortpkt; 1273184610Salfred len_old = temp->len; 1274184610Salfred precompute = 1; 1275184610Salfred 1276184610Salfred /* software is used to detect short incoming transfers */ 1277184610Salfred 1278184610Salfred if ((temp->td_flags & htole32(OHCI_TD_DP_MASK)) == htole32(OHCI_TD_IN)) { 1279184610Salfred temp->td_flags |= htole32(OHCI_TD_R); 1280184610Salfred } else { 1281184610Salfred temp->td_flags &= ~htole32(OHCI_TD_R); 1282184610Salfred } 1283184610Salfred 1284184610Salfredrestart: 1285184610Salfred 1286184610Salfred td = temp->td; 1287184610Salfred td_next = temp->td_next; 1288184610Salfred 1289184610Salfred while (1) { 1290184610Salfred 1291184610Salfred if (temp->len == 0) { 1292184610Salfred 1293184610Salfred if (temp->shortpkt) { 1294184610Salfred break; 1295184610Salfred } 1296184610Salfred /* send a Zero Length Packet, ZLP, last */ 1297184610Salfred 1298184610Salfred temp->shortpkt = 1; 1299184610Salfred average = 0; 1300184610Salfred 1301184610Salfred } else { 1302184610Salfred 1303184610Salfred average = temp->average; 1304184610Salfred 1305184610Salfred if (temp->len < average) { 1306184610Salfred if (temp->len % temp->max_frame_size) { 1307184610Salfred temp->shortpkt = 1; 1308184610Salfred } 1309184610Salfred average = temp->len; 1310184610Salfred } 1311184610Salfred } 1312184610Salfred 1313184610Salfred if (td_next == NULL) { 1314184610Salfred panic("%s: out of OHCI transfer descriptors!", __FUNCTION__); 1315184610Salfred } 1316184610Salfred /* get next TD */ 1317184610Salfred 1318184610Salfred td = td_next; 1319184610Salfred td_next = td->obj_next; 1320184610Salfred 1321184610Salfred /* check if we are pre-computing */ 1322184610Salfred 1323184610Salfred if (precompute) { 1324184610Salfred 1325184610Salfred /* update remaining length */ 1326184610Salfred 1327184610Salfred temp->len -= average; 1328184610Salfred 1329184610Salfred continue; 1330184610Salfred } 1331184610Salfred /* fill out current TD */ 1332184610Salfred td->td_flags = temp->td_flags; 1333184610Salfred 1334184610Salfred /* the next TD uses TOGGLE_CARRY */ 1335184610Salfred temp->td_flags &= ~htole32(OHCI_TD_TOGGLE_MASK); 1336184610Salfred 1337184610Salfred if (average == 0) { 1338184610Salfred 1339184610Salfred td->td_cbp = 0; 1340184610Salfred td->td_be = ~0; 1341184610Salfred td->len = 0; 1342184610Salfred 1343184610Salfred } else { 1344184610Salfred 1345184610Salfred usb2_get_page(temp->pc, buf_offset, &buf_res); 1346184610Salfred td->td_cbp = htole32(buf_res.physaddr); 1347184610Salfred buf_offset += (average - 1); 1348184610Salfred 1349184610Salfred usb2_get_page(temp->pc, buf_offset, &buf_res); 1350184610Salfred td->td_be = htole32(buf_res.physaddr); 1351184610Salfred buf_offset++; 1352184610Salfred 1353184610Salfred td->len = average; 1354184610Salfred 1355184610Salfred /* update remaining length */ 1356184610Salfred 1357184610Salfred temp->len -= average; 1358184610Salfred } 1359184610Salfred 1360184610Salfred if ((td_next == td_alt_next) && temp->setup_alt_next) { 1361184610Salfred /* we need to receive these frames one by one ! */ 1362184610Salfred td->td_flags &= htole32(~OHCI_TD_INTR_MASK); 1363184610Salfred td->td_flags |= htole32(OHCI_TD_SET_DI(1)); 1364184610Salfred td->td_next = htole32(OHCI_TD_NEXT_END); 1365184610Salfred } else { 1366184610Salfred if (td_next) { 1367184610Salfred /* link the current TD with the next one */ 1368184610Salfred td->td_next = td_next->td_self; 1369184610Salfred } 1370184610Salfred } 1371184610Salfred 1372184610Salfred td->alt_next = td_alt_next; 1373184610Salfred 1374184610Salfred usb2_pc_cpu_flush(td->page_cache); 1375184610Salfred } 1376184610Salfred 1377184610Salfred if (precompute) { 1378184610Salfred precompute = 0; 1379184610Salfred 1380184610Salfred /* setup alt next pointer, if any */ 1381184610Salfred if (temp->short_frames_ok) { 1382184610Salfred if (temp->setup_alt_next) { 1383184610Salfred td_alt_next = td_next; 1384184610Salfred } 1385184610Salfred } else { 1386184610Salfred /* we use this field internally */ 1387184610Salfred td_alt_next = td_next; 1388184610Salfred } 1389184610Salfred 1390184610Salfred /* restore */ 1391184610Salfred temp->shortpkt = shortpkt_old; 1392184610Salfred temp->len = len_old; 1393184610Salfred goto restart; 1394184610Salfred } 1395184610Salfred temp->td = td; 1396184610Salfred temp->td_next = td_next; 1397184610Salfred} 1398184610Salfred 1399184610Salfredstatic void 1400184610Salfredohci_setup_standard_chain(struct usb2_xfer *xfer, ohci_ed_t **ed_last) 1401184610Salfred{ 1402184610Salfred struct ohci_std_temp temp; 1403184610Salfred struct usb2_pipe_methods *methods; 1404184610Salfred ohci_ed_t *ed; 1405184610Salfred ohci_td_t *td; 1406184610Salfred uint32_t ed_flags; 1407184610Salfred uint32_t x; 1408184610Salfred 1409184610Salfred DPRINTFN(9, "addr=%d endpt=%d sumlen=%d speed=%d\n", 1410184610Salfred xfer->address, UE_GET_ADDR(xfer->endpoint), 1411184610Salfred xfer->sumlen, usb2_get_speed(xfer->udev)); 1412184610Salfred 1413184610Salfred temp.average = xfer->max_usb2_frame_size; 1414184610Salfred temp.max_frame_size = xfer->max_frame_size; 1415184610Salfred 1416184610Salfred /* toggle the DMA set we are using */ 1417184610Salfred xfer->flags_int.curr_dma_set ^= 1; 1418184610Salfred 1419184610Salfred /* get next DMA set */ 1420184610Salfred td = xfer->td_start[xfer->flags_int.curr_dma_set]; 1421184610Salfred 1422184610Salfred xfer->td_transfer_first = td; 1423184610Salfred xfer->td_transfer_cache = td; 1424184610Salfred 1425184610Salfred temp.td = NULL; 1426184610Salfred temp.td_next = td; 1427184610Salfred temp.setup_alt_next = xfer->flags_int.short_frames_ok; 1428184610Salfred temp.short_frames_ok = xfer->flags_int.short_frames_ok; 1429184610Salfred 1430184610Salfred methods = xfer->pipe->methods; 1431184610Salfred 1432184610Salfred /* check if we should prepend a setup message */ 1433184610Salfred 1434184610Salfred if (xfer->flags_int.control_xfr) { 1435184610Salfred if (xfer->flags_int.control_hdr) { 1436184610Salfred 1437184610Salfred temp.td_flags = htole32(OHCI_TD_SETUP | OHCI_TD_NOCC | 1438184610Salfred OHCI_TD_TOGGLE_0 | OHCI_TD_NOINTR); 1439184610Salfred 1440184610Salfred temp.len = xfer->frlengths[0]; 1441184610Salfred temp.pc = xfer->frbuffers + 0; 1442184610Salfred temp.shortpkt = temp.len ? 1 : 0; 1443184610Salfred 1444184610Salfred ohci_setup_standard_chain_sub(&temp); 1445184610Salfred 1446184610Salfred /* 1447184610Salfred * XXX assume that the setup message is 1448184610Salfred * contained within one USB packet: 1449184610Salfred */ 1450184610Salfred xfer->pipe->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 1460184610Salfred if (xfer->pipe->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 1468184610Salfred if (UE_GET_DIR(xfer->endpoint) == 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) { 1484184610Salfred temp.setup_alt_next = 0; 1485184610Salfred } 1486184610Salfred if (temp.len == 0) { 1487184610Salfred 1488184610Salfred /* make sure that we send an USB packet */ 1489184610Salfred 1490184610Salfred temp.shortpkt = 0; 1491184610Salfred 1492184610Salfred } else { 1493184610Salfred 1494184610Salfred /* regular data transfer */ 1495184610Salfred 1496184610Salfred temp.shortpkt = (xfer->flags.force_short_xfer) ? 0 : 1; 1497184610Salfred } 1498184610Salfred 1499184610Salfred ohci_setup_standard_chain_sub(&temp); 1500184610Salfred } 1501184610Salfred 1502184610Salfred /* check if we should append a status stage */ 1503184610Salfred 1504184610Salfred if (xfer->flags_int.control_xfr && 1505184610Salfred !xfer->flags_int.control_act) { 1506184610Salfred 1507184610Salfred /* 1508184610Salfred * Send a DATA1 message and invert the current endpoint 1509184610Salfred * direction. 1510184610Salfred */ 1511184610Salfred 1512184610Salfred /* set endpoint direction and data toggle */ 1513184610Salfred 1514184610Salfred if (UE_GET_DIR(xfer->endpoint) == UE_DIR_IN) { 1515184610Salfred temp.td_flags = htole32(OHCI_TD_OUT | 1516184610Salfred OHCI_TD_NOCC | OHCI_TD_TOGGLE_1 | OHCI_TD_SET_DI(1)); 1517184610Salfred } else { 1518184610Salfred temp.td_flags = htole32(OHCI_TD_IN | 1519184610Salfred OHCI_TD_NOCC | OHCI_TD_TOGGLE_1 | OHCI_TD_SET_DI(1)); 1520184610Salfred } 1521184610Salfred 1522184610Salfred temp.len = 0; 1523184610Salfred temp.pc = NULL; 1524184610Salfred temp.shortpkt = 0; 1525184610Salfred 1526184610Salfred ohci_setup_standard_chain_sub(&temp); 1527184610Salfred } 1528184610Salfred td = temp.td; 1529184610Salfred 1530184610Salfred td->td_next = htole32(OHCI_TD_NEXT_END); 1531184610Salfred td->td_flags &= ~htole32(OHCI_TD_INTR_MASK); 1532184610Salfred td->td_flags |= htole32(OHCI_TD_SET_DI(1)); 1533184610Salfred 1534184610Salfred usb2_pc_cpu_flush(td->page_cache); 1535184610Salfred 1536184610Salfred /* must have at least one frame! */ 1537184610Salfred 1538184610Salfred xfer->td_transfer_last = td; 1539184610Salfred 1540184610Salfred#if USB_DEBUG 1541184610Salfred if (ohcidebug > 8) { 1542184610Salfred DPRINTF("nexttog=%d; data before transfer:\n", 1543184610Salfred xfer->pipe->toggle_next); 1544184610Salfred ohci_dump_tds(xfer->td_transfer_first); 1545184610Salfred } 1546184610Salfred#endif 1547184610Salfred 1548184610Salfred ed = xfer->qh_start[xfer->flags_int.curr_dma_set]; 1549184610Salfred 1550184610Salfred ed_flags = (OHCI_ED_SET_FA(xfer->address) | 1551184610Salfred OHCI_ED_SET_EN(UE_GET_ADDR(xfer->endpoint)) | 1552184610Salfred OHCI_ED_SET_MAXP(xfer->max_frame_size)); 1553184610Salfred 1554184610Salfred ed_flags |= (OHCI_ED_FORMAT_GEN | OHCI_ED_DIR_TD); 1555184610Salfred 1556184610Salfred if (xfer->udev->speed == USB_SPEED_LOW) { 1557184610Salfred ed_flags |= OHCI_ED_SPEED; 1558184610Salfred } 1559184610Salfred ed->ed_flags = htole32(ed_flags); 1560184610Salfred 1561184610Salfred usb2_pc_cpu_flush(ed->page_cache); 1562184610Salfred 1563184610Salfred td = xfer->td_transfer_first; 1564184610Salfred 1565186730Salfred ed->ed_headp = td->td_self; 1566184610Salfred 1567186730Salfred if (xfer->udev->pwr_save.suspended == 0) { 1568186730Salfred OHCI_APPEND_QH(ed, *ed_last); 1569184610Salfred 1570186730Salfred if (methods == &ohci_device_bulk_methods) { 1571186730Salfred ohci_softc_t *sc = xfer->usb2_sc; 1572184610Salfred 1573186730Salfred OWRITE4(sc, OHCI_COMMAND_STATUS, OHCI_BLF); 1574186730Salfred } 1575186730Salfred if (methods == &ohci_device_ctrl_methods) { 1576186730Salfred ohci_softc_t *sc = xfer->usb2_sc; 1577186730Salfred 1578186730Salfred OWRITE4(sc, OHCI_COMMAND_STATUS, OHCI_CLF); 1579186730Salfred } 1580186730Salfred } else { 1581186730Salfred usb2_pc_cpu_flush(ed->page_cache); 1582184610Salfred } 1583184610Salfred} 1584184610Salfred 1585184610Salfredstatic void 1586184610Salfredohci_root_intr_done(struct usb2_xfer *xfer, 1587184610Salfred struct usb2_sw_transfer *std) 1588184610Salfred{ 1589184610Salfred ohci_softc_t *sc = xfer->usb2_sc; 1590184610Salfred uint32_t hstatus; 1591184610Salfred uint16_t i; 1592184610Salfred uint16_t m; 1593184610Salfred 1594184824Sthompsa USB_BUS_LOCK_ASSERT(&sc->sc_bus, MA_OWNED); 1595184610Salfred 1596184610Salfred if (std->state != USB_SW_TR_PRE_DATA) { 1597184610Salfred if (std->state == USB_SW_TR_PRE_CALLBACK) { 1598184610Salfred /* transfer transferred */ 1599184610Salfred ohci_device_done(xfer, std->err); 1600184610Salfred } 1601184610Salfred goto done; 1602184610Salfred } 1603184610Salfred /* setup buffer */ 1604184610Salfred std->ptr = sc->sc_hub_idata; 1605184610Salfred std->len = sizeof(sc->sc_hub_idata); 1606184610Salfred 1607184610Salfred /* clear any old interrupt data */ 1608184610Salfred bzero(sc->sc_hub_idata, sizeof(sc->sc_hub_idata)); 1609184610Salfred 1610184610Salfred hstatus = OREAD4(sc, OHCI_RH_STATUS); 1611184610Salfred DPRINTF("sc=%p xfer=%p hstatus=0x%08x\n", 1612184610Salfred sc, xfer, hstatus); 1613184610Salfred 1614184610Salfred /* set bits */ 1615184610Salfred m = (sc->sc_noport + 1); 1616184610Salfred if (m > (8 * sizeof(sc->sc_hub_idata))) { 1617184610Salfred m = (8 * sizeof(sc->sc_hub_idata)); 1618184610Salfred } 1619184610Salfred for (i = 1; i < m; i++) { 1620184610Salfred /* pick out CHANGE bits from the status register */ 1621184610Salfred if (OREAD4(sc, OHCI_RH_PORT_STATUS(i)) >> 16) { 1622184610Salfred sc->sc_hub_idata[i / 8] |= 1 << (i % 8); 1623184610Salfred DPRINTF("port %d changed\n", i); 1624184610Salfred } 1625184610Salfred } 1626184610Salfreddone: 1627184610Salfred return; 1628184610Salfred} 1629184610Salfred 1630184610Salfred/* NOTE: "done" can be run two times in a row, 1631184610Salfred * from close and from interrupt 1632184610Salfred */ 1633184610Salfredstatic void 1634184610Salfredohci_device_done(struct usb2_xfer *xfer, usb2_error_t error) 1635184610Salfred{ 1636184610Salfred struct usb2_pipe_methods *methods = xfer->pipe->methods; 1637184610Salfred ohci_softc_t *sc = xfer->usb2_sc; 1638184610Salfred ohci_ed_t *ed; 1639184610Salfred 1640184824Sthompsa USB_BUS_LOCK_ASSERT(&sc->sc_bus, MA_OWNED); 1641184610Salfred 1642184610Salfred 1643184610Salfred DPRINTFN(2, "xfer=%p, pipe=%p, error=%d\n", 1644184610Salfred xfer, xfer->pipe, error); 1645184610Salfred 1646184610Salfred ed = xfer->qh_start[xfer->flags_int.curr_dma_set]; 1647184610Salfred if (ed) { 1648184610Salfred usb2_pc_cpu_invalidate(ed->page_cache); 1649184610Salfred } 1650184610Salfred if (methods == &ohci_device_bulk_methods) { 1651184610Salfred OHCI_REMOVE_QH(ed, sc->sc_bulk_p_last); 1652184610Salfred } 1653184610Salfred if (methods == &ohci_device_ctrl_methods) { 1654184610Salfred OHCI_REMOVE_QH(ed, sc->sc_ctrl_p_last); 1655184610Salfred } 1656184610Salfred if (methods == &ohci_device_intr_methods) { 1657184610Salfred OHCI_REMOVE_QH(ed, sc->sc_intr_p_last[xfer->qh_pos]); 1658184610Salfred } 1659184610Salfred if (methods == &ohci_device_isoc_methods) { 1660184610Salfred OHCI_REMOVE_QH(ed, sc->sc_isoc_p_last); 1661184610Salfred } 1662184610Salfred xfer->td_transfer_first = NULL; 1663184610Salfred xfer->td_transfer_last = NULL; 1664184610Salfred 1665184610Salfred /* dequeue transfer and start next transfer */ 1666184610Salfred usb2_transfer_done(xfer, error); 1667184610Salfred} 1668184610Salfred 1669184610Salfred/*------------------------------------------------------------------------* 1670184610Salfred * ohci bulk support 1671184610Salfred *------------------------------------------------------------------------*/ 1672184610Salfredstatic void 1673184610Salfredohci_device_bulk_open(struct usb2_xfer *xfer) 1674184610Salfred{ 1675184610Salfred return; 1676184610Salfred} 1677184610Salfred 1678184610Salfredstatic void 1679184610Salfredohci_device_bulk_close(struct usb2_xfer *xfer) 1680184610Salfred{ 1681184610Salfred ohci_device_done(xfer, USB_ERR_CANCELLED); 1682184610Salfred} 1683184610Salfred 1684184610Salfredstatic void 1685184610Salfredohci_device_bulk_enter(struct usb2_xfer *xfer) 1686184610Salfred{ 1687184610Salfred return; 1688184610Salfred} 1689184610Salfred 1690184610Salfredstatic void 1691184610Salfredohci_device_bulk_start(struct usb2_xfer *xfer) 1692184610Salfred{ 1693184610Salfred ohci_softc_t *sc = xfer->usb2_sc; 1694184610Salfred 1695184610Salfred /* setup TD's and QH */ 1696184610Salfred ohci_setup_standard_chain(xfer, &sc->sc_bulk_p_last); 1697184610Salfred 1698184610Salfred /* put transfer on interrupt queue */ 1699184610Salfred ohci_transfer_intr_enqueue(xfer); 1700184610Salfred} 1701184610Salfred 1702184610Salfredstruct usb2_pipe_methods ohci_device_bulk_methods = 1703184610Salfred{ 1704184610Salfred .open = ohci_device_bulk_open, 1705184610Salfred .close = ohci_device_bulk_close, 1706184610Salfred .enter = ohci_device_bulk_enter, 1707184610Salfred .start = ohci_device_bulk_start, 1708184610Salfred .enter_is_cancelable = 1, 1709184610Salfred .start_is_cancelable = 1, 1710184610Salfred}; 1711184610Salfred 1712184610Salfred/*------------------------------------------------------------------------* 1713184610Salfred * ohci control support 1714184610Salfred *------------------------------------------------------------------------*/ 1715184610Salfredstatic void 1716184610Salfredohci_device_ctrl_open(struct usb2_xfer *xfer) 1717184610Salfred{ 1718184610Salfred return; 1719184610Salfred} 1720184610Salfred 1721184610Salfredstatic void 1722184610Salfredohci_device_ctrl_close(struct usb2_xfer *xfer) 1723184610Salfred{ 1724184610Salfred ohci_device_done(xfer, USB_ERR_CANCELLED); 1725184610Salfred} 1726184610Salfred 1727184610Salfredstatic void 1728184610Salfredohci_device_ctrl_enter(struct usb2_xfer *xfer) 1729184610Salfred{ 1730184610Salfred return; 1731184610Salfred} 1732184610Salfred 1733184610Salfredstatic void 1734184610Salfredohci_device_ctrl_start(struct usb2_xfer *xfer) 1735184610Salfred{ 1736184610Salfred ohci_softc_t *sc = xfer->usb2_sc; 1737184610Salfred 1738184610Salfred /* setup TD's and QH */ 1739184610Salfred ohci_setup_standard_chain(xfer, &sc->sc_ctrl_p_last); 1740184610Salfred 1741184610Salfred /* put transfer on interrupt queue */ 1742184610Salfred ohci_transfer_intr_enqueue(xfer); 1743184610Salfred} 1744184610Salfred 1745184610Salfredstruct usb2_pipe_methods ohci_device_ctrl_methods = 1746184610Salfred{ 1747184610Salfred .open = ohci_device_ctrl_open, 1748184610Salfred .close = ohci_device_ctrl_close, 1749184610Salfred .enter = ohci_device_ctrl_enter, 1750184610Salfred .start = ohci_device_ctrl_start, 1751184610Salfred .enter_is_cancelable = 1, 1752184610Salfred .start_is_cancelable = 1, 1753184610Salfred}; 1754184610Salfred 1755184610Salfred/*------------------------------------------------------------------------* 1756184610Salfred * ohci interrupt support 1757184610Salfred *------------------------------------------------------------------------*/ 1758184610Salfredstatic void 1759184610Salfredohci_device_intr_open(struct usb2_xfer *xfer) 1760184610Salfred{ 1761184610Salfred ohci_softc_t *sc = xfer->usb2_sc; 1762184610Salfred uint16_t best; 1763184610Salfred uint16_t bit; 1764184610Salfred uint16_t x; 1765184610Salfred 1766184610Salfred best = 0; 1767184610Salfred bit = OHCI_NO_EDS / 2; 1768184610Salfred while (bit) { 1769184610Salfred if (xfer->interval >= bit) { 1770184610Salfred x = bit; 1771184610Salfred best = bit; 1772184610Salfred while (x & bit) { 1773184610Salfred if (sc->sc_intr_stat[x] < 1774184610Salfred sc->sc_intr_stat[best]) { 1775184610Salfred best = x; 1776184610Salfred } 1777184610Salfred x++; 1778184610Salfred } 1779184610Salfred break; 1780184610Salfred } 1781184610Salfred bit >>= 1; 1782184610Salfred } 1783184610Salfred 1784184610Salfred sc->sc_intr_stat[best]++; 1785184610Salfred xfer->qh_pos = best; 1786184610Salfred 1787184610Salfred DPRINTFN(3, "best=%d interval=%d\n", 1788184610Salfred best, xfer->interval); 1789184610Salfred} 1790184610Salfred 1791184610Salfredstatic void 1792184610Salfredohci_device_intr_close(struct usb2_xfer *xfer) 1793184610Salfred{ 1794184610Salfred ohci_softc_t *sc = xfer->usb2_sc; 1795184610Salfred 1796184610Salfred sc->sc_intr_stat[xfer->qh_pos]--; 1797184610Salfred 1798184610Salfred ohci_device_done(xfer, USB_ERR_CANCELLED); 1799184610Salfred} 1800184610Salfred 1801184610Salfredstatic void 1802184610Salfredohci_device_intr_enter(struct usb2_xfer *xfer) 1803184610Salfred{ 1804184610Salfred return; 1805184610Salfred} 1806184610Salfred 1807184610Salfredstatic void 1808184610Salfredohci_device_intr_start(struct usb2_xfer *xfer) 1809184610Salfred{ 1810184610Salfred ohci_softc_t *sc = xfer->usb2_sc; 1811184610Salfred 1812184610Salfred /* setup TD's and QH */ 1813184610Salfred ohci_setup_standard_chain(xfer, &sc->sc_intr_p_last[xfer->qh_pos]); 1814184610Salfred 1815184610Salfred /* put transfer on interrupt queue */ 1816184610Salfred ohci_transfer_intr_enqueue(xfer); 1817184610Salfred} 1818184610Salfred 1819184610Salfredstruct usb2_pipe_methods ohci_device_intr_methods = 1820184610Salfred{ 1821184610Salfred .open = ohci_device_intr_open, 1822184610Salfred .close = ohci_device_intr_close, 1823184610Salfred .enter = ohci_device_intr_enter, 1824184610Salfred .start = ohci_device_intr_start, 1825184610Salfred .enter_is_cancelable = 1, 1826184610Salfred .start_is_cancelable = 1, 1827184610Salfred}; 1828184610Salfred 1829184610Salfred/*------------------------------------------------------------------------* 1830184610Salfred * ohci isochronous support 1831184610Salfred *------------------------------------------------------------------------*/ 1832184610Salfredstatic void 1833184610Salfredohci_device_isoc_open(struct usb2_xfer *xfer) 1834184610Salfred{ 1835184610Salfred return; 1836184610Salfred} 1837184610Salfred 1838184610Salfredstatic void 1839184610Salfredohci_device_isoc_close(struct usb2_xfer *xfer) 1840184610Salfred{ 1841184610Salfred /**/ 1842184610Salfred ohci_device_done(xfer, USB_ERR_CANCELLED); 1843184610Salfred} 1844184610Salfred 1845184610Salfredstatic void 1846184610Salfredohci_device_isoc_enter(struct usb2_xfer *xfer) 1847184610Salfred{ 1848184610Salfred struct usb2_page_search buf_res; 1849184610Salfred ohci_softc_t *sc = xfer->usb2_sc; 1850184610Salfred struct ohci_hcca *hcca; 1851184610Salfred uint32_t buf_offset; 1852184610Salfred uint32_t nframes; 1853184610Salfred uint32_t ed_flags; 1854184610Salfred uint32_t *plen; 1855184610Salfred uint16_t itd_offset[OHCI_ITD_NOFFSET]; 1856184610Salfred uint16_t length; 1857184610Salfred uint8_t ncur; 1858184610Salfred ohci_itd_t *td; 1859184610Salfred ohci_itd_t *td_last = NULL; 1860184610Salfred ohci_ed_t *ed; 1861184610Salfred 1862184610Salfred hcca = ohci_get_hcca(sc); 1863184610Salfred 1864184610Salfred nframes = le32toh(hcca->hcca_frame_number); 1865184610Salfred 1866184610Salfred DPRINTFN(6, "xfer=%p isoc_next=%u nframes=%u hcca_fn=%u\n", 1867184610Salfred xfer, xfer->pipe->isoc_next, xfer->nframes, nframes); 1868184610Salfred 1869184610Salfred if ((xfer->pipe->is_synced == 0) || 1870184610Salfred (((nframes - xfer->pipe->isoc_next) & 0xFFFF) < xfer->nframes) || 1871184610Salfred (((xfer->pipe->isoc_next - nframes) & 0xFFFF) >= 128)) { 1872184610Salfred /* 1873184610Salfred * If there is data underflow or the pipe queue is empty we 1874184610Salfred * schedule the transfer a few frames ahead of the current 1875184610Salfred * frame position. Else two isochronous transfers might 1876184610Salfred * overlap. 1877184610Salfred */ 1878184610Salfred xfer->pipe->isoc_next = (nframes + 3) & 0xFFFF; 1879184610Salfred xfer->pipe->is_synced = 1; 1880184610Salfred DPRINTFN(3, "start next=%d\n", xfer->pipe->isoc_next); 1881184610Salfred } 1882184610Salfred /* 1883184610Salfred * compute how many milliseconds the insertion is ahead of the 1884184610Salfred * current frame position: 1885184610Salfred */ 1886184610Salfred buf_offset = ((xfer->pipe->isoc_next - nframes) & 0xFFFF); 1887184610Salfred 1888184610Salfred /* 1889184610Salfred * pre-compute when the isochronous transfer will be finished: 1890184610Salfred */ 1891184610Salfred xfer->isoc_time_complete = 1892184610Salfred (usb2_isoc_time_expand(&sc->sc_bus, nframes) + buf_offset + 1893184610Salfred xfer->nframes); 1894184610Salfred 1895184610Salfred /* get the real number of frames */ 1896184610Salfred 1897184610Salfred nframes = xfer->nframes; 1898184610Salfred 1899184610Salfred buf_offset = 0; 1900184610Salfred 1901184610Salfred plen = xfer->frlengths; 1902184610Salfred 1903184610Salfred /* toggle the DMA set we are using */ 1904184610Salfred xfer->flags_int.curr_dma_set ^= 1; 1905184610Salfred 1906184610Salfred /* get next DMA set */ 1907184610Salfred td = xfer->td_start[xfer->flags_int.curr_dma_set]; 1908184610Salfred 1909184610Salfred xfer->td_transfer_first = td; 1910184610Salfred 1911184610Salfred ncur = 0; 1912184610Salfred length = 0; 1913184610Salfred 1914184610Salfred while (nframes--) { 1915184610Salfred if (td == NULL) { 1916184610Salfred panic("%s:%d: out of TD's\n", 1917184610Salfred __FUNCTION__, __LINE__); 1918184610Salfred } 1919184610Salfred itd_offset[ncur] = length; 1920184610Salfred buf_offset += *plen; 1921184610Salfred length += *plen; 1922184610Salfred plen++; 1923184610Salfred ncur++; 1924184610Salfred 1925184610Salfred if ( /* check if the ITD is full */ 1926184610Salfred (ncur == OHCI_ITD_NOFFSET) || 1927184610Salfred /* check if we have put more than 4K into the ITD */ 1928184610Salfred (length & 0xF000) || 1929184610Salfred /* check if it is the last frame */ 1930184610Salfred (nframes == 0)) { 1931184610Salfred 1932184610Salfred /* fill current ITD */ 1933184610Salfred td->itd_flags = htole32( 1934184610Salfred OHCI_ITD_NOCC | 1935184610Salfred OHCI_ITD_SET_SF(xfer->pipe->isoc_next) | 1936184610Salfred OHCI_ITD_NOINTR | 1937184610Salfred OHCI_ITD_SET_FC(ncur)); 1938184610Salfred 1939184610Salfred td->frames = ncur; 1940184610Salfred xfer->pipe->isoc_next += ncur; 1941184610Salfred 1942184610Salfred if (length == 0) { 1943184610Salfred /* all zero */ 1944184610Salfred td->itd_bp0 = 0; 1945184610Salfred td->itd_be = ~0; 1946184610Salfred 1947184610Salfred while (ncur--) { 1948184610Salfred td->itd_offset[ncur] = 1949184610Salfred htole16(OHCI_ITD_MK_OFFS(0)); 1950184610Salfred } 1951184610Salfred } else { 1952184610Salfred usb2_get_page(xfer->frbuffers, buf_offset - length, &buf_res); 1953184610Salfred length = OHCI_PAGE_MASK(buf_res.physaddr); 1954184610Salfred buf_res.physaddr = 1955184610Salfred OHCI_PAGE(buf_res.physaddr); 1956184610Salfred td->itd_bp0 = htole32(buf_res.physaddr); 1957184610Salfred usb2_get_page(xfer->frbuffers, buf_offset - 1, &buf_res); 1958184610Salfred td->itd_be = htole32(buf_res.physaddr); 1959184610Salfred 1960184610Salfred while (ncur--) { 1961184610Salfred itd_offset[ncur] += length; 1962184610Salfred itd_offset[ncur] = 1963184610Salfred OHCI_ITD_MK_OFFS(itd_offset[ncur]); 1964184610Salfred td->itd_offset[ncur] = 1965184610Salfred htole16(itd_offset[ncur]); 1966184610Salfred } 1967184610Salfred } 1968184610Salfred ncur = 0; 1969184610Salfred length = 0; 1970184610Salfred td_last = td; 1971184610Salfred td = td->obj_next; 1972184610Salfred 1973184610Salfred if (td) { 1974184610Salfred /* link the last TD with the next one */ 1975184610Salfred td_last->itd_next = td->itd_self; 1976184610Salfred } 1977184610Salfred usb2_pc_cpu_flush(td_last->page_cache); 1978184610Salfred } 1979184610Salfred } 1980184610Salfred 1981184610Salfred /* update the last TD */ 1982184610Salfred td_last->itd_flags &= ~htole32(OHCI_ITD_NOINTR); 1983184610Salfred td_last->itd_flags |= htole32(OHCI_ITD_SET_DI(0)); 1984184610Salfred td_last->itd_next = 0; 1985184610Salfred 1986184610Salfred usb2_pc_cpu_flush(td_last->page_cache); 1987184610Salfred 1988184610Salfred xfer->td_transfer_last = td_last; 1989184610Salfred 1990184610Salfred#if USB_DEBUG 1991184610Salfred if (ohcidebug > 8) { 1992184610Salfred DPRINTF("data before transfer:\n"); 1993184610Salfred ohci_dump_itds(xfer->td_transfer_first); 1994184610Salfred } 1995184610Salfred#endif 1996184610Salfred ed = xfer->qh_start[xfer->flags_int.curr_dma_set]; 1997184610Salfred 1998184610Salfred if (UE_GET_DIR(xfer->endpoint) == UE_DIR_IN) 1999184610Salfred ed_flags = (OHCI_ED_DIR_IN | OHCI_ED_FORMAT_ISO); 2000184610Salfred else 2001184610Salfred ed_flags = (OHCI_ED_DIR_OUT | OHCI_ED_FORMAT_ISO); 2002184610Salfred 2003184610Salfred ed_flags |= (OHCI_ED_SET_FA(xfer->address) | 2004184610Salfred OHCI_ED_SET_EN(UE_GET_ADDR(xfer->endpoint)) | 2005184610Salfred OHCI_ED_SET_MAXP(xfer->max_frame_size)); 2006184610Salfred 2007184610Salfred if (xfer->udev->speed == USB_SPEED_LOW) { 2008184610Salfred ed_flags |= OHCI_ED_SPEED; 2009184610Salfred } 2010184610Salfred ed->ed_flags = htole32(ed_flags); 2011184610Salfred 2012184610Salfred usb2_pc_cpu_flush(ed->page_cache); 2013184610Salfred 2014184610Salfred td = xfer->td_transfer_first; 2015184610Salfred 2016186730Salfred ed->ed_headp = td->itd_self; 2017186730Salfred 2018186730Salfred /* isochronous transfers are not affected by suspend / resume */ 2019186730Salfred 2020186730Salfred OHCI_APPEND_QH(ed, sc->sc_isoc_p_last); 2021184610Salfred} 2022184610Salfred 2023184610Salfredstatic void 2024184610Salfredohci_device_isoc_start(struct usb2_xfer *xfer) 2025184610Salfred{ 2026184610Salfred /* put transfer on interrupt queue */ 2027184610Salfred ohci_transfer_intr_enqueue(xfer); 2028184610Salfred} 2029184610Salfred 2030184610Salfredstruct usb2_pipe_methods ohci_device_isoc_methods = 2031184610Salfred{ 2032184610Salfred .open = ohci_device_isoc_open, 2033184610Salfred .close = ohci_device_isoc_close, 2034184610Salfred .enter = ohci_device_isoc_enter, 2035184610Salfred .start = ohci_device_isoc_start, 2036184610Salfred .enter_is_cancelable = 1, 2037184610Salfred .start_is_cancelable = 1, 2038184610Salfred}; 2039184610Salfred 2040184610Salfred/*------------------------------------------------------------------------* 2041184610Salfred * ohci root control support 2042184610Salfred *------------------------------------------------------------------------* 2043184610Salfred * simulate a hardware hub by handling 2044184610Salfred * all the necessary requests 2045184610Salfred *------------------------------------------------------------------------*/ 2046184610Salfred 2047184610Salfredstatic void 2048184610Salfredohci_root_ctrl_open(struct usb2_xfer *xfer) 2049184610Salfred{ 2050184610Salfred return; 2051184610Salfred} 2052184610Salfred 2053184610Salfredstatic void 2054184610Salfredohci_root_ctrl_close(struct usb2_xfer *xfer) 2055184610Salfred{ 2056184610Salfred ohci_softc_t *sc = xfer->usb2_sc; 2057184610Salfred 2058184610Salfred if (sc->sc_root_ctrl.xfer == xfer) { 2059184610Salfred sc->sc_root_ctrl.xfer = NULL; 2060184610Salfred } 2061184610Salfred ohci_device_done(xfer, USB_ERR_CANCELLED); 2062184610Salfred} 2063184610Salfred 2064184610Salfred/* data structures and routines 2065184610Salfred * to emulate the root hub: 2066184610Salfred */ 2067184610Salfredstatic const 2068184610Salfredstruct usb2_device_descriptor ohci_devd = 2069184610Salfred{ 2070184610Salfred sizeof(struct usb2_device_descriptor), 2071184610Salfred UDESC_DEVICE, /* type */ 2072184610Salfred {0x00, 0x01}, /* USB version */ 2073184610Salfred UDCLASS_HUB, /* class */ 2074184610Salfred UDSUBCLASS_HUB, /* subclass */ 2075184610Salfred UDPROTO_FSHUB, /* protocol */ 2076184610Salfred 64, /* max packet */ 2077184610Salfred {0}, {0}, {0x00, 0x01}, /* device id */ 2078184610Salfred 1, 2, 0, /* string indicies */ 2079184610Salfred 1 /* # of configurations */ 2080184610Salfred}; 2081184610Salfred 2082184610Salfredstatic const 2083184610Salfredstruct ohci_config_desc ohci_confd = 2084184610Salfred{ 2085184610Salfred .confd = { 2086184610Salfred .bLength = sizeof(struct usb2_config_descriptor), 2087184610Salfred .bDescriptorType = UDESC_CONFIG, 2088184610Salfred .wTotalLength[0] = sizeof(ohci_confd), 2089184610Salfred .bNumInterface = 1, 2090184610Salfred .bConfigurationValue = 1, 2091184610Salfred .iConfiguration = 0, 2092184610Salfred .bmAttributes = UC_SELF_POWERED, 2093184610Salfred .bMaxPower = 0, /* max power */ 2094184610Salfred }, 2095184610Salfred 2096184610Salfred .ifcd = { 2097184610Salfred .bLength = sizeof(struct usb2_interface_descriptor), 2098184610Salfred .bDescriptorType = UDESC_INTERFACE, 2099184610Salfred .bNumEndpoints = 1, 2100184610Salfred .bInterfaceClass = UICLASS_HUB, 2101184610Salfred .bInterfaceSubClass = UISUBCLASS_HUB, 2102184610Salfred .bInterfaceProtocol = UIPROTO_FSHUB, 2103184610Salfred }, 2104184610Salfred 2105184610Salfred .endpd = { 2106184610Salfred .bLength = sizeof(struct usb2_endpoint_descriptor), 2107184610Salfred .bDescriptorType = UDESC_ENDPOINT, 2108184610Salfred .bEndpointAddress = UE_DIR_IN | OHCI_INTR_ENDPT, 2109184610Salfred .bmAttributes = UE_INTERRUPT, 2110184610Salfred .wMaxPacketSize[0] = 32,/* max packet (255 ports) */ 2111184610Salfred .bInterval = 255, 2112184610Salfred }, 2113184610Salfred}; 2114184610Salfred 2115184610Salfredstatic const 2116184610Salfredstruct usb2_hub_descriptor ohci_hubd = 2117184610Salfred{ 2118184610Salfred 0, /* dynamic length */ 2119184610Salfred UDESC_HUB, 2120184610Salfred 0, 2121184610Salfred {0, 0}, 2122184610Salfred 0, 2123184610Salfred 0, 2124184610Salfred {0}, 2125184610Salfred}; 2126184610Salfred 2127184610Salfredstatic void 2128184610Salfredohci_root_ctrl_enter(struct usb2_xfer *xfer) 2129184610Salfred{ 2130184610Salfred return; 2131184610Salfred} 2132184610Salfred 2133184610Salfredstatic void 2134184610Salfredohci_root_ctrl_start(struct usb2_xfer *xfer) 2135184610Salfred{ 2136184610Salfred ohci_softc_t *sc = xfer->usb2_sc; 2137184610Salfred 2138184610Salfred sc->sc_root_ctrl.xfer = xfer; 2139184610Salfred 2140184610Salfred usb2_config_td_queue_command 2141184610Salfred (&sc->sc_config_td, NULL, &ohci_root_ctrl_task, 0, 0); 2142184610Salfred} 2143184610Salfred 2144184610Salfredstatic void 2145184610Salfredohci_root_ctrl_task(struct ohci_softc *sc, 2146184610Salfred struct ohci_config_copy *cc, uint16_t refcount) 2147184610Salfred{ 2148184610Salfred ohci_root_ctrl_poll(sc); 2149184610Salfred} 2150184610Salfred 2151184610Salfredstatic void 2152184610Salfredohci_root_ctrl_done(struct usb2_xfer *xfer, 2153184610Salfred struct usb2_sw_transfer *std) 2154184610Salfred{ 2155184610Salfred ohci_softc_t *sc = xfer->usb2_sc; 2156184610Salfred char *ptr; 2157184610Salfred uint32_t port; 2158184610Salfred uint32_t v; 2159184610Salfred uint16_t value; 2160184610Salfred uint16_t index; 2161184610Salfred uint8_t l; 2162184610Salfred uint8_t use_polling; 2163184610Salfred 2164184824Sthompsa USB_BUS_LOCK_ASSERT(&sc->sc_bus, MA_OWNED); 2165184610Salfred 2166184610Salfred if (std->state != USB_SW_TR_SETUP) { 2167184610Salfred if (std->state == USB_SW_TR_PRE_CALLBACK) { 2168184610Salfred /* transfer transferred */ 2169184610Salfred ohci_device_done(xfer, std->err); 2170184610Salfred } 2171184610Salfred goto done; 2172184610Salfred } 2173184610Salfred /* buffer reset */ 2174184610Salfred std->ptr = sc->sc_hub_desc.temp; 2175184610Salfred std->len = 0; 2176184610Salfred 2177184610Salfred value = UGETW(std->req.wValue); 2178184610Salfred index = UGETW(std->req.wIndex); 2179184610Salfred 2180184824Sthompsa use_polling = mtx_owned(xfer->xfer_mtx) ? 1 : 0; 2181184610Salfred 2182184610Salfred DPRINTFN(3, "type=0x%02x request=0x%02x wLen=0x%04x " 2183184610Salfred "wValue=0x%04x wIndex=0x%04x\n", 2184184610Salfred std->req.bmRequestType, std->req.bRequest, 2185184610Salfred UGETW(std->req.wLength), value, index); 2186184610Salfred 2187184610Salfred#define C(x,y) ((x) | ((y) << 8)) 2188184610Salfred switch (C(std->req.bRequest, std->req.bmRequestType)) { 2189184610Salfred case C(UR_CLEAR_FEATURE, UT_WRITE_DEVICE): 2190184610Salfred case C(UR_CLEAR_FEATURE, UT_WRITE_INTERFACE): 2191184610Salfred case C(UR_CLEAR_FEATURE, UT_WRITE_ENDPOINT): 2192184610Salfred /* 2193184610Salfred * DEVICE_REMOTE_WAKEUP and ENDPOINT_HALT are no-ops 2194184610Salfred * for the integrated root hub. 2195184610Salfred */ 2196184610Salfred break; 2197184610Salfred case C(UR_GET_CONFIG, UT_READ_DEVICE): 2198184610Salfred std->len = 1; 2199184610Salfred sc->sc_hub_desc.temp[0] = sc->sc_conf; 2200184610Salfred break; 2201184610Salfred case C(UR_GET_DESCRIPTOR, UT_READ_DEVICE): 2202184610Salfred switch (value >> 8) { 2203184610Salfred case UDESC_DEVICE: 2204184610Salfred if ((value & 0xff) != 0) { 2205184610Salfred std->err = USB_ERR_IOERROR; 2206184610Salfred goto done; 2207184610Salfred } 2208184610Salfred std->len = sizeof(ohci_devd); 2209184610Salfred sc->sc_hub_desc.devd = ohci_devd; 2210184610Salfred break; 2211184610Salfred 2212184610Salfred case UDESC_CONFIG: 2213184610Salfred if ((value & 0xff) != 0) { 2214184610Salfred std->err = USB_ERR_IOERROR; 2215184610Salfred goto done; 2216184610Salfred } 2217184610Salfred std->len = sizeof(ohci_confd); 2218184610Salfred std->ptr = USB_ADD_BYTES(&ohci_confd, 0); 2219184610Salfred break; 2220184610Salfred 2221184610Salfred case UDESC_STRING: 2222184610Salfred switch (value & 0xff) { 2223184610Salfred case 0: /* Language table */ 2224184610Salfred ptr = "\001"; 2225184610Salfred break; 2226184610Salfred 2227184610Salfred case 1: /* Vendor */ 2228184610Salfred ptr = sc->sc_vendor; 2229184610Salfred break; 2230184610Salfred 2231184610Salfred case 2: /* Product */ 2232184610Salfred ptr = "OHCI root HUB"; 2233184610Salfred break; 2234184610Salfred 2235184610Salfred default: 2236184610Salfred ptr = ""; 2237184610Salfred break; 2238184610Salfred } 2239184610Salfred 2240184610Salfred std->len = usb2_make_str_desc 2241184610Salfred (sc->sc_hub_desc.temp, 2242184610Salfred sizeof(sc->sc_hub_desc.temp), 2243184610Salfred ptr); 2244184610Salfred break; 2245184610Salfred 2246184610Salfred default: 2247184610Salfred std->err = USB_ERR_IOERROR; 2248184610Salfred goto done; 2249184610Salfred } 2250184610Salfred break; 2251184610Salfred case C(UR_GET_INTERFACE, UT_READ_INTERFACE): 2252184610Salfred std->len = 1; 2253184610Salfred sc->sc_hub_desc.temp[0] = 0; 2254184610Salfred break; 2255184610Salfred case C(UR_GET_STATUS, UT_READ_DEVICE): 2256184610Salfred std->len = 2; 2257184610Salfred USETW(sc->sc_hub_desc.stat.wStatus, UDS_SELF_POWERED); 2258184610Salfred break; 2259184610Salfred case C(UR_GET_STATUS, UT_READ_INTERFACE): 2260184610Salfred case C(UR_GET_STATUS, UT_READ_ENDPOINT): 2261184610Salfred std->len = 2; 2262184610Salfred USETW(sc->sc_hub_desc.stat.wStatus, 0); 2263184610Salfred break; 2264184610Salfred case C(UR_SET_ADDRESS, UT_WRITE_DEVICE): 2265184610Salfred if (value >= USB_MAX_DEVICES) { 2266184610Salfred std->err = USB_ERR_IOERROR; 2267184610Salfred goto done; 2268184610Salfred } 2269184610Salfred sc->sc_addr = value; 2270184610Salfred break; 2271184610Salfred case C(UR_SET_CONFIG, UT_WRITE_DEVICE): 2272184610Salfred if ((value != 0) && (value != 1)) { 2273184610Salfred std->err = USB_ERR_IOERROR; 2274184610Salfred goto done; 2275184610Salfred } 2276184610Salfred sc->sc_conf = value; 2277184610Salfred break; 2278184610Salfred case C(UR_SET_DESCRIPTOR, UT_WRITE_DEVICE): 2279184610Salfred break; 2280184610Salfred case C(UR_SET_FEATURE, UT_WRITE_DEVICE): 2281184610Salfred case C(UR_SET_FEATURE, UT_WRITE_INTERFACE): 2282184610Salfred case C(UR_SET_FEATURE, UT_WRITE_ENDPOINT): 2283184610Salfred std->err = USB_ERR_IOERROR; 2284184610Salfred goto done; 2285184610Salfred case C(UR_SET_INTERFACE, UT_WRITE_INTERFACE): 2286184610Salfred break; 2287184610Salfred case C(UR_SYNCH_FRAME, UT_WRITE_ENDPOINT): 2288184610Salfred break; 2289184610Salfred /* Hub requests */ 2290184610Salfred case C(UR_CLEAR_FEATURE, UT_WRITE_CLASS_DEVICE): 2291184610Salfred break; 2292184610Salfred case C(UR_CLEAR_FEATURE, UT_WRITE_CLASS_OTHER): 2293184610Salfred DPRINTFN(9, "UR_CLEAR_PORT_FEATURE " 2294184610Salfred "port=%d feature=%d\n", 2295184610Salfred index, value); 2296184610Salfred if ((index < 1) || 2297184610Salfred (index > sc->sc_noport)) { 2298184610Salfred std->err = USB_ERR_IOERROR; 2299184610Salfred goto done; 2300184610Salfred } 2301184610Salfred port = OHCI_RH_PORT_STATUS(index); 2302184610Salfred switch (value) { 2303184610Salfred case UHF_PORT_ENABLE: 2304184610Salfred OWRITE4(sc, port, UPS_CURRENT_CONNECT_STATUS); 2305184610Salfred break; 2306184610Salfred case UHF_PORT_SUSPEND: 2307184610Salfred OWRITE4(sc, port, UPS_OVERCURRENT_INDICATOR); 2308184610Salfred break; 2309184610Salfred case UHF_PORT_POWER: 2310184610Salfred /* Yes, writing to the LOW_SPEED bit clears power. */ 2311184610Salfred OWRITE4(sc, port, UPS_LOW_SPEED); 2312184610Salfred break; 2313184610Salfred case UHF_C_PORT_CONNECTION: 2314184610Salfred OWRITE4(sc, port, UPS_C_CONNECT_STATUS << 16); 2315184610Salfred break; 2316184610Salfred case UHF_C_PORT_ENABLE: 2317184610Salfred OWRITE4(sc, port, UPS_C_PORT_ENABLED << 16); 2318184610Salfred break; 2319184610Salfred case UHF_C_PORT_SUSPEND: 2320184610Salfred OWRITE4(sc, port, UPS_C_SUSPEND << 16); 2321184610Salfred break; 2322184610Salfred case UHF_C_PORT_OVER_CURRENT: 2323184610Salfred OWRITE4(sc, port, UPS_C_OVERCURRENT_INDICATOR << 16); 2324184610Salfred break; 2325184610Salfred case UHF_C_PORT_RESET: 2326184610Salfred OWRITE4(sc, port, UPS_C_PORT_RESET << 16); 2327184610Salfred break; 2328184610Salfred default: 2329184610Salfred std->err = USB_ERR_IOERROR; 2330184610Salfred goto done; 2331184610Salfred } 2332184610Salfred switch (value) { 2333184610Salfred case UHF_C_PORT_CONNECTION: 2334184610Salfred case UHF_C_PORT_ENABLE: 2335184610Salfred case UHF_C_PORT_SUSPEND: 2336184610Salfred case UHF_C_PORT_OVER_CURRENT: 2337184610Salfred case UHF_C_PORT_RESET: 2338184610Salfred /* enable RHSC interrupt if condition is cleared. */ 2339186454Sthompsa if ((OREAD4(sc, port) >> 16) == 0) 2340184610Salfred ohci_rhsc_enable(sc); 2341184610Salfred break; 2342184610Salfred default: 2343184610Salfred break; 2344184610Salfred } 2345184610Salfred break; 2346184610Salfred case C(UR_GET_DESCRIPTOR, UT_READ_CLASS_DEVICE): 2347184610Salfred if ((value & 0xff) != 0) { 2348184610Salfred std->err = USB_ERR_IOERROR; 2349184610Salfred goto done; 2350184610Salfred } 2351184610Salfred v = OREAD4(sc, OHCI_RH_DESCRIPTOR_A); 2352184610Salfred 2353184610Salfred sc->sc_hub_desc.hubd = ohci_hubd; 2354184610Salfred sc->sc_hub_desc.hubd.bNbrPorts = sc->sc_noport; 2355184610Salfred USETW(sc->sc_hub_desc.hubd.wHubCharacteristics, 2356184610Salfred (v & OHCI_NPS ? UHD_PWR_NO_SWITCH : 2357184610Salfred v & OHCI_PSM ? UHD_PWR_GANGED : UHD_PWR_INDIVIDUAL) 2358184610Salfred /* XXX overcurrent */ 2359184610Salfred ); 2360184610Salfred sc->sc_hub_desc.hubd.bPwrOn2PwrGood = OHCI_GET_POTPGT(v); 2361184610Salfred v = OREAD4(sc, OHCI_RH_DESCRIPTOR_B); 2362184610Salfred 2363184610Salfred for (l = 0; l < sc->sc_noport; l++) { 2364184610Salfred if (v & 1) { 2365184610Salfred sc->sc_hub_desc.hubd.DeviceRemovable[l / 8] |= (1 << (l % 8)); 2366184610Salfred } 2367184610Salfred v >>= 1; 2368184610Salfred } 2369184610Salfred sc->sc_hub_desc.hubd.bDescLength = 2370184610Salfred 8 + ((sc->sc_noport + 7) / 8); 2371184610Salfred std->len = sc->sc_hub_desc.hubd.bDescLength; 2372184610Salfred break; 2373184610Salfred 2374184610Salfred case C(UR_GET_STATUS, UT_READ_CLASS_DEVICE): 2375184610Salfred std->len = 16; 2376184610Salfred bzero(sc->sc_hub_desc.temp, 16); 2377184610Salfred break; 2378184610Salfred case C(UR_GET_STATUS, UT_READ_CLASS_OTHER): 2379184610Salfred DPRINTFN(9, "get port status i=%d\n", 2380184610Salfred index); 2381184610Salfred if ((index < 1) || 2382184610Salfred (index > sc->sc_noport)) { 2383184610Salfred std->err = USB_ERR_IOERROR; 2384184610Salfred goto done; 2385184610Salfred } 2386184610Salfred v = OREAD4(sc, OHCI_RH_PORT_STATUS(index)); 2387184610Salfred DPRINTFN(9, "port status=0x%04x\n", v); 2388184610Salfred USETW(sc->sc_hub_desc.ps.wPortStatus, v); 2389184610Salfred USETW(sc->sc_hub_desc.ps.wPortChange, v >> 16); 2390184610Salfred std->len = sizeof(sc->sc_hub_desc.ps); 2391184610Salfred break; 2392184610Salfred case C(UR_SET_DESCRIPTOR, UT_WRITE_CLASS_DEVICE): 2393184610Salfred std->err = USB_ERR_IOERROR; 2394184610Salfred goto done; 2395184610Salfred case C(UR_SET_FEATURE, UT_WRITE_CLASS_DEVICE): 2396184610Salfred break; 2397184610Salfred case C(UR_SET_FEATURE, UT_WRITE_CLASS_OTHER): 2398184610Salfred if ((index < 1) || 2399184610Salfred (index > sc->sc_noport)) { 2400184610Salfred std->err = USB_ERR_IOERROR; 2401184610Salfred goto done; 2402184610Salfred } 2403184610Salfred port = OHCI_RH_PORT_STATUS(index); 2404184610Salfred switch (value) { 2405184610Salfred case UHF_PORT_ENABLE: 2406184610Salfred OWRITE4(sc, port, UPS_PORT_ENABLED); 2407184610Salfred break; 2408184610Salfred case UHF_PORT_SUSPEND: 2409184610Salfred OWRITE4(sc, port, UPS_SUSPEND); 2410184610Salfred break; 2411184610Salfred case UHF_PORT_RESET: 2412184610Salfred DPRINTFN(6, "reset port %d\n", index); 2413184610Salfred OWRITE4(sc, port, UPS_RESET); 2414184610Salfred for (v = 0;; v++) { 2415184610Salfred if (v < 12) { 2416184610Salfred if (use_polling) { 2417184610Salfred /* polling */ 2418184610Salfred DELAY(USB_PORT_ROOT_RESET_DELAY * 1000); 2419184610Salfred } else { 2420184824Sthompsa usb2_pause_mtx(&sc->sc_bus.bus_mtx, 2421184610Salfred USB_PORT_ROOT_RESET_DELAY); 2422184610Salfred } 2423184610Salfred 2424184610Salfred if ((OREAD4(sc, port) & UPS_RESET) == 0) { 2425184610Salfred break; 2426184610Salfred } 2427184610Salfred } else { 2428184610Salfred std->err = USB_ERR_TIMEOUT; 2429184610Salfred goto done; 2430184610Salfred } 2431184610Salfred } 2432184610Salfred DPRINTFN(9, "ohci port %d reset, status = 0x%04x\n", 2433184610Salfred index, OREAD4(sc, port)); 2434184610Salfred break; 2435184610Salfred case UHF_PORT_POWER: 2436184610Salfred DPRINTFN(3, "set port power %d\n", index); 2437184610Salfred OWRITE4(sc, port, UPS_PORT_POWER); 2438184610Salfred break; 2439184610Salfred default: 2440184610Salfred std->err = USB_ERR_IOERROR; 2441184610Salfred goto done; 2442184610Salfred } 2443184610Salfred break; 2444184610Salfred default: 2445184610Salfred std->err = USB_ERR_IOERROR; 2446184610Salfred goto done; 2447184610Salfred } 2448184610Salfreddone: 2449184610Salfred return; 2450184610Salfred} 2451184610Salfred 2452184610Salfredstatic void 2453184610Salfredohci_root_ctrl_poll(struct ohci_softc *sc) 2454184610Salfred{ 2455184610Salfred usb2_sw_transfer(&sc->sc_root_ctrl, 2456184610Salfred &ohci_root_ctrl_done); 2457184610Salfred} 2458184610Salfred 2459184610Salfredstruct usb2_pipe_methods ohci_root_ctrl_methods = 2460184610Salfred{ 2461184610Salfred .open = ohci_root_ctrl_open, 2462184610Salfred .close = ohci_root_ctrl_close, 2463184610Salfred .enter = ohci_root_ctrl_enter, 2464184610Salfred .start = ohci_root_ctrl_start, 2465184610Salfred .enter_is_cancelable = 1, 2466184610Salfred .start_is_cancelable = 0, 2467184610Salfred}; 2468184610Salfred 2469184610Salfred/*------------------------------------------------------------------------* 2470184610Salfred * ohci root interrupt support 2471184610Salfred *------------------------------------------------------------------------*/ 2472184610Salfredstatic void 2473184610Salfredohci_root_intr_open(struct usb2_xfer *xfer) 2474184610Salfred{ 2475184610Salfred return; 2476184610Salfred} 2477184610Salfred 2478184610Salfredstatic void 2479184610Salfredohci_root_intr_close(struct usb2_xfer *xfer) 2480184610Salfred{ 2481184610Salfred ohci_softc_t *sc = xfer->usb2_sc; 2482184610Salfred 2483184610Salfred if (sc->sc_root_intr.xfer == xfer) { 2484184610Salfred sc->sc_root_intr.xfer = NULL; 2485184610Salfred } 2486184610Salfred ohci_device_done(xfer, USB_ERR_CANCELLED); 2487184610Salfred} 2488184610Salfred 2489184610Salfredstatic void 2490184610Salfredohci_root_intr_enter(struct usb2_xfer *xfer) 2491184610Salfred{ 2492184610Salfred return; 2493184610Salfred} 2494184610Salfred 2495184610Salfredstatic void 2496184610Salfredohci_root_intr_start(struct usb2_xfer *xfer) 2497184610Salfred{ 2498184610Salfred ohci_softc_t *sc = xfer->usb2_sc; 2499184610Salfred 2500184610Salfred sc->sc_root_intr.xfer = xfer; 2501184610Salfred} 2502184610Salfred 2503184610Salfredstruct usb2_pipe_methods ohci_root_intr_methods = 2504184610Salfred{ 2505184610Salfred .open = ohci_root_intr_open, 2506184610Salfred .close = ohci_root_intr_close, 2507184610Salfred .enter = ohci_root_intr_enter, 2508184610Salfred .start = ohci_root_intr_start, 2509184610Salfred .enter_is_cancelable = 1, 2510184610Salfred .start_is_cancelable = 1, 2511184610Salfred}; 2512184610Salfred 2513184610Salfredstatic void 2514184610Salfredohci_xfer_setup(struct usb2_setup_params *parm) 2515184610Salfred{ 2516184610Salfred struct usb2_page_search page_info; 2517184610Salfred struct usb2_page_cache *pc; 2518184610Salfred ohci_softc_t *sc; 2519184610Salfred struct usb2_xfer *xfer; 2520184610Salfred void *last_obj; 2521184610Salfred uint32_t ntd; 2522184610Salfred uint32_t nitd; 2523184610Salfred uint32_t nqh; 2524184610Salfred uint32_t n; 2525184610Salfred 2526184610Salfred sc = OHCI_BUS2SC(parm->udev->bus); 2527184610Salfred xfer = parm->curr_xfer; 2528184610Salfred 2529184610Salfred /* 2530184610Salfred * setup xfer 2531184610Salfred */ 2532184610Salfred xfer->usb2_sc = sc; 2533184610Salfred 2534184610Salfred parm->hc_max_packet_size = 0x500; 2535184610Salfred parm->hc_max_packet_count = 1; 2536184610Salfred parm->hc_max_frame_size = OHCI_PAGE_SIZE; 2537184610Salfred 2538184610Salfred /* 2539184610Salfred * calculate ntd and nqh 2540184610Salfred */ 2541184610Salfred if (parm->methods == &ohci_device_ctrl_methods) { 2542184610Salfred xfer->flags_int.bdma_enable = 1; 2543184610Salfred 2544184610Salfred usb2_transfer_setup_sub(parm); 2545184610Salfred 2546184610Salfred nitd = 0; 2547184610Salfred ntd = ((2 * xfer->nframes) + 1 /* STATUS */ 2548184610Salfred + (xfer->max_data_length / xfer->max_usb2_frame_size)); 2549184610Salfred nqh = 1; 2550184610Salfred 2551184610Salfred } else if (parm->methods == &ohci_device_bulk_methods) { 2552184610Salfred xfer->flags_int.bdma_enable = 1; 2553184610Salfred 2554184610Salfred usb2_transfer_setup_sub(parm); 2555184610Salfred 2556184610Salfred nitd = 0; 2557184610Salfred ntd = ((2 * xfer->nframes) 2558184610Salfred + (xfer->max_data_length / xfer->max_usb2_frame_size)); 2559184610Salfred nqh = 1; 2560184610Salfred 2561184610Salfred } else if (parm->methods == &ohci_device_intr_methods) { 2562184610Salfred xfer->flags_int.bdma_enable = 1; 2563184610Salfred 2564184610Salfred usb2_transfer_setup_sub(parm); 2565184610Salfred 2566184610Salfred nitd = 0; 2567184610Salfred ntd = ((2 * xfer->nframes) 2568184610Salfred + (xfer->max_data_length / xfer->max_usb2_frame_size)); 2569184610Salfred nqh = 1; 2570184610Salfred 2571184610Salfred } else if (parm->methods == &ohci_device_isoc_methods) { 2572184610Salfred xfer->flags_int.bdma_enable = 1; 2573184610Salfred 2574184610Salfred usb2_transfer_setup_sub(parm); 2575184610Salfred 2576184610Salfred nitd = ((xfer->max_data_length / OHCI_PAGE_SIZE) + 2577184610Salfred ((xfer->nframes + OHCI_ITD_NOFFSET - 1) / OHCI_ITD_NOFFSET) + 2578184610Salfred 1 /* EXTRA */ ); 2579184610Salfred ntd = 0; 2580184610Salfred nqh = 1; 2581184610Salfred 2582184610Salfred } else { 2583184610Salfred 2584184610Salfred usb2_transfer_setup_sub(parm); 2585184610Salfred 2586184610Salfred nitd = 0; 2587184610Salfred ntd = 0; 2588184610Salfred nqh = 0; 2589184610Salfred } 2590184610Salfred 2591184610Salfredalloc_dma_set: 2592184610Salfred 2593184610Salfred if (parm->err) { 2594184610Salfred return; 2595184610Salfred } 2596184610Salfred last_obj = NULL; 2597184610Salfred 2598184610Salfred if (usb2_transfer_setup_sub_malloc( 2599184610Salfred parm, &pc, sizeof(ohci_td_t), 2600184610Salfred OHCI_TD_ALIGN, ntd)) { 2601184610Salfred parm->err = USB_ERR_NOMEM; 2602184610Salfred return; 2603184610Salfred } 2604184610Salfred if (parm->buf) { 2605184610Salfred for (n = 0; n != ntd; n++) { 2606184610Salfred ohci_td_t *td; 2607184610Salfred 2608184610Salfred usb2_get_page(pc + n, 0, &page_info); 2609184610Salfred 2610184610Salfred td = page_info.buffer; 2611184610Salfred 2612184610Salfred /* init TD */ 2613184610Salfred td->td_self = htole32(page_info.physaddr); 2614184610Salfred td->obj_next = last_obj; 2615184610Salfred td->page_cache = pc + n; 2616184610Salfred 2617184610Salfred last_obj = td; 2618184610Salfred 2619184610Salfred usb2_pc_cpu_flush(pc + n); 2620184610Salfred } 2621184610Salfred } 2622184610Salfred if (usb2_transfer_setup_sub_malloc( 2623184610Salfred parm, &pc, sizeof(ohci_itd_t), 2624184610Salfred OHCI_ITD_ALIGN, nitd)) { 2625184610Salfred parm->err = USB_ERR_NOMEM; 2626184610Salfred return; 2627184610Salfred } 2628184610Salfred if (parm->buf) { 2629184610Salfred for (n = 0; n != nitd; n++) { 2630184610Salfred ohci_itd_t *itd; 2631184610Salfred 2632184610Salfred usb2_get_page(pc + n, 0, &page_info); 2633184610Salfred 2634184610Salfred itd = page_info.buffer; 2635184610Salfred 2636184610Salfred /* init TD */ 2637184610Salfred itd->itd_self = htole32(page_info.physaddr); 2638184610Salfred itd->obj_next = last_obj; 2639184610Salfred itd->page_cache = pc + n; 2640184610Salfred 2641184610Salfred last_obj = itd; 2642184610Salfred 2643184610Salfred usb2_pc_cpu_flush(pc + n); 2644184610Salfred } 2645184610Salfred } 2646184610Salfred xfer->td_start[xfer->flags_int.curr_dma_set] = last_obj; 2647184610Salfred 2648184610Salfred last_obj = NULL; 2649184610Salfred 2650184610Salfred if (usb2_transfer_setup_sub_malloc( 2651184610Salfred parm, &pc, sizeof(ohci_ed_t), 2652184610Salfred OHCI_ED_ALIGN, nqh)) { 2653184610Salfred parm->err = USB_ERR_NOMEM; 2654184610Salfred return; 2655184610Salfred } 2656184610Salfred if (parm->buf) { 2657184610Salfred for (n = 0; n != nqh; n++) { 2658184610Salfred ohci_ed_t *ed; 2659184610Salfred 2660184610Salfred usb2_get_page(pc + n, 0, &page_info); 2661184610Salfred 2662184610Salfred ed = page_info.buffer; 2663184610Salfred 2664184610Salfred /* init QH */ 2665184610Salfred ed->ed_self = htole32(page_info.physaddr); 2666184610Salfred ed->obj_next = last_obj; 2667184610Salfred ed->page_cache = pc + n; 2668184610Salfred 2669184610Salfred last_obj = ed; 2670184610Salfred 2671184610Salfred usb2_pc_cpu_flush(pc + n); 2672184610Salfred } 2673184610Salfred } 2674184610Salfred xfer->qh_start[xfer->flags_int.curr_dma_set] = last_obj; 2675184610Salfred 2676184610Salfred if (!xfer->flags_int.curr_dma_set) { 2677184610Salfred xfer->flags_int.curr_dma_set = 1; 2678184610Salfred goto alloc_dma_set; 2679184610Salfred } 2680184610Salfred} 2681184610Salfred 2682184610Salfredstatic void 2683184610Salfredohci_pipe_init(struct usb2_device *udev, struct usb2_endpoint_descriptor *edesc, 2684184610Salfred struct usb2_pipe *pipe) 2685184610Salfred{ 2686184610Salfred ohci_softc_t *sc = OHCI_BUS2SC(udev->bus); 2687184610Salfred 2688184610Salfred DPRINTFN(2, "pipe=%p, addr=%d, endpt=%d, mode=%d (%d)\n", 2689184610Salfred pipe, udev->address, 2690184610Salfred edesc->bEndpointAddress, udev->flags.usb2_mode, 2691184610Salfred sc->sc_addr); 2692184610Salfred 2693184610Salfred if (udev->flags.usb2_mode != USB_MODE_HOST) { 2694184610Salfred /* not supported */ 2695184610Salfred return; 2696184610Salfred } 2697184610Salfred if (udev->device_index == sc->sc_addr) { 2698184610Salfred switch (edesc->bEndpointAddress) { 2699184610Salfred case USB_CONTROL_ENDPOINT: 2700184610Salfred pipe->methods = &ohci_root_ctrl_methods; 2701184610Salfred break; 2702184610Salfred case UE_DIR_IN | OHCI_INTR_ENDPT: 2703184610Salfred pipe->methods = &ohci_root_intr_methods; 2704184610Salfred break; 2705184610Salfred default: 2706184610Salfred /* do nothing */ 2707184610Salfred break; 2708184610Salfred } 2709184610Salfred } else { 2710184610Salfred switch (edesc->bmAttributes & UE_XFERTYPE) { 2711184610Salfred case UE_CONTROL: 2712184610Salfred pipe->methods = &ohci_device_ctrl_methods; 2713184610Salfred break; 2714184610Salfred case UE_INTERRUPT: 2715184610Salfred pipe->methods = &ohci_device_intr_methods; 2716184610Salfred break; 2717184610Salfred case UE_ISOCHRONOUS: 2718184610Salfred if (udev->speed == USB_SPEED_FULL) { 2719184610Salfred pipe->methods = &ohci_device_isoc_methods; 2720184610Salfred } 2721184610Salfred break; 2722184610Salfred case UE_BULK: 2723184610Salfred if (udev->speed != USB_SPEED_LOW) { 2724184610Salfred pipe->methods = &ohci_device_bulk_methods; 2725184610Salfred } 2726184610Salfred break; 2727184610Salfred default: 2728184610Salfred /* do nothing */ 2729184610Salfred break; 2730184610Salfred } 2731184610Salfred } 2732184610Salfred} 2733184610Salfred 2734184610Salfredstatic void 2735184610Salfredohci_xfer_unsetup(struct usb2_xfer *xfer) 2736184610Salfred{ 2737184610Salfred return; 2738184610Salfred} 2739184610Salfred 2740184610Salfredstatic void 2741184610Salfredohci_get_dma_delay(struct usb2_bus *bus, uint32_t *pus) 2742184610Salfred{ 2743184610Salfred /* 2744184610Salfred * Wait until hardware has finished any possible use of the 2745184610Salfred * transfer descriptor(s) and QH 2746184610Salfred */ 2747184610Salfred *pus = (1125); /* microseconds */ 2748184610Salfred} 2749184610Salfred 2750186730Salfredstatic void 2751186730Salfredohci_device_resume(struct usb2_device *udev) 2752186730Salfred{ 2753186730Salfred struct ohci_softc *sc = OHCI_BUS2SC(udev->bus); 2754186730Salfred struct usb2_xfer *xfer; 2755186730Salfred struct usb2_pipe_methods *methods; 2756186730Salfred ohci_ed_t *ed; 2757186730Salfred 2758186730Salfred DPRINTF("\n"); 2759186730Salfred 2760186730Salfred USB_BUS_LOCK(udev->bus); 2761186730Salfred 2762186730Salfred TAILQ_FOREACH(xfer, &sc->sc_bus.intr_q.head, wait_entry) { 2763186730Salfred 2764186730Salfred if (xfer->udev == udev) { 2765186730Salfred 2766186730Salfred methods = xfer->pipe->methods; 2767186730Salfred ed = xfer->qh_start[xfer->flags_int.curr_dma_set]; 2768186730Salfred 2769186730Salfred if (methods == &ohci_device_bulk_methods) { 2770186730Salfred OHCI_APPEND_QH(ed, sc->sc_bulk_p_last); 2771186730Salfred OWRITE4(sc, OHCI_COMMAND_STATUS, OHCI_BLF); 2772186730Salfred } 2773186730Salfred if (methods == &ohci_device_ctrl_methods) { 2774186730Salfred OHCI_APPEND_QH(ed, sc->sc_ctrl_p_last); 2775186730Salfred OWRITE4(sc, OHCI_COMMAND_STATUS, OHCI_CLF); 2776186730Salfred } 2777186730Salfred if (methods == &ohci_device_intr_methods) { 2778186730Salfred OHCI_APPEND_QH(ed, sc->sc_intr_p_last[xfer->qh_pos]); 2779186730Salfred } 2780186730Salfred } 2781186730Salfred } 2782186730Salfred 2783186730Salfred USB_BUS_UNLOCK(udev->bus); 2784186730Salfred 2785186730Salfred return; 2786186730Salfred} 2787186730Salfred 2788186730Salfredstatic void 2789186730Salfredohci_device_suspend(struct usb2_device *udev) 2790186730Salfred{ 2791186730Salfred struct ohci_softc *sc = OHCI_BUS2SC(udev->bus); 2792186730Salfred struct usb2_xfer *xfer; 2793186730Salfred struct usb2_pipe_methods *methods; 2794186730Salfred ohci_ed_t *ed; 2795186730Salfred 2796186730Salfred DPRINTF("\n"); 2797186730Salfred 2798186730Salfred USB_BUS_LOCK(udev->bus); 2799186730Salfred 2800186730Salfred TAILQ_FOREACH(xfer, &sc->sc_bus.intr_q.head, wait_entry) { 2801186730Salfred 2802186730Salfred if (xfer->udev == udev) { 2803186730Salfred 2804186730Salfred methods = xfer->pipe->methods; 2805186730Salfred ed = xfer->qh_start[xfer->flags_int.curr_dma_set]; 2806186730Salfred 2807186730Salfred if (methods == &ohci_device_bulk_methods) { 2808186730Salfred OHCI_REMOVE_QH(ed, sc->sc_bulk_p_last); 2809186730Salfred } 2810186730Salfred if (methods == &ohci_device_ctrl_methods) { 2811186730Salfred OHCI_REMOVE_QH(ed, sc->sc_ctrl_p_last); 2812186730Salfred } 2813186730Salfred if (methods == &ohci_device_intr_methods) { 2814186730Salfred OHCI_REMOVE_QH(ed, sc->sc_intr_p_last[xfer->qh_pos]); 2815186730Salfred } 2816186730Salfred } 2817186730Salfred } 2818186730Salfred 2819186730Salfred USB_BUS_UNLOCK(udev->bus); 2820186730Salfred 2821186730Salfred return; 2822186730Salfred} 2823186730Salfred 2824186730Salfredstatic void 2825186730Salfredohci_set_hw_power(struct usb2_bus *bus) 2826186730Salfred{ 2827186730Salfred struct ohci_softc *sc = OHCI_BUS2SC(bus); 2828186730Salfred uint32_t temp; 2829186730Salfred uint32_t flags; 2830186730Salfred 2831186730Salfred DPRINTF("\n"); 2832186730Salfred 2833186730Salfred USB_BUS_LOCK(bus); 2834186730Salfred 2835186730Salfred flags = bus->hw_power_state; 2836186730Salfred 2837186730Salfred temp = OREAD4(sc, OHCI_CONTROL); 2838186730Salfred temp &= ~(OHCI_PLE | OHCI_IE | OHCI_CLE | OHCI_BLE); 2839186730Salfred 2840186730Salfred if (flags & USB_HW_POWER_CONTROL) 2841186730Salfred temp |= OHCI_CLE; 2842186730Salfred 2843186730Salfred if (flags & USB_HW_POWER_BULK) 2844186730Salfred temp |= OHCI_BLE; 2845186730Salfred 2846186730Salfred if (flags & USB_HW_POWER_INTERRUPT) 2847186730Salfred temp |= OHCI_PLE; 2848186730Salfred 2849186730Salfred if (flags & USB_HW_POWER_ISOC) 2850186730Salfred temp |= OHCI_IE | OHCI_PLE; 2851186730Salfred 2852186730Salfred OWRITE4(sc, OHCI_CONTROL, temp); 2853186730Salfred 2854186730Salfred USB_BUS_UNLOCK(bus); 2855186730Salfred 2856186730Salfred return; 2857186730Salfred} 2858186730Salfred 2859184610Salfredstruct usb2_bus_methods ohci_bus_methods = 2860184610Salfred{ 2861184610Salfred .pipe_init = ohci_pipe_init, 2862184610Salfred .xfer_setup = ohci_xfer_setup, 2863184610Salfred .xfer_unsetup = ohci_xfer_unsetup, 2864184610Salfred .do_poll = ohci_do_poll, 2865184610Salfred .get_dma_delay = ohci_get_dma_delay, 2866186730Salfred .device_resume = ohci_device_resume, 2867186730Salfred .device_suspend = ohci_device_suspend, 2868186730Salfred .set_hw_power = ohci_set_hw_power, 2869184610Salfred}; 2870