ohci.c revision 191824
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/usb/controller/ohci.c 191824 2009-05-05 15:36:23Z thompsa $");
30184610Salfred
31184610Salfred/*
32184610Salfred * USB Open Host Controller driver.
33184610Salfred *
34184610Salfred * OHCI spec: http://www.compaq.com/productinfo/development/openhci.html
35190754Sthompsa * USB spec:  http://www.usb.org/developers/docs/usbspec.zip
36184610Salfred */
37184610Salfred
38188942Sthompsa#include <dev/usb/usb.h>
39188942Sthompsa#include <dev/usb/usb_mfunc.h>
40188942Sthompsa#include <dev/usb/usb_error.h>
41184610Salfred
42184610Salfred#define	USB_DEBUG_VAR ohcidebug
43184610Salfred
44188942Sthompsa#include <dev/usb/usb_core.h>
45188942Sthompsa#include <dev/usb/usb_debug.h>
46188942Sthompsa#include <dev/usb/usb_busdma.h>
47188942Sthompsa#include <dev/usb/usb_process.h>
48188942Sthompsa#include <dev/usb/usb_transfer.h>
49188942Sthompsa#include <dev/usb/usb_device.h>
50188942Sthompsa#include <dev/usb/usb_hub.h>
51188942Sthompsa#include <dev/usb/usb_util.h>
52184610Salfred
53188942Sthompsa#include <dev/usb/usb_controller.h>
54188942Sthompsa#include <dev/usb/usb_bus.h>
55188942Sthompsa#include <dev/usb/controller/ohci.h>
56184610Salfred
57190181Sthompsa#define	OHCI_BUS2SC(bus) \
58190181Sthompsa   ((ohci_softc_t *)(((uint8_t *)(bus)) - \
59190181Sthompsa    ((uint8_t *)&(((ohci_softc_t *)0)->sc_bus))))
60184610Salfred
61184610Salfred#if USB_DEBUG
62184610Salfredstatic int ohcidebug = 0;
63184610Salfred
64184610SalfredSYSCTL_NODE(_hw_usb2, OID_AUTO, ohci, CTLFLAG_RW, 0, "USB ohci");
65184610SalfredSYSCTL_INT(_hw_usb2_ohci, OID_AUTO, debug, CTLFLAG_RW,
66184610Salfred    &ohcidebug, 0, "ohci debug level");
67184610Salfredstatic void ohci_dumpregs(ohci_softc_t *);
68184610Salfredstatic void ohci_dump_tds(ohci_td_t *);
69184610Salfredstatic uint8_t ohci_dump_td(ohci_td_t *);
70184610Salfredstatic void ohci_dump_ed(ohci_ed_t *);
71184610Salfredstatic uint8_t ohci_dump_itd(ohci_itd_t *);
72184610Salfredstatic void ohci_dump_itds(ohci_itd_t *);
73184610Salfred
74184610Salfred#endif
75184610Salfred
76184610Salfred#define	OBARR(sc) bus_space_barrier((sc)->sc_io_tag, (sc)->sc_io_hdl, 0, (sc)->sc_io_size, \
77184610Salfred			BUS_SPACE_BARRIER_READ|BUS_SPACE_BARRIER_WRITE)
78184610Salfred#define	OWRITE1(sc, r, x) \
79184610Salfred do { OBARR(sc); bus_space_write_1((sc)->sc_io_tag, (sc)->sc_io_hdl, (r), (x)); } while (0)
80184610Salfred#define	OWRITE2(sc, r, x) \
81184610Salfred do { OBARR(sc); bus_space_write_2((sc)->sc_io_tag, (sc)->sc_io_hdl, (r), (x)); } while (0)
82184610Salfred#define	OWRITE4(sc, r, x) \
83184610Salfred do { OBARR(sc); bus_space_write_4((sc)->sc_io_tag, (sc)->sc_io_hdl, (r), (x)); } while (0)
84184610Salfred#define	OREAD1(sc, r) (OBARR(sc), bus_space_read_1((sc)->sc_io_tag, (sc)->sc_io_hdl, (r)))
85184610Salfred#define	OREAD2(sc, r) (OBARR(sc), bus_space_read_2((sc)->sc_io_tag, (sc)->sc_io_hdl, (r)))
86184610Salfred#define	OREAD4(sc, r) (OBARR(sc), bus_space_read_4((sc)->sc_io_tag, (sc)->sc_io_hdl, (r)))
87184610Salfred
88184610Salfred#define	OHCI_INTR_ENDPT 1
89184610Salfred
90184610Salfredextern struct usb2_bus_methods ohci_bus_methods;
91184610Salfredextern struct usb2_pipe_methods ohci_device_bulk_methods;
92184610Salfredextern struct usb2_pipe_methods ohci_device_ctrl_methods;
93184610Salfredextern struct usb2_pipe_methods ohci_device_intr_methods;
94184610Salfredextern struct usb2_pipe_methods ohci_device_isoc_methods;
95184610Salfred
96184610Salfredstatic void ohci_do_poll(struct usb2_bus *bus);
97184610Salfredstatic void ohci_device_done(struct usb2_xfer *xfer, usb2_error_t error);
98184610Salfredstatic void ohci_timeout(void *arg);
99184610Salfredstatic uint8_t ohci_check_transfer(struct usb2_xfer *xfer);
100190735Sthompsastatic void ohci_root_intr(ohci_softc_t *sc);
101184610Salfred
102184610Salfredstruct ohci_std_temp {
103184610Salfred	struct usb2_page_cache *pc;
104184610Salfred	ohci_td_t *td;
105184610Salfred	ohci_td_t *td_next;
106184610Salfred	uint32_t average;
107184610Salfred	uint32_t td_flags;
108184610Salfred	uint32_t len;
109184610Salfred	uint16_t max_frame_size;
110184610Salfred	uint8_t	shortpkt;
111184610Salfred	uint8_t	setup_alt_next;
112190183Sthompsa	uint8_t last_frame;
113184610Salfred};
114184610Salfred
115184610Salfredstatic struct ohci_hcca *
116184610Salfredohci_get_hcca(ohci_softc_t *sc)
117184610Salfred{
118184610Salfred	usb2_pc_cpu_invalidate(&sc->sc_hw.hcca_pc);
119184610Salfred	return (sc->sc_hcca_p);
120184610Salfred}
121184610Salfred
122184610Salfredvoid
123184610Salfredohci_iterate_hw_softc(struct usb2_bus *bus, usb2_bus_mem_sub_cb_t *cb)
124184610Salfred{
125184610Salfred	struct ohci_softc *sc = OHCI_BUS2SC(bus);
126184610Salfred	uint32_t i;
127184610Salfred
128184610Salfred	cb(bus, &sc->sc_hw.hcca_pc, &sc->sc_hw.hcca_pg,
129184610Salfred	    sizeof(ohci_hcca_t), OHCI_HCCA_ALIGN);
130184610Salfred
131184610Salfred	cb(bus, &sc->sc_hw.ctrl_start_pc, &sc->sc_hw.ctrl_start_pg,
132184610Salfred	    sizeof(ohci_ed_t), OHCI_ED_ALIGN);
133184610Salfred
134184610Salfred	cb(bus, &sc->sc_hw.bulk_start_pc, &sc->sc_hw.bulk_start_pg,
135184610Salfred	    sizeof(ohci_ed_t), OHCI_ED_ALIGN);
136184610Salfred
137184610Salfred	cb(bus, &sc->sc_hw.isoc_start_pc, &sc->sc_hw.isoc_start_pg,
138184610Salfred	    sizeof(ohci_ed_t), OHCI_ED_ALIGN);
139184610Salfred
140184610Salfred	for (i = 0; i != OHCI_NO_EDS; i++) {
141184610Salfred		cb(bus, sc->sc_hw.intr_start_pc + i, sc->sc_hw.intr_start_pg + i,
142184610Salfred		    sizeof(ohci_ed_t), OHCI_ED_ALIGN);
143184610Salfred	}
144184610Salfred}
145184610Salfred
146184610Salfredstatic usb2_error_t
147184610Salfredohci_controller_init(ohci_softc_t *sc)
148184610Salfred{
149184610Salfred	struct usb2_page_search buf_res;
150184610Salfred	uint32_t i;
151184610Salfred	uint32_t ctl;
152184610Salfred	uint32_t ival;
153184610Salfred	uint32_t hcr;
154184610Salfred	uint32_t fm;
155184610Salfred	uint32_t per;
156184610Salfred	uint32_t desca;
157184610Salfred
158184610Salfred	/* Determine in what context we are running. */
159184610Salfred	ctl = OREAD4(sc, OHCI_CONTROL);
160184610Salfred	if (ctl & OHCI_IR) {
161184610Salfred		/* SMM active, request change */
162184610Salfred		DPRINTF("SMM active, request owner change\n");
163184610Salfred		OWRITE4(sc, OHCI_COMMAND_STATUS, OHCI_OCR);
164184610Salfred		for (i = 0; (i < 100) && (ctl & OHCI_IR); i++) {
165188409Sthompsa			usb2_pause_mtx(NULL, hz / 1000);
166184610Salfred			ctl = OREAD4(sc, OHCI_CONTROL);
167184610Salfred		}
168184610Salfred		if (ctl & OHCI_IR) {
169184610Salfred			device_printf(sc->sc_bus.bdev,
170184610Salfred			    "SMM does not respond, resetting\n");
171184610Salfred			OWRITE4(sc, OHCI_CONTROL, OHCI_HCFS_RESET);
172184610Salfred			goto reset;
173184610Salfred		}
174184610Salfred	} else {
175184610Salfred		DPRINTF("cold started\n");
176184610Salfredreset:
177184610Salfred		/* controller was cold started */
178188409Sthompsa		usb2_pause_mtx(NULL,
179188409Sthompsa		    USB_MS_TO_TICKS(USB_BUS_RESET_DELAY));
180184610Salfred	}
181184610Salfred
182184610Salfred	/*
183184610Salfred	 * This reset should not be necessary according to the OHCI spec, but
184184610Salfred	 * without it some controllers do not start.
185184610Salfred	 */
186184610Salfred	DPRINTF("%s: resetting\n", device_get_nameunit(sc->sc_bus.bdev));
187184610Salfred	OWRITE4(sc, OHCI_CONTROL, OHCI_HCFS_RESET);
188184610Salfred
189188409Sthompsa	usb2_pause_mtx(NULL,
190188409Sthompsa	    USB_MS_TO_TICKS(USB_BUS_RESET_DELAY));
191184610Salfred
192184610Salfred	/* we now own the host controller and the bus has been reset */
193184610Salfred	ival = OHCI_GET_IVAL(OREAD4(sc, OHCI_FM_INTERVAL));
194184610Salfred
195184610Salfred	OWRITE4(sc, OHCI_COMMAND_STATUS, OHCI_HCR);	/* Reset HC */
196184610Salfred	/* nominal time for a reset is 10 us */
197184610Salfred	for (i = 0; i < 10; i++) {
198184610Salfred		DELAY(10);
199184610Salfred		hcr = OREAD4(sc, OHCI_COMMAND_STATUS) & OHCI_HCR;
200184610Salfred		if (!hcr) {
201184610Salfred			break;
202184610Salfred		}
203184610Salfred	}
204184610Salfred	if (hcr) {
205184610Salfred		device_printf(sc->sc_bus.bdev, "reset timeout\n");
206184610Salfred		return (USB_ERR_IOERROR);
207184610Salfred	}
208184610Salfred#if USB_DEBUG
209184610Salfred	if (ohcidebug > 15) {
210184610Salfred		ohci_dumpregs(sc);
211184610Salfred	}
212184610Salfred#endif
213184610Salfred
214184610Salfred	/* The controller is now in SUSPEND state, we have 2ms to finish. */
215184610Salfred
216184610Salfred	/* set up HC registers */
217184610Salfred	usb2_get_page(&sc->sc_hw.hcca_pc, 0, &buf_res);
218184610Salfred	OWRITE4(sc, OHCI_HCCA, buf_res.physaddr);
219184610Salfred
220184610Salfred	usb2_get_page(&sc->sc_hw.ctrl_start_pc, 0, &buf_res);
221184610Salfred	OWRITE4(sc, OHCI_CONTROL_HEAD_ED, buf_res.physaddr);
222184610Salfred
223184610Salfred	usb2_get_page(&sc->sc_hw.bulk_start_pc, 0, &buf_res);
224184610Salfred	OWRITE4(sc, OHCI_BULK_HEAD_ED, buf_res.physaddr);
225184610Salfred
226184610Salfred	/* disable all interrupts and then switch on all desired interrupts */
227184610Salfred	OWRITE4(sc, OHCI_INTERRUPT_DISABLE, OHCI_ALL_INTRS);
228184610Salfred	OWRITE4(sc, OHCI_INTERRUPT_ENABLE, sc->sc_eintrs | OHCI_MIE);
229184610Salfred	/* switch on desired functional features */
230184610Salfred	ctl = OREAD4(sc, OHCI_CONTROL);
231184610Salfred	ctl &= ~(OHCI_CBSR_MASK | OHCI_LES | OHCI_HCFS_MASK | OHCI_IR);
232184610Salfred	ctl |= OHCI_PLE | OHCI_IE | OHCI_CLE | OHCI_BLE |
233184610Salfred	    OHCI_RATIO_1_4 | OHCI_HCFS_OPERATIONAL;
234184610Salfred	/* And finally start it! */
235184610Salfred	OWRITE4(sc, OHCI_CONTROL, ctl);
236184610Salfred
237184610Salfred	/*
238184610Salfred	 * The controller is now OPERATIONAL.  Set a some final
239184610Salfred	 * registers that should be set earlier, but that the
240184610Salfred	 * controller ignores when in the SUSPEND state.
241184610Salfred	 */
242184610Salfred	fm = (OREAD4(sc, OHCI_FM_INTERVAL) & OHCI_FIT) ^ OHCI_FIT;
243184610Salfred	fm |= OHCI_FSMPS(ival) | ival;
244184610Salfred	OWRITE4(sc, OHCI_FM_INTERVAL, fm);
245184610Salfred	per = OHCI_PERIODIC(ival);	/* 90% periodic */
246184610Salfred	OWRITE4(sc, OHCI_PERIODIC_START, per);
247184610Salfred
248184610Salfred	/* Fiddle the No OverCurrent Protection bit to avoid chip bug. */
249184610Salfred	desca = OREAD4(sc, OHCI_RH_DESCRIPTOR_A);
250184610Salfred	OWRITE4(sc, OHCI_RH_DESCRIPTOR_A, desca | OHCI_NOCP);
251184610Salfred	OWRITE4(sc, OHCI_RH_STATUS, OHCI_LPSC);	/* Enable port power */
252188409Sthompsa	usb2_pause_mtx(NULL,
253188409Sthompsa	    USB_MS_TO_TICKS(OHCI_ENABLE_POWER_DELAY));
254184610Salfred	OWRITE4(sc, OHCI_RH_DESCRIPTOR_A, desca);
255184610Salfred
256184610Salfred	/*
257184610Salfred	 * The AMD756 requires a delay before re-reading the register,
258184610Salfred	 * otherwise it will occasionally report 0 ports.
259184610Salfred	 */
260184610Salfred	sc->sc_noport = 0;
261184610Salfred	for (i = 0; (i < 10) && (sc->sc_noport == 0); i++) {
262188409Sthompsa		usb2_pause_mtx(NULL,
263188409Sthompsa		    USB_MS_TO_TICKS(OHCI_READ_DESC_DELAY));
264184610Salfred		sc->sc_noport = OHCI_GET_NDP(OREAD4(sc, OHCI_RH_DESCRIPTOR_A));
265184610Salfred	}
266184610Salfred
267184610Salfred#if USB_DEBUG
268184610Salfred	if (ohcidebug > 5) {
269184610Salfred		ohci_dumpregs(sc);
270184610Salfred	}
271184610Salfred#endif
272184610Salfred	return (USB_ERR_NORMAL_COMPLETION);
273184610Salfred}
274184610Salfred
275184610Salfredstatic struct ohci_ed *
276184610Salfredohci_init_ed(struct usb2_page_cache *pc)
277184610Salfred{
278184610Salfred	struct usb2_page_search buf_res;
279184610Salfred	struct ohci_ed *ed;
280184610Salfred
281184610Salfred	usb2_get_page(pc, 0, &buf_res);
282184610Salfred
283184610Salfred	ed = buf_res.buffer;
284184610Salfred
285184610Salfred	ed->ed_self = htole32(buf_res.physaddr);
286184610Salfred	ed->ed_flags = htole32(OHCI_ED_SKIP);
287184610Salfred	ed->page_cache = pc;
288184610Salfred
289184610Salfred	return (ed);
290184610Salfred}
291184610Salfred
292184610Salfredusb2_error_t
293184610Salfredohci_init(ohci_softc_t *sc)
294184610Salfred{
295184610Salfred	struct usb2_page_search buf_res;
296184610Salfred	uint16_t i;
297184610Salfred	uint16_t bit;
298184610Salfred	uint16_t x;
299184610Salfred	uint16_t y;
300184610Salfred
301184610Salfred	DPRINTF("start\n");
302184610Salfred
303184610Salfred	sc->sc_eintrs = OHCI_NORMAL_INTRS;
304184610Salfred
305184610Salfred	/*
306184610Salfred	 * Setup all ED's
307184610Salfred	 */
308184610Salfred
309184610Salfred	sc->sc_ctrl_p_last =
310184610Salfred	    ohci_init_ed(&sc->sc_hw.ctrl_start_pc);
311184610Salfred
312184610Salfred	sc->sc_bulk_p_last =
313184610Salfred	    ohci_init_ed(&sc->sc_hw.bulk_start_pc);
314184610Salfred
315184610Salfred	sc->sc_isoc_p_last =
316184610Salfred	    ohci_init_ed(&sc->sc_hw.isoc_start_pc);
317184610Salfred
318184610Salfred	for (i = 0; i != OHCI_NO_EDS; i++) {
319184610Salfred		sc->sc_intr_p_last[i] =
320184610Salfred		    ohci_init_ed(sc->sc_hw.intr_start_pc + i);
321184610Salfred	}
322184610Salfred
323184610Salfred	/*
324184610Salfred	 * the QHs are arranged to give poll intervals that are
325184610Salfred	 * powers of 2 times 1ms
326184610Salfred	 */
327184610Salfred	bit = OHCI_NO_EDS / 2;
328184610Salfred	while (bit) {
329184610Salfred		x = bit;
330184610Salfred		while (x & bit) {
331184610Salfred			ohci_ed_t *ed_x;
332184610Salfred			ohci_ed_t *ed_y;
333184610Salfred
334184610Salfred			y = (x ^ bit) | (bit / 2);
335184610Salfred
336184610Salfred			/*
337184610Salfred			 * the next QH has half the poll interval
338184610Salfred			 */
339184610Salfred			ed_x = sc->sc_intr_p_last[x];
340184610Salfred			ed_y = sc->sc_intr_p_last[y];
341184610Salfred
342184610Salfred			ed_x->next = NULL;
343184610Salfred			ed_x->ed_next = ed_y->ed_self;
344184610Salfred
345184610Salfred			x++;
346184610Salfred		}
347184610Salfred		bit >>= 1;
348184610Salfred	}
349184610Salfred
350184610Salfred	if (1) {
351184610Salfred
352184610Salfred		ohci_ed_t *ed_int;
353184610Salfred		ohci_ed_t *ed_isc;
354184610Salfred
355184610Salfred		ed_int = sc->sc_intr_p_last[0];
356184610Salfred		ed_isc = sc->sc_isoc_p_last;
357184610Salfred
358184610Salfred		/* the last (1ms) QH */
359184610Salfred		ed_int->next = ed_isc;
360184610Salfred		ed_int->ed_next = ed_isc->ed_self;
361184610Salfred	}
362184610Salfred	usb2_get_page(&sc->sc_hw.hcca_pc, 0, &buf_res);
363184610Salfred
364184610Salfred	sc->sc_hcca_p = buf_res.buffer;
365184610Salfred
366184610Salfred	/*
367184610Salfred	 * Fill HCCA interrupt table.  The bit reversal is to get
368184610Salfred	 * the tree set up properly to spread the interrupts.
369184610Salfred	 */
370184610Salfred	for (i = 0; i != OHCI_NO_INTRS; i++) {
371184610Salfred		sc->sc_hcca_p->hcca_interrupt_table[i] =
372184610Salfred		    sc->sc_intr_p_last[i | (OHCI_NO_EDS / 2)]->ed_self;
373184610Salfred	}
374184610Salfred	/* flush all cache into memory */
375184610Salfred
376184610Salfred	usb2_bus_mem_flush_all(&sc->sc_bus, &ohci_iterate_hw_softc);
377184610Salfred
378184610Salfred	/* set up the bus struct */
379184610Salfred	sc->sc_bus.methods = &ohci_bus_methods;
380184610Salfred
381186454Sthompsa	usb2_callout_init_mtx(&sc->sc_tmo_rhsc, &sc->sc_bus.bus_mtx, 0);
382184610Salfred
383184610Salfred#if USB_DEBUG
384184610Salfred	if (ohcidebug > 15) {
385184610Salfred		for (i = 0; i != OHCI_NO_EDS; i++) {
386184610Salfred			printf("ed#%d ", i);
387184610Salfred			ohci_dump_ed(sc->sc_intr_p_last[i]);
388184610Salfred		}
389184610Salfred		printf("iso ");
390184610Salfred		ohci_dump_ed(sc->sc_isoc_p_last);
391184610Salfred	}
392184610Salfred#endif
393184610Salfred
394184610Salfred	sc->sc_bus.usbrev = USB_REV_1_0;
395184610Salfred
396184610Salfred	if (ohci_controller_init(sc)) {
397184610Salfred		return (USB_ERR_INVAL);
398184610Salfred	} else {
399184610Salfred		/* catch any lost interrupts */
400184610Salfred		ohci_do_poll(&sc->sc_bus);
401184610Salfred		return (USB_ERR_NORMAL_COMPLETION);
402184610Salfred	}
403184610Salfred}
404184610Salfred
405184610Salfred/*
406184610Salfred * shut down the controller when the system is going down
407184610Salfred */
408184610Salfredvoid
409184610Salfredohci_detach(struct ohci_softc *sc)
410184610Salfred{
411184824Sthompsa	USB_BUS_LOCK(&sc->sc_bus);
412184610Salfred
413184610Salfred	usb2_callout_stop(&sc->sc_tmo_rhsc);
414184610Salfred
415184610Salfred	OWRITE4(sc, OHCI_INTERRUPT_DISABLE, OHCI_ALL_INTRS);
416184610Salfred	OWRITE4(sc, OHCI_CONTROL, OHCI_HCFS_RESET);
417184610Salfred
418188409Sthompsa	USB_BUS_UNLOCK(&sc->sc_bus);
419188409Sthompsa
420184610Salfred	/* XXX let stray task complete */
421188409Sthompsa	usb2_pause_mtx(NULL, hz / 20);
422184610Salfred
423184610Salfred	usb2_callout_drain(&sc->sc_tmo_rhsc);
424184610Salfred}
425184610Salfred
426184610Salfred/* NOTE: suspend/resume is called from
427184610Salfred * interrupt context and cannot sleep!
428184610Salfred */
429184610Salfredvoid
430184610Salfredohci_suspend(ohci_softc_t *sc)
431184610Salfred{
432184610Salfred	uint32_t ctl;
433184610Salfred
434184824Sthompsa	USB_BUS_LOCK(&sc->sc_bus);
435184610Salfred
436184610Salfred#if USB_DEBUG
437184610Salfred	DPRINTF("\n");
438184610Salfred	if (ohcidebug > 2) {
439184610Salfred		ohci_dumpregs(sc);
440184610Salfred	}
441184610Salfred#endif
442184610Salfred
443184610Salfred	ctl = OREAD4(sc, OHCI_CONTROL) & ~OHCI_HCFS_MASK;
444184610Salfred	if (sc->sc_control == 0) {
445184610Salfred		/*
446184610Salfred		 * Preserve register values, in case that APM BIOS
447184610Salfred		 * does not recover them.
448184610Salfred		 */
449184610Salfred		sc->sc_control = ctl;
450184610Salfred		sc->sc_intre = OREAD4(sc, OHCI_INTERRUPT_ENABLE);
451184610Salfred	}
452184610Salfred	ctl |= OHCI_HCFS_SUSPEND;
453184610Salfred	OWRITE4(sc, OHCI_CONTROL, ctl);
454184610Salfred
455184824Sthompsa	usb2_pause_mtx(&sc->sc_bus.bus_mtx,
456188409Sthompsa	    USB_MS_TO_TICKS(USB_RESUME_WAIT));
457184610Salfred
458184824Sthompsa	USB_BUS_UNLOCK(&sc->sc_bus);
459184610Salfred}
460184610Salfred
461184610Salfredvoid
462184610Salfredohci_resume(ohci_softc_t *sc)
463184610Salfred{
464184610Salfred	uint32_t ctl;
465184610Salfred
466184610Salfred#if USB_DEBUG
467184610Salfred	DPRINTF("\n");
468184610Salfred	if (ohcidebug > 2) {
469184610Salfred		ohci_dumpregs(sc);
470184610Salfred	}
471184610Salfred#endif
472184610Salfred	/* some broken BIOSes never initialize the Controller chip */
473184610Salfred	ohci_controller_init(sc);
474184610Salfred
475188273Sthompsa	USB_BUS_LOCK(&sc->sc_bus);
476184610Salfred	if (sc->sc_intre) {
477184610Salfred		OWRITE4(sc, OHCI_INTERRUPT_ENABLE,
478184610Salfred		    sc->sc_intre & (OHCI_ALL_INTRS | OHCI_MIE));
479184610Salfred	}
480184610Salfred	if (sc->sc_control)
481184610Salfred		ctl = sc->sc_control;
482184610Salfred	else
483184610Salfred		ctl = OREAD4(sc, OHCI_CONTROL);
484184610Salfred	ctl |= OHCI_HCFS_RESUME;
485184610Salfred	OWRITE4(sc, OHCI_CONTROL, ctl);
486188409Sthompsa	usb2_pause_mtx(&sc->sc_bus.bus_mtx,
487188409Sthompsa	    USB_MS_TO_TICKS(USB_RESUME_DELAY));
488184610Salfred	ctl = (ctl & ~OHCI_HCFS_MASK) | OHCI_HCFS_OPERATIONAL;
489184610Salfred	OWRITE4(sc, OHCI_CONTROL, ctl);
490188409Sthompsa	usb2_pause_mtx(&sc->sc_bus.bus_mtx,
491188409Sthompsa	    USB_MS_TO_TICKS(USB_RESUME_RECOVERY));
492184610Salfred	sc->sc_control = sc->sc_intre = 0;
493184610Salfred
494184824Sthompsa	USB_BUS_UNLOCK(&sc->sc_bus);
495184610Salfred
496184610Salfred	/* catch any lost interrupts */
497184610Salfred	ohci_do_poll(&sc->sc_bus);
498184610Salfred}
499184610Salfred
500184610Salfred#if USB_DEBUG
501184610Salfredstatic void
502184610Salfredohci_dumpregs(ohci_softc_t *sc)
503184610Salfred{
504184610Salfred	struct ohci_hcca *hcca;
505184610Salfred
506184610Salfred	DPRINTF("ohci_dumpregs: rev=0x%08x control=0x%08x command=0x%08x\n",
507184610Salfred	    OREAD4(sc, OHCI_REVISION),
508184610Salfred	    OREAD4(sc, OHCI_CONTROL),
509184610Salfred	    OREAD4(sc, OHCI_COMMAND_STATUS));
510184610Salfred	DPRINTF("               intrstat=0x%08x intre=0x%08x intrd=0x%08x\n",
511184610Salfred	    OREAD4(sc, OHCI_INTERRUPT_STATUS),
512184610Salfred	    OREAD4(sc, OHCI_INTERRUPT_ENABLE),
513184610Salfred	    OREAD4(sc, OHCI_INTERRUPT_DISABLE));
514184610Salfred	DPRINTF("               hcca=0x%08x percur=0x%08x ctrlhd=0x%08x\n",
515184610Salfred	    OREAD4(sc, OHCI_HCCA),
516184610Salfred	    OREAD4(sc, OHCI_PERIOD_CURRENT_ED),
517184610Salfred	    OREAD4(sc, OHCI_CONTROL_HEAD_ED));
518184610Salfred	DPRINTF("               ctrlcur=0x%08x bulkhd=0x%08x bulkcur=0x%08x\n",
519184610Salfred	    OREAD4(sc, OHCI_CONTROL_CURRENT_ED),
520184610Salfred	    OREAD4(sc, OHCI_BULK_HEAD_ED),
521184610Salfred	    OREAD4(sc, OHCI_BULK_CURRENT_ED));
522184610Salfred	DPRINTF("               done=0x%08x fmival=0x%08x fmrem=0x%08x\n",
523184610Salfred	    OREAD4(sc, OHCI_DONE_HEAD),
524184610Salfred	    OREAD4(sc, OHCI_FM_INTERVAL),
525184610Salfred	    OREAD4(sc, OHCI_FM_REMAINING));
526184610Salfred	DPRINTF("               fmnum=0x%08x perst=0x%08x lsthrs=0x%08x\n",
527184610Salfred	    OREAD4(sc, OHCI_FM_NUMBER),
528184610Salfred	    OREAD4(sc, OHCI_PERIODIC_START),
529184610Salfred	    OREAD4(sc, OHCI_LS_THRESHOLD));
530184610Salfred	DPRINTF("               desca=0x%08x descb=0x%08x stat=0x%08x\n",
531184610Salfred	    OREAD4(sc, OHCI_RH_DESCRIPTOR_A),
532184610Salfred	    OREAD4(sc, OHCI_RH_DESCRIPTOR_B),
533184610Salfred	    OREAD4(sc, OHCI_RH_STATUS));
534184610Salfred	DPRINTF("               port1=0x%08x port2=0x%08x\n",
535184610Salfred	    OREAD4(sc, OHCI_RH_PORT_STATUS(1)),
536184610Salfred	    OREAD4(sc, OHCI_RH_PORT_STATUS(2)));
537184610Salfred
538184610Salfred	hcca = ohci_get_hcca(sc);
539184610Salfred
540184610Salfred	DPRINTF("         HCCA: frame_number=0x%04x done_head=0x%08x\n",
541184610Salfred	    le32toh(hcca->hcca_frame_number),
542184610Salfred	    le32toh(hcca->hcca_done_head));
543184610Salfred}
544184610Salfredstatic void
545184610Salfredohci_dump_tds(ohci_td_t *std)
546184610Salfred{
547184610Salfred	for (; std; std = std->obj_next) {
548184610Salfred		if (ohci_dump_td(std)) {
549184610Salfred			break;
550184610Salfred		}
551184610Salfred	}
552184610Salfred}
553184610Salfred
554184610Salfredstatic uint8_t
555184610Salfredohci_dump_td(ohci_td_t *std)
556184610Salfred{
557184610Salfred	uint32_t td_flags;
558184610Salfred	uint8_t temp;
559184610Salfred
560184610Salfred	usb2_pc_cpu_invalidate(std->page_cache);
561184610Salfred
562184610Salfred	td_flags = le32toh(std->td_flags);
563184610Salfred	temp = (std->td_next == 0);
564184610Salfred
565184610Salfred	printf("TD(%p) at 0x%08x: %s%s%s%s%s delay=%d ec=%d "
566184610Salfred	    "cc=%d\ncbp=0x%08x next=0x%08x be=0x%08x\n",
567184610Salfred	    std, le32toh(std->td_self),
568184610Salfred	    (td_flags & OHCI_TD_R) ? "-R" : "",
569184610Salfred	    (td_flags & OHCI_TD_OUT) ? "-OUT" : "",
570184610Salfred	    (td_flags & OHCI_TD_IN) ? "-IN" : "",
571184610Salfred	    ((td_flags & OHCI_TD_TOGGLE_MASK) == OHCI_TD_TOGGLE_1) ? "-TOG1" : "",
572184610Salfred	    ((td_flags & OHCI_TD_TOGGLE_MASK) == OHCI_TD_TOGGLE_0) ? "-TOG0" : "",
573184610Salfred	    OHCI_TD_GET_DI(td_flags),
574184610Salfred	    OHCI_TD_GET_EC(td_flags),
575184610Salfred	    OHCI_TD_GET_CC(td_flags),
576184610Salfred	    le32toh(std->td_cbp),
577184610Salfred	    le32toh(std->td_next),
578184610Salfred	    le32toh(std->td_be));
579184610Salfred
580184610Salfred	return (temp);
581184610Salfred}
582184610Salfred
583184610Salfredstatic uint8_t
584184610Salfredohci_dump_itd(ohci_itd_t *sitd)
585184610Salfred{
586184610Salfred	uint32_t itd_flags;
587184610Salfred	uint16_t i;
588184610Salfred	uint8_t temp;
589184610Salfred
590184610Salfred	usb2_pc_cpu_invalidate(sitd->page_cache);
591184610Salfred
592184610Salfred	itd_flags = le32toh(sitd->itd_flags);
593184610Salfred	temp = (sitd->itd_next == 0);
594184610Salfred
595184610Salfred	printf("ITD(%p) at 0x%08x: sf=%d di=%d fc=%d cc=%d\n"
596184610Salfred	    "bp0=0x%08x next=0x%08x be=0x%08x\n",
597184610Salfred	    sitd, le32toh(sitd->itd_self),
598184610Salfred	    OHCI_ITD_GET_SF(itd_flags),
599184610Salfred	    OHCI_ITD_GET_DI(itd_flags),
600184610Salfred	    OHCI_ITD_GET_FC(itd_flags),
601184610Salfred	    OHCI_ITD_GET_CC(itd_flags),
602184610Salfred	    le32toh(sitd->itd_bp0),
603184610Salfred	    le32toh(sitd->itd_next),
604184610Salfred	    le32toh(sitd->itd_be));
605184610Salfred	for (i = 0; i < OHCI_ITD_NOFFSET; i++) {
606184610Salfred		printf("offs[%d]=0x%04x ", i,
607184610Salfred		    (uint32_t)le16toh(sitd->itd_offset[i]));
608184610Salfred	}
609184610Salfred	printf("\n");
610184610Salfred
611184610Salfred	return (temp);
612184610Salfred}
613184610Salfred
614184610Salfredstatic void
615184610Salfredohci_dump_itds(ohci_itd_t *sitd)
616184610Salfred{
617184610Salfred	for (; sitd; sitd = sitd->obj_next) {
618184610Salfred		if (ohci_dump_itd(sitd)) {
619184610Salfred			break;
620184610Salfred		}
621184610Salfred	}
622184610Salfred}
623184610Salfred
624184610Salfredstatic void
625184610Salfredohci_dump_ed(ohci_ed_t *sed)
626184610Salfred{
627184610Salfred	uint32_t ed_flags;
628184610Salfred	uint32_t ed_headp;
629184610Salfred
630184610Salfred	usb2_pc_cpu_invalidate(sed->page_cache);
631184610Salfred
632184610Salfred	ed_flags = le32toh(sed->ed_flags);
633184610Salfred	ed_headp = le32toh(sed->ed_headp);
634184610Salfred
635184610Salfred	printf("ED(%p) at 0x%08x: addr=%d endpt=%d maxp=%d flags=%s%s%s%s%s\n"
636184610Salfred	    "tailp=0x%08x headflags=%s%s headp=0x%08x nexted=0x%08x\n",
637184610Salfred	    sed, le32toh(sed->ed_self),
638184610Salfred	    OHCI_ED_GET_FA(ed_flags),
639184610Salfred	    OHCI_ED_GET_EN(ed_flags),
640184610Salfred	    OHCI_ED_GET_MAXP(ed_flags),
641184610Salfred	    (ed_flags & OHCI_ED_DIR_OUT) ? "-OUT" : "",
642184610Salfred	    (ed_flags & OHCI_ED_DIR_IN) ? "-IN" : "",
643184610Salfred	    (ed_flags & OHCI_ED_SPEED) ? "-LOWSPEED" : "",
644184610Salfred	    (ed_flags & OHCI_ED_SKIP) ? "-SKIP" : "",
645184610Salfred	    (ed_flags & OHCI_ED_FORMAT_ISO) ? "-ISO" : "",
646184610Salfred	    le32toh(sed->ed_tailp),
647184610Salfred	    (ed_headp & OHCI_HALTED) ? "-HALTED" : "",
648184610Salfred	    (ed_headp & OHCI_TOGGLECARRY) ? "-CARRY" : "",
649184610Salfred	    le32toh(sed->ed_headp),
650184610Salfred	    le32toh(sed->ed_next));
651184610Salfred}
652184610Salfred
653184610Salfred#endif
654184610Salfred
655184610Salfredstatic void
656184610Salfredohci_transfer_intr_enqueue(struct usb2_xfer *xfer)
657184610Salfred{
658184610Salfred	/* check for early completion */
659184610Salfred	if (ohci_check_transfer(xfer)) {
660184610Salfred		return;
661184610Salfred	}
662184610Salfred	/* put transfer on interrupt queue */
663187173Sthompsa	usb2_transfer_enqueue(&xfer->xroot->bus->intr_q, xfer);
664184610Salfred
665184610Salfred	/* start timeout, if any */
666184610Salfred	if (xfer->timeout != 0) {
667184610Salfred		usb2_transfer_timeout_ms(xfer, &ohci_timeout, xfer->timeout);
668184610Salfred	}
669184610Salfred}
670184610Salfred
671186730Salfred#define	OHCI_APPEND_QH(sed,last) (last) = _ohci_append_qh(sed,last)
672184610Salfredstatic ohci_ed_t *
673186730Salfred_ohci_append_qh(ohci_ed_t *sed, ohci_ed_t *last)
674184610Salfred{
675184610Salfred	DPRINTFN(11, "%p to %p\n", sed, last);
676184610Salfred
677186730Salfred	if (sed->prev != NULL) {
678186730Salfred		/* should not happen */
679186730Salfred		DPRINTFN(0, "ED already linked!\n");
680186730Salfred		return (last);
681186730Salfred	}
682184824Sthompsa	/* (sc->sc_bus.bus_mtx) must be locked */
683184610Salfred
684184610Salfred	sed->next = last->next;
685184610Salfred	sed->ed_next = last->ed_next;
686184610Salfred	sed->ed_tailp = 0;
687184610Salfred
688184610Salfred	sed->prev = last;
689184610Salfred
690184610Salfred	usb2_pc_cpu_flush(sed->page_cache);
691184610Salfred
692184610Salfred	/*
693184610Salfred	 * the last->next->prev is never followed: sed->next->prev = sed;
694184610Salfred	 */
695184610Salfred
696184610Salfred	last->next = sed;
697184610Salfred	last->ed_next = sed->ed_self;
698184610Salfred
699184610Salfred	usb2_pc_cpu_flush(last->page_cache);
700184610Salfred
701184610Salfred	return (sed);
702184610Salfred}
703184610Salfred
704184610Salfred#define	OHCI_REMOVE_QH(sed,last) (last) = _ohci_remove_qh(sed,last)
705184610Salfredstatic ohci_ed_t *
706184610Salfred_ohci_remove_qh(ohci_ed_t *sed, ohci_ed_t *last)
707184610Salfred{
708184610Salfred	DPRINTFN(11, "%p from %p\n", sed, last);
709184610Salfred
710184824Sthompsa	/* (sc->sc_bus.bus_mtx) must be locked */
711184610Salfred
712184610Salfred	/* only remove if not removed from a queue */
713184610Salfred	if (sed->prev) {
714184610Salfred
715184610Salfred		sed->prev->next = sed->next;
716184610Salfred		sed->prev->ed_next = sed->ed_next;
717184610Salfred
718184610Salfred		usb2_pc_cpu_flush(sed->prev->page_cache);
719184610Salfred
720184610Salfred		if (sed->next) {
721184610Salfred			sed->next->prev = sed->prev;
722184610Salfred			usb2_pc_cpu_flush(sed->next->page_cache);
723184610Salfred		}
724184610Salfred		last = ((last == sed) ? sed->prev : last);
725184610Salfred
726184610Salfred		sed->prev = 0;
727184610Salfred
728184610Salfred		usb2_pc_cpu_flush(sed->page_cache);
729184610Salfred	}
730184610Salfred	return (last);
731184610Salfred}
732184610Salfred
733184610Salfredstatic void
734184610Salfredohci_isoc_done(struct usb2_xfer *xfer)
735184610Salfred{
736184610Salfred	uint8_t nframes;
737184610Salfred	uint32_t *plen = xfer->frlengths;
738184610Salfred	volatile uint16_t *olen;
739184610Salfred	uint16_t len = 0;
740184610Salfred	ohci_itd_t *td = xfer->td_transfer_first;
741184610Salfred
742184610Salfred	while (1) {
743184610Salfred		if (td == NULL) {
744184610Salfred			panic("%s:%d: out of TD's\n",
745184610Salfred			    __FUNCTION__, __LINE__);
746184610Salfred		}
747184610Salfred#if USB_DEBUG
748184610Salfred		if (ohcidebug > 5) {
749184610Salfred			DPRINTF("isoc TD\n");
750184610Salfred			ohci_dump_itd(td);
751184610Salfred		}
752184610Salfred#endif
753184610Salfred		usb2_pc_cpu_invalidate(td->page_cache);
754184610Salfred
755184610Salfred		nframes = td->frames;
756184610Salfred		olen = &td->itd_offset[0];
757184610Salfred
758184610Salfred		if (nframes > 8) {
759184610Salfred			nframes = 8;
760184610Salfred		}
761184610Salfred		while (nframes--) {
762184610Salfred			len = le16toh(*olen);
763184610Salfred
764184610Salfred			if ((len >> 12) == OHCI_CC_NOT_ACCESSED) {
765184610Salfred				len = 0;
766184610Salfred			} else {
767184610Salfred				len &= ((1 << 12) - 1);
768184610Salfred			}
769184610Salfred
770184610Salfred			if (len > *plen) {
771184610Salfred				len = 0;/* invalid length */
772184610Salfred			}
773184610Salfred			*plen = len;
774184610Salfred			plen++;
775184610Salfred			olen++;
776184610Salfred		}
777184610Salfred
778184610Salfred		if (((void *)td) == xfer->td_transfer_last) {
779184610Salfred			break;
780184610Salfred		}
781184610Salfred		td = td->obj_next;
782184610Salfred	}
783184610Salfred
784184610Salfred	xfer->aframes = xfer->nframes;
785184610Salfred	ohci_device_done(xfer, USB_ERR_NORMAL_COMPLETION);
786184610Salfred}
787184610Salfred
788184610Salfred#if USB_DEBUG
789184610Salfredstatic const char *const
790184610Salfred	ohci_cc_strs[] =
791184610Salfred{
792184610Salfred	"NO_ERROR",
793184610Salfred	"CRC",
794184610Salfred	"BIT_STUFFING",
795184610Salfred	"DATA_TOGGLE_MISMATCH",
796184610Salfred
797184610Salfred	"STALL",
798184610Salfred	"DEVICE_NOT_RESPONDING",
799184610Salfred	"PID_CHECK_FAILURE",
800184610Salfred	"UNEXPECTED_PID",
801184610Salfred
802184610Salfred	"DATA_OVERRUN",
803184610Salfred	"DATA_UNDERRUN",
804184610Salfred	"BUFFER_OVERRUN",
805184610Salfred	"BUFFER_UNDERRUN",
806184610Salfred
807184610Salfred	"reserved",
808184610Salfred	"reserved",
809184610Salfred	"NOT_ACCESSED",
810184610Salfred	"NOT_ACCESSED"
811184610Salfred};
812184610Salfred
813184610Salfred#endif
814184610Salfred
815184610Salfredstatic usb2_error_t
816184610Salfredohci_non_isoc_done_sub(struct usb2_xfer *xfer)
817184610Salfred{
818184610Salfred	ohci_td_t *td;
819184610Salfred	ohci_td_t *td_alt_next;
820184610Salfred	uint32_t temp;
821184610Salfred	uint32_t phy_start;
822184610Salfred	uint32_t phy_end;
823184610Salfred	uint32_t td_flags;
824184610Salfred	uint16_t cc;
825184610Salfred
826184610Salfred	td = xfer->td_transfer_cache;
827184610Salfred	td_alt_next = td->alt_next;
828184610Salfred	td_flags = 0;
829184610Salfred
830188409Sthompsa	if (xfer->aframes != xfer->nframes) {
831188409Sthompsa		xfer->frlengths[xfer->aframes] = 0;
832188409Sthompsa	}
833184610Salfred	while (1) {
834184610Salfred
835184610Salfred		usb2_pc_cpu_invalidate(td->page_cache);
836184610Salfred		phy_start = le32toh(td->td_cbp);
837184610Salfred		td_flags = le32toh(td->td_flags);
838184610Salfred		cc = OHCI_TD_GET_CC(td_flags);
839184610Salfred
840184610Salfred		if (phy_start) {
841184610Salfred			/*
842184610Salfred			 * short transfer - compute the number of remaining
843184610Salfred			 * bytes in the hardware buffer:
844184610Salfred			 */
845184610Salfred			phy_end = le32toh(td->td_be);
846184610Salfred			temp = (OHCI_PAGE(phy_start ^ phy_end) ?
847184610Salfred			    (OHCI_PAGE_SIZE + 1) : 0x0001);
848184610Salfred			temp += OHCI_PAGE_OFFSET(phy_end);
849184610Salfred			temp -= OHCI_PAGE_OFFSET(phy_start);
850184610Salfred
851184610Salfred			if (temp > td->len) {
852184610Salfred				/* guard against corruption */
853184610Salfred				cc = OHCI_CC_STALL;
854184610Salfred			} else if (xfer->aframes != xfer->nframes) {
855184610Salfred				/*
856188409Sthompsa				 * Sum up total transfer length
857188409Sthompsa				 * in "frlengths[]":
858184610Salfred				 */
859188409Sthompsa				xfer->frlengths[xfer->aframes] += td->len - temp;
860184610Salfred			}
861188409Sthompsa		} else {
862188409Sthompsa			if (xfer->aframes != xfer->nframes) {
863188409Sthompsa				/* transfer was complete */
864188409Sthompsa				xfer->frlengths[xfer->aframes] += td->len;
865188409Sthompsa			}
866184610Salfred		}
867184610Salfred		/* Check for last transfer */
868184610Salfred		if (((void *)td) == xfer->td_transfer_last) {
869184610Salfred			td = NULL;
870184610Salfred			break;
871184610Salfred		}
872184610Salfred		/* Check transfer status */
873184610Salfred		if (cc) {
874184610Salfred			/* the transfer is finished */
875184610Salfred			td = NULL;
876184610Salfred			break;
877184610Salfred		}
878184610Salfred		/* Check for short transfer */
879184610Salfred		if (phy_start) {
880184610Salfred			if (xfer->flags_int.short_frames_ok) {
881184610Salfred				/* follow alt next */
882184610Salfred				td = td->alt_next;
883184610Salfred			} else {
884184610Salfred				/* the transfer is finished */
885184610Salfred				td = NULL;
886184610Salfred			}
887184610Salfred			break;
888184610Salfred		}
889184610Salfred		td = td->obj_next;
890184610Salfred
891184610Salfred		if (td->alt_next != td_alt_next) {
892184610Salfred			/* this USB frame is complete */
893184610Salfred			break;
894184610Salfred		}
895184610Salfred	}
896184610Salfred
897184610Salfred	/* update transfer cache */
898184610Salfred
899184610Salfred	xfer->td_transfer_cache = td;
900184610Salfred
901184610Salfred	DPRINTFN(16, "error cc=%d (%s)\n",
902184610Salfred	    cc, ohci_cc_strs[cc]);
903184610Salfred
904184610Salfred	return ((cc == 0) ? USB_ERR_NORMAL_COMPLETION :
905184610Salfred	    (cc == OHCI_CC_STALL) ? USB_ERR_STALLED : USB_ERR_IOERROR);
906184610Salfred}
907184610Salfred
908184610Salfredstatic void
909184610Salfredohci_non_isoc_done(struct usb2_xfer *xfer)
910184610Salfred{
911184610Salfred	usb2_error_t err = 0;
912184610Salfred
913184610Salfred	DPRINTFN(13, "xfer=%p pipe=%p transfer done\n",
914184610Salfred	    xfer, xfer->pipe);
915184610Salfred
916184610Salfred#if USB_DEBUG
917184610Salfred	if (ohcidebug > 10) {
918184610Salfred		ohci_dump_tds(xfer->td_transfer_first);
919184610Salfred	}
920184610Salfred#endif
921184610Salfred
922184610Salfred	/* reset scanner */
923184610Salfred
924184610Salfred	xfer->td_transfer_cache = xfer->td_transfer_first;
925184610Salfred
926184610Salfred	if (xfer->flags_int.control_xfr) {
927184610Salfred
928184610Salfred		if (xfer->flags_int.control_hdr) {
929184610Salfred
930184610Salfred			err = ohci_non_isoc_done_sub(xfer);
931184610Salfred		}
932184610Salfred		xfer->aframes = 1;
933184610Salfred
934184610Salfred		if (xfer->td_transfer_cache == NULL) {
935184610Salfred			goto done;
936184610Salfred		}
937184610Salfred	}
938184610Salfred	while (xfer->aframes != xfer->nframes) {
939184610Salfred
940184610Salfred		err = ohci_non_isoc_done_sub(xfer);
941184610Salfred		xfer->aframes++;
942184610Salfred
943184610Salfred		if (xfer->td_transfer_cache == NULL) {
944184610Salfred			goto done;
945184610Salfred		}
946184610Salfred	}
947184610Salfred
948184610Salfred	if (xfer->flags_int.control_xfr &&
949184610Salfred	    !xfer->flags_int.control_act) {
950184610Salfred
951184610Salfred		err = ohci_non_isoc_done_sub(xfer);
952184610Salfred	}
953184610Salfreddone:
954184610Salfred	ohci_device_done(xfer, err);
955184610Salfred}
956184610Salfred
957184610Salfred/*------------------------------------------------------------------------*
958184610Salfred *	ohci_check_transfer_sub
959184610Salfred *------------------------------------------------------------------------*/
960184610Salfredstatic void
961184610Salfredohci_check_transfer_sub(struct usb2_xfer *xfer)
962184610Salfred{
963184610Salfred	ohci_td_t *td;
964184610Salfred	ohci_ed_t *ed;
965184610Salfred	uint32_t phy_start;
966184610Salfred	uint32_t td_flags;
967184610Salfred	uint32_t td_next;
968184610Salfred	uint16_t cc;
969184610Salfred
970184610Salfred	td = xfer->td_transfer_cache;
971184610Salfred
972184610Salfred	while (1) {
973184610Salfred
974184610Salfred		usb2_pc_cpu_invalidate(td->page_cache);
975184610Salfred		phy_start = le32toh(td->td_cbp);
976184610Salfred		td_flags = le32toh(td->td_flags);
977184610Salfred		td_next = le32toh(td->td_next);
978184610Salfred
979184610Salfred		/* Check for last transfer */
980184610Salfred		if (((void *)td) == xfer->td_transfer_last) {
981184610Salfred			/* the transfer is finished */
982184610Salfred			td = NULL;
983184610Salfred			break;
984184610Salfred		}
985184610Salfred		/* Check transfer status */
986184610Salfred		cc = OHCI_TD_GET_CC(td_flags);
987184610Salfred		if (cc) {
988184610Salfred			/* the transfer is finished */
989184610Salfred			td = NULL;
990184610Salfred			break;
991184610Salfred		}
992184610Salfred		/*
993184610Salfred	         * Check if we reached the last packet
994184610Salfred	         * or if there is a short packet:
995184610Salfred	         */
996184610Salfred
997184610Salfred		if (((td_next & (~0xF)) == OHCI_TD_NEXT_END) || phy_start) {
998184610Salfred			/* follow alt next */
999184610Salfred			td = td->alt_next;
1000184610Salfred			break;
1001184610Salfred		}
1002184610Salfred		td = td->obj_next;
1003184610Salfred	}
1004184610Salfred
1005184610Salfred	/* update transfer cache */
1006184610Salfred
1007184610Salfred	xfer->td_transfer_cache = td;
1008184610Salfred
1009184610Salfred	if (td) {
1010184610Salfred
1011184610Salfred		ed = xfer->qh_start[xfer->flags_int.curr_dma_set];
1012184610Salfred
1013184610Salfred		ed->ed_headp = td->td_self;
1014184610Salfred		usb2_pc_cpu_flush(ed->page_cache);
1015184610Salfred
1016184610Salfred		DPRINTFN(13, "xfer=%p following alt next\n", xfer);
1017190183Sthompsa
1018190183Sthompsa		/*
1019190183Sthompsa		 * Make sure that the OHCI re-scans the schedule by
1020190183Sthompsa		 * writing the BLF and CLF bits:
1021190183Sthompsa		 */
1022190183Sthompsa
1023191824Sthompsa		if (xfer->xroot->udev->flags.self_suspended) {
1024190183Sthompsa			/* nothing to do */
1025190183Sthompsa		} else if (xfer->pipe->methods == &ohci_device_bulk_methods) {
1026190183Sthompsa			ohci_softc_t *sc = OHCI_BUS2SC(xfer->xroot->bus);
1027190183Sthompsa
1028190183Sthompsa			OWRITE4(sc, OHCI_COMMAND_STATUS, OHCI_BLF);
1029190183Sthompsa		} else if (xfer->pipe->methods == &ohci_device_ctrl_methods) {
1030190183Sthompsa			ohci_softc_t *sc = OHCI_BUS2SC(xfer->xroot->bus);
1031190183Sthompsa
1032190183Sthompsa			OWRITE4(sc, OHCI_COMMAND_STATUS, OHCI_CLF);
1033190183Sthompsa		}
1034184610Salfred	}
1035184610Salfred}
1036184610Salfred
1037184610Salfred/*------------------------------------------------------------------------*
1038184610Salfred *	ohci_check_transfer
1039184610Salfred *
1040184610Salfred * Return values:
1041184610Salfred *    0: USB transfer is not finished
1042184610Salfred * Else: USB transfer is finished
1043184610Salfred *------------------------------------------------------------------------*/
1044184610Salfredstatic uint8_t
1045184610Salfredohci_check_transfer(struct usb2_xfer *xfer)
1046184610Salfred{
1047184610Salfred	ohci_ed_t *ed;
1048184610Salfred	uint32_t ed_headp;
1049184610Salfred	uint32_t ed_tailp;
1050184610Salfred
1051184610Salfred	DPRINTFN(13, "xfer=%p checking transfer\n", xfer);
1052184610Salfred
1053184610Salfred	ed = xfer->qh_start[xfer->flags_int.curr_dma_set];
1054184610Salfred
1055184610Salfred	usb2_pc_cpu_invalidate(ed->page_cache);
1056184610Salfred	ed_headp = le32toh(ed->ed_headp);
1057184610Salfred	ed_tailp = le32toh(ed->ed_tailp);
1058184610Salfred
1059190183Sthompsa	if ((ed_headp & OHCI_HALTED) ||
1060184610Salfred	    (((ed_headp ^ ed_tailp) & (~0xF)) == 0)) {
1061184610Salfred		if (xfer->pipe->methods == &ohci_device_isoc_methods) {
1062184610Salfred			/* isochronous transfer */
1063184610Salfred			ohci_isoc_done(xfer);
1064184610Salfred		} else {
1065184610Salfred			if (xfer->flags_int.short_frames_ok) {
1066184610Salfred				ohci_check_transfer_sub(xfer);
1067184610Salfred				if (xfer->td_transfer_cache) {
1068184610Salfred					/* not finished yet */
1069184610Salfred					return (0);
1070184610Salfred				}
1071184610Salfred			}
1072184610Salfred			/* store data-toggle */
1073184610Salfred			if (ed_headp & OHCI_TOGGLECARRY) {
1074184610Salfred				xfer->pipe->toggle_next = 1;
1075184610Salfred			} else {
1076184610Salfred				xfer->pipe->toggle_next = 0;
1077184610Salfred			}
1078184610Salfred
1079184610Salfred			/* non-isochronous transfer */
1080184610Salfred			ohci_non_isoc_done(xfer);
1081184610Salfred		}
1082184610Salfred		return (1);
1083184610Salfred	}
1084184610Salfred	DPRINTFN(13, "xfer=%p is still active\n", xfer);
1085184610Salfred	return (0);
1086184610Salfred}
1087184610Salfred
1088184610Salfredstatic void
1089184610Salfredohci_rhsc_enable(ohci_softc_t *sc)
1090184610Salfred{
1091184610Salfred	DPRINTFN(5, "\n");
1092184610Salfred
1093184824Sthompsa	USB_BUS_LOCK_ASSERT(&sc->sc_bus, MA_OWNED);
1094184610Salfred
1095184610Salfred	sc->sc_eintrs |= OHCI_RHSC;
1096184610Salfred	OWRITE4(sc, OHCI_INTERRUPT_ENABLE, OHCI_RHSC);
1097184610Salfred
1098184610Salfred	/* acknowledge any RHSC interrupt */
1099184610Salfred	OWRITE4(sc, OHCI_INTERRUPT_STATUS, OHCI_RHSC);
1100184610Salfred
1101190735Sthompsa	ohci_root_intr(sc);
1102184610Salfred}
1103184610Salfred
1104184610Salfredstatic void
1105184610Salfredohci_interrupt_poll(ohci_softc_t *sc)
1106184610Salfred{
1107184610Salfred	struct usb2_xfer *xfer;
1108184610Salfred
1109184610Salfredrepeat:
1110184610Salfred	TAILQ_FOREACH(xfer, &sc->sc_bus.intr_q.head, wait_entry) {
1111184610Salfred		/*
1112184610Salfred		 * check if transfer is transferred
1113184610Salfred		 */
1114184610Salfred		if (ohci_check_transfer(xfer)) {
1115184610Salfred			/* queue has been modified */
1116184610Salfred			goto repeat;
1117184610Salfred		}
1118184610Salfred	}
1119184610Salfred}
1120184610Salfred
1121184610Salfred/*------------------------------------------------------------------------*
1122184610Salfred *	ohci_interrupt - OHCI interrupt handler
1123184610Salfred *
1124184610Salfred * NOTE: Do not access "sc->sc_bus.bdev" inside the interrupt handler,
1125184610Salfred * hence the interrupt handler will be setup before "sc->sc_bus.bdev"
1126184610Salfred * is present !
1127184610Salfred *------------------------------------------------------------------------*/
1128184610Salfredvoid
1129184610Salfredohci_interrupt(ohci_softc_t *sc)
1130184610Salfred{
1131184610Salfred	struct ohci_hcca *hcca;
1132184610Salfred	uint32_t status;
1133184610Salfred	uint32_t done;
1134184610Salfred
1135184824Sthompsa	USB_BUS_LOCK(&sc->sc_bus);
1136184610Salfred
1137184610Salfred	hcca = ohci_get_hcca(sc);
1138184610Salfred
1139184610Salfred	DPRINTFN(16, "real interrupt\n");
1140184610Salfred
1141184610Salfred#if USB_DEBUG
1142184610Salfred	if (ohcidebug > 15) {
1143184610Salfred		ohci_dumpregs(sc);
1144184610Salfred	}
1145184610Salfred#endif
1146184610Salfred
1147184610Salfred	done = le32toh(hcca->hcca_done_head);
1148184610Salfred
1149184610Salfred	/*
1150184610Salfred	 * The LSb of done is used to inform the HC Driver that an interrupt
1151184610Salfred	 * condition exists for both the Done list and for another event
1152184610Salfred	 * recorded in HcInterruptStatus. On an interrupt from the HC, the
1153184610Salfred	 * HC Driver checks the HccaDoneHead Value. If this value is 0, then
1154184610Salfred	 * the interrupt was caused by other than the HccaDoneHead update
1155184610Salfred	 * and the HcInterruptStatus register needs to be accessed to
1156184610Salfred	 * determine that exact interrupt cause. If HccaDoneHead is nonzero,
1157184610Salfred	 * then a Done list update interrupt is indicated and if the LSb of
1158184610Salfred	 * done is nonzero, then an additional interrupt event is indicated
1159184610Salfred	 * and HcInterruptStatus should be checked to determine its cause.
1160184610Salfred	 */
1161184610Salfred	if (done != 0) {
1162184610Salfred		status = 0;
1163184610Salfred
1164184610Salfred		if (done & ~OHCI_DONE_INTRS) {
1165184610Salfred			status |= OHCI_WDH;
1166184610Salfred		}
1167184610Salfred		if (done & OHCI_DONE_INTRS) {
1168184610Salfred			status |= OREAD4(sc, OHCI_INTERRUPT_STATUS);
1169184610Salfred		}
1170184610Salfred		hcca->hcca_done_head = 0;
1171184610Salfred
1172184610Salfred		usb2_pc_cpu_flush(&sc->sc_hw.hcca_pc);
1173184610Salfred	} else {
1174184610Salfred		status = OREAD4(sc, OHCI_INTERRUPT_STATUS) & ~OHCI_WDH;
1175184610Salfred	}
1176184610Salfred
1177184610Salfred	status &= ~OHCI_MIE;
1178184610Salfred	if (status == 0) {
1179184610Salfred		/*
1180184610Salfred		 * nothing to be done (PCI shared
1181184610Salfred		 * interrupt)
1182184610Salfred		 */
1183184610Salfred		goto done;
1184184610Salfred	}
1185184610Salfred	OWRITE4(sc, OHCI_INTERRUPT_STATUS, status);	/* Acknowledge */
1186184610Salfred
1187184610Salfred	status &= sc->sc_eintrs;
1188184610Salfred	if (status == 0) {
1189184610Salfred		goto done;
1190184610Salfred	}
1191184610Salfred	if (status & (OHCI_SO | OHCI_RD | OHCI_UE | OHCI_RHSC)) {
1192184610Salfred#if 0
1193184610Salfred		if (status & OHCI_SO) {
1194184610Salfred			/* XXX do what */
1195184610Salfred		}
1196184610Salfred#endif
1197184610Salfred		if (status & OHCI_RD) {
1198184610Salfred			printf("%s: resume detect\n", __FUNCTION__);
1199184610Salfred			/* XXX process resume detect */
1200184610Salfred		}
1201184610Salfred		if (status & OHCI_UE) {
1202184610Salfred			printf("%s: unrecoverable error, "
1203184610Salfred			    "controller halted\n", __FUNCTION__);
1204184610Salfred			OWRITE4(sc, OHCI_CONTROL, OHCI_HCFS_RESET);
1205184610Salfred			/* XXX what else */
1206184610Salfred		}
1207184610Salfred		if (status & OHCI_RHSC) {
1208184610Salfred			/*
1209184610Salfred			 * Disable RHSC interrupt for now, because it will be
1210184610Salfred			 * on until the port has been reset.
1211184610Salfred			 */
1212184610Salfred			sc->sc_eintrs &= ~OHCI_RHSC;
1213184610Salfred			OWRITE4(sc, OHCI_INTERRUPT_DISABLE, OHCI_RHSC);
1214184610Salfred
1215190735Sthompsa			ohci_root_intr(sc);
1216184610Salfred
1217184610Salfred			/* do not allow RHSC interrupts > 1 per second */
1218184610Salfred			usb2_callout_reset(&sc->sc_tmo_rhsc, hz,
1219184610Salfred			    (void *)&ohci_rhsc_enable, sc);
1220184610Salfred		}
1221184610Salfred	}
1222184610Salfred	status &= ~(OHCI_RHSC | OHCI_WDH | OHCI_SO);
1223184610Salfred	if (status != 0) {
1224184610Salfred		/* Block unprocessed interrupts. XXX */
1225184610Salfred		OWRITE4(sc, OHCI_INTERRUPT_DISABLE, status);
1226184610Salfred		sc->sc_eintrs &= ~status;
1227184610Salfred		printf("%s: blocking intrs 0x%x\n",
1228184610Salfred		    __FUNCTION__, status);
1229184610Salfred	}
1230184610Salfred	/* poll all the USB transfers */
1231184610Salfred	ohci_interrupt_poll(sc);
1232184610Salfred
1233184610Salfreddone:
1234184824Sthompsa	USB_BUS_UNLOCK(&sc->sc_bus);
1235184610Salfred}
1236184610Salfred
1237184610Salfred/*
1238184610Salfred * called when a request does not complete
1239184610Salfred */
1240184610Salfredstatic void
1241184610Salfredohci_timeout(void *arg)
1242184610Salfred{
1243184610Salfred	struct usb2_xfer *xfer = arg;
1244184610Salfred
1245184610Salfred	DPRINTF("xfer=%p\n", xfer);
1246184610Salfred
1247187173Sthompsa	USB_BUS_LOCK_ASSERT(xfer->xroot->bus, MA_OWNED);
1248184610Salfred
1249184610Salfred	/* transfer is transferred */
1250184610Salfred	ohci_device_done(xfer, USB_ERR_TIMEOUT);
1251184610Salfred}
1252184610Salfred
1253184610Salfredstatic void
1254184610Salfredohci_do_poll(struct usb2_bus *bus)
1255184610Salfred{
1256184610Salfred	struct ohci_softc *sc = OHCI_BUS2SC(bus);
1257184610Salfred
1258184824Sthompsa	USB_BUS_LOCK(&sc->sc_bus);
1259184610Salfred	ohci_interrupt_poll(sc);
1260184824Sthompsa	USB_BUS_UNLOCK(&sc->sc_bus);
1261184610Salfred}
1262184610Salfred
1263184610Salfredstatic void
1264184610Salfredohci_setup_standard_chain_sub(struct ohci_std_temp *temp)
1265184610Salfred{
1266184610Salfred	struct usb2_page_search buf_res;
1267184610Salfred	ohci_td_t *td;
1268184610Salfred	ohci_td_t *td_next;
1269184610Salfred	ohci_td_t *td_alt_next;
1270184610Salfred	uint32_t buf_offset;
1271184610Salfred	uint32_t average;
1272184610Salfred	uint32_t len_old;
1273184610Salfred	uint8_t shortpkt_old;
1274184610Salfred	uint8_t precompute;
1275184610Salfred
1276184610Salfred	td_alt_next = NULL;
1277184610Salfred	buf_offset = 0;
1278184610Salfred	shortpkt_old = temp->shortpkt;
1279184610Salfred	len_old = temp->len;
1280184610Salfred	precompute = 1;
1281184610Salfred
1282184610Salfred	/* software is used to detect short incoming transfers */
1283184610Salfred
1284184610Salfred	if ((temp->td_flags & htole32(OHCI_TD_DP_MASK)) == htole32(OHCI_TD_IN)) {
1285184610Salfred		temp->td_flags |= htole32(OHCI_TD_R);
1286184610Salfred	} else {
1287184610Salfred		temp->td_flags &= ~htole32(OHCI_TD_R);
1288184610Salfred	}
1289184610Salfred
1290184610Salfredrestart:
1291184610Salfred
1292184610Salfred	td = temp->td;
1293184610Salfred	td_next = temp->td_next;
1294184610Salfred
1295184610Salfred	while (1) {
1296184610Salfred
1297184610Salfred		if (temp->len == 0) {
1298184610Salfred
1299184610Salfred			if (temp->shortpkt) {
1300184610Salfred				break;
1301184610Salfred			}
1302184610Salfred			/* send a Zero Length Packet, ZLP, last */
1303184610Salfred
1304184610Salfred			temp->shortpkt = 1;
1305184610Salfred			average = 0;
1306184610Salfred
1307184610Salfred		} else {
1308184610Salfred
1309184610Salfred			average = temp->average;
1310184610Salfred
1311184610Salfred			if (temp->len < average) {
1312184610Salfred				if (temp->len % temp->max_frame_size) {
1313184610Salfred					temp->shortpkt = 1;
1314184610Salfred				}
1315184610Salfred				average = temp->len;
1316184610Salfred			}
1317184610Salfred		}
1318184610Salfred
1319184610Salfred		if (td_next == NULL) {
1320184610Salfred			panic("%s: out of OHCI transfer descriptors!", __FUNCTION__);
1321184610Salfred		}
1322184610Salfred		/* get next TD */
1323184610Salfred
1324184610Salfred		td = td_next;
1325184610Salfred		td_next = td->obj_next;
1326184610Salfred
1327184610Salfred		/* check if we are pre-computing */
1328184610Salfred
1329184610Salfred		if (precompute) {
1330184610Salfred
1331184610Salfred			/* update remaining length */
1332184610Salfred
1333184610Salfred			temp->len -= average;
1334184610Salfred
1335184610Salfred			continue;
1336184610Salfred		}
1337184610Salfred		/* fill out current TD */
1338184610Salfred		td->td_flags = temp->td_flags;
1339184610Salfred
1340184610Salfred		/* the next TD uses TOGGLE_CARRY */
1341184610Salfred		temp->td_flags &= ~htole32(OHCI_TD_TOGGLE_MASK);
1342184610Salfred
1343184610Salfred		if (average == 0) {
1344190471Sthompsa			/*
1345190471Sthompsa			 * The buffer start and end phys addresses should be
1346190471Sthompsa			 * 0x0 for a zero length packet.
1347190471Sthompsa			 */
1348184610Salfred			td->td_cbp = 0;
1349190471Sthompsa			td->td_be = 0;
1350184610Salfred			td->len = 0;
1351184610Salfred
1352184610Salfred		} else {
1353184610Salfred
1354184610Salfred			usb2_get_page(temp->pc, buf_offset, &buf_res);
1355184610Salfred			td->td_cbp = htole32(buf_res.physaddr);
1356184610Salfred			buf_offset += (average - 1);
1357184610Salfred
1358184610Salfred			usb2_get_page(temp->pc, buf_offset, &buf_res);
1359184610Salfred			td->td_be = htole32(buf_res.physaddr);
1360184610Salfred			buf_offset++;
1361184610Salfred
1362184610Salfred			td->len = average;
1363184610Salfred
1364184610Salfred			/* update remaining length */
1365184610Salfred
1366184610Salfred			temp->len -= average;
1367184610Salfred		}
1368184610Salfred
1369184610Salfred		if ((td_next == td_alt_next) && temp->setup_alt_next) {
1370184610Salfred			/* we need to receive these frames one by one ! */
1371184610Salfred			td->td_flags &= htole32(~OHCI_TD_INTR_MASK);
1372184610Salfred			td->td_flags |= htole32(OHCI_TD_SET_DI(1));
1373184610Salfred			td->td_next = htole32(OHCI_TD_NEXT_END);
1374184610Salfred		} else {
1375184610Salfred			if (td_next) {
1376184610Salfred				/* link the current TD with the next one */
1377184610Salfred				td->td_next = td_next->td_self;
1378184610Salfred			}
1379184610Salfred		}
1380184610Salfred
1381184610Salfred		td->alt_next = td_alt_next;
1382184610Salfred
1383184610Salfred		usb2_pc_cpu_flush(td->page_cache);
1384184610Salfred	}
1385184610Salfred
1386184610Salfred	if (precompute) {
1387184610Salfred		precompute = 0;
1388184610Salfred
1389184610Salfred		/* setup alt next pointer, if any */
1390190183Sthompsa		if (temp->last_frame) {
1391190183Sthompsa			/* no alternate next */
1392190183Sthompsa			td_alt_next = NULL;
1393184610Salfred		} else {
1394184610Salfred			/* we use this field internally */
1395184610Salfred			td_alt_next = td_next;
1396184610Salfred		}
1397184610Salfred
1398184610Salfred		/* restore */
1399184610Salfred		temp->shortpkt = shortpkt_old;
1400184610Salfred		temp->len = len_old;
1401184610Salfred		goto restart;
1402184610Salfred	}
1403184610Salfred	temp->td = td;
1404184610Salfred	temp->td_next = td_next;
1405184610Salfred}
1406184610Salfred
1407184610Salfredstatic void
1408184610Salfredohci_setup_standard_chain(struct usb2_xfer *xfer, ohci_ed_t **ed_last)
1409184610Salfred{
1410184610Salfred	struct ohci_std_temp temp;
1411184610Salfred	struct usb2_pipe_methods *methods;
1412184610Salfred	ohci_ed_t *ed;
1413184610Salfred	ohci_td_t *td;
1414184610Salfred	uint32_t ed_flags;
1415184610Salfred	uint32_t x;
1416184610Salfred
1417184610Salfred	DPRINTFN(9, "addr=%d endpt=%d sumlen=%d speed=%d\n",
1418184610Salfred	    xfer->address, UE_GET_ADDR(xfer->endpoint),
1419187173Sthompsa	    xfer->sumlen, usb2_get_speed(xfer->xroot->udev));
1420184610Salfred
1421190181Sthompsa	temp.average = xfer->max_hc_frame_size;
1422184610Salfred	temp.max_frame_size = xfer->max_frame_size;
1423184610Salfred
1424184610Salfred	/* toggle the DMA set we are using */
1425184610Salfred	xfer->flags_int.curr_dma_set ^= 1;
1426184610Salfred
1427184610Salfred	/* get next DMA set */
1428184610Salfred	td = xfer->td_start[xfer->flags_int.curr_dma_set];
1429184610Salfred
1430184610Salfred	xfer->td_transfer_first = td;
1431184610Salfred	xfer->td_transfer_cache = td;
1432184610Salfred
1433184610Salfred	temp.td = NULL;
1434184610Salfred	temp.td_next = td;
1435190183Sthompsa	temp.last_frame = 0;
1436184610Salfred	temp.setup_alt_next = xfer->flags_int.short_frames_ok;
1437184610Salfred
1438184610Salfred	methods = xfer->pipe->methods;
1439184610Salfred
1440184610Salfred	/* check if we should prepend a setup message */
1441184610Salfred
1442184610Salfred	if (xfer->flags_int.control_xfr) {
1443184610Salfred		if (xfer->flags_int.control_hdr) {
1444184610Salfred
1445184610Salfred			temp.td_flags = htole32(OHCI_TD_SETUP | OHCI_TD_NOCC |
1446184610Salfred			    OHCI_TD_TOGGLE_0 | OHCI_TD_NOINTR);
1447184610Salfred
1448184610Salfred			temp.len = xfer->frlengths[0];
1449184610Salfred			temp.pc = xfer->frbuffers + 0;
1450184610Salfred			temp.shortpkt = temp.len ? 1 : 0;
1451190183Sthompsa			/* check for last frame */
1452190183Sthompsa			if (xfer->nframes == 1) {
1453190183Sthompsa				/* no STATUS stage yet, SETUP is last */
1454190183Sthompsa				if (xfer->flags_int.control_act) {
1455190183Sthompsa					temp.last_frame = 1;
1456190183Sthompsa					temp.setup_alt_next = 0;
1457190183Sthompsa				}
1458190183Sthompsa			}
1459184610Salfred			ohci_setup_standard_chain_sub(&temp);
1460184610Salfred
1461184610Salfred			/*
1462184610Salfred			 * XXX assume that the setup message is
1463184610Salfred			 * contained within one USB packet:
1464184610Salfred			 */
1465184610Salfred			xfer->pipe->toggle_next = 1;
1466184610Salfred		}
1467184610Salfred		x = 1;
1468184610Salfred	} else {
1469184610Salfred		x = 0;
1470184610Salfred	}
1471184610Salfred	temp.td_flags = htole32(OHCI_TD_NOCC | OHCI_TD_NOINTR);
1472184610Salfred
1473184610Salfred	/* set data toggle */
1474184610Salfred
1475184610Salfred	if (xfer->pipe->toggle_next) {
1476184610Salfred		temp.td_flags |= htole32(OHCI_TD_TOGGLE_1);
1477184610Salfred	} else {
1478184610Salfred		temp.td_flags |= htole32(OHCI_TD_TOGGLE_0);
1479184610Salfred	}
1480184610Salfred
1481184610Salfred	/* set endpoint direction */
1482184610Salfred
1483184610Salfred	if (UE_GET_DIR(xfer->endpoint) == UE_DIR_IN) {
1484184610Salfred		temp.td_flags |= htole32(OHCI_TD_IN);
1485184610Salfred	} else {
1486184610Salfred		temp.td_flags |= htole32(OHCI_TD_OUT);
1487184610Salfred	}
1488184610Salfred
1489184610Salfred	while (x != xfer->nframes) {
1490184610Salfred
1491184610Salfred		/* DATA0 / DATA1 message */
1492184610Salfred
1493184610Salfred		temp.len = xfer->frlengths[x];
1494184610Salfred		temp.pc = xfer->frbuffers + x;
1495184610Salfred
1496184610Salfred		x++;
1497184610Salfred
1498184610Salfred		if (x == xfer->nframes) {
1499190183Sthompsa			if (xfer->flags_int.control_xfr) {
1500190183Sthompsa				/* no STATUS stage yet, DATA is last */
1501190183Sthompsa				if (xfer->flags_int.control_act) {
1502190183Sthompsa					temp.last_frame = 1;
1503190183Sthompsa					temp.setup_alt_next = 0;
1504190183Sthompsa				}
1505190183Sthompsa			} else {
1506190183Sthompsa				temp.last_frame = 1;
1507190183Sthompsa				temp.setup_alt_next = 0;
1508190183Sthompsa			}
1509184610Salfred		}
1510184610Salfred		if (temp.len == 0) {
1511184610Salfred
1512184610Salfred			/* make sure that we send an USB packet */
1513184610Salfred
1514184610Salfred			temp.shortpkt = 0;
1515184610Salfred
1516184610Salfred		} else {
1517184610Salfred
1518184610Salfred			/* regular data transfer */
1519184610Salfred
1520184610Salfred			temp.shortpkt = (xfer->flags.force_short_xfer) ? 0 : 1;
1521184610Salfred		}
1522184610Salfred
1523184610Salfred		ohci_setup_standard_chain_sub(&temp);
1524184610Salfred	}
1525184610Salfred
1526184610Salfred	/* check if we should append a status stage */
1527184610Salfred
1528184610Salfred	if (xfer->flags_int.control_xfr &&
1529184610Salfred	    !xfer->flags_int.control_act) {
1530184610Salfred
1531184610Salfred		/*
1532184610Salfred		 * Send a DATA1 message and invert the current endpoint
1533184610Salfred		 * direction.
1534184610Salfred		 */
1535184610Salfred
1536184610Salfred		/* set endpoint direction and data toggle */
1537184610Salfred
1538184610Salfred		if (UE_GET_DIR(xfer->endpoint) == UE_DIR_IN) {
1539184610Salfred			temp.td_flags = htole32(OHCI_TD_OUT |
1540184610Salfred			    OHCI_TD_NOCC | OHCI_TD_TOGGLE_1 | OHCI_TD_SET_DI(1));
1541184610Salfred		} else {
1542184610Salfred			temp.td_flags = htole32(OHCI_TD_IN |
1543184610Salfred			    OHCI_TD_NOCC | OHCI_TD_TOGGLE_1 | OHCI_TD_SET_DI(1));
1544184610Salfred		}
1545184610Salfred
1546184610Salfred		temp.len = 0;
1547184610Salfred		temp.pc = NULL;
1548184610Salfred		temp.shortpkt = 0;
1549190183Sthompsa		temp.last_frame = 1;
1550190183Sthompsa		temp.setup_alt_next = 0;
1551184610Salfred
1552184610Salfred		ohci_setup_standard_chain_sub(&temp);
1553184610Salfred	}
1554184610Salfred	td = temp.td;
1555184610Salfred
1556190183Sthompsa	/* Ensure that last TD is terminating: */
1557184610Salfred	td->td_next = htole32(OHCI_TD_NEXT_END);
1558184610Salfred	td->td_flags &= ~htole32(OHCI_TD_INTR_MASK);
1559184610Salfred	td->td_flags |= htole32(OHCI_TD_SET_DI(1));
1560184610Salfred
1561184610Salfred	usb2_pc_cpu_flush(td->page_cache);
1562184610Salfred
1563184610Salfred	/* must have at least one frame! */
1564184610Salfred
1565184610Salfred	xfer->td_transfer_last = td;
1566184610Salfred
1567184610Salfred#if USB_DEBUG
1568184610Salfred	if (ohcidebug > 8) {
1569184610Salfred		DPRINTF("nexttog=%d; data before transfer:\n",
1570184610Salfred		    xfer->pipe->toggle_next);
1571184610Salfred		ohci_dump_tds(xfer->td_transfer_first);
1572184610Salfred	}
1573184610Salfred#endif
1574184610Salfred
1575184610Salfred	ed = xfer->qh_start[xfer->flags_int.curr_dma_set];
1576184610Salfred
1577184610Salfred	ed_flags = (OHCI_ED_SET_FA(xfer->address) |
1578184610Salfred	    OHCI_ED_SET_EN(UE_GET_ADDR(xfer->endpoint)) |
1579184610Salfred	    OHCI_ED_SET_MAXP(xfer->max_frame_size));
1580184610Salfred
1581184610Salfred	ed_flags |= (OHCI_ED_FORMAT_GEN | OHCI_ED_DIR_TD);
1582184610Salfred
1583187173Sthompsa	if (xfer->xroot->udev->speed == USB_SPEED_LOW) {
1584184610Salfred		ed_flags |= OHCI_ED_SPEED;
1585184610Salfred	}
1586184610Salfred	ed->ed_flags = htole32(ed_flags);
1587184610Salfred
1588184610Salfred	td = xfer->td_transfer_first;
1589184610Salfred
1590186730Salfred	ed->ed_headp = td->td_self;
1591184610Salfred
1592191824Sthompsa	if (xfer->xroot->udev->flags.self_suspended == 0) {
1593187167Sthompsa		/* the append function will flush the endpoint descriptor */
1594186730Salfred		OHCI_APPEND_QH(ed, *ed_last);
1595184610Salfred
1596186730Salfred		if (methods == &ohci_device_bulk_methods) {
1597187173Sthompsa			ohci_softc_t *sc = OHCI_BUS2SC(xfer->xroot->bus);
1598184610Salfred
1599186730Salfred			OWRITE4(sc, OHCI_COMMAND_STATUS, OHCI_BLF);
1600186730Salfred		}
1601186730Salfred		if (methods == &ohci_device_ctrl_methods) {
1602187173Sthompsa			ohci_softc_t *sc = OHCI_BUS2SC(xfer->xroot->bus);
1603186730Salfred
1604186730Salfred			OWRITE4(sc, OHCI_COMMAND_STATUS, OHCI_CLF);
1605186730Salfred		}
1606186730Salfred	} else {
1607186730Salfred		usb2_pc_cpu_flush(ed->page_cache);
1608184610Salfred	}
1609184610Salfred}
1610184610Salfred
1611184610Salfredstatic void
1612190735Sthompsaohci_root_intr(ohci_softc_t *sc)
1613184610Salfred{
1614184610Salfred	uint32_t hstatus;
1615184610Salfred	uint16_t i;
1616184610Salfred	uint16_t m;
1617184610Salfred
1618184824Sthompsa	USB_BUS_LOCK_ASSERT(&sc->sc_bus, MA_OWNED);
1619184610Salfred
1620184610Salfred	/* clear any old interrupt data */
1621190735Sthompsa	memset(sc->sc_hub_idata, 0, sizeof(sc->sc_hub_idata));
1622184610Salfred
1623184610Salfred	hstatus = OREAD4(sc, OHCI_RH_STATUS);
1624190735Sthompsa	DPRINTF("sc=%p hstatus=0x%08x\n",
1625190735Sthompsa	    sc, hstatus);
1626184610Salfred
1627184610Salfred	/* set bits */
1628184610Salfred	m = (sc->sc_noport + 1);
1629184610Salfred	if (m > (8 * sizeof(sc->sc_hub_idata))) {
1630184610Salfred		m = (8 * sizeof(sc->sc_hub_idata));
1631184610Salfred	}
1632184610Salfred	for (i = 1; i < m; i++) {
1633184610Salfred		/* pick out CHANGE bits from the status register */
1634184610Salfred		if (OREAD4(sc, OHCI_RH_PORT_STATUS(i)) >> 16) {
1635184610Salfred			sc->sc_hub_idata[i / 8] |= 1 << (i % 8);
1636184610Salfred			DPRINTF("port %d changed\n", i);
1637184610Salfred		}
1638184610Salfred	}
1639190735Sthompsa
1640190735Sthompsa	uhub_root_intr(&sc->sc_bus, sc->sc_hub_idata,
1641190735Sthompsa	    sizeof(sc->sc_hub_idata));
1642184610Salfred}
1643184610Salfred
1644184610Salfred/* NOTE: "done" can be run two times in a row,
1645184610Salfred * from close and from interrupt
1646184610Salfred */
1647184610Salfredstatic void
1648184610Salfredohci_device_done(struct usb2_xfer *xfer, usb2_error_t error)
1649184610Salfred{
1650184610Salfred	struct usb2_pipe_methods *methods = xfer->pipe->methods;
1651187173Sthompsa	ohci_softc_t *sc = OHCI_BUS2SC(xfer->xroot->bus);
1652184610Salfred	ohci_ed_t *ed;
1653184610Salfred
1654184824Sthompsa	USB_BUS_LOCK_ASSERT(&sc->sc_bus, MA_OWNED);
1655184610Salfred
1656184610Salfred
1657184610Salfred	DPRINTFN(2, "xfer=%p, pipe=%p, error=%d\n",
1658184610Salfred	    xfer, xfer->pipe, error);
1659184610Salfred
1660184610Salfred	ed = xfer->qh_start[xfer->flags_int.curr_dma_set];
1661184610Salfred	if (ed) {
1662184610Salfred		usb2_pc_cpu_invalidate(ed->page_cache);
1663184610Salfred	}
1664184610Salfred	if (methods == &ohci_device_bulk_methods) {
1665184610Salfred		OHCI_REMOVE_QH(ed, sc->sc_bulk_p_last);
1666184610Salfred	}
1667184610Salfred	if (methods == &ohci_device_ctrl_methods) {
1668184610Salfred		OHCI_REMOVE_QH(ed, sc->sc_ctrl_p_last);
1669184610Salfred	}
1670184610Salfred	if (methods == &ohci_device_intr_methods) {
1671184610Salfred		OHCI_REMOVE_QH(ed, sc->sc_intr_p_last[xfer->qh_pos]);
1672184610Salfred	}
1673184610Salfred	if (methods == &ohci_device_isoc_methods) {
1674184610Salfred		OHCI_REMOVE_QH(ed, sc->sc_isoc_p_last);
1675184610Salfred	}
1676184610Salfred	xfer->td_transfer_first = NULL;
1677184610Salfred	xfer->td_transfer_last = NULL;
1678184610Salfred
1679184610Salfred	/* dequeue transfer and start next transfer */
1680184610Salfred	usb2_transfer_done(xfer, error);
1681184610Salfred}
1682184610Salfred
1683184610Salfred/*------------------------------------------------------------------------*
1684184610Salfred * ohci bulk support
1685184610Salfred *------------------------------------------------------------------------*/
1686184610Salfredstatic void
1687184610Salfredohci_device_bulk_open(struct usb2_xfer *xfer)
1688184610Salfred{
1689184610Salfred	return;
1690184610Salfred}
1691184610Salfred
1692184610Salfredstatic void
1693184610Salfredohci_device_bulk_close(struct usb2_xfer *xfer)
1694184610Salfred{
1695184610Salfred	ohci_device_done(xfer, USB_ERR_CANCELLED);
1696184610Salfred}
1697184610Salfred
1698184610Salfredstatic void
1699184610Salfredohci_device_bulk_enter(struct usb2_xfer *xfer)
1700184610Salfred{
1701184610Salfred	return;
1702184610Salfred}
1703184610Salfred
1704184610Salfredstatic void
1705184610Salfredohci_device_bulk_start(struct usb2_xfer *xfer)
1706184610Salfred{
1707187173Sthompsa	ohci_softc_t *sc = OHCI_BUS2SC(xfer->xroot->bus);
1708184610Salfred
1709184610Salfred	/* setup TD's and QH */
1710184610Salfred	ohci_setup_standard_chain(xfer, &sc->sc_bulk_p_last);
1711184610Salfred
1712184610Salfred	/* put transfer on interrupt queue */
1713184610Salfred	ohci_transfer_intr_enqueue(xfer);
1714184610Salfred}
1715184610Salfred
1716184610Salfredstruct usb2_pipe_methods ohci_device_bulk_methods =
1717184610Salfred{
1718184610Salfred	.open = ohci_device_bulk_open,
1719184610Salfred	.close = ohci_device_bulk_close,
1720184610Salfred	.enter = ohci_device_bulk_enter,
1721184610Salfred	.start = ohci_device_bulk_start,
1722184610Salfred};
1723184610Salfred
1724184610Salfred/*------------------------------------------------------------------------*
1725184610Salfred * ohci control support
1726184610Salfred *------------------------------------------------------------------------*/
1727184610Salfredstatic void
1728184610Salfredohci_device_ctrl_open(struct usb2_xfer *xfer)
1729184610Salfred{
1730184610Salfred	return;
1731184610Salfred}
1732184610Salfred
1733184610Salfredstatic void
1734184610Salfredohci_device_ctrl_close(struct usb2_xfer *xfer)
1735184610Salfred{
1736184610Salfred	ohci_device_done(xfer, USB_ERR_CANCELLED);
1737184610Salfred}
1738184610Salfred
1739184610Salfredstatic void
1740184610Salfredohci_device_ctrl_enter(struct usb2_xfer *xfer)
1741184610Salfred{
1742184610Salfred	return;
1743184610Salfred}
1744184610Salfred
1745184610Salfredstatic void
1746184610Salfredohci_device_ctrl_start(struct usb2_xfer *xfer)
1747184610Salfred{
1748187173Sthompsa	ohci_softc_t *sc = OHCI_BUS2SC(xfer->xroot->bus);
1749184610Salfred
1750184610Salfred	/* setup TD's and QH */
1751184610Salfred	ohci_setup_standard_chain(xfer, &sc->sc_ctrl_p_last);
1752184610Salfred
1753184610Salfred	/* put transfer on interrupt queue */
1754184610Salfred	ohci_transfer_intr_enqueue(xfer);
1755184610Salfred}
1756184610Salfred
1757184610Salfredstruct usb2_pipe_methods ohci_device_ctrl_methods =
1758184610Salfred{
1759184610Salfred	.open = ohci_device_ctrl_open,
1760184610Salfred	.close = ohci_device_ctrl_close,
1761184610Salfred	.enter = ohci_device_ctrl_enter,
1762184610Salfred	.start = ohci_device_ctrl_start,
1763184610Salfred};
1764184610Salfred
1765184610Salfred/*------------------------------------------------------------------------*
1766184610Salfred * ohci interrupt support
1767184610Salfred *------------------------------------------------------------------------*/
1768184610Salfredstatic void
1769184610Salfredohci_device_intr_open(struct usb2_xfer *xfer)
1770184610Salfred{
1771187173Sthompsa	ohci_softc_t *sc = OHCI_BUS2SC(xfer->xroot->bus);
1772184610Salfred	uint16_t best;
1773184610Salfred	uint16_t bit;
1774184610Salfred	uint16_t x;
1775184610Salfred
1776184610Salfred	best = 0;
1777184610Salfred	bit = OHCI_NO_EDS / 2;
1778184610Salfred	while (bit) {
1779184610Salfred		if (xfer->interval >= bit) {
1780184610Salfred			x = bit;
1781184610Salfred			best = bit;
1782184610Salfred			while (x & bit) {
1783184610Salfred				if (sc->sc_intr_stat[x] <
1784184610Salfred				    sc->sc_intr_stat[best]) {
1785184610Salfred					best = x;
1786184610Salfred				}
1787184610Salfred				x++;
1788184610Salfred			}
1789184610Salfred			break;
1790184610Salfred		}
1791184610Salfred		bit >>= 1;
1792184610Salfred	}
1793184610Salfred
1794184610Salfred	sc->sc_intr_stat[best]++;
1795184610Salfred	xfer->qh_pos = best;
1796184610Salfred
1797184610Salfred	DPRINTFN(3, "best=%d interval=%d\n",
1798184610Salfred	    best, xfer->interval);
1799184610Salfred}
1800184610Salfred
1801184610Salfredstatic void
1802184610Salfredohci_device_intr_close(struct usb2_xfer *xfer)
1803184610Salfred{
1804187173Sthompsa	ohci_softc_t *sc = OHCI_BUS2SC(xfer->xroot->bus);
1805184610Salfred
1806184610Salfred	sc->sc_intr_stat[xfer->qh_pos]--;
1807184610Salfred
1808184610Salfred	ohci_device_done(xfer, USB_ERR_CANCELLED);
1809184610Salfred}
1810184610Salfred
1811184610Salfredstatic void
1812184610Salfredohci_device_intr_enter(struct usb2_xfer *xfer)
1813184610Salfred{
1814184610Salfred	return;
1815184610Salfred}
1816184610Salfred
1817184610Salfredstatic void
1818184610Salfredohci_device_intr_start(struct usb2_xfer *xfer)
1819184610Salfred{
1820187173Sthompsa	ohci_softc_t *sc = OHCI_BUS2SC(xfer->xroot->bus);
1821184610Salfred
1822184610Salfred	/* setup TD's and QH */
1823184610Salfred	ohci_setup_standard_chain(xfer, &sc->sc_intr_p_last[xfer->qh_pos]);
1824184610Salfred
1825184610Salfred	/* put transfer on interrupt queue */
1826184610Salfred	ohci_transfer_intr_enqueue(xfer);
1827184610Salfred}
1828184610Salfred
1829184610Salfredstruct usb2_pipe_methods ohci_device_intr_methods =
1830184610Salfred{
1831184610Salfred	.open = ohci_device_intr_open,
1832184610Salfred	.close = ohci_device_intr_close,
1833184610Salfred	.enter = ohci_device_intr_enter,
1834184610Salfred	.start = ohci_device_intr_start,
1835184610Salfred};
1836184610Salfred
1837184610Salfred/*------------------------------------------------------------------------*
1838184610Salfred * ohci isochronous support
1839184610Salfred *------------------------------------------------------------------------*/
1840184610Salfredstatic void
1841184610Salfredohci_device_isoc_open(struct usb2_xfer *xfer)
1842184610Salfred{
1843184610Salfred	return;
1844184610Salfred}
1845184610Salfred
1846184610Salfredstatic void
1847184610Salfredohci_device_isoc_close(struct usb2_xfer *xfer)
1848184610Salfred{
1849184610Salfred	/**/
1850184610Salfred	ohci_device_done(xfer, USB_ERR_CANCELLED);
1851184610Salfred}
1852184610Salfred
1853184610Salfredstatic void
1854184610Salfredohci_device_isoc_enter(struct usb2_xfer *xfer)
1855184610Salfred{
1856184610Salfred	struct usb2_page_search buf_res;
1857187173Sthompsa	ohci_softc_t *sc = OHCI_BUS2SC(xfer->xroot->bus);
1858184610Salfred	struct ohci_hcca *hcca;
1859184610Salfred	uint32_t buf_offset;
1860184610Salfred	uint32_t nframes;
1861184610Salfred	uint32_t ed_flags;
1862184610Salfred	uint32_t *plen;
1863184610Salfred	uint16_t itd_offset[OHCI_ITD_NOFFSET];
1864184610Salfred	uint16_t length;
1865184610Salfred	uint8_t ncur;
1866184610Salfred	ohci_itd_t *td;
1867184610Salfred	ohci_itd_t *td_last = NULL;
1868184610Salfred	ohci_ed_t *ed;
1869184610Salfred
1870184610Salfred	hcca = ohci_get_hcca(sc);
1871184610Salfred
1872184610Salfred	nframes = le32toh(hcca->hcca_frame_number);
1873184610Salfred
1874184610Salfred	DPRINTFN(6, "xfer=%p isoc_next=%u nframes=%u hcca_fn=%u\n",
1875184610Salfred	    xfer, xfer->pipe->isoc_next, xfer->nframes, nframes);
1876184610Salfred
1877184610Salfred	if ((xfer->pipe->is_synced == 0) ||
1878184610Salfred	    (((nframes - xfer->pipe->isoc_next) & 0xFFFF) < xfer->nframes) ||
1879184610Salfred	    (((xfer->pipe->isoc_next - nframes) & 0xFFFF) >= 128)) {
1880184610Salfred		/*
1881184610Salfred		 * If there is data underflow or the pipe queue is empty we
1882184610Salfred		 * schedule the transfer a few frames ahead of the current
1883184610Salfred		 * frame position. Else two isochronous transfers might
1884184610Salfred		 * overlap.
1885184610Salfred		 */
1886184610Salfred		xfer->pipe->isoc_next = (nframes + 3) & 0xFFFF;
1887184610Salfred		xfer->pipe->is_synced = 1;
1888184610Salfred		DPRINTFN(3, "start next=%d\n", xfer->pipe->isoc_next);
1889184610Salfred	}
1890184610Salfred	/*
1891184610Salfred	 * compute how many milliseconds the insertion is ahead of the
1892184610Salfred	 * current frame position:
1893184610Salfred	 */
1894184610Salfred	buf_offset = ((xfer->pipe->isoc_next - nframes) & 0xFFFF);
1895184610Salfred
1896184610Salfred	/*
1897184610Salfred	 * pre-compute when the isochronous transfer will be finished:
1898184610Salfred	 */
1899184610Salfred	xfer->isoc_time_complete =
1900184610Salfred	    (usb2_isoc_time_expand(&sc->sc_bus, nframes) + buf_offset +
1901184610Salfred	    xfer->nframes);
1902184610Salfred
1903184610Salfred	/* get the real number of frames */
1904184610Salfred
1905184610Salfred	nframes = xfer->nframes;
1906184610Salfred
1907184610Salfred	buf_offset = 0;
1908184610Salfred
1909184610Salfred	plen = xfer->frlengths;
1910184610Salfred
1911184610Salfred	/* toggle the DMA set we are using */
1912184610Salfred	xfer->flags_int.curr_dma_set ^= 1;
1913184610Salfred
1914184610Salfred	/* get next DMA set */
1915184610Salfred	td = xfer->td_start[xfer->flags_int.curr_dma_set];
1916184610Salfred
1917184610Salfred	xfer->td_transfer_first = td;
1918184610Salfred
1919184610Salfred	ncur = 0;
1920184610Salfred	length = 0;
1921184610Salfred
1922184610Salfred	while (nframes--) {
1923184610Salfred		if (td == NULL) {
1924184610Salfred			panic("%s:%d: out of TD's\n",
1925184610Salfred			    __FUNCTION__, __LINE__);
1926184610Salfred		}
1927184610Salfred		itd_offset[ncur] = length;
1928184610Salfred		buf_offset += *plen;
1929184610Salfred		length += *plen;
1930184610Salfred		plen++;
1931184610Salfred		ncur++;
1932184610Salfred
1933184610Salfred		if (			/* check if the ITD is full */
1934184610Salfred		    (ncur == OHCI_ITD_NOFFSET) ||
1935184610Salfred		/* check if we have put more than 4K into the ITD */
1936184610Salfred		    (length & 0xF000) ||
1937184610Salfred		/* check if it is the last frame */
1938184610Salfred		    (nframes == 0)) {
1939184610Salfred
1940184610Salfred			/* fill current ITD */
1941184610Salfred			td->itd_flags = htole32(
1942184610Salfred			    OHCI_ITD_NOCC |
1943184610Salfred			    OHCI_ITD_SET_SF(xfer->pipe->isoc_next) |
1944184610Salfred			    OHCI_ITD_NOINTR |
1945184610Salfred			    OHCI_ITD_SET_FC(ncur));
1946184610Salfred
1947184610Salfred			td->frames = ncur;
1948184610Salfred			xfer->pipe->isoc_next += ncur;
1949184610Salfred
1950184610Salfred			if (length == 0) {
1951184610Salfred				/* all zero */
1952184610Salfred				td->itd_bp0 = 0;
1953184610Salfred				td->itd_be = ~0;
1954184610Salfred
1955184610Salfred				while (ncur--) {
1956184610Salfred					td->itd_offset[ncur] =
1957184610Salfred					    htole16(OHCI_ITD_MK_OFFS(0));
1958184610Salfred				}
1959184610Salfred			} else {
1960184610Salfred				usb2_get_page(xfer->frbuffers, buf_offset - length, &buf_res);
1961184610Salfred				length = OHCI_PAGE_MASK(buf_res.physaddr);
1962184610Salfred				buf_res.physaddr =
1963184610Salfred				    OHCI_PAGE(buf_res.physaddr);
1964184610Salfred				td->itd_bp0 = htole32(buf_res.physaddr);
1965184610Salfred				usb2_get_page(xfer->frbuffers, buf_offset - 1, &buf_res);
1966184610Salfred				td->itd_be = htole32(buf_res.physaddr);
1967184610Salfred
1968184610Salfred				while (ncur--) {
1969184610Salfred					itd_offset[ncur] += length;
1970184610Salfred					itd_offset[ncur] =
1971184610Salfred					    OHCI_ITD_MK_OFFS(itd_offset[ncur]);
1972184610Salfred					td->itd_offset[ncur] =
1973184610Salfred					    htole16(itd_offset[ncur]);
1974184610Salfred				}
1975184610Salfred			}
1976184610Salfred			ncur = 0;
1977184610Salfred			length = 0;
1978184610Salfred			td_last = td;
1979184610Salfred			td = td->obj_next;
1980184610Salfred
1981184610Salfred			if (td) {
1982184610Salfred				/* link the last TD with the next one */
1983184610Salfred				td_last->itd_next = td->itd_self;
1984184610Salfred			}
1985184610Salfred			usb2_pc_cpu_flush(td_last->page_cache);
1986184610Salfred		}
1987184610Salfred	}
1988184610Salfred
1989184610Salfred	/* update the last TD */
1990184610Salfred	td_last->itd_flags &= ~htole32(OHCI_ITD_NOINTR);
1991184610Salfred	td_last->itd_flags |= htole32(OHCI_ITD_SET_DI(0));
1992184610Salfred	td_last->itd_next = 0;
1993184610Salfred
1994184610Salfred	usb2_pc_cpu_flush(td_last->page_cache);
1995184610Salfred
1996184610Salfred	xfer->td_transfer_last = td_last;
1997184610Salfred
1998184610Salfred#if USB_DEBUG
1999184610Salfred	if (ohcidebug > 8) {
2000184610Salfred		DPRINTF("data before transfer:\n");
2001184610Salfred		ohci_dump_itds(xfer->td_transfer_first);
2002184610Salfred	}
2003184610Salfred#endif
2004184610Salfred	ed = xfer->qh_start[xfer->flags_int.curr_dma_set];
2005184610Salfred
2006184610Salfred	if (UE_GET_DIR(xfer->endpoint) == UE_DIR_IN)
2007184610Salfred		ed_flags = (OHCI_ED_DIR_IN | OHCI_ED_FORMAT_ISO);
2008184610Salfred	else
2009184610Salfred		ed_flags = (OHCI_ED_DIR_OUT | OHCI_ED_FORMAT_ISO);
2010184610Salfred
2011184610Salfred	ed_flags |= (OHCI_ED_SET_FA(xfer->address) |
2012184610Salfred	    OHCI_ED_SET_EN(UE_GET_ADDR(xfer->endpoint)) |
2013184610Salfred	    OHCI_ED_SET_MAXP(xfer->max_frame_size));
2014184610Salfred
2015187173Sthompsa	if (xfer->xroot->udev->speed == USB_SPEED_LOW) {
2016184610Salfred		ed_flags |= OHCI_ED_SPEED;
2017184610Salfred	}
2018184610Salfred	ed->ed_flags = htole32(ed_flags);
2019184610Salfred
2020184610Salfred	td = xfer->td_transfer_first;
2021184610Salfred
2022186730Salfred	ed->ed_headp = td->itd_self;
2023186730Salfred
2024186730Salfred	/* isochronous transfers are not affected by suspend / resume */
2025187167Sthompsa	/* the append function will flush the endpoint descriptor */
2026186730Salfred
2027186730Salfred	OHCI_APPEND_QH(ed, sc->sc_isoc_p_last);
2028184610Salfred}
2029184610Salfred
2030184610Salfredstatic void
2031184610Salfredohci_device_isoc_start(struct usb2_xfer *xfer)
2032184610Salfred{
2033184610Salfred	/* put transfer on interrupt queue */
2034184610Salfred	ohci_transfer_intr_enqueue(xfer);
2035184610Salfred}
2036184610Salfred
2037184610Salfredstruct usb2_pipe_methods ohci_device_isoc_methods =
2038184610Salfred{
2039184610Salfred	.open = ohci_device_isoc_open,
2040184610Salfred	.close = ohci_device_isoc_close,
2041184610Salfred	.enter = ohci_device_isoc_enter,
2042184610Salfred	.start = ohci_device_isoc_start,
2043184610Salfred};
2044184610Salfred
2045184610Salfred/*------------------------------------------------------------------------*
2046184610Salfred * ohci root control support
2047184610Salfred *------------------------------------------------------------------------*
2048190735Sthompsa * Simulate a hardware hub by handling all the necessary requests.
2049184610Salfred *------------------------------------------------------------------------*/
2050184610Salfred
2051184610Salfredstatic const
2052184610Salfredstruct usb2_device_descriptor ohci_devd =
2053184610Salfred{
2054184610Salfred	sizeof(struct usb2_device_descriptor),
2055184610Salfred	UDESC_DEVICE,			/* type */
2056184610Salfred	{0x00, 0x01},			/* USB version */
2057184610Salfred	UDCLASS_HUB,			/* class */
2058184610Salfred	UDSUBCLASS_HUB,			/* subclass */
2059184610Salfred	UDPROTO_FSHUB,			/* protocol */
2060184610Salfred	64,				/* max packet */
2061184610Salfred	{0}, {0}, {0x00, 0x01},		/* device id */
2062184610Salfred	1, 2, 0,			/* string indicies */
2063184610Salfred	1				/* # of configurations */
2064184610Salfred};
2065184610Salfred
2066184610Salfredstatic const
2067184610Salfredstruct ohci_config_desc ohci_confd =
2068184610Salfred{
2069184610Salfred	.confd = {
2070184610Salfred		.bLength = sizeof(struct usb2_config_descriptor),
2071184610Salfred		.bDescriptorType = UDESC_CONFIG,
2072184610Salfred		.wTotalLength[0] = sizeof(ohci_confd),
2073184610Salfred		.bNumInterface = 1,
2074184610Salfred		.bConfigurationValue = 1,
2075184610Salfred		.iConfiguration = 0,
2076184610Salfred		.bmAttributes = UC_SELF_POWERED,
2077184610Salfred		.bMaxPower = 0,		/* max power */
2078184610Salfred	},
2079184610Salfred	.ifcd = {
2080184610Salfred		.bLength = sizeof(struct usb2_interface_descriptor),
2081184610Salfred		.bDescriptorType = UDESC_INTERFACE,
2082184610Salfred		.bNumEndpoints = 1,
2083184610Salfred		.bInterfaceClass = UICLASS_HUB,
2084184610Salfred		.bInterfaceSubClass = UISUBCLASS_HUB,
2085184610Salfred		.bInterfaceProtocol = UIPROTO_FSHUB,
2086184610Salfred	},
2087184610Salfred	.endpd = {
2088184610Salfred		.bLength = sizeof(struct usb2_endpoint_descriptor),
2089184610Salfred		.bDescriptorType = UDESC_ENDPOINT,
2090184610Salfred		.bEndpointAddress = UE_DIR_IN | OHCI_INTR_ENDPT,
2091184610Salfred		.bmAttributes = UE_INTERRUPT,
2092184610Salfred		.wMaxPacketSize[0] = 32,/* max packet (255 ports) */
2093184610Salfred		.bInterval = 255,
2094184610Salfred	},
2095184610Salfred};
2096184610Salfred
2097184610Salfredstatic const
2098184610Salfredstruct usb2_hub_descriptor ohci_hubd =
2099184610Salfred{
2100184610Salfred	0,				/* dynamic length */
2101184610Salfred	UDESC_HUB,
2102184610Salfred	0,
2103184610Salfred	{0, 0},
2104184610Salfred	0,
2105184610Salfred	0,
2106184610Salfred	{0},
2107184610Salfred};
2108184610Salfred
2109191402Sthompsastatic usb2_error_t
2110191402Sthompsaohci_roothub_exec(struct usb2_device *udev,
2111191402Sthompsa    struct usb2_device_request *req, const void **pptr, uint16_t *plength)
2112184610Salfred{
2113191402Sthompsa	ohci_softc_t *sc = OHCI_BUS2SC(udev->bus);
2114191402Sthompsa	const void *ptr;
2115191402Sthompsa	const char *str_ptr;
2116184610Salfred	uint32_t port;
2117184610Salfred	uint32_t v;
2118191402Sthompsa	uint16_t len;
2119184610Salfred	uint16_t value;
2120184610Salfred	uint16_t index;
2121184610Salfred	uint8_t l;
2122191402Sthompsa	usb2_error_t err;
2123184610Salfred
2124184824Sthompsa	USB_BUS_LOCK_ASSERT(&sc->sc_bus, MA_OWNED);
2125184610Salfred
2126184610Salfred	/* buffer reset */
2127191402Sthompsa	ptr = (const void *)&sc->sc_hub_desc.temp;
2128191402Sthompsa	len = 0;
2129191402Sthompsa	err = 0;
2130184610Salfred
2131191402Sthompsa	value = UGETW(req->wValue);
2132191402Sthompsa	index = UGETW(req->wIndex);
2133184610Salfred
2134184610Salfred	DPRINTFN(3, "type=0x%02x request=0x%02x wLen=0x%04x "
2135184610Salfred	    "wValue=0x%04x wIndex=0x%04x\n",
2136191402Sthompsa	    req->bmRequestType, req->bRequest,
2137191402Sthompsa	    UGETW(req->wLength), value, index);
2138184610Salfred
2139184610Salfred#define	C(x,y) ((x) | ((y) << 8))
2140191402Sthompsa	switch (C(req->bRequest, req->bmRequestType)) {
2141184610Salfred	case C(UR_CLEAR_FEATURE, UT_WRITE_DEVICE):
2142184610Salfred	case C(UR_CLEAR_FEATURE, UT_WRITE_INTERFACE):
2143184610Salfred	case C(UR_CLEAR_FEATURE, UT_WRITE_ENDPOINT):
2144184610Salfred		/*
2145184610Salfred		 * DEVICE_REMOTE_WAKEUP and ENDPOINT_HALT are no-ops
2146184610Salfred		 * for the integrated root hub.
2147184610Salfred		 */
2148184610Salfred		break;
2149184610Salfred	case C(UR_GET_CONFIG, UT_READ_DEVICE):
2150191402Sthompsa		len = 1;
2151184610Salfred		sc->sc_hub_desc.temp[0] = sc->sc_conf;
2152184610Salfred		break;
2153184610Salfred	case C(UR_GET_DESCRIPTOR, UT_READ_DEVICE):
2154184610Salfred		switch (value >> 8) {
2155184610Salfred		case UDESC_DEVICE:
2156184610Salfred			if ((value & 0xff) != 0) {
2157191402Sthompsa				err = USB_ERR_IOERROR;
2158184610Salfred				goto done;
2159184610Salfred			}
2160191402Sthompsa			len = sizeof(ohci_devd);
2161191402Sthompsa			ptr = (const void *)&ohci_devd;
2162184610Salfred			break;
2163184610Salfred
2164184610Salfred		case UDESC_CONFIG:
2165184610Salfred			if ((value & 0xff) != 0) {
2166191402Sthompsa				err = USB_ERR_IOERROR;
2167184610Salfred				goto done;
2168184610Salfred			}
2169191402Sthompsa			len = sizeof(ohci_confd);
2170191402Sthompsa			ptr = (const void *)&ohci_confd;
2171184610Salfred			break;
2172184610Salfred
2173184610Salfred		case UDESC_STRING:
2174184610Salfred			switch (value & 0xff) {
2175184610Salfred			case 0:	/* Language table */
2176191402Sthompsa				str_ptr = "\001";
2177184610Salfred				break;
2178184610Salfred
2179184610Salfred			case 1:	/* Vendor */
2180191402Sthompsa				str_ptr = sc->sc_vendor;
2181184610Salfred				break;
2182184610Salfred
2183184610Salfred			case 2:	/* Product */
2184191402Sthompsa				str_ptr = "OHCI root HUB";
2185184610Salfred				break;
2186184610Salfred
2187184610Salfred			default:
2188191402Sthompsa				str_ptr = "";
2189184610Salfred				break;
2190184610Salfred			}
2191184610Salfred
2192191402Sthompsa			len = usb2_make_str_desc(
2193191402Sthompsa			    sc->sc_hub_desc.temp,
2194184610Salfred			    sizeof(sc->sc_hub_desc.temp),
2195191402Sthompsa			    str_ptr);
2196184610Salfred			break;
2197184610Salfred
2198184610Salfred		default:
2199191402Sthompsa			err = USB_ERR_IOERROR;
2200184610Salfred			goto done;
2201184610Salfred		}
2202184610Salfred		break;
2203184610Salfred	case C(UR_GET_INTERFACE, UT_READ_INTERFACE):
2204191402Sthompsa		len = 1;
2205184610Salfred		sc->sc_hub_desc.temp[0] = 0;
2206184610Salfred		break;
2207184610Salfred	case C(UR_GET_STATUS, UT_READ_DEVICE):
2208191402Sthompsa		len = 2;
2209184610Salfred		USETW(sc->sc_hub_desc.stat.wStatus, UDS_SELF_POWERED);
2210184610Salfred		break;
2211184610Salfred	case C(UR_GET_STATUS, UT_READ_INTERFACE):
2212184610Salfred	case C(UR_GET_STATUS, UT_READ_ENDPOINT):
2213191402Sthompsa		len = 2;
2214184610Salfred		USETW(sc->sc_hub_desc.stat.wStatus, 0);
2215184610Salfred		break;
2216184610Salfred	case C(UR_SET_ADDRESS, UT_WRITE_DEVICE):
2217190174Sthompsa		if (value >= OHCI_MAX_DEVICES) {
2218191402Sthompsa			err = USB_ERR_IOERROR;
2219184610Salfred			goto done;
2220184610Salfred		}
2221184610Salfred		sc->sc_addr = value;
2222184610Salfred		break;
2223184610Salfred	case C(UR_SET_CONFIG, UT_WRITE_DEVICE):
2224184610Salfred		if ((value != 0) && (value != 1)) {
2225191402Sthompsa			err = USB_ERR_IOERROR;
2226184610Salfred			goto done;
2227184610Salfred		}
2228184610Salfred		sc->sc_conf = value;
2229184610Salfred		break;
2230184610Salfred	case C(UR_SET_DESCRIPTOR, UT_WRITE_DEVICE):
2231184610Salfred		break;
2232184610Salfred	case C(UR_SET_FEATURE, UT_WRITE_DEVICE):
2233184610Salfred	case C(UR_SET_FEATURE, UT_WRITE_INTERFACE):
2234184610Salfred	case C(UR_SET_FEATURE, UT_WRITE_ENDPOINT):
2235191402Sthompsa		err = USB_ERR_IOERROR;
2236184610Salfred		goto done;
2237184610Salfred	case C(UR_SET_INTERFACE, UT_WRITE_INTERFACE):
2238184610Salfred		break;
2239184610Salfred	case C(UR_SYNCH_FRAME, UT_WRITE_ENDPOINT):
2240184610Salfred		break;
2241184610Salfred		/* Hub requests */
2242184610Salfred	case C(UR_CLEAR_FEATURE, UT_WRITE_CLASS_DEVICE):
2243184610Salfred		break;
2244184610Salfred	case C(UR_CLEAR_FEATURE, UT_WRITE_CLASS_OTHER):
2245184610Salfred		DPRINTFN(9, "UR_CLEAR_PORT_FEATURE "
2246184610Salfred		    "port=%d feature=%d\n",
2247184610Salfred		    index, value);
2248184610Salfred		if ((index < 1) ||
2249184610Salfred		    (index > sc->sc_noport)) {
2250191402Sthompsa			err = USB_ERR_IOERROR;
2251184610Salfred			goto done;
2252184610Salfred		}
2253184610Salfred		port = OHCI_RH_PORT_STATUS(index);
2254184610Salfred		switch (value) {
2255184610Salfred		case UHF_PORT_ENABLE:
2256184610Salfred			OWRITE4(sc, port, UPS_CURRENT_CONNECT_STATUS);
2257184610Salfred			break;
2258184610Salfred		case UHF_PORT_SUSPEND:
2259184610Salfred			OWRITE4(sc, port, UPS_OVERCURRENT_INDICATOR);
2260184610Salfred			break;
2261184610Salfred		case UHF_PORT_POWER:
2262184610Salfred			/* Yes, writing to the LOW_SPEED bit clears power. */
2263184610Salfred			OWRITE4(sc, port, UPS_LOW_SPEED);
2264184610Salfred			break;
2265184610Salfred		case UHF_C_PORT_CONNECTION:
2266184610Salfred			OWRITE4(sc, port, UPS_C_CONNECT_STATUS << 16);
2267184610Salfred			break;
2268184610Salfred		case UHF_C_PORT_ENABLE:
2269184610Salfred			OWRITE4(sc, port, UPS_C_PORT_ENABLED << 16);
2270184610Salfred			break;
2271184610Salfred		case UHF_C_PORT_SUSPEND:
2272184610Salfred			OWRITE4(sc, port, UPS_C_SUSPEND << 16);
2273184610Salfred			break;
2274184610Salfred		case UHF_C_PORT_OVER_CURRENT:
2275184610Salfred			OWRITE4(sc, port, UPS_C_OVERCURRENT_INDICATOR << 16);
2276184610Salfred			break;
2277184610Salfred		case UHF_C_PORT_RESET:
2278184610Salfred			OWRITE4(sc, port, UPS_C_PORT_RESET << 16);
2279184610Salfred			break;
2280184610Salfred		default:
2281191402Sthompsa			err = USB_ERR_IOERROR;
2282184610Salfred			goto done;
2283184610Salfred		}
2284184610Salfred		switch (value) {
2285184610Salfred		case UHF_C_PORT_CONNECTION:
2286184610Salfred		case UHF_C_PORT_ENABLE:
2287184610Salfred		case UHF_C_PORT_SUSPEND:
2288184610Salfred		case UHF_C_PORT_OVER_CURRENT:
2289184610Salfred		case UHF_C_PORT_RESET:
2290184610Salfred			/* enable RHSC interrupt if condition is cleared. */
2291186454Sthompsa			if ((OREAD4(sc, port) >> 16) == 0)
2292184610Salfred				ohci_rhsc_enable(sc);
2293184610Salfred			break;
2294184610Salfred		default:
2295184610Salfred			break;
2296184610Salfred		}
2297184610Salfred		break;
2298184610Salfred	case C(UR_GET_DESCRIPTOR, UT_READ_CLASS_DEVICE):
2299184610Salfred		if ((value & 0xff) != 0) {
2300191402Sthompsa			err = USB_ERR_IOERROR;
2301184610Salfred			goto done;
2302184610Salfred		}
2303184610Salfred		v = OREAD4(sc, OHCI_RH_DESCRIPTOR_A);
2304184610Salfred
2305184610Salfred		sc->sc_hub_desc.hubd = ohci_hubd;
2306184610Salfred		sc->sc_hub_desc.hubd.bNbrPorts = sc->sc_noport;
2307184610Salfred		USETW(sc->sc_hub_desc.hubd.wHubCharacteristics,
2308184610Salfred		    (v & OHCI_NPS ? UHD_PWR_NO_SWITCH :
2309184610Salfred		    v & OHCI_PSM ? UHD_PWR_GANGED : UHD_PWR_INDIVIDUAL)
2310184610Salfred		/* XXX overcurrent */
2311184610Salfred		    );
2312184610Salfred		sc->sc_hub_desc.hubd.bPwrOn2PwrGood = OHCI_GET_POTPGT(v);
2313184610Salfred		v = OREAD4(sc, OHCI_RH_DESCRIPTOR_B);
2314184610Salfred
2315184610Salfred		for (l = 0; l < sc->sc_noport; l++) {
2316184610Salfred			if (v & 1) {
2317184610Salfred				sc->sc_hub_desc.hubd.DeviceRemovable[l / 8] |= (1 << (l % 8));
2318184610Salfred			}
2319184610Salfred			v >>= 1;
2320184610Salfred		}
2321184610Salfred		sc->sc_hub_desc.hubd.bDescLength =
2322184610Salfred		    8 + ((sc->sc_noport + 7) / 8);
2323191402Sthompsa		len = sc->sc_hub_desc.hubd.bDescLength;
2324184610Salfred		break;
2325184610Salfred
2326184610Salfred	case C(UR_GET_STATUS, UT_READ_CLASS_DEVICE):
2327191402Sthompsa		len = 16;
2328184610Salfred		bzero(sc->sc_hub_desc.temp, 16);
2329184610Salfred		break;
2330184610Salfred	case C(UR_GET_STATUS, UT_READ_CLASS_OTHER):
2331184610Salfred		DPRINTFN(9, "get port status i=%d\n",
2332184610Salfred		    index);
2333184610Salfred		if ((index < 1) ||
2334184610Salfred		    (index > sc->sc_noport)) {
2335191402Sthompsa			err = USB_ERR_IOERROR;
2336184610Salfred			goto done;
2337184610Salfred		}
2338184610Salfred		v = OREAD4(sc, OHCI_RH_PORT_STATUS(index));
2339184610Salfred		DPRINTFN(9, "port status=0x%04x\n", v);
2340184610Salfred		USETW(sc->sc_hub_desc.ps.wPortStatus, v);
2341184610Salfred		USETW(sc->sc_hub_desc.ps.wPortChange, v >> 16);
2342191402Sthompsa		len = sizeof(sc->sc_hub_desc.ps);
2343184610Salfred		break;
2344184610Salfred	case C(UR_SET_DESCRIPTOR, UT_WRITE_CLASS_DEVICE):
2345191402Sthompsa		err = USB_ERR_IOERROR;
2346184610Salfred		goto done;
2347184610Salfred	case C(UR_SET_FEATURE, UT_WRITE_CLASS_DEVICE):
2348184610Salfred		break;
2349184610Salfred	case C(UR_SET_FEATURE, UT_WRITE_CLASS_OTHER):
2350184610Salfred		if ((index < 1) ||
2351184610Salfred		    (index > sc->sc_noport)) {
2352191402Sthompsa			err = USB_ERR_IOERROR;
2353184610Salfred			goto done;
2354184610Salfred		}
2355184610Salfred		port = OHCI_RH_PORT_STATUS(index);
2356184610Salfred		switch (value) {
2357184610Salfred		case UHF_PORT_ENABLE:
2358184610Salfred			OWRITE4(sc, port, UPS_PORT_ENABLED);
2359184610Salfred			break;
2360184610Salfred		case UHF_PORT_SUSPEND:
2361184610Salfred			OWRITE4(sc, port, UPS_SUSPEND);
2362184610Salfred			break;
2363184610Salfred		case UHF_PORT_RESET:
2364184610Salfred			DPRINTFN(6, "reset port %d\n", index);
2365184610Salfred			OWRITE4(sc, port, UPS_RESET);
2366184610Salfred			for (v = 0;; v++) {
2367184610Salfred				if (v < 12) {
2368188983Sthompsa					usb2_pause_mtx(&sc->sc_bus.bus_mtx,
2369188983Sthompsa					    USB_MS_TO_TICKS(USB_PORT_ROOT_RESET_DELAY));
2370184610Salfred
2371184610Salfred					if ((OREAD4(sc, port) & UPS_RESET) == 0) {
2372184610Salfred						break;
2373184610Salfred					}
2374184610Salfred				} else {
2375191402Sthompsa					err = USB_ERR_TIMEOUT;
2376184610Salfred					goto done;
2377184610Salfred				}
2378184610Salfred			}
2379184610Salfred			DPRINTFN(9, "ohci port %d reset, status = 0x%04x\n",
2380184610Salfred			    index, OREAD4(sc, port));
2381184610Salfred			break;
2382184610Salfred		case UHF_PORT_POWER:
2383184610Salfred			DPRINTFN(3, "set port power %d\n", index);
2384184610Salfred			OWRITE4(sc, port, UPS_PORT_POWER);
2385184610Salfred			break;
2386184610Salfred		default:
2387191402Sthompsa			err = USB_ERR_IOERROR;
2388184610Salfred			goto done;
2389184610Salfred		}
2390184610Salfred		break;
2391184610Salfred	default:
2392191402Sthompsa		err = USB_ERR_IOERROR;
2393184610Salfred		goto done;
2394184610Salfred	}
2395184610Salfreddone:
2396191402Sthompsa	*plength = len;
2397191402Sthompsa	*pptr = ptr;
2398191402Sthompsa	return (err);
2399184610Salfred}
2400184610Salfred
2401184610Salfredstatic void
2402184610Salfredohci_xfer_setup(struct usb2_setup_params *parm)
2403184610Salfred{
2404184610Salfred	struct usb2_page_search page_info;
2405184610Salfred	struct usb2_page_cache *pc;
2406184610Salfred	ohci_softc_t *sc;
2407184610Salfred	struct usb2_xfer *xfer;
2408184610Salfred	void *last_obj;
2409184610Salfred	uint32_t ntd;
2410184610Salfred	uint32_t nitd;
2411184610Salfred	uint32_t nqh;
2412184610Salfred	uint32_t n;
2413184610Salfred
2414184610Salfred	sc = OHCI_BUS2SC(parm->udev->bus);
2415184610Salfred	xfer = parm->curr_xfer;
2416184610Salfred
2417184610Salfred	parm->hc_max_packet_size = 0x500;
2418184610Salfred	parm->hc_max_packet_count = 1;
2419184610Salfred	parm->hc_max_frame_size = OHCI_PAGE_SIZE;
2420184610Salfred
2421184610Salfred	/*
2422184610Salfred	 * calculate ntd and nqh
2423184610Salfred	 */
2424184610Salfred	if (parm->methods == &ohci_device_ctrl_methods) {
2425184610Salfred		xfer->flags_int.bdma_enable = 1;
2426184610Salfred
2427184610Salfred		usb2_transfer_setup_sub(parm);
2428184610Salfred
2429184610Salfred		nitd = 0;
2430184610Salfred		ntd = ((2 * xfer->nframes) + 1	/* STATUS */
2431190181Sthompsa		    + (xfer->max_data_length / xfer->max_hc_frame_size));
2432184610Salfred		nqh = 1;
2433184610Salfred
2434184610Salfred	} else if (parm->methods == &ohci_device_bulk_methods) {
2435184610Salfred		xfer->flags_int.bdma_enable = 1;
2436184610Salfred
2437184610Salfred		usb2_transfer_setup_sub(parm);
2438184610Salfred
2439184610Salfred		nitd = 0;
2440184610Salfred		ntd = ((2 * xfer->nframes)
2441190181Sthompsa		    + (xfer->max_data_length / xfer->max_hc_frame_size));
2442184610Salfred		nqh = 1;
2443184610Salfred
2444184610Salfred	} else if (parm->methods == &ohci_device_intr_methods) {
2445184610Salfred		xfer->flags_int.bdma_enable = 1;
2446184610Salfred
2447184610Salfred		usb2_transfer_setup_sub(parm);
2448184610Salfred
2449184610Salfred		nitd = 0;
2450184610Salfred		ntd = ((2 * xfer->nframes)
2451190181Sthompsa		    + (xfer->max_data_length / xfer->max_hc_frame_size));
2452184610Salfred		nqh = 1;
2453184610Salfred
2454184610Salfred	} else if (parm->methods == &ohci_device_isoc_methods) {
2455184610Salfred		xfer->flags_int.bdma_enable = 1;
2456184610Salfred
2457184610Salfred		usb2_transfer_setup_sub(parm);
2458184610Salfred
2459184610Salfred		nitd = ((xfer->max_data_length / OHCI_PAGE_SIZE) +
2460184610Salfred		    ((xfer->nframes + OHCI_ITD_NOFFSET - 1) / OHCI_ITD_NOFFSET) +
2461184610Salfred		    1 /* EXTRA */ );
2462184610Salfred		ntd = 0;
2463184610Salfred		nqh = 1;
2464184610Salfred
2465184610Salfred	} else {
2466184610Salfred
2467184610Salfred		usb2_transfer_setup_sub(parm);
2468184610Salfred
2469184610Salfred		nitd = 0;
2470184610Salfred		ntd = 0;
2471184610Salfred		nqh = 0;
2472184610Salfred	}
2473184610Salfred
2474184610Salfredalloc_dma_set:
2475184610Salfred
2476184610Salfred	if (parm->err) {
2477184610Salfred		return;
2478184610Salfred	}
2479184610Salfred	last_obj = NULL;
2480184610Salfred
2481184610Salfred	if (usb2_transfer_setup_sub_malloc(
2482184610Salfred	    parm, &pc, sizeof(ohci_td_t),
2483184610Salfred	    OHCI_TD_ALIGN, ntd)) {
2484184610Salfred		parm->err = USB_ERR_NOMEM;
2485184610Salfred		return;
2486184610Salfred	}
2487184610Salfred	if (parm->buf) {
2488184610Salfred		for (n = 0; n != ntd; n++) {
2489184610Salfred			ohci_td_t *td;
2490184610Salfred
2491184610Salfred			usb2_get_page(pc + n, 0, &page_info);
2492184610Salfred
2493184610Salfred			td = page_info.buffer;
2494184610Salfred
2495184610Salfred			/* init TD */
2496184610Salfred			td->td_self = htole32(page_info.physaddr);
2497184610Salfred			td->obj_next = last_obj;
2498184610Salfred			td->page_cache = pc + n;
2499184610Salfred
2500184610Salfred			last_obj = td;
2501184610Salfred
2502184610Salfred			usb2_pc_cpu_flush(pc + n);
2503184610Salfred		}
2504184610Salfred	}
2505184610Salfred	if (usb2_transfer_setup_sub_malloc(
2506184610Salfred	    parm, &pc, sizeof(ohci_itd_t),
2507184610Salfred	    OHCI_ITD_ALIGN, nitd)) {
2508184610Salfred		parm->err = USB_ERR_NOMEM;
2509184610Salfred		return;
2510184610Salfred	}
2511184610Salfred	if (parm->buf) {
2512184610Salfred		for (n = 0; n != nitd; n++) {
2513184610Salfred			ohci_itd_t *itd;
2514184610Salfred
2515184610Salfred			usb2_get_page(pc + n, 0, &page_info);
2516184610Salfred
2517184610Salfred			itd = page_info.buffer;
2518184610Salfred
2519184610Salfred			/* init TD */
2520184610Salfred			itd->itd_self = htole32(page_info.physaddr);
2521184610Salfred			itd->obj_next = last_obj;
2522184610Salfred			itd->page_cache = pc + n;
2523184610Salfred
2524184610Salfred			last_obj = itd;
2525184610Salfred
2526184610Salfred			usb2_pc_cpu_flush(pc + n);
2527184610Salfred		}
2528184610Salfred	}
2529184610Salfred	xfer->td_start[xfer->flags_int.curr_dma_set] = last_obj;
2530184610Salfred
2531184610Salfred	last_obj = NULL;
2532184610Salfred
2533184610Salfred	if (usb2_transfer_setup_sub_malloc(
2534184610Salfred	    parm, &pc, sizeof(ohci_ed_t),
2535184610Salfred	    OHCI_ED_ALIGN, nqh)) {
2536184610Salfred		parm->err = USB_ERR_NOMEM;
2537184610Salfred		return;
2538184610Salfred	}
2539184610Salfred	if (parm->buf) {
2540184610Salfred		for (n = 0; n != nqh; n++) {
2541184610Salfred			ohci_ed_t *ed;
2542184610Salfred
2543184610Salfred			usb2_get_page(pc + n, 0, &page_info);
2544184610Salfred
2545184610Salfred			ed = page_info.buffer;
2546184610Salfred
2547184610Salfred			/* init QH */
2548184610Salfred			ed->ed_self = htole32(page_info.physaddr);
2549184610Salfred			ed->obj_next = last_obj;
2550184610Salfred			ed->page_cache = pc + n;
2551184610Salfred
2552184610Salfred			last_obj = ed;
2553184610Salfred
2554184610Salfred			usb2_pc_cpu_flush(pc + n);
2555184610Salfred		}
2556184610Salfred	}
2557184610Salfred	xfer->qh_start[xfer->flags_int.curr_dma_set] = last_obj;
2558184610Salfred
2559184610Salfred	if (!xfer->flags_int.curr_dma_set) {
2560184610Salfred		xfer->flags_int.curr_dma_set = 1;
2561184610Salfred		goto alloc_dma_set;
2562184610Salfred	}
2563184610Salfred}
2564184610Salfred
2565184610Salfredstatic void
2566184610Salfredohci_pipe_init(struct usb2_device *udev, struct usb2_endpoint_descriptor *edesc,
2567184610Salfred    struct usb2_pipe *pipe)
2568184610Salfred{
2569184610Salfred	ohci_softc_t *sc = OHCI_BUS2SC(udev->bus);
2570184610Salfred
2571184610Salfred	DPRINTFN(2, "pipe=%p, addr=%d, endpt=%d, mode=%d (%d)\n",
2572184610Salfred	    pipe, udev->address,
2573184610Salfred	    edesc->bEndpointAddress, udev->flags.usb2_mode,
2574184610Salfred	    sc->sc_addr);
2575184610Salfred
2576184610Salfred	if (udev->flags.usb2_mode != USB_MODE_HOST) {
2577184610Salfred		/* not supported */
2578184610Salfred		return;
2579184610Salfred	}
2580190735Sthompsa	if (udev->device_index != sc->sc_addr) {
2581184610Salfred		switch (edesc->bmAttributes & UE_XFERTYPE) {
2582184610Salfred		case UE_CONTROL:
2583184610Salfred			pipe->methods = &ohci_device_ctrl_methods;
2584184610Salfred			break;
2585184610Salfred		case UE_INTERRUPT:
2586184610Salfred			pipe->methods = &ohci_device_intr_methods;
2587184610Salfred			break;
2588184610Salfred		case UE_ISOCHRONOUS:
2589184610Salfred			if (udev->speed == USB_SPEED_FULL) {
2590184610Salfred				pipe->methods = &ohci_device_isoc_methods;
2591184610Salfred			}
2592184610Salfred			break;
2593184610Salfred		case UE_BULK:
2594184610Salfred			if (udev->speed != USB_SPEED_LOW) {
2595184610Salfred				pipe->methods = &ohci_device_bulk_methods;
2596184610Salfred			}
2597184610Salfred			break;
2598184610Salfred		default:
2599184610Salfred			/* do nothing */
2600184610Salfred			break;
2601184610Salfred		}
2602184610Salfred	}
2603184610Salfred}
2604184610Salfred
2605184610Salfredstatic void
2606184610Salfredohci_xfer_unsetup(struct usb2_xfer *xfer)
2607184610Salfred{
2608184610Salfred	return;
2609184610Salfred}
2610184610Salfred
2611184610Salfredstatic void
2612184610Salfredohci_get_dma_delay(struct usb2_bus *bus, uint32_t *pus)
2613184610Salfred{
2614184610Salfred	/*
2615184610Salfred	 * Wait until hardware has finished any possible use of the
2616184610Salfred	 * transfer descriptor(s) and QH
2617184610Salfred	 */
2618184610Salfred	*pus = (1125);			/* microseconds */
2619184610Salfred}
2620184610Salfred
2621186730Salfredstatic void
2622186730Salfredohci_device_resume(struct usb2_device *udev)
2623186730Salfred{
2624186730Salfred	struct ohci_softc *sc = OHCI_BUS2SC(udev->bus);
2625186730Salfred	struct usb2_xfer *xfer;
2626186730Salfred	struct usb2_pipe_methods *methods;
2627186730Salfred	ohci_ed_t *ed;
2628186730Salfred
2629186730Salfred	DPRINTF("\n");
2630186730Salfred
2631186730Salfred	USB_BUS_LOCK(udev->bus);
2632186730Salfred
2633186730Salfred	TAILQ_FOREACH(xfer, &sc->sc_bus.intr_q.head, wait_entry) {
2634186730Salfred
2635187173Sthompsa		if (xfer->xroot->udev == udev) {
2636186730Salfred
2637186730Salfred			methods = xfer->pipe->methods;
2638186730Salfred			ed = xfer->qh_start[xfer->flags_int.curr_dma_set];
2639186730Salfred
2640186730Salfred			if (methods == &ohci_device_bulk_methods) {
2641186730Salfred				OHCI_APPEND_QH(ed, sc->sc_bulk_p_last);
2642186730Salfred				OWRITE4(sc, OHCI_COMMAND_STATUS, OHCI_BLF);
2643186730Salfred			}
2644186730Salfred			if (methods == &ohci_device_ctrl_methods) {
2645186730Salfred				OHCI_APPEND_QH(ed, sc->sc_ctrl_p_last);
2646186730Salfred				OWRITE4(sc, OHCI_COMMAND_STATUS, OHCI_CLF);
2647186730Salfred			}
2648186730Salfred			if (methods == &ohci_device_intr_methods) {
2649186730Salfred				OHCI_APPEND_QH(ed, sc->sc_intr_p_last[xfer->qh_pos]);
2650186730Salfred			}
2651186730Salfred		}
2652186730Salfred	}
2653186730Salfred
2654186730Salfred	USB_BUS_UNLOCK(udev->bus);
2655186730Salfred
2656186730Salfred	return;
2657186730Salfred}
2658186730Salfred
2659186730Salfredstatic void
2660186730Salfredohci_device_suspend(struct usb2_device *udev)
2661186730Salfred{
2662186730Salfred	struct ohci_softc *sc = OHCI_BUS2SC(udev->bus);
2663186730Salfred	struct usb2_xfer *xfer;
2664186730Salfred	struct usb2_pipe_methods *methods;
2665186730Salfred	ohci_ed_t *ed;
2666186730Salfred
2667186730Salfred	DPRINTF("\n");
2668186730Salfred
2669186730Salfred	USB_BUS_LOCK(udev->bus);
2670186730Salfred
2671186730Salfred	TAILQ_FOREACH(xfer, &sc->sc_bus.intr_q.head, wait_entry) {
2672186730Salfred
2673187173Sthompsa		if (xfer->xroot->udev == udev) {
2674186730Salfred
2675186730Salfred			methods = xfer->pipe->methods;
2676186730Salfred			ed = xfer->qh_start[xfer->flags_int.curr_dma_set];
2677186730Salfred
2678186730Salfred			if (methods == &ohci_device_bulk_methods) {
2679186730Salfred				OHCI_REMOVE_QH(ed, sc->sc_bulk_p_last);
2680186730Salfred			}
2681186730Salfred			if (methods == &ohci_device_ctrl_methods) {
2682186730Salfred				OHCI_REMOVE_QH(ed, sc->sc_ctrl_p_last);
2683186730Salfred			}
2684186730Salfred			if (methods == &ohci_device_intr_methods) {
2685186730Salfred				OHCI_REMOVE_QH(ed, sc->sc_intr_p_last[xfer->qh_pos]);
2686186730Salfred			}
2687186730Salfred		}
2688186730Salfred	}
2689186730Salfred
2690186730Salfred	USB_BUS_UNLOCK(udev->bus);
2691186730Salfred
2692186730Salfred	return;
2693186730Salfred}
2694186730Salfred
2695186730Salfredstatic void
2696186730Salfredohci_set_hw_power(struct usb2_bus *bus)
2697186730Salfred{
2698186730Salfred	struct ohci_softc *sc = OHCI_BUS2SC(bus);
2699186730Salfred	uint32_t temp;
2700186730Salfred	uint32_t flags;
2701186730Salfred
2702186730Salfred	DPRINTF("\n");
2703186730Salfred
2704186730Salfred	USB_BUS_LOCK(bus);
2705186730Salfred
2706186730Salfred	flags = bus->hw_power_state;
2707186730Salfred
2708186730Salfred	temp = OREAD4(sc, OHCI_CONTROL);
2709186730Salfred	temp &= ~(OHCI_PLE | OHCI_IE | OHCI_CLE | OHCI_BLE);
2710186730Salfred
2711186730Salfred	if (flags & USB_HW_POWER_CONTROL)
2712186730Salfred		temp |= OHCI_CLE;
2713186730Salfred
2714186730Salfred	if (flags & USB_HW_POWER_BULK)
2715186730Salfred		temp |= OHCI_BLE;
2716186730Salfred
2717186730Salfred	if (flags & USB_HW_POWER_INTERRUPT)
2718186730Salfred		temp |= OHCI_PLE;
2719186730Salfred
2720186730Salfred	if (flags & USB_HW_POWER_ISOC)
2721186730Salfred		temp |= OHCI_IE | OHCI_PLE;
2722186730Salfred
2723186730Salfred	OWRITE4(sc, OHCI_CONTROL, temp);
2724186730Salfred
2725186730Salfred	USB_BUS_UNLOCK(bus);
2726186730Salfred
2727186730Salfred	return;
2728186730Salfred}
2729186730Salfred
2730184610Salfredstruct usb2_bus_methods ohci_bus_methods =
2731184610Salfred{
2732184610Salfred	.pipe_init = ohci_pipe_init,
2733184610Salfred	.xfer_setup = ohci_xfer_setup,
2734184610Salfred	.xfer_unsetup = ohci_xfer_unsetup,
2735184610Salfred	.get_dma_delay = ohci_get_dma_delay,
2736186730Salfred	.device_resume = ohci_device_resume,
2737186730Salfred	.device_suspend = ohci_device_suspend,
2738186730Salfred	.set_hw_power = ohci_set_hw_power,
2739190735Sthompsa	.roothub_exec = ohci_roothub_exec,
2740184610Salfred};
2741