uss820dci.c revision 190722
1184610Salfred/* $FreeBSD: head/sys/dev/usb/controller/uss820dci.c 190722 2009-04-05 18:18:25Z thompsa $ */
2184610Salfred/*-
3189002Sed * Copyright (c) 2008 Hans Petter Selasky <hselasky@FreeBSD.org>
4184610Salfred * 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/*
29184610Salfred * This file contains the driver for the USS820 series USB Device
30184610Salfred * Controller
31184610Salfred *
32184610Salfred * NOTE: The datasheet does not document everything!
33184610Salfred */
34184610Salfred
35188942Sthompsa#include <dev/usb/usb.h>
36188942Sthompsa#include <dev/usb/usb_mfunc.h>
37188942Sthompsa#include <dev/usb/usb_revision.h>
38188942Sthompsa#include <dev/usb/usb_error.h>
39184610Salfred
40184610Salfred#define	USB_DEBUG_VAR uss820dcidebug
41184610Salfred
42188942Sthompsa#include <dev/usb/usb_core.h>
43188942Sthompsa#include <dev/usb/usb_debug.h>
44188942Sthompsa#include <dev/usb/usb_busdma.h>
45188942Sthompsa#include <dev/usb/usb_process.h>
46188942Sthompsa#include <dev/usb/usb_sw_transfer.h>
47188942Sthompsa#include <dev/usb/usb_transfer.h>
48188942Sthompsa#include <dev/usb/usb_device.h>
49188942Sthompsa#include <dev/usb/usb_hub.h>
50188942Sthompsa#include <dev/usb/usb_util.h>
51184610Salfred
52188942Sthompsa#include <dev/usb/usb_controller.h>
53188942Sthompsa#include <dev/usb/usb_bus.h>
54188942Sthompsa#include <dev/usb/controller/uss820dci.h>
55184610Salfred
56184610Salfred#define	USS820_DCI_BUS2SC(bus) \
57184610Salfred   ((struct uss820dci_softc *)(((uint8_t *)(bus)) - \
58190181Sthompsa    ((uint8_t *)&(((struct uss820dci_softc *)0)->sc_bus))))
59184610Salfred
60184610Salfred#define	USS820_DCI_PC2SC(pc) \
61190180Sthompsa   USS820_DCI_BUS2SC(USB_DMATAG_TO_XROOT((pc)->tag_parent)->bus)
62184610Salfred
63184610Salfred#if USB_DEBUG
64184610Salfredstatic int uss820dcidebug = 0;
65184610Salfred
66184610SalfredSYSCTL_NODE(_hw_usb2, OID_AUTO, uss820dci, CTLFLAG_RW, 0, "USB uss820dci");
67184610SalfredSYSCTL_INT(_hw_usb2_uss820dci, OID_AUTO, debug, CTLFLAG_RW,
68184610Salfred    &uss820dcidebug, 0, "uss820dci debug level");
69184610Salfred#endif
70184610Salfred
71184610Salfred#define	USS820_DCI_INTR_ENDPT 1
72184610Salfred
73184610Salfred/* prototypes */
74184610Salfred
75184610Salfredstruct usb2_bus_methods uss820dci_bus_methods;
76184610Salfredstruct usb2_pipe_methods uss820dci_device_bulk_methods;
77184610Salfredstruct usb2_pipe_methods uss820dci_device_ctrl_methods;
78184610Salfredstruct usb2_pipe_methods uss820dci_device_intr_methods;
79184610Salfredstruct usb2_pipe_methods uss820dci_device_isoc_fs_methods;
80184610Salfredstruct usb2_pipe_methods uss820dci_root_ctrl_methods;
81184610Salfredstruct usb2_pipe_methods uss820dci_root_intr_methods;
82184610Salfred
83184610Salfredstatic uss820dci_cmd_t uss820dci_setup_rx;
84184610Salfredstatic uss820dci_cmd_t uss820dci_data_rx;
85184610Salfredstatic uss820dci_cmd_t uss820dci_data_tx;
86184610Salfredstatic uss820dci_cmd_t uss820dci_data_tx_sync;
87185948Sthompsastatic void	uss820dci_device_done(struct usb2_xfer *, usb2_error_t);
88185948Sthompsastatic void	uss820dci_do_poll(struct usb2_bus *);
89185948Sthompsastatic void	uss820dci_root_ctrl_poll(struct uss820dci_softc *);
90185948Sthompsastatic void	uss820dci_standard_done(struct usb2_xfer *);
91185948Sthompsastatic void	uss820dci_intr_set(struct usb2_xfer *, uint8_t);
92185948Sthompsastatic void	uss820dci_update_shared_1(struct uss820dci_softc *, uint8_t,
93185948Sthompsa		    uint8_t, uint8_t);
94184610Salfred
95184610Salfredstatic usb2_sw_transfer_func_t uss820dci_root_intr_done;
96184610Salfredstatic usb2_sw_transfer_func_t uss820dci_root_ctrl_done;
97184610Salfred
98184610Salfred/*
99184610Salfred * Here is a list of what the USS820D chip can support. The main
100184610Salfred * limitation is that the sum of the buffer sizes must be less than
101184610Salfred * 1120 bytes.
102184610Salfred */
103184610Salfredstatic const struct usb2_hw_ep_profile
104184610Salfred	uss820dci_ep_profile[] = {
105184610Salfred
106184610Salfred	[0] = {
107184610Salfred		.max_in_frame_size = 32,
108184610Salfred		.max_out_frame_size = 32,
109184610Salfred		.is_simplex = 0,
110184610Salfred		.support_control = 1,
111184610Salfred	},
112184610Salfred	[1] = {
113184610Salfred		.max_in_frame_size = 64,
114184610Salfred		.max_out_frame_size = 64,
115184610Salfred		.is_simplex = 0,
116184610Salfred		.support_multi_buffer = 1,
117184610Salfred		.support_bulk = 1,
118184610Salfred		.support_interrupt = 1,
119184610Salfred		.support_in = 1,
120184610Salfred		.support_out = 1,
121184610Salfred	},
122184610Salfred	[2] = {
123184610Salfred		.max_in_frame_size = 8,
124184610Salfred		.max_out_frame_size = 8,
125184610Salfred		.is_simplex = 0,
126184610Salfred		.support_multi_buffer = 1,
127184610Salfred		.support_bulk = 1,
128184610Salfred		.support_interrupt = 1,
129184610Salfred		.support_in = 1,
130184610Salfred		.support_out = 1,
131184610Salfred	},
132184610Salfred	[3] = {
133184610Salfred		.max_in_frame_size = 256,
134184610Salfred		.max_out_frame_size = 256,
135184610Salfred		.is_simplex = 0,
136184610Salfred		.support_multi_buffer = 1,
137184610Salfred		.support_isochronous = 1,
138184610Salfred		.support_in = 1,
139184610Salfred		.support_out = 1,
140184610Salfred	},
141184610Salfred};
142184610Salfred
143184610Salfredstatic void
144184610Salfreduss820dci_update_shared_1(struct uss820dci_softc *sc, uint8_t reg,
145184610Salfred    uint8_t keep_mask, uint8_t set_mask)
146184610Salfred{
147184610Salfred	uint8_t temp;
148184610Salfred
149184610Salfred	USS820_WRITE_1(sc, USS820_PEND, 1);
150184610Salfred	temp = USS820_READ_1(sc, reg);
151184610Salfred	temp &= (keep_mask);
152184610Salfred	temp |= (set_mask);
153184610Salfred	USS820_WRITE_1(sc, reg, temp);
154184610Salfred	USS820_WRITE_1(sc, USS820_PEND, 0);
155184610Salfred}
156184610Salfred
157184610Salfredstatic void
158184610Salfreduss820dci_get_hw_ep_profile(struct usb2_device *udev,
159184610Salfred    const struct usb2_hw_ep_profile **ppf, uint8_t ep_addr)
160184610Salfred{
161184610Salfred	if (ep_addr == 0) {
162184610Salfred		*ppf = uss820dci_ep_profile + 0;
163184610Salfred	} else if (ep_addr < 5) {
164184610Salfred		*ppf = uss820dci_ep_profile + 1;
165184610Salfred	} else if (ep_addr < 7) {
166184610Salfred		*ppf = uss820dci_ep_profile + 2;
167184610Salfred	} else if (ep_addr == 7) {
168184610Salfred		*ppf = uss820dci_ep_profile + 3;
169184610Salfred	} else {
170184610Salfred		*ppf = NULL;
171184610Salfred	}
172184610Salfred}
173184610Salfred
174184610Salfredstatic void
175184610Salfreduss820dci_pull_up(struct uss820dci_softc *sc)
176184610Salfred{
177184610Salfred	uint8_t temp;
178184610Salfred
179184610Salfred	/* pullup D+, if possible */
180184610Salfred
181184610Salfred	if (!sc->sc_flags.d_pulled_up &&
182184610Salfred	    sc->sc_flags.port_powered) {
183184610Salfred		sc->sc_flags.d_pulled_up = 1;
184184610Salfred
185184610Salfred		DPRINTF("\n");
186184610Salfred
187184610Salfred		temp = USS820_READ_1(sc, USS820_MCSR);
188184610Salfred		temp |= USS820_MCSR_DPEN;
189184610Salfred		USS820_WRITE_1(sc, USS820_MCSR, temp);
190184610Salfred	}
191184610Salfred}
192184610Salfred
193184610Salfredstatic void
194184610Salfreduss820dci_pull_down(struct uss820dci_softc *sc)
195184610Salfred{
196184610Salfred	uint8_t temp;
197184610Salfred
198184610Salfred	/* pulldown D+, if possible */
199184610Salfred
200184610Salfred	if (sc->sc_flags.d_pulled_up) {
201184610Salfred		sc->sc_flags.d_pulled_up = 0;
202184610Salfred
203184610Salfred		DPRINTF("\n");
204184610Salfred
205184610Salfred		temp = USS820_READ_1(sc, USS820_MCSR);
206184610Salfred		temp &= ~USS820_MCSR_DPEN;
207184610Salfred		USS820_WRITE_1(sc, USS820_MCSR, temp);
208184610Salfred	}
209184610Salfred}
210184610Salfred
211184610Salfredstatic void
212184610Salfreduss820dci_wakeup_peer(struct uss820dci_softc *sc)
213184610Salfred{
214184610Salfred	if (!(sc->sc_flags.status_suspend)) {
215184610Salfred		return;
216184610Salfred	}
217184610Salfred	DPRINTFN(0, "not supported\n");
218184610Salfred}
219184610Salfred
220184610Salfredstatic void
221184610Salfreduss820dci_set_address(struct uss820dci_softc *sc, uint8_t addr)
222184610Salfred{
223184610Salfred	DPRINTFN(5, "addr=%d\n", addr);
224184610Salfred
225184610Salfred	USS820_WRITE_1(sc, USS820_FADDR, addr);
226184610Salfred}
227184610Salfred
228184610Salfredstatic uint8_t
229184610Salfreduss820dci_setup_rx(struct uss820dci_td *td)
230184610Salfred{
231184610Salfred	struct uss820dci_softc *sc;
232184610Salfred	struct usb2_device_request req;
233184610Salfred	uint16_t count;
234184610Salfred	uint8_t rx_stat;
235184610Salfred	uint8_t temp;
236184610Salfred
237184610Salfred	/* select the correct endpoint */
238184610Salfred	bus_space_write_1(td->io_tag, td->io_hdl,
239184610Salfred	    td->ep_reg, td->ep_index);
240184610Salfred
241184610Salfred	/* read out FIFO status */
242184610Salfred	rx_stat = bus_space_read_1(td->io_tag, td->io_hdl,
243184610Salfred	    td->rx_stat_reg);
244184610Salfred
245184610Salfred	/* get pointer to softc */
246184610Salfred	sc = USS820_DCI_PC2SC(td->pc);
247184610Salfred
248184610Salfred	DPRINTFN(5, "rx_stat=0x%02x rem=%u\n", rx_stat, td->remainder);
249184610Salfred
250184610Salfred	if (!(rx_stat & USS820_RXSTAT_RXSETUP)) {
251184610Salfred		goto not_complete;
252184610Salfred	}
253190721Sthompsa	/* clear did stall */
254190721Sthompsa	td->did_stall = 0;
255190721Sthompsa
256184610Salfred	/* clear stall and all I/O */
257184610Salfred	uss820dci_update_shared_1(sc, USS820_EPCON,
258184610Salfred	    0xFF ^ (USS820_EPCON_TXSTL |
259184610Salfred	    USS820_EPCON_RXSTL |
260184610Salfred	    USS820_EPCON_RXIE |
261184610Salfred	    USS820_EPCON_TXOE), 0);
262184610Salfred
263184610Salfred	/* clear end overwrite flag */
264184610Salfred	uss820dci_update_shared_1(sc, USS820_RXSTAT,
265184610Salfred	    0xFF ^ USS820_RXSTAT_EDOVW, 0);
266184610Salfred
267184610Salfred	/* get the packet byte count */
268184610Salfred	count = bus_space_read_1(td->io_tag, td->io_hdl,
269184610Salfred	    td->rx_count_low_reg);
270184610Salfred	count |= (bus_space_read_1(td->io_tag, td->io_hdl,
271184610Salfred	    td->rx_count_high_reg) << 8);
272184610Salfred	count &= 0x3FF;
273184610Salfred
274184610Salfred	/* verify data length */
275184610Salfred	if (count != td->remainder) {
276184610Salfred		DPRINTFN(0, "Invalid SETUP packet "
277184610Salfred		    "length, %d bytes\n", count);
278190722Sthompsa		goto setup_not_complete;
279184610Salfred	}
280184610Salfred	if (count != sizeof(req)) {
281184610Salfred		DPRINTFN(0, "Unsupported SETUP packet "
282184610Salfred		    "length, %d bytes\n", count);
283190722Sthompsa		goto setup_not_complete;
284184610Salfred	}
285184610Salfred	/* receive data */
286184610Salfred	bus_space_read_multi_1(td->io_tag, td->io_hdl,
287184610Salfred	    td->rx_fifo_reg, (void *)&req, sizeof(req));
288184610Salfred
289184610Salfred	/* read out FIFO status */
290184610Salfred	rx_stat = bus_space_read_1(td->io_tag, td->io_hdl,
291184610Salfred	    td->rx_stat_reg);
292184610Salfred
293184610Salfred	if (rx_stat & (USS820_RXSTAT_EDOVW |
294184610Salfred	    USS820_RXSTAT_STOVW)) {
295184610Salfred		DPRINTF("new SETUP packet received\n");
296184610Salfred		return (1);		/* not complete */
297184610Salfred	}
298184610Salfred	/* clear receive setup bit */
299184610Salfred	uss820dci_update_shared_1(sc, USS820_RXSTAT,
300184610Salfred	    0xFF ^ (USS820_RXSTAT_RXSETUP |
301184610Salfred	    USS820_RXSTAT_EDOVW |
302184610Salfred	    USS820_RXSTAT_STOVW), 0);
303184610Salfred
304184610Salfred	/* set RXFFRC bit */
305184610Salfred	temp = bus_space_read_1(td->io_tag, td->io_hdl,
306184610Salfred	    td->rx_cntl_reg);
307184610Salfred	temp |= USS820_RXCON_RXFFRC;
308184610Salfred	bus_space_write_1(td->io_tag, td->io_hdl,
309184610Salfred	    td->rx_cntl_reg, temp);
310184610Salfred
311184610Salfred	/* copy data into real buffer */
312184610Salfred	usb2_copy_in(td->pc, 0, &req, sizeof(req));
313184610Salfred
314184610Salfred	td->offset = sizeof(req);
315184610Salfred	td->remainder = 0;
316184610Salfred
317184610Salfred	/* sneak peek the set address */
318184610Salfred	if ((req.bmRequestType == UT_WRITE_DEVICE) &&
319184610Salfred	    (req.bRequest == UR_SET_ADDRESS)) {
320184610Salfred		sc->sc_dv_addr = req.wValue[0] & 0x7F;
321184610Salfred	} else {
322184610Salfred		sc->sc_dv_addr = 0xFF;
323184610Salfred	}
324184610Salfred	return (0);			/* complete */
325184610Salfred
326190722Sthompsasetup_not_complete:
327190722Sthompsa
328190722Sthompsa	/* set RXFFRC bit */
329190722Sthompsa	temp = bus_space_read_1(td->io_tag, td->io_hdl,
330190722Sthompsa	    td->rx_cntl_reg);
331190722Sthompsa	temp |= USS820_RXCON_RXFFRC;
332190722Sthompsa	bus_space_write_1(td->io_tag, td->io_hdl,
333190722Sthompsa	    td->rx_cntl_reg, temp);
334190722Sthompsa
335190722Sthompsa	/* FALLTHROUGH */
336190722Sthompsa
337184610Salfrednot_complete:
338190721Sthompsa	/* abort any ongoing transfer */
339190721Sthompsa	if (!td->did_stall) {
340190721Sthompsa		DPRINTFN(5, "stalling\n");
341190721Sthompsa		/* set stall */
342190721Sthompsa		uss820dci_update_shared_1(sc, USS820_EPCON, 0xFF,
343190721Sthompsa		    (USS820_EPCON_TXSTL | USS820_EPCON_RXSTL));
344190721Sthompsa
345190721Sthompsa		td->did_stall = 1;
346190721Sthompsa	}
347190721Sthompsa
348184610Salfred	/* clear end overwrite flag, if any */
349184610Salfred	if (rx_stat & USS820_RXSTAT_RXSETUP) {
350184610Salfred		uss820dci_update_shared_1(sc, USS820_RXSTAT,
351184610Salfred		    0xFF ^ (USS820_RXSTAT_EDOVW |
352184610Salfred		    USS820_RXSTAT_STOVW |
353184610Salfred		    USS820_RXSTAT_RXSETUP), 0);
354184610Salfred	}
355184610Salfred	return (1);			/* not complete */
356184610Salfred
357184610Salfred}
358184610Salfred
359184610Salfredstatic uint8_t
360184610Salfreduss820dci_data_rx(struct uss820dci_td *td)
361184610Salfred{
362184610Salfred	struct usb2_page_search buf_res;
363184610Salfred	uint16_t count;
364184610Salfred	uint8_t rx_flag;
365184610Salfred	uint8_t rx_stat;
366184610Salfred	uint8_t rx_cntl;
367184610Salfred	uint8_t to;
368184610Salfred	uint8_t got_short;
369184610Salfred
370184610Salfred	to = 2;				/* don't loop forever! */
371184610Salfred	got_short = 0;
372184610Salfred
373184610Salfred	/* select the correct endpoint */
374184610Salfred	bus_space_write_1(td->io_tag, td->io_hdl, td->ep_reg, td->ep_index);
375184610Salfred
376184610Salfred	/* check if any of the FIFO banks have data */
377184610Salfredrepeat:
378184610Salfred	/* read out FIFO flag */
379184610Salfred	rx_flag = bus_space_read_1(td->io_tag, td->io_hdl,
380184610Salfred	    td->rx_flag_reg);
381184610Salfred	/* read out FIFO status */
382184610Salfred	rx_stat = bus_space_read_1(td->io_tag, td->io_hdl,
383184610Salfred	    td->rx_stat_reg);
384184610Salfred
385184610Salfred	DPRINTFN(5, "rx_stat=0x%02x rx_flag=0x%02x rem=%u\n",
386184610Salfred	    rx_stat, rx_flag, td->remainder);
387184610Salfred
388184610Salfred	if (rx_stat & (USS820_RXSTAT_RXSETUP |
389184610Salfred	    USS820_RXSTAT_RXSOVW |
390184610Salfred	    USS820_RXSTAT_EDOVW)) {
391184610Salfred		if (td->remainder == 0) {
392184610Salfred			/*
393184610Salfred			 * We are actually complete and have
394184610Salfred			 * received the next SETUP
395184610Salfred			 */
396184610Salfred			DPRINTFN(5, "faking complete\n");
397184610Salfred			return (0);	/* complete */
398184610Salfred		}
399184610Salfred		/*
400184610Salfred	         * USB Host Aborted the transfer.
401184610Salfred	         */
402184610Salfred		td->error = 1;
403184610Salfred		return (0);		/* complete */
404184610Salfred	}
405184610Salfred	/* check for errors */
406184610Salfred	if (rx_flag & (USS820_RXFLG_RXOVF |
407184610Salfred	    USS820_RXFLG_RXURF)) {
408184610Salfred		DPRINTFN(5, "overflow or underflow\n");
409184610Salfred		/* should not happen */
410184610Salfred		td->error = 1;
411184610Salfred		return (0);		/* complete */
412184610Salfred	}
413184610Salfred	/* check status */
414184610Salfred	if (!(rx_flag & (USS820_RXFLG_RXFIF0 |
415184610Salfred	    USS820_RXFLG_RXFIF1))) {
416184610Salfred
417184610Salfred		/* read out EPCON register */
418184610Salfred		/* enable RX input */
419184610Salfred		if (!td->did_stall) {
420184610Salfred			uss820dci_update_shared_1(USS820_DCI_PC2SC(td->pc),
421184610Salfred			    USS820_EPCON, 0xFF, USS820_EPCON_RXIE);
422184610Salfred			td->did_stall = 1;
423184610Salfred		}
424184610Salfred		return (1);		/* not complete */
425184610Salfred	}
426184610Salfred	/* get the packet byte count */
427184610Salfred	count = bus_space_read_1(td->io_tag, td->io_hdl,
428184610Salfred	    td->rx_count_low_reg);
429184610Salfred
430184610Salfred	count |= (bus_space_read_1(td->io_tag, td->io_hdl,
431184610Salfred	    td->rx_count_high_reg) << 8);
432184610Salfred	count &= 0x3FF;
433184610Salfred
434184610Salfred	DPRINTFN(5, "count=0x%04x\n", count);
435184610Salfred
436184610Salfred	/* verify the packet byte count */
437184610Salfred	if (count != td->max_packet_size) {
438184610Salfred		if (count < td->max_packet_size) {
439184610Salfred			/* we have a short packet */
440184610Salfred			td->short_pkt = 1;
441184610Salfred			got_short = 1;
442184610Salfred		} else {
443184610Salfred			/* invalid USB packet */
444184610Salfred			td->error = 1;
445184610Salfred			return (0);	/* we are complete */
446184610Salfred		}
447184610Salfred	}
448184610Salfred	/* verify the packet byte count */
449184610Salfred	if (count > td->remainder) {
450184610Salfred		/* invalid USB packet */
451184610Salfred		td->error = 1;
452184610Salfred		return (0);		/* we are complete */
453184610Salfred	}
454184610Salfred	while (count > 0) {
455184610Salfred		usb2_get_page(td->pc, td->offset, &buf_res);
456184610Salfred
457184610Salfred		/* get correct length */
458184610Salfred		if (buf_res.length > count) {
459184610Salfred			buf_res.length = count;
460184610Salfred		}
461184610Salfred		/* receive data */
462184610Salfred		bus_space_read_multi_1(td->io_tag, td->io_hdl,
463184610Salfred		    td->rx_fifo_reg, buf_res.buffer, buf_res.length);
464184610Salfred
465184610Salfred		/* update counters */
466184610Salfred		count -= buf_res.length;
467184610Salfred		td->offset += buf_res.length;
468184610Salfred		td->remainder -= buf_res.length;
469184610Salfred	}
470184610Salfred
471184610Salfred	/* set RXFFRC bit */
472184610Salfred	rx_cntl = bus_space_read_1(td->io_tag, td->io_hdl,
473184610Salfred	    td->rx_cntl_reg);
474184610Salfred	rx_cntl |= USS820_RXCON_RXFFRC;
475184610Salfred	bus_space_write_1(td->io_tag, td->io_hdl,
476184610Salfred	    td->rx_cntl_reg, rx_cntl);
477184610Salfred
478184610Salfred	/* check if we are complete */
479184610Salfred	if ((td->remainder == 0) || got_short) {
480184610Salfred		if (td->short_pkt) {
481184610Salfred			/* we are complete */
482184610Salfred			return (0);
483184610Salfred		}
484184610Salfred		/* else need to receive a zero length packet */
485184610Salfred	}
486184610Salfred	if (--to) {
487184610Salfred		goto repeat;
488184610Salfred	}
489184610Salfred	return (1);			/* not complete */
490184610Salfred}
491184610Salfred
492184610Salfredstatic uint8_t
493184610Salfreduss820dci_data_tx(struct uss820dci_td *td)
494184610Salfred{
495184610Salfred	struct usb2_page_search buf_res;
496184610Salfred	uint16_t count;
497184610Salfred	uint16_t count_copy;
498184610Salfred	uint8_t rx_stat;
499184610Salfred	uint8_t tx_flag;
500184610Salfred	uint8_t to;
501184610Salfred
502184610Salfred	/* select the correct endpoint */
503184610Salfred	bus_space_write_1(td->io_tag, td->io_hdl,
504184610Salfred	    td->ep_reg, td->ep_index);
505184610Salfred
506184610Salfred	to = 2;				/* don't loop forever! */
507184610Salfred
508184610Salfredrepeat:
509184610Salfred	/* read out TX FIFO flags */
510184610Salfred	tx_flag = bus_space_read_1(td->io_tag, td->io_hdl,
511184610Salfred	    td->tx_flag_reg);
512184610Salfred
513184610Salfred	/* read out RX FIFO status last */
514184610Salfred	rx_stat = bus_space_read_1(td->io_tag, td->io_hdl,
515184610Salfred	    td->rx_stat_reg);
516184610Salfred
517184610Salfred	DPRINTFN(5, "rx_stat=0x%02x tx_flag=0x%02x rem=%u\n",
518184610Salfred	    rx_stat, tx_flag, td->remainder);
519184610Salfred
520184610Salfred	if (rx_stat & (USS820_RXSTAT_RXSETUP |
521184610Salfred	    USS820_RXSTAT_RXSOVW |
522184610Salfred	    USS820_RXSTAT_EDOVW)) {
523184610Salfred		/*
524184610Salfred	         * The current transfer was aborted
525184610Salfred	         * by the USB Host
526184610Salfred	         */
527184610Salfred		td->error = 1;
528184610Salfred		return (0);		/* complete */
529184610Salfred	}
530184610Salfred	if (tx_flag & (USS820_TXFLG_TXOVF |
531184610Salfred	    USS820_TXFLG_TXURF)) {
532184610Salfred		td->error = 1;
533184610Salfred		return (0);		/* complete */
534184610Salfred	}
535184610Salfred	if (tx_flag & USS820_TXFLG_TXFIF0) {
536184610Salfred		if (tx_flag & USS820_TXFLG_TXFIF1) {
537184610Salfred			return (1);	/* not complete */
538184610Salfred		}
539184610Salfred	}
540184610Salfred	if ((!td->support_multi_buffer) &&
541184610Salfred	    (tx_flag & (USS820_TXFLG_TXFIF0 |
542184610Salfred	    USS820_TXFLG_TXFIF1))) {
543184610Salfred		return (1);		/* not complete */
544184610Salfred	}
545184610Salfred	count = td->max_packet_size;
546184610Salfred	if (td->remainder < count) {
547184610Salfred		/* we have a short packet */
548184610Salfred		td->short_pkt = 1;
549184610Salfred		count = td->remainder;
550184610Salfred	}
551184610Salfred	count_copy = count;
552184610Salfred	while (count > 0) {
553184610Salfred
554184610Salfred		usb2_get_page(td->pc, td->offset, &buf_res);
555184610Salfred
556184610Salfred		/* get correct length */
557184610Salfred		if (buf_res.length > count) {
558184610Salfred			buf_res.length = count;
559184610Salfred		}
560184610Salfred		/* transmit data */
561184610Salfred		bus_space_write_multi_1(td->io_tag, td->io_hdl,
562184610Salfred		    td->tx_fifo_reg, buf_res.buffer, buf_res.length);
563184610Salfred
564184610Salfred		/* update counters */
565184610Salfred		count -= buf_res.length;
566184610Salfred		td->offset += buf_res.length;
567184610Salfred		td->remainder -= buf_res.length;
568184610Salfred	}
569184610Salfred
570184610Salfred	/* post-write high packet byte count first */
571184610Salfred	bus_space_write_1(td->io_tag, td->io_hdl,
572184610Salfred	    td->tx_count_high_reg, count_copy >> 8);
573184610Salfred
574184610Salfred	/* post-write low packet byte count last */
575184610Salfred	bus_space_write_1(td->io_tag, td->io_hdl,
576184610Salfred	    td->tx_count_low_reg, count_copy);
577184610Salfred
578184610Salfred	/*
579184610Salfred	 * Enable TX output, which must happen after that we have written
580184610Salfred	 * data into the FIFO. This is undocumented.
581184610Salfred	 */
582184610Salfred	if (!td->did_stall) {
583184610Salfred		uss820dci_update_shared_1(USS820_DCI_PC2SC(td->pc),
584184610Salfred		    USS820_EPCON, 0xFF, USS820_EPCON_TXOE);
585184610Salfred		td->did_stall = 1;
586184610Salfred	}
587184610Salfred	/* check remainder */
588184610Salfred	if (td->remainder == 0) {
589184610Salfred		if (td->short_pkt) {
590184610Salfred			return (0);	/* complete */
591184610Salfred		}
592184610Salfred		/* else we need to transmit a short packet */
593184610Salfred	}
594184610Salfred	if (--to) {
595184610Salfred		goto repeat;
596184610Salfred	}
597184610Salfred	return (1);			/* not complete */
598184610Salfred}
599184610Salfred
600184610Salfredstatic uint8_t
601184610Salfreduss820dci_data_tx_sync(struct uss820dci_td *td)
602184610Salfred{
603184610Salfred	struct uss820dci_softc *sc;
604184610Salfred	uint8_t rx_stat;
605184610Salfred	uint8_t tx_flag;
606184610Salfred
607184610Salfred	/* select the correct endpoint */
608184610Salfred	bus_space_write_1(td->io_tag, td->io_hdl,
609184610Salfred	    td->ep_reg, td->ep_index);
610184610Salfred
611184610Salfred	/* read out TX FIFO flag */
612184610Salfred	tx_flag = bus_space_read_1(td->io_tag, td->io_hdl,
613184610Salfred	    td->tx_flag_reg);
614184610Salfred
615184610Salfred	/* read out RX FIFO status last */
616184610Salfred	rx_stat = bus_space_read_1(td->io_tag, td->io_hdl,
617184610Salfred	    td->rx_stat_reg);
618184610Salfred
619184610Salfred	DPRINTFN(5, "rx_stat=0x%02x rem=%u\n", rx_stat, td->remainder);
620184610Salfred
621184610Salfred	if (rx_stat & (USS820_RXSTAT_RXSETUP |
622184610Salfred	    USS820_RXSTAT_RXSOVW |
623184610Salfred	    USS820_RXSTAT_EDOVW)) {
624184610Salfred		DPRINTFN(5, "faking complete\n");
625184610Salfred		/* Race condition */
626184610Salfred		return (0);		/* complete */
627184610Salfred	}
628184610Salfred	DPRINTFN(5, "tx_flag=0x%02x rem=%u\n",
629184610Salfred	    tx_flag, td->remainder);
630184610Salfred
631184610Salfred	if (tx_flag & (USS820_TXFLG_TXOVF |
632184610Salfred	    USS820_TXFLG_TXURF)) {
633184610Salfred		td->error = 1;
634184610Salfred		return (0);		/* complete */
635184610Salfred	}
636184610Salfred	if (tx_flag & (USS820_TXFLG_TXFIF0 |
637184610Salfred	    USS820_TXFLG_TXFIF1)) {
638184610Salfred		return (1);		/* not complete */
639184610Salfred	}
640184610Salfred	sc = USS820_DCI_PC2SC(td->pc);
641184610Salfred	if (sc->sc_dv_addr != 0xFF) {
642184610Salfred		/* write function address */
643184610Salfred		uss820dci_set_address(sc, sc->sc_dv_addr);
644184610Salfred	}
645184610Salfred	return (0);			/* complete */
646184610Salfred}
647184610Salfred
648184610Salfredstatic uint8_t
649184610Salfreduss820dci_xfer_do_fifo(struct usb2_xfer *xfer)
650184610Salfred{
651184610Salfred	struct uss820dci_td *td;
652184610Salfred
653184610Salfred	DPRINTFN(9, "\n");
654184610Salfred
655184610Salfred	td = xfer->td_transfer_cache;
656184610Salfred	while (1) {
657184610Salfred		if ((td->func) (td)) {
658184610Salfred			/* operation in progress */
659184610Salfred			break;
660184610Salfred		}
661184610Salfred		if (((void *)td) == xfer->td_transfer_last) {
662184610Salfred			goto done;
663184610Salfred		}
664184610Salfred		if (td->error) {
665184610Salfred			goto done;
666184610Salfred		} else if (td->remainder > 0) {
667184610Salfred			/*
668184610Salfred			 * We had a short transfer. If there is no alternate
669184610Salfred			 * next, stop processing !
670184610Salfred			 */
671184610Salfred			if (!td->alt_next) {
672184610Salfred				goto done;
673184610Salfred			}
674184610Salfred		}
675184610Salfred		/*
676184610Salfred		 * Fetch the next transfer descriptor.
677184610Salfred		 */
678184610Salfred		td = td->obj_next;
679184610Salfred		xfer->td_transfer_cache = td;
680184610Salfred	}
681184610Salfred	return (1);			/* not complete */
682184610Salfred
683184610Salfreddone:
684184610Salfred	/* compute all actual lengths */
685184610Salfred
686184610Salfred	uss820dci_standard_done(xfer);
687184610Salfred
688184610Salfred	return (0);			/* complete */
689184610Salfred}
690184610Salfred
691184610Salfredstatic void
692184610Salfreduss820dci_interrupt_poll(struct uss820dci_softc *sc)
693184610Salfred{
694184610Salfred	struct usb2_xfer *xfer;
695184610Salfred
696184610Salfredrepeat:
697184610Salfred	TAILQ_FOREACH(xfer, &sc->sc_bus.intr_q.head, wait_entry) {
698184610Salfred		if (!uss820dci_xfer_do_fifo(xfer)) {
699184610Salfred			/* queue has been modified */
700184610Salfred			goto repeat;
701184610Salfred		}
702184610Salfred	}
703184610Salfred}
704184610Salfred
705184610Salfredstatic void
706184610Salfreduss820dci_wait_suspend(struct uss820dci_softc *sc, uint8_t on)
707184610Salfred{
708184610Salfred	uint8_t scr;
709184610Salfred	uint8_t scratch;
710184610Salfred
711184610Salfred	scr = USS820_READ_1(sc, USS820_SCR);
712184610Salfred	scratch = USS820_READ_1(sc, USS820_SCRATCH);
713184610Salfred
714184610Salfred	if (on) {
715184610Salfred		scr |= USS820_SCR_IE_SUSP;
716184610Salfred		scratch &= ~USS820_SCRATCH_IE_RESUME;
717184610Salfred	} else {
718184610Salfred		scr &= ~USS820_SCR_IE_SUSP;
719184610Salfred		scratch |= USS820_SCRATCH_IE_RESUME;
720184610Salfred	}
721184610Salfred
722184610Salfred	USS820_WRITE_1(sc, USS820_SCR, scr);
723184610Salfred	USS820_WRITE_1(sc, USS820_SCRATCH, scratch);
724184610Salfred}
725184610Salfred
726184610Salfredvoid
727184610Salfreduss820dci_interrupt(struct uss820dci_softc *sc)
728184610Salfred{
729184610Salfred	uint8_t ssr;
730184610Salfred	uint8_t event;
731184610Salfred
732184824Sthompsa	USB_BUS_LOCK(&sc->sc_bus);
733184610Salfred
734184610Salfred	ssr = USS820_READ_1(sc, USS820_SSR);
735184610Salfred
736184610Salfred	ssr &= (USS820_SSR_SUSPEND |
737184610Salfred	    USS820_SSR_RESUME |
738184610Salfred	    USS820_SSR_RESET);
739184610Salfred
740184610Salfred	/* acknowledge all interrupts */
741184610Salfred
742184610Salfred	uss820dci_update_shared_1(sc, USS820_SSR, 0, 0);
743184610Salfred
744184610Salfred	/* check for any bus state change interrupts */
745184610Salfred
746184610Salfred	if (ssr) {
747184610Salfred
748184610Salfred		event = 0;
749184610Salfred
750184610Salfred		if (ssr & USS820_SSR_RESET) {
751184610Salfred			sc->sc_flags.status_bus_reset = 1;
752184610Salfred			sc->sc_flags.status_suspend = 0;
753184610Salfred			sc->sc_flags.change_suspend = 0;
754184610Salfred			sc->sc_flags.change_connect = 1;
755184610Salfred
756184610Salfred			/* disable resume interrupt */
757184610Salfred			uss820dci_wait_suspend(sc, 1);
758184610Salfred
759184610Salfred			event = 1;
760184610Salfred		}
761184610Salfred		/*
762184610Salfred	         * If "RESUME" and "SUSPEND" is set at the same time
763184610Salfred	         * we interpret that like "RESUME". Resume is set when
764184610Salfred	         * there is at least 3 milliseconds of inactivity on
765184610Salfred	         * the USB BUS.
766184610Salfred	         */
767184610Salfred		if (ssr & USS820_SSR_RESUME) {
768184610Salfred			if (sc->sc_flags.status_suspend) {
769184610Salfred				sc->sc_flags.status_suspend = 0;
770184610Salfred				sc->sc_flags.change_suspend = 1;
771184610Salfred				/* disable resume interrupt */
772184610Salfred				uss820dci_wait_suspend(sc, 1);
773184610Salfred				event = 1;
774184610Salfred			}
775184610Salfred		} else if (ssr & USS820_SSR_SUSPEND) {
776184610Salfred			if (!sc->sc_flags.status_suspend) {
777184610Salfred				sc->sc_flags.status_suspend = 1;
778184610Salfred				sc->sc_flags.change_suspend = 1;
779184610Salfred				/* enable resume interrupt */
780184610Salfred				uss820dci_wait_suspend(sc, 0);
781184610Salfred				event = 1;
782184610Salfred			}
783184610Salfred		}
784184610Salfred		if (event) {
785184610Salfred
786184610Salfred			DPRINTF("real bus interrupt 0x%02x\n", ssr);
787184610Salfred
788184610Salfred			/* complete root HUB interrupt endpoint */
789184610Salfred
790184610Salfred			usb2_sw_transfer(&sc->sc_root_intr,
791184610Salfred			    &uss820dci_root_intr_done);
792184610Salfred		}
793184610Salfred	}
794184610Salfred	/* acknowledge all SBI interrupts */
795184610Salfred	uss820dci_update_shared_1(sc, USS820_SBI, 0, 0);
796184610Salfred
797184610Salfred	/* acknowledge all SBI1 interrupts */
798184610Salfred	uss820dci_update_shared_1(sc, USS820_SBI1, 0, 0);
799184610Salfred
800184610Salfred	/* poll all active transfers */
801184610Salfred	uss820dci_interrupt_poll(sc);
802184610Salfred
803184824Sthompsa	USB_BUS_UNLOCK(&sc->sc_bus);
804184610Salfred}
805184610Salfred
806184610Salfredstatic void
807184610Salfreduss820dci_setup_standard_chain_sub(struct uss820_std_temp *temp)
808184610Salfred{
809184610Salfred	struct uss820dci_td *td;
810184610Salfred
811184610Salfred	/* get current Transfer Descriptor */
812184610Salfred	td = temp->td_next;
813184610Salfred	temp->td = td;
814184610Salfred
815184610Salfred	/* prepare for next TD */
816184610Salfred	temp->td_next = td->obj_next;
817184610Salfred
818184610Salfred	/* fill out the Transfer Descriptor */
819184610Salfred	td->func = temp->func;
820184610Salfred	td->pc = temp->pc;
821184610Salfred	td->offset = temp->offset;
822184610Salfred	td->remainder = temp->len;
823184610Salfred	td->error = 0;
824184610Salfred	td->did_stall = 0;
825184610Salfred	td->short_pkt = temp->short_pkt;
826184610Salfred	td->alt_next = temp->setup_alt_next;
827184610Salfred}
828184610Salfred
829184610Salfredstatic void
830184610Salfreduss820dci_setup_standard_chain(struct usb2_xfer *xfer)
831184610Salfred{
832184610Salfred	struct uss820_std_temp temp;
833184610Salfred	struct uss820dci_softc *sc;
834184610Salfred	struct uss820dci_td *td;
835184610Salfred	uint32_t x;
836184610Salfred	uint8_t ep_no;
837184610Salfred
838184610Salfred	DPRINTFN(9, "addr=%d endpt=%d sumlen=%d speed=%d\n",
839184610Salfred	    xfer->address, UE_GET_ADDR(xfer->endpoint),
840187173Sthompsa	    xfer->sumlen, usb2_get_speed(xfer->xroot->udev));
841184610Salfred
842184610Salfred	temp.max_frame_size = xfer->max_frame_size;
843184610Salfred
844184610Salfred	td = xfer->td_start[0];
845184610Salfred	xfer->td_transfer_first = td;
846184610Salfred	xfer->td_transfer_cache = td;
847184610Salfred
848184610Salfred	/* setup temp */
849184610Salfred
850184610Salfred	temp.td = NULL;
851184610Salfred	temp.td_next = xfer->td_start[0];
852190183Sthompsa	temp.offset = 0;
853184610Salfred	temp.setup_alt_next = xfer->flags_int.short_frames_ok;
854184610Salfred
855187173Sthompsa	sc = USS820_DCI_BUS2SC(xfer->xroot->bus);
856184610Salfred	ep_no = (xfer->endpoint & UE_ADDR);
857184610Salfred
858184610Salfred	/* check if we should prepend a setup message */
859184610Salfred
860184610Salfred	if (xfer->flags_int.control_xfr) {
861184610Salfred		if (xfer->flags_int.control_hdr) {
862184610Salfred
863184610Salfred			temp.func = &uss820dci_setup_rx;
864184610Salfred			temp.len = xfer->frlengths[0];
865184610Salfred			temp.pc = xfer->frbuffers + 0;
866184610Salfred			temp.short_pkt = temp.len ? 1 : 0;
867190183Sthompsa			/* check for last frame */
868190183Sthompsa			if (xfer->nframes == 1) {
869190183Sthompsa				/* no STATUS stage yet, SETUP is last */
870190183Sthompsa				if (xfer->flags_int.control_act)
871190183Sthompsa					temp.setup_alt_next = 0;
872190183Sthompsa			}
873184610Salfred
874184610Salfred			uss820dci_setup_standard_chain_sub(&temp);
875184610Salfred		}
876184610Salfred		x = 1;
877184610Salfred	} else {
878184610Salfred		x = 0;
879184610Salfred	}
880184610Salfred
881184610Salfred	if (x != xfer->nframes) {
882184610Salfred		if (xfer->endpoint & UE_DIR_IN) {
883184610Salfred			temp.func = &uss820dci_data_tx;
884184610Salfred		} else {
885184610Salfred			temp.func = &uss820dci_data_rx;
886184610Salfred		}
887184610Salfred
888184610Salfred		/* setup "pc" pointer */
889184610Salfred		temp.pc = xfer->frbuffers + x;
890184610Salfred	}
891184610Salfred	while (x != xfer->nframes) {
892184610Salfred
893184610Salfred		/* DATA0 / DATA1 message */
894184610Salfred
895184610Salfred		temp.len = xfer->frlengths[x];
896184610Salfred
897184610Salfred		x++;
898184610Salfred
899184610Salfred		if (x == xfer->nframes) {
900190183Sthompsa			if (xfer->flags_int.control_xfr) {
901190183Sthompsa				if (xfer->flags_int.control_act) {
902190183Sthompsa					temp.setup_alt_next = 0;
903190183Sthompsa				}
904190183Sthompsa			} else {
905190183Sthompsa				temp.setup_alt_next = 0;
906190183Sthompsa			}
907184610Salfred		}
908184610Salfred		if (temp.len == 0) {
909184610Salfred
910184610Salfred			/* make sure that we send an USB packet */
911184610Salfred
912184610Salfred			temp.short_pkt = 0;
913184610Salfred
914184610Salfred		} else {
915184610Salfred
916184610Salfred			/* regular data transfer */
917184610Salfred
918184610Salfred			temp.short_pkt = (xfer->flags.force_short_xfer) ? 0 : 1;
919184610Salfred		}
920184610Salfred
921184610Salfred		uss820dci_setup_standard_chain_sub(&temp);
922184610Salfred
923184610Salfred		if (xfer->flags_int.isochronous_xfr) {
924184610Salfred			temp.offset += temp.len;
925184610Salfred		} else {
926184610Salfred			/* get next Page Cache pointer */
927184610Salfred			temp.pc = xfer->frbuffers + x;
928184610Salfred		}
929184610Salfred	}
930184610Salfred
931190183Sthompsa	/* check for control transfer */
932190183Sthompsa	if (xfer->flags_int.control_xfr) {
933184610Salfred		uint8_t need_sync;
934184610Salfred
935190183Sthompsa		/* always setup a valid "pc" pointer for status and sync */
936190183Sthompsa		temp.pc = xfer->frbuffers + 0;
937184610Salfred		temp.len = 0;
938184610Salfred		temp.short_pkt = 0;
939190183Sthompsa		temp.setup_alt_next = 0;
940184610Salfred
941190183Sthompsa		/* check if we should append a status stage */
942190183Sthompsa		if (!xfer->flags_int.control_act) {
943190183Sthompsa
944190183Sthompsa			/*
945190183Sthompsa			 * Send a DATA1 message and invert the current
946190183Sthompsa			 * endpoint direction.
947190183Sthompsa			 */
948190183Sthompsa			if (xfer->endpoint & UE_DIR_IN) {
949190183Sthompsa				temp.func = &uss820dci_data_rx;
950190183Sthompsa				need_sync = 0;
951190183Sthompsa			} else {
952190183Sthompsa				temp.func = &uss820dci_data_tx;
953190183Sthompsa				need_sync = 1;
954190183Sthompsa			}
955184610Salfred			temp.len = 0;
956184610Salfred			temp.short_pkt = 0;
957184610Salfred
958184610Salfred			uss820dci_setup_standard_chain_sub(&temp);
959190183Sthompsa			if (need_sync) {
960190183Sthompsa				/* we need a SYNC point after TX */
961190183Sthompsa				temp.func = &uss820dci_data_tx_sync;
962190183Sthompsa				uss820dci_setup_standard_chain_sub(&temp);
963190183Sthompsa			}
964184610Salfred		}
965184610Salfred	}
966184610Salfred	/* must have at least one frame! */
967184610Salfred	td = temp.td;
968184610Salfred	xfer->td_transfer_last = td;
969184610Salfred}
970184610Salfred
971184610Salfredstatic void
972184610Salfreduss820dci_timeout(void *arg)
973184610Salfred{
974184610Salfred	struct usb2_xfer *xfer = arg;
975184610Salfred
976184610Salfred	DPRINTF("xfer=%p\n", xfer);
977184610Salfred
978187173Sthompsa	USB_BUS_LOCK_ASSERT(xfer->xroot->bus, MA_OWNED);
979184610Salfred
980184610Salfred	/* transfer is transferred */
981184610Salfred	uss820dci_device_done(xfer, USB_ERR_TIMEOUT);
982184610Salfred}
983184610Salfred
984184610Salfredstatic void
985184610Salfreduss820dci_intr_set(struct usb2_xfer *xfer, uint8_t set)
986184610Salfred{
987187173Sthompsa	struct uss820dci_softc *sc = USS820_DCI_BUS2SC(xfer->xroot->bus);
988184610Salfred	uint8_t ep_no = (xfer->endpoint & UE_ADDR);
989184610Salfred	uint8_t ep_reg;
990184610Salfred	uint8_t temp;
991184610Salfred
992184610Salfred	DPRINTFN(15, "endpoint 0x%02x\n", xfer->endpoint);
993184610Salfred
994184610Salfred	if (ep_no > 3) {
995184610Salfred		ep_reg = USS820_SBIE1;
996184610Salfred	} else {
997184610Salfred		ep_reg = USS820_SBIE;
998184610Salfred	}
999184610Salfred
1000184610Salfred	ep_no &= 3;
1001184610Salfred	ep_no = 1 << (2 * ep_no);
1002184610Salfred
1003184610Salfred	if (xfer->flags_int.control_xfr) {
1004184610Salfred		if (xfer->flags_int.control_hdr) {
1005184610Salfred			ep_no <<= 1;	/* RX interrupt only */
1006184610Salfred		} else {
1007184610Salfred			ep_no |= (ep_no << 1);	/* RX and TX interrupt */
1008184610Salfred		}
1009184610Salfred	} else {
1010184610Salfred		if (!(xfer->endpoint & UE_DIR_IN)) {
1011184610Salfred			ep_no <<= 1;
1012184610Salfred		}
1013184610Salfred	}
1014184610Salfred	temp = USS820_READ_1(sc, ep_reg);
1015184610Salfred	if (set) {
1016184610Salfred		temp |= ep_no;
1017184610Salfred	} else {
1018184610Salfred		temp &= ~ep_no;
1019184610Salfred	}
1020184610Salfred	USS820_WRITE_1(sc, ep_reg, temp);
1021184610Salfred}
1022184610Salfred
1023184610Salfredstatic void
1024184610Salfreduss820dci_start_standard_chain(struct usb2_xfer *xfer)
1025184610Salfred{
1026184610Salfred	DPRINTFN(9, "\n");
1027184610Salfred
1028184610Salfred	/* poll one time */
1029184610Salfred	if (uss820dci_xfer_do_fifo(xfer)) {
1030184610Salfred
1031184610Salfred		/*
1032184610Salfred		 * Only enable the endpoint interrupt when we are
1033184610Salfred		 * actually waiting for data, hence we are dealing
1034184610Salfred		 * with level triggered interrupts !
1035184610Salfred		 */
1036184610Salfred		uss820dci_intr_set(xfer, 1);
1037184610Salfred
1038184610Salfred		/* put transfer on interrupt queue */
1039187173Sthompsa		usb2_transfer_enqueue(&xfer->xroot->bus->intr_q, xfer);
1040184610Salfred
1041184610Salfred		/* start timeout, if any */
1042184610Salfred		if (xfer->timeout != 0) {
1043184610Salfred			usb2_transfer_timeout_ms(xfer,
1044184610Salfred			    &uss820dci_timeout, xfer->timeout);
1045184610Salfred		}
1046184610Salfred	}
1047184610Salfred}
1048184610Salfred
1049184610Salfredstatic void
1050184610Salfreduss820dci_root_intr_done(struct usb2_xfer *xfer,
1051184610Salfred    struct usb2_sw_transfer *std)
1052184610Salfred{
1053187173Sthompsa	struct uss820dci_softc *sc = USS820_DCI_BUS2SC(xfer->xroot->bus);
1054184610Salfred
1055184610Salfred	DPRINTFN(9, "\n");
1056184610Salfred
1057184824Sthompsa	USB_BUS_LOCK_ASSERT(&sc->sc_bus, MA_OWNED);
1058184610Salfred
1059184610Salfred	if (std->state != USB_SW_TR_PRE_DATA) {
1060184610Salfred		if (std->state == USB_SW_TR_PRE_CALLBACK) {
1061184610Salfred			/* transfer transferred */
1062184610Salfred			uss820dci_device_done(xfer, std->err);
1063184610Salfred		}
1064184610Salfred		goto done;
1065184610Salfred	}
1066184610Salfred	/* setup buffer */
1067184610Salfred	std->ptr = sc->sc_hub_idata;
1068184610Salfred	std->len = sizeof(sc->sc_hub_idata);
1069184610Salfred
1070184610Salfred	/* set port bit */
1071184610Salfred	sc->sc_hub_idata[0] = 0x02;	/* we only have one port */
1072184610Salfred
1073184610Salfreddone:
1074184610Salfred	return;
1075184610Salfred}
1076184610Salfred
1077184610Salfredstatic usb2_error_t
1078184610Salfreduss820dci_standard_done_sub(struct usb2_xfer *xfer)
1079184610Salfred{
1080184610Salfred	struct uss820dci_td *td;
1081184610Salfred	uint32_t len;
1082184610Salfred	uint8_t error;
1083184610Salfred
1084184610Salfred	DPRINTFN(9, "\n");
1085184610Salfred
1086184610Salfred	td = xfer->td_transfer_cache;
1087184610Salfred
1088184610Salfred	do {
1089184610Salfred		len = td->remainder;
1090184610Salfred
1091184610Salfred		if (xfer->aframes != xfer->nframes) {
1092184610Salfred			/*
1093184610Salfred		         * Verify the length and subtract
1094184610Salfred		         * the remainder from "frlengths[]":
1095184610Salfred		         */
1096184610Salfred			if (len > xfer->frlengths[xfer->aframes]) {
1097184610Salfred				td->error = 1;
1098184610Salfred			} else {
1099184610Salfred				xfer->frlengths[xfer->aframes] -= len;
1100184610Salfred			}
1101184610Salfred		}
1102184610Salfred		/* Check for transfer error */
1103184610Salfred		if (td->error) {
1104184610Salfred			/* the transfer is finished */
1105184610Salfred			error = 1;
1106184610Salfred			td = NULL;
1107184610Salfred			break;
1108184610Salfred		}
1109184610Salfred		/* Check for short transfer */
1110184610Salfred		if (len > 0) {
1111184610Salfred			if (xfer->flags_int.short_frames_ok) {
1112184610Salfred				/* follow alt next */
1113184610Salfred				if (td->alt_next) {
1114184610Salfred					td = td->obj_next;
1115184610Salfred				} else {
1116184610Salfred					td = NULL;
1117184610Salfred				}
1118184610Salfred			} else {
1119184610Salfred				/* the transfer is finished */
1120184610Salfred				td = NULL;
1121184610Salfred			}
1122184610Salfred			error = 0;
1123184610Salfred			break;
1124184610Salfred		}
1125184610Salfred		td = td->obj_next;
1126184610Salfred
1127184610Salfred		/* this USB frame is complete */
1128184610Salfred		error = 0;
1129184610Salfred		break;
1130184610Salfred
1131184610Salfred	} while (0);
1132184610Salfred
1133184610Salfred	/* update transfer cache */
1134184610Salfred
1135184610Salfred	xfer->td_transfer_cache = td;
1136184610Salfred
1137184610Salfred	return (error ?
1138184610Salfred	    USB_ERR_STALLED : USB_ERR_NORMAL_COMPLETION);
1139184610Salfred}
1140184610Salfred
1141184610Salfredstatic void
1142184610Salfreduss820dci_standard_done(struct usb2_xfer *xfer)
1143184610Salfred{
1144184610Salfred	usb2_error_t err = 0;
1145184610Salfred
1146184610Salfred	DPRINTFN(13, "xfer=%p pipe=%p transfer done\n",
1147184610Salfred	    xfer, xfer->pipe);
1148184610Salfred
1149184610Salfred	/* reset scanner */
1150184610Salfred
1151184610Salfred	xfer->td_transfer_cache = xfer->td_transfer_first;
1152184610Salfred
1153184610Salfred	if (xfer->flags_int.control_xfr) {
1154184610Salfred
1155184610Salfred		if (xfer->flags_int.control_hdr) {
1156184610Salfred
1157184610Salfred			err = uss820dci_standard_done_sub(xfer);
1158184610Salfred		}
1159184610Salfred		xfer->aframes = 1;
1160184610Salfred
1161184610Salfred		if (xfer->td_transfer_cache == NULL) {
1162184610Salfred			goto done;
1163184610Salfred		}
1164184610Salfred	}
1165184610Salfred	while (xfer->aframes != xfer->nframes) {
1166184610Salfred
1167184610Salfred		err = uss820dci_standard_done_sub(xfer);
1168184610Salfred		xfer->aframes++;
1169184610Salfred
1170184610Salfred		if (xfer->td_transfer_cache == NULL) {
1171184610Salfred			goto done;
1172184610Salfred		}
1173184610Salfred	}
1174184610Salfred
1175184610Salfred	if (xfer->flags_int.control_xfr &&
1176184610Salfred	    !xfer->flags_int.control_act) {
1177184610Salfred
1178184610Salfred		err = uss820dci_standard_done_sub(xfer);
1179184610Salfred	}
1180184610Salfreddone:
1181184610Salfred	uss820dci_device_done(xfer, err);
1182184610Salfred}
1183184610Salfred
1184184610Salfred/*------------------------------------------------------------------------*
1185184610Salfred *	uss820dci_device_done
1186184610Salfred *
1187184610Salfred * NOTE: this function can be called more than one time on the
1188184610Salfred * same USB transfer!
1189184610Salfred *------------------------------------------------------------------------*/
1190184610Salfredstatic void
1191184610Salfreduss820dci_device_done(struct usb2_xfer *xfer, usb2_error_t error)
1192184610Salfred{
1193187173Sthompsa	USB_BUS_LOCK_ASSERT(xfer->xroot->bus, MA_OWNED);
1194184610Salfred
1195184610Salfred	DPRINTFN(2, "xfer=%p, pipe=%p, error=%d\n",
1196184610Salfred	    xfer, xfer->pipe, error);
1197184610Salfred
1198184610Salfred	if (xfer->flags_int.usb2_mode == USB_MODE_DEVICE) {
1199184610Salfred		uss820dci_intr_set(xfer, 0);
1200184610Salfred	}
1201184610Salfred	/* dequeue transfer and start next transfer */
1202184610Salfred	usb2_transfer_done(xfer, error);
1203184610Salfred}
1204184610Salfred
1205184610Salfredstatic void
1206184610Salfreduss820dci_set_stall(struct usb2_device *udev, struct usb2_xfer *xfer,
1207184610Salfred    struct usb2_pipe *pipe)
1208184610Salfred{
1209184610Salfred	struct uss820dci_softc *sc;
1210184610Salfred	uint8_t ep_no;
1211184610Salfred	uint8_t ep_type;
1212184610Salfred	uint8_t ep_dir;
1213184610Salfred	uint8_t temp;
1214184610Salfred
1215184824Sthompsa	USB_BUS_LOCK_ASSERT(udev->bus, MA_OWNED);
1216184610Salfred
1217184610Salfred	DPRINTFN(5, "pipe=%p\n", pipe);
1218184610Salfred
1219184610Salfred	if (xfer) {
1220184610Salfred		/* cancel any ongoing transfers */
1221184610Salfred		uss820dci_device_done(xfer, USB_ERR_STALLED);
1222184610Salfred	}
1223184610Salfred	/* set FORCESTALL */
1224184610Salfred	sc = USS820_DCI_BUS2SC(udev->bus);
1225184610Salfred	ep_no = (pipe->edesc->bEndpointAddress & UE_ADDR);
1226184610Salfred	ep_dir = (pipe->edesc->bEndpointAddress & (UE_DIR_IN | UE_DIR_OUT));
1227184610Salfred	ep_type = (pipe->edesc->bmAttributes & UE_XFERTYPE);
1228184610Salfred
1229184610Salfred	if (ep_type == UE_CONTROL) {
1230184610Salfred		/* should not happen */
1231184610Salfred		return;
1232184610Salfred	}
1233184610Salfred	USS820_WRITE_1(sc, USS820_EPINDEX, ep_no);
1234184610Salfred
1235184610Salfred	if (ep_dir == UE_DIR_IN) {
1236184610Salfred		temp = USS820_EPCON_TXSTL;
1237184610Salfred	} else {
1238184610Salfred		temp = USS820_EPCON_RXSTL;
1239184610Salfred	}
1240184610Salfred	uss820dci_update_shared_1(sc, USS820_EPCON, 0xFF, temp);
1241184610Salfred}
1242184610Salfred
1243184610Salfredstatic void
1244184610Salfreduss820dci_clear_stall_sub(struct uss820dci_softc *sc,
1245184610Salfred    uint8_t ep_no, uint8_t ep_type, uint8_t ep_dir)
1246184610Salfred{
1247184610Salfred	uint8_t temp;
1248184610Salfred
1249184610Salfred	if (ep_type == UE_CONTROL) {
1250184610Salfred		/* clearing stall is not needed */
1251184610Salfred		return;
1252184610Salfred	}
1253184610Salfred	/* select endpoint index */
1254184610Salfred	USS820_WRITE_1(sc, USS820_EPINDEX, ep_no);
1255184610Salfred
1256184610Salfred	/* clear stall and disable I/O transfers */
1257184610Salfred	if (ep_dir == UE_DIR_IN) {
1258184610Salfred		temp = 0xFF ^ (USS820_EPCON_TXOE |
1259184610Salfred		    USS820_EPCON_TXSTL);
1260184610Salfred	} else {
1261184610Salfred		temp = 0xFF ^ (USS820_EPCON_RXIE |
1262184610Salfred		    USS820_EPCON_RXSTL);
1263184610Salfred	}
1264184610Salfred	uss820dci_update_shared_1(sc, USS820_EPCON, temp, 0);
1265184610Salfred
1266184610Salfred	if (ep_dir == UE_DIR_IN) {
1267184610Salfred		/* reset data toggle */
1268184610Salfred		USS820_WRITE_1(sc, USS820_TXSTAT,
1269184610Salfred		    USS820_TXSTAT_TXSOVW);
1270184610Salfred
1271184610Salfred		/* reset FIFO */
1272184610Salfred		temp = USS820_READ_1(sc, USS820_TXCON);
1273184610Salfred		temp |= USS820_TXCON_TXCLR;
1274184610Salfred		USS820_WRITE_1(sc, USS820_TXCON, temp);
1275184610Salfred		temp &= ~USS820_TXCON_TXCLR;
1276184610Salfred		USS820_WRITE_1(sc, USS820_TXCON, temp);
1277184610Salfred	} else {
1278184610Salfred
1279184610Salfred		/* reset data toggle */
1280184610Salfred		uss820dci_update_shared_1(sc, USS820_RXSTAT,
1281184610Salfred		    0, USS820_RXSTAT_RXSOVW);
1282184610Salfred
1283184610Salfred		/* reset FIFO */
1284184610Salfred		temp = USS820_READ_1(sc, USS820_RXCON);
1285184610Salfred		temp |= USS820_RXCON_RXCLR;
1286184610Salfred		temp &= ~USS820_RXCON_RXFFRC;
1287184610Salfred		USS820_WRITE_1(sc, USS820_RXCON, temp);
1288184610Salfred		temp &= ~USS820_RXCON_RXCLR;
1289184610Salfred		USS820_WRITE_1(sc, USS820_RXCON, temp);
1290184610Salfred	}
1291184610Salfred}
1292184610Salfred
1293184610Salfredstatic void
1294184610Salfreduss820dci_clear_stall(struct usb2_device *udev, struct usb2_pipe *pipe)
1295184610Salfred{
1296184610Salfred	struct uss820dci_softc *sc;
1297184610Salfred	struct usb2_endpoint_descriptor *ed;
1298184610Salfred
1299184824Sthompsa	USB_BUS_LOCK_ASSERT(udev->bus, MA_OWNED);
1300184610Salfred
1301184610Salfred	DPRINTFN(5, "pipe=%p\n", pipe);
1302184610Salfred
1303184610Salfred	/* check mode */
1304184610Salfred	if (udev->flags.usb2_mode != USB_MODE_DEVICE) {
1305184610Salfred		/* not supported */
1306184610Salfred		return;
1307184610Salfred	}
1308184610Salfred	/* get softc */
1309184610Salfred	sc = USS820_DCI_BUS2SC(udev->bus);
1310184610Salfred
1311184610Salfred	/* get endpoint descriptor */
1312184610Salfred	ed = pipe->edesc;
1313184610Salfred
1314184610Salfred	/* reset endpoint */
1315184610Salfred	uss820dci_clear_stall_sub(sc,
1316184610Salfred	    (ed->bEndpointAddress & UE_ADDR),
1317184610Salfred	    (ed->bmAttributes & UE_XFERTYPE),
1318184610Salfred	    (ed->bEndpointAddress & (UE_DIR_IN | UE_DIR_OUT)));
1319184610Salfred}
1320184610Salfred
1321184610Salfredusb2_error_t
1322184610Salfreduss820dci_init(struct uss820dci_softc *sc)
1323184610Salfred{
1324184610Salfred	const struct usb2_hw_ep_profile *pf;
1325184610Salfred	uint8_t n;
1326184610Salfred	uint8_t temp;
1327184610Salfred
1328184610Salfred	DPRINTF("start\n");
1329184610Salfred
1330184610Salfred	/* set up the bus structure */
1331184610Salfred	sc->sc_bus.usbrev = USB_REV_1_1;
1332184610Salfred	sc->sc_bus.methods = &uss820dci_bus_methods;
1333184610Salfred
1334184824Sthompsa	USB_BUS_LOCK(&sc->sc_bus);
1335184610Salfred
1336184610Salfred	/* we always have VBUS */
1337184610Salfred	sc->sc_flags.status_vbus = 1;
1338184610Salfred
1339184610Salfred	/* reset the chip */
1340184610Salfred	USS820_WRITE_1(sc, USS820_SCR, USS820_SCR_SRESET);
1341184610Salfred	DELAY(100);
1342184610Salfred	USS820_WRITE_1(sc, USS820_SCR, 0);
1343184610Salfred
1344184610Salfred	/* wait for reset to complete */
1345184610Salfred	for (n = 0;; n++) {
1346184610Salfred
1347184610Salfred		temp = USS820_READ_1(sc, USS820_MCSR);
1348184610Salfred
1349184610Salfred		if (temp & USS820_MCSR_INIT) {
1350184610Salfred			break;
1351184610Salfred		}
1352184610Salfred		if (n == 100) {
1353184824Sthompsa			USB_BUS_UNLOCK(&sc->sc_bus);
1354184610Salfred			return (USB_ERR_INVAL);
1355184610Salfred		}
1356184610Salfred		/* wait a little for things to stabilise */
1357184610Salfred		DELAY(100);
1358184610Salfred	}
1359184610Salfred
1360184610Salfred	/* do a pulldown */
1361184610Salfred	uss820dci_pull_down(sc);
1362184610Salfred
1363184610Salfred	/* wait 10ms for pulldown to stabilise */
1364188409Sthompsa	usb2_pause_mtx(&sc->sc_bus.bus_mtx, hz / 100);
1365184610Salfred
1366184610Salfred	/* check hardware revision */
1367184610Salfred	temp = USS820_READ_1(sc, USS820_REV);
1368184610Salfred
1369184610Salfred	if (temp < 0x13) {
1370184824Sthompsa		USB_BUS_UNLOCK(&sc->sc_bus);
1371184610Salfred		return (USB_ERR_INVAL);
1372184610Salfred	}
1373184610Salfred	/* enable interrupts */
1374184610Salfred	USS820_WRITE_1(sc, USS820_SCR,
1375184610Salfred	    USS820_SCR_T_IRQ |
1376184610Salfred	    USS820_SCR_IE_RESET |
1377186730Salfred	/* USS820_SCR_RWUPE | */
1378184610Salfred	    USS820_SCR_IE_SUSP |
1379184610Salfred	    USS820_SCR_IRQPOL);
1380184610Salfred
1381184610Salfred	/* enable interrupts */
1382184610Salfred	USS820_WRITE_1(sc, USS820_SCRATCH,
1383184610Salfred	    USS820_SCRATCH_IE_RESUME);
1384184610Salfred
1385184610Salfred	/* enable features */
1386184610Salfred	USS820_WRITE_1(sc, USS820_MCSR,
1387184610Salfred	    USS820_MCSR_BDFEAT |
1388184610Salfred	    USS820_MCSR_FEAT);
1389184610Salfred
1390184610Salfred	sc->sc_flags.mcsr_feat = 1;
1391184610Salfred
1392184610Salfred	/* disable interrupts */
1393184610Salfred	USS820_WRITE_1(sc, USS820_SBIE, 0);
1394184610Salfred
1395184610Salfred	/* disable interrupts */
1396184610Salfred	USS820_WRITE_1(sc, USS820_SBIE1, 0);
1397184610Salfred
1398184610Salfred	/* disable all endpoints */
1399184610Salfred	for (n = 0; n != USS820_EP_MAX; n++) {
1400184610Salfred
1401184610Salfred		/* select endpoint */
1402184610Salfred		USS820_WRITE_1(sc, USS820_EPINDEX, n);
1403184610Salfred
1404184610Salfred		/* disable endpoint */
1405184610Salfred		uss820dci_update_shared_1(sc, USS820_EPCON, 0, 0);
1406184610Salfred	}
1407184610Salfred
1408184610Salfred	/*
1409184610Salfred	 * Initialise default values for some registers that cannot be
1410184610Salfred	 * changed during operation!
1411184610Salfred	 */
1412184610Salfred	for (n = 0; n != USS820_EP_MAX; n++) {
1413184610Salfred
1414184610Salfred		uss820dci_get_hw_ep_profile(NULL, &pf, n);
1415184610Salfred
1416184610Salfred		/* the maximum frame sizes should be the same */
1417184610Salfred		if (pf->max_in_frame_size != pf->max_out_frame_size) {
1418184610Salfred			DPRINTF("Max frame size mismatch %u != %u\n",
1419184610Salfred			    pf->max_in_frame_size, pf->max_out_frame_size);
1420184610Salfred		}
1421184610Salfred		if (pf->support_isochronous) {
1422184610Salfred			if (pf->max_in_frame_size <= 64) {
1423184610Salfred				temp = (USS820_TXCON_FFSZ_16_64 |
1424184610Salfred				    USS820_TXCON_TXISO |
1425184610Salfred				    USS820_TXCON_ATM);
1426184610Salfred			} else if (pf->max_in_frame_size <= 256) {
1427184610Salfred				temp = (USS820_TXCON_FFSZ_64_256 |
1428184610Salfred				    USS820_TXCON_TXISO |
1429184610Salfred				    USS820_TXCON_ATM);
1430184610Salfred			} else if (pf->max_in_frame_size <= 512) {
1431184610Salfred				temp = (USS820_TXCON_FFSZ_8_512 |
1432184610Salfred				    USS820_TXCON_TXISO |
1433184610Salfred				    USS820_TXCON_ATM);
1434184610Salfred			} else {	/* 1024 bytes */
1435184610Salfred				temp = (USS820_TXCON_FFSZ_32_1024 |
1436184610Salfred				    USS820_TXCON_TXISO |
1437184610Salfred				    USS820_TXCON_ATM);
1438184610Salfred			}
1439184610Salfred		} else {
1440184610Salfred			if ((pf->max_in_frame_size <= 8) &&
1441184610Salfred			    (sc->sc_flags.mcsr_feat)) {
1442184610Salfred				temp = (USS820_TXCON_FFSZ_8_512 |
1443184610Salfred				    USS820_TXCON_ATM);
1444184610Salfred			} else if (pf->max_in_frame_size <= 16) {
1445184610Salfred				temp = (USS820_TXCON_FFSZ_16_64 |
1446184610Salfred				    USS820_TXCON_ATM);
1447184610Salfred			} else if ((pf->max_in_frame_size <= 32) &&
1448184610Salfred			    (sc->sc_flags.mcsr_feat)) {
1449184610Salfred				temp = (USS820_TXCON_FFSZ_32_1024 |
1450184610Salfred				    USS820_TXCON_ATM);
1451184610Salfred			} else {	/* 64 bytes */
1452184610Salfred				temp = (USS820_TXCON_FFSZ_64_256 |
1453184610Salfred				    USS820_TXCON_ATM);
1454184610Salfred			}
1455184610Salfred		}
1456184610Salfred
1457184610Salfred		/* need to configure the chip early */
1458184610Salfred
1459184610Salfred		USS820_WRITE_1(sc, USS820_EPINDEX, n);
1460184610Salfred		USS820_WRITE_1(sc, USS820_TXCON, temp);
1461184610Salfred		USS820_WRITE_1(sc, USS820_RXCON, temp);
1462184610Salfred
1463184610Salfred		if (pf->support_control) {
1464184610Salfred			temp = USS820_EPCON_CTLEP |
1465184610Salfred			    USS820_EPCON_RXSPM |
1466184610Salfred			    USS820_EPCON_RXIE |
1467184610Salfred			    USS820_EPCON_RXEPEN |
1468184610Salfred			    USS820_EPCON_TXOE |
1469184610Salfred			    USS820_EPCON_TXEPEN;
1470184610Salfred		} else {
1471184610Salfred			temp = USS820_EPCON_RXEPEN | USS820_EPCON_TXEPEN;
1472184610Salfred		}
1473184610Salfred
1474184610Salfred		uss820dci_update_shared_1(sc, USS820_EPCON, 0xFF, temp);
1475184610Salfred	}
1476184610Salfred
1477184824Sthompsa	USB_BUS_UNLOCK(&sc->sc_bus);
1478184610Salfred
1479184610Salfred	/* catch any lost interrupts */
1480184610Salfred
1481184610Salfred	uss820dci_do_poll(&sc->sc_bus);
1482184610Salfred
1483184610Salfred	return (0);			/* success */
1484184610Salfred}
1485184610Salfred
1486184610Salfredvoid
1487184610Salfreduss820dci_uninit(struct uss820dci_softc *sc)
1488184610Salfred{
1489184610Salfred	uint8_t temp;
1490184610Salfred
1491184824Sthompsa	USB_BUS_LOCK(&sc->sc_bus);
1492184610Salfred
1493184610Salfred	/* disable all interrupts */
1494184610Salfred	temp = USS820_READ_1(sc, USS820_SCR);
1495184610Salfred	temp &= ~USS820_SCR_T_IRQ;
1496184610Salfred	USS820_WRITE_1(sc, USS820_SCR, temp);
1497184610Salfred
1498184610Salfred	sc->sc_flags.port_powered = 0;
1499184610Salfred	sc->sc_flags.status_vbus = 0;
1500184610Salfred	sc->sc_flags.status_bus_reset = 0;
1501184610Salfred	sc->sc_flags.status_suspend = 0;
1502184610Salfred	sc->sc_flags.change_suspend = 0;
1503184610Salfred	sc->sc_flags.change_connect = 1;
1504184610Salfred
1505184610Salfred	uss820dci_pull_down(sc);
1506184824Sthompsa	USB_BUS_UNLOCK(&sc->sc_bus);
1507184610Salfred}
1508184610Salfred
1509184610Salfredvoid
1510184610Salfreduss820dci_suspend(struct uss820dci_softc *sc)
1511184610Salfred{
1512184610Salfred	return;
1513184610Salfred}
1514184610Salfred
1515184610Salfredvoid
1516184610Salfreduss820dci_resume(struct uss820dci_softc *sc)
1517184610Salfred{
1518184610Salfred	return;
1519184610Salfred}
1520184610Salfred
1521184610Salfredstatic void
1522184610Salfreduss820dci_do_poll(struct usb2_bus *bus)
1523184610Salfred{
1524184610Salfred	struct uss820dci_softc *sc = USS820_DCI_BUS2SC(bus);
1525184610Salfred
1526184824Sthompsa	USB_BUS_LOCK(&sc->sc_bus);
1527184610Salfred	uss820dci_interrupt_poll(sc);
1528184610Salfred	uss820dci_root_ctrl_poll(sc);
1529184824Sthompsa	USB_BUS_UNLOCK(&sc->sc_bus);
1530184610Salfred}
1531184610Salfred
1532184610Salfred/*------------------------------------------------------------------------*
1533184610Salfred * at91dci bulk support
1534184610Salfred *------------------------------------------------------------------------*/
1535184610Salfredstatic void
1536184610Salfreduss820dci_device_bulk_open(struct usb2_xfer *xfer)
1537184610Salfred{
1538184610Salfred	return;
1539184610Salfred}
1540184610Salfred
1541184610Salfredstatic void
1542184610Salfreduss820dci_device_bulk_close(struct usb2_xfer *xfer)
1543184610Salfred{
1544184610Salfred	uss820dci_device_done(xfer, USB_ERR_CANCELLED);
1545184610Salfred}
1546184610Salfred
1547184610Salfredstatic void
1548184610Salfreduss820dci_device_bulk_enter(struct usb2_xfer *xfer)
1549184610Salfred{
1550184610Salfred	return;
1551184610Salfred}
1552184610Salfred
1553184610Salfredstatic void
1554184610Salfreduss820dci_device_bulk_start(struct usb2_xfer *xfer)
1555184610Salfred{
1556184610Salfred	/* setup TDs */
1557184610Salfred	uss820dci_setup_standard_chain(xfer);
1558184610Salfred	uss820dci_start_standard_chain(xfer);
1559184610Salfred}
1560184610Salfred
1561184610Salfredstruct usb2_pipe_methods uss820dci_device_bulk_methods =
1562184610Salfred{
1563184610Salfred	.open = uss820dci_device_bulk_open,
1564184610Salfred	.close = uss820dci_device_bulk_close,
1565184610Salfred	.enter = uss820dci_device_bulk_enter,
1566184610Salfred	.start = uss820dci_device_bulk_start,
1567184610Salfred	.enter_is_cancelable = 1,
1568184610Salfred	.start_is_cancelable = 1,
1569184610Salfred};
1570184610Salfred
1571184610Salfred/*------------------------------------------------------------------------*
1572184610Salfred * at91dci control support
1573184610Salfred *------------------------------------------------------------------------*/
1574184610Salfredstatic void
1575184610Salfreduss820dci_device_ctrl_open(struct usb2_xfer *xfer)
1576184610Salfred{
1577184610Salfred	return;
1578184610Salfred}
1579184610Salfred
1580184610Salfredstatic void
1581184610Salfreduss820dci_device_ctrl_close(struct usb2_xfer *xfer)
1582184610Salfred{
1583184610Salfred	uss820dci_device_done(xfer, USB_ERR_CANCELLED);
1584184610Salfred}
1585184610Salfred
1586184610Salfredstatic void
1587184610Salfreduss820dci_device_ctrl_enter(struct usb2_xfer *xfer)
1588184610Salfred{
1589184610Salfred	return;
1590184610Salfred}
1591184610Salfred
1592184610Salfredstatic void
1593184610Salfreduss820dci_device_ctrl_start(struct usb2_xfer *xfer)
1594184610Salfred{
1595184610Salfred	/* setup TDs */
1596184610Salfred	uss820dci_setup_standard_chain(xfer);
1597184610Salfred	uss820dci_start_standard_chain(xfer);
1598184610Salfred}
1599184610Salfred
1600184610Salfredstruct usb2_pipe_methods uss820dci_device_ctrl_methods =
1601184610Salfred{
1602184610Salfred	.open = uss820dci_device_ctrl_open,
1603184610Salfred	.close = uss820dci_device_ctrl_close,
1604184610Salfred	.enter = uss820dci_device_ctrl_enter,
1605184610Salfred	.start = uss820dci_device_ctrl_start,
1606184610Salfred	.enter_is_cancelable = 1,
1607184610Salfred	.start_is_cancelable = 1,
1608184610Salfred};
1609184610Salfred
1610184610Salfred/*------------------------------------------------------------------------*
1611184610Salfred * at91dci interrupt support
1612184610Salfred *------------------------------------------------------------------------*/
1613184610Salfredstatic void
1614184610Salfreduss820dci_device_intr_open(struct usb2_xfer *xfer)
1615184610Salfred{
1616184610Salfred	return;
1617184610Salfred}
1618184610Salfred
1619184610Salfredstatic void
1620184610Salfreduss820dci_device_intr_close(struct usb2_xfer *xfer)
1621184610Salfred{
1622184610Salfred	uss820dci_device_done(xfer, USB_ERR_CANCELLED);
1623184610Salfred}
1624184610Salfred
1625184610Salfredstatic void
1626184610Salfreduss820dci_device_intr_enter(struct usb2_xfer *xfer)
1627184610Salfred{
1628184610Salfred	return;
1629184610Salfred}
1630184610Salfred
1631184610Salfredstatic void
1632184610Salfreduss820dci_device_intr_start(struct usb2_xfer *xfer)
1633184610Salfred{
1634184610Salfred	/* setup TDs */
1635184610Salfred	uss820dci_setup_standard_chain(xfer);
1636184610Salfred	uss820dci_start_standard_chain(xfer);
1637184610Salfred}
1638184610Salfred
1639184610Salfredstruct usb2_pipe_methods uss820dci_device_intr_methods =
1640184610Salfred{
1641184610Salfred	.open = uss820dci_device_intr_open,
1642184610Salfred	.close = uss820dci_device_intr_close,
1643184610Salfred	.enter = uss820dci_device_intr_enter,
1644184610Salfred	.start = uss820dci_device_intr_start,
1645184610Salfred	.enter_is_cancelable = 1,
1646184610Salfred	.start_is_cancelable = 1,
1647184610Salfred};
1648184610Salfred
1649184610Salfred/*------------------------------------------------------------------------*
1650184610Salfred * at91dci full speed isochronous support
1651184610Salfred *------------------------------------------------------------------------*/
1652184610Salfredstatic void
1653184610Salfreduss820dci_device_isoc_fs_open(struct usb2_xfer *xfer)
1654184610Salfred{
1655184610Salfred	return;
1656184610Salfred}
1657184610Salfred
1658184610Salfredstatic void
1659184610Salfreduss820dci_device_isoc_fs_close(struct usb2_xfer *xfer)
1660184610Salfred{
1661184610Salfred	uss820dci_device_done(xfer, USB_ERR_CANCELLED);
1662184610Salfred}
1663184610Salfred
1664184610Salfredstatic void
1665184610Salfreduss820dci_device_isoc_fs_enter(struct usb2_xfer *xfer)
1666184610Salfred{
1667187173Sthompsa	struct uss820dci_softc *sc = USS820_DCI_BUS2SC(xfer->xroot->bus);
1668184610Salfred	uint32_t temp;
1669184610Salfred	uint32_t nframes;
1670184610Salfred
1671184610Salfred	DPRINTFN(6, "xfer=%p next=%d nframes=%d\n",
1672184610Salfred	    xfer, xfer->pipe->isoc_next, xfer->nframes);
1673184610Salfred
1674184610Salfred	/* get the current frame index - we don't need the high bits */
1675184610Salfred
1676184610Salfred	nframes = USS820_READ_1(sc, USS820_SOFL);
1677184610Salfred
1678184610Salfred	/*
1679184610Salfred	 * check if the frame index is within the window where the
1680184610Salfred	 * frames will be inserted
1681184610Salfred	 */
1682184610Salfred	temp = (nframes - xfer->pipe->isoc_next) & USS820_SOFL_MASK;
1683184610Salfred
1684184610Salfred	if ((xfer->pipe->is_synced == 0) ||
1685184610Salfred	    (temp < xfer->nframes)) {
1686184610Salfred		/*
1687184610Salfred		 * If there is data underflow or the pipe queue is
1688184610Salfred		 * empty we schedule the transfer a few frames ahead
1689184610Salfred		 * of the current frame position. Else two isochronous
1690184610Salfred		 * transfers might overlap.
1691184610Salfred		 */
1692184610Salfred		xfer->pipe->isoc_next = (nframes + 3) & USS820_SOFL_MASK;
1693184610Salfred		xfer->pipe->is_synced = 1;
1694184610Salfred		DPRINTFN(3, "start next=%d\n", xfer->pipe->isoc_next);
1695184610Salfred	}
1696184610Salfred	/*
1697184610Salfred	 * compute how many milliseconds the insertion is ahead of the
1698184610Salfred	 * current frame position:
1699184610Salfred	 */
1700184610Salfred	temp = (xfer->pipe->isoc_next - nframes) & USS820_SOFL_MASK;
1701184610Salfred
1702184610Salfred	/*
1703184610Salfred	 * pre-compute when the isochronous transfer will be finished:
1704184610Salfred	 */
1705184610Salfred	xfer->isoc_time_complete =
1706184610Salfred	    usb2_isoc_time_expand(&sc->sc_bus, nframes) + temp +
1707184610Salfred	    xfer->nframes;
1708184610Salfred
1709184610Salfred	/* compute frame number for next insertion */
1710184610Salfred	xfer->pipe->isoc_next += xfer->nframes;
1711184610Salfred
1712184610Salfred	/* setup TDs */
1713184610Salfred	uss820dci_setup_standard_chain(xfer);
1714184610Salfred}
1715184610Salfred
1716184610Salfredstatic void
1717184610Salfreduss820dci_device_isoc_fs_start(struct usb2_xfer *xfer)
1718184610Salfred{
1719184610Salfred	/* start TD chain */
1720184610Salfred	uss820dci_start_standard_chain(xfer);
1721184610Salfred}
1722184610Salfred
1723184610Salfredstruct usb2_pipe_methods uss820dci_device_isoc_fs_methods =
1724184610Salfred{
1725184610Salfred	.open = uss820dci_device_isoc_fs_open,
1726184610Salfred	.close = uss820dci_device_isoc_fs_close,
1727184610Salfred	.enter = uss820dci_device_isoc_fs_enter,
1728184610Salfred	.start = uss820dci_device_isoc_fs_start,
1729184610Salfred	.enter_is_cancelable = 1,
1730184610Salfred	.start_is_cancelable = 1,
1731184610Salfred};
1732184610Salfred
1733184610Salfred/*------------------------------------------------------------------------*
1734184610Salfred * at91dci root control support
1735184610Salfred *------------------------------------------------------------------------*
1736184610Salfred * simulate a hardware HUB by handling
1737184610Salfred * all the necessary requests
1738184610Salfred *------------------------------------------------------------------------*/
1739184610Salfred
1740184610Salfredstatic void
1741184610Salfreduss820dci_root_ctrl_open(struct usb2_xfer *xfer)
1742184610Salfred{
1743184610Salfred	return;
1744184610Salfred}
1745184610Salfred
1746184610Salfredstatic void
1747184610Salfreduss820dci_root_ctrl_close(struct usb2_xfer *xfer)
1748184610Salfred{
1749187173Sthompsa	struct uss820dci_softc *sc = USS820_DCI_BUS2SC(xfer->xroot->bus);
1750184610Salfred
1751184610Salfred	if (sc->sc_root_ctrl.xfer == xfer) {
1752184610Salfred		sc->sc_root_ctrl.xfer = NULL;
1753184610Salfred	}
1754184610Salfred	uss820dci_device_done(xfer, USB_ERR_CANCELLED);
1755184610Salfred}
1756184610Salfred
1757184610Salfred/*
1758184610Salfred * USB descriptors for the virtual Root HUB:
1759184610Salfred */
1760184610Salfred
1761184610Salfredstatic const struct usb2_device_descriptor uss820dci_devd = {
1762184610Salfred	.bLength = sizeof(struct usb2_device_descriptor),
1763184610Salfred	.bDescriptorType = UDESC_DEVICE,
1764184610Salfred	.bcdUSB = {0x00, 0x02},
1765184610Salfred	.bDeviceClass = UDCLASS_HUB,
1766184610Salfred	.bDeviceSubClass = UDSUBCLASS_HUB,
1767184610Salfred	.bDeviceProtocol = UDPROTO_HSHUBSTT,
1768184610Salfred	.bMaxPacketSize = 64,
1769184610Salfred	.bcdDevice = {0x00, 0x01},
1770184610Salfred	.iManufacturer = 1,
1771184610Salfred	.iProduct = 2,
1772184610Salfred	.bNumConfigurations = 1,
1773184610Salfred};
1774184610Salfred
1775184610Salfredstatic const struct usb2_device_qualifier uss820dci_odevd = {
1776184610Salfred	.bLength = sizeof(struct usb2_device_qualifier),
1777184610Salfred	.bDescriptorType = UDESC_DEVICE_QUALIFIER,
1778184610Salfred	.bcdUSB = {0x00, 0x02},
1779184610Salfred	.bDeviceClass = UDCLASS_HUB,
1780184610Salfred	.bDeviceSubClass = UDSUBCLASS_HUB,
1781184610Salfred	.bDeviceProtocol = UDPROTO_FSHUB,
1782184610Salfred	.bMaxPacketSize0 = 0,
1783184610Salfred	.bNumConfigurations = 0,
1784184610Salfred};
1785184610Salfred
1786184610Salfredstatic const struct uss820dci_config_desc uss820dci_confd = {
1787184610Salfred	.confd = {
1788184610Salfred		.bLength = sizeof(struct usb2_config_descriptor),
1789184610Salfred		.bDescriptorType = UDESC_CONFIG,
1790184610Salfred		.wTotalLength[0] = sizeof(uss820dci_confd),
1791184610Salfred		.bNumInterface = 1,
1792184610Salfred		.bConfigurationValue = 1,
1793184610Salfred		.iConfiguration = 0,
1794184610Salfred		.bmAttributes = UC_SELF_POWERED,
1795184610Salfred		.bMaxPower = 0,
1796184610Salfred	},
1797184610Salfred	.ifcd = {
1798184610Salfred		.bLength = sizeof(struct usb2_interface_descriptor),
1799184610Salfred		.bDescriptorType = UDESC_INTERFACE,
1800184610Salfred		.bNumEndpoints = 1,
1801184610Salfred		.bInterfaceClass = UICLASS_HUB,
1802184610Salfred		.bInterfaceSubClass = UISUBCLASS_HUB,
1803184610Salfred		.bInterfaceProtocol = UIPROTO_HSHUBSTT,
1804184610Salfred	},
1805184610Salfred
1806184610Salfred	.endpd = {
1807184610Salfred		.bLength = sizeof(struct usb2_endpoint_descriptor),
1808184610Salfred		.bDescriptorType = UDESC_ENDPOINT,
1809184610Salfred		.bEndpointAddress = (UE_DIR_IN | USS820_DCI_INTR_ENDPT),
1810184610Salfred		.bmAttributes = UE_INTERRUPT,
1811184610Salfred		.wMaxPacketSize[0] = 8,
1812184610Salfred		.bInterval = 255,
1813184610Salfred	},
1814184610Salfred};
1815184610Salfred
1816184610Salfredstatic const struct usb2_hub_descriptor_min uss820dci_hubd = {
1817184610Salfred	.bDescLength = sizeof(uss820dci_hubd),
1818184610Salfred	.bDescriptorType = UDESC_HUB,
1819184610Salfred	.bNbrPorts = 1,
1820184610Salfred	.wHubCharacteristics[0] =
1821184610Salfred	(UHD_PWR_NO_SWITCH | UHD_OC_INDIVIDUAL) & 0xFF,
1822184610Salfred	.wHubCharacteristics[1] =
1823187183Sthompsa	(UHD_PWR_NO_SWITCH | UHD_OC_INDIVIDUAL) >> 8,
1824184610Salfred	.bPwrOn2PwrGood = 50,
1825184610Salfred	.bHubContrCurrent = 0,
1826184610Salfred	.DeviceRemovable = {0},		/* port is removable */
1827184610Salfred};
1828184610Salfred
1829184610Salfred#define	STRING_LANG \
1830184610Salfred  0x09, 0x04,				/* American English */
1831184610Salfred
1832184610Salfred#define	STRING_VENDOR \
1833184610Salfred  'A', 0, 'G', 0, 'E', 0, 'R', 0, 'E', 0
1834184610Salfred
1835184610Salfred#define	STRING_PRODUCT \
1836184610Salfred  'D', 0, 'C', 0, 'I', 0, ' ', 0, 'R', 0, \
1837184610Salfred  'o', 0, 'o', 0, 't', 0, ' ', 0, 'H', 0, \
1838184610Salfred  'U', 0, 'B', 0,
1839184610Salfred
1840184610SalfredUSB_MAKE_STRING_DESC(STRING_LANG, uss820dci_langtab);
1841184610SalfredUSB_MAKE_STRING_DESC(STRING_VENDOR, uss820dci_vendor);
1842184610SalfredUSB_MAKE_STRING_DESC(STRING_PRODUCT, uss820dci_product);
1843184610Salfred
1844184610Salfredstatic void
1845184610Salfreduss820dci_root_ctrl_enter(struct usb2_xfer *xfer)
1846184610Salfred{
1847184610Salfred	return;
1848184610Salfred}
1849184610Salfred
1850184610Salfredstatic void
1851184610Salfreduss820dci_root_ctrl_start(struct usb2_xfer *xfer)
1852184610Salfred{
1853187173Sthompsa	struct uss820dci_softc *sc = USS820_DCI_BUS2SC(xfer->xroot->bus);
1854184610Salfred
1855184610Salfred	sc->sc_root_ctrl.xfer = xfer;
1856184610Salfred
1857187173Sthompsa	usb2_bus_roothub_exec(xfer->xroot->bus);
1858184610Salfred}
1859184610Salfred
1860184610Salfredstatic void
1861187172Sthompsauss820dci_root_ctrl_task(struct usb2_bus *bus)
1862184610Salfred{
1863187172Sthompsa	uss820dci_root_ctrl_poll(USS820_DCI_BUS2SC(bus));
1864184610Salfred}
1865184610Salfred
1866184610Salfredstatic void
1867184610Salfreduss820dci_root_ctrl_done(struct usb2_xfer *xfer,
1868184610Salfred    struct usb2_sw_transfer *std)
1869184610Salfred{
1870187173Sthompsa	struct uss820dci_softc *sc = USS820_DCI_BUS2SC(xfer->xroot->bus);
1871184610Salfred	uint16_t value;
1872184610Salfred	uint16_t index;
1873184610Salfred
1874184824Sthompsa	USB_BUS_LOCK_ASSERT(&sc->sc_bus, MA_OWNED);
1875184610Salfred
1876184610Salfred	if (std->state != USB_SW_TR_SETUP) {
1877184610Salfred		if (std->state == USB_SW_TR_PRE_CALLBACK) {
1878184610Salfred			/* transfer transferred */
1879184610Salfred			uss820dci_device_done(xfer, std->err);
1880184610Salfred		}
1881184610Salfred		goto done;
1882184610Salfred	}
1883184610Salfred	/* buffer reset */
1884184610Salfred	std->ptr = USB_ADD_BYTES(&sc->sc_hub_temp, 0);
1885184610Salfred	std->len = 0;
1886184610Salfred
1887184610Salfred	value = UGETW(std->req.wValue);
1888184610Salfred	index = UGETW(std->req.wIndex);
1889184610Salfred
1890184610Salfred	/* demultiplex the control request */
1891184610Salfred
1892184610Salfred	switch (std->req.bmRequestType) {
1893184610Salfred	case UT_READ_DEVICE:
1894184610Salfred		switch (std->req.bRequest) {
1895184610Salfred		case UR_GET_DESCRIPTOR:
1896184610Salfred			goto tr_handle_get_descriptor;
1897184610Salfred		case UR_GET_CONFIG:
1898184610Salfred			goto tr_handle_get_config;
1899184610Salfred		case UR_GET_STATUS:
1900184610Salfred			goto tr_handle_get_status;
1901184610Salfred		default:
1902184610Salfred			goto tr_stalled;
1903184610Salfred		}
1904184610Salfred		break;
1905184610Salfred
1906184610Salfred	case UT_WRITE_DEVICE:
1907184610Salfred		switch (std->req.bRequest) {
1908184610Salfred		case UR_SET_ADDRESS:
1909184610Salfred			goto tr_handle_set_address;
1910184610Salfred		case UR_SET_CONFIG:
1911184610Salfred			goto tr_handle_set_config;
1912184610Salfred		case UR_CLEAR_FEATURE:
1913184610Salfred			goto tr_valid;	/* nop */
1914184610Salfred		case UR_SET_DESCRIPTOR:
1915184610Salfred			goto tr_valid;	/* nop */
1916184610Salfred		case UR_SET_FEATURE:
1917184610Salfred		default:
1918184610Salfred			goto tr_stalled;
1919184610Salfred		}
1920184610Salfred		break;
1921184610Salfred
1922184610Salfred	case UT_WRITE_ENDPOINT:
1923184610Salfred		switch (std->req.bRequest) {
1924184610Salfred		case UR_CLEAR_FEATURE:
1925184610Salfred			switch (UGETW(std->req.wValue)) {
1926184610Salfred			case UF_ENDPOINT_HALT:
1927184610Salfred				goto tr_handle_clear_halt;
1928184610Salfred			case UF_DEVICE_REMOTE_WAKEUP:
1929184610Salfred				goto tr_handle_clear_wakeup;
1930184610Salfred			default:
1931184610Salfred				goto tr_stalled;
1932184610Salfred			}
1933184610Salfred			break;
1934184610Salfred		case UR_SET_FEATURE:
1935184610Salfred			switch (UGETW(std->req.wValue)) {
1936184610Salfred			case UF_ENDPOINT_HALT:
1937184610Salfred				goto tr_handle_set_halt;
1938184610Salfred			case UF_DEVICE_REMOTE_WAKEUP:
1939184610Salfred				goto tr_handle_set_wakeup;
1940184610Salfred			default:
1941184610Salfred				goto tr_stalled;
1942184610Salfred			}
1943184610Salfred			break;
1944184610Salfred		case UR_SYNCH_FRAME:
1945184610Salfred			goto tr_valid;	/* nop */
1946184610Salfred		default:
1947184610Salfred			goto tr_stalled;
1948184610Salfred		}
1949184610Salfred		break;
1950184610Salfred
1951184610Salfred	case UT_READ_ENDPOINT:
1952184610Salfred		switch (std->req.bRequest) {
1953184610Salfred		case UR_GET_STATUS:
1954184610Salfred			goto tr_handle_get_ep_status;
1955184610Salfred		default:
1956184610Salfred			goto tr_stalled;
1957184610Salfred		}
1958184610Salfred		break;
1959184610Salfred
1960184610Salfred	case UT_WRITE_INTERFACE:
1961184610Salfred		switch (std->req.bRequest) {
1962184610Salfred		case UR_SET_INTERFACE:
1963184610Salfred			goto tr_handle_set_interface;
1964184610Salfred		case UR_CLEAR_FEATURE:
1965184610Salfred			goto tr_valid;	/* nop */
1966184610Salfred		case UR_SET_FEATURE:
1967184610Salfred		default:
1968184610Salfred			goto tr_stalled;
1969184610Salfred		}
1970184610Salfred		break;
1971184610Salfred
1972184610Salfred	case UT_READ_INTERFACE:
1973184610Salfred		switch (std->req.bRequest) {
1974184610Salfred		case UR_GET_INTERFACE:
1975184610Salfred			goto tr_handle_get_interface;
1976184610Salfred		case UR_GET_STATUS:
1977184610Salfred			goto tr_handle_get_iface_status;
1978184610Salfred		default:
1979184610Salfred			goto tr_stalled;
1980184610Salfred		}
1981184610Salfred		break;
1982184610Salfred
1983184610Salfred	case UT_WRITE_CLASS_INTERFACE:
1984184610Salfred	case UT_WRITE_VENDOR_INTERFACE:
1985184610Salfred		/* XXX forward */
1986184610Salfred		break;
1987184610Salfred
1988184610Salfred	case UT_READ_CLASS_INTERFACE:
1989184610Salfred	case UT_READ_VENDOR_INTERFACE:
1990184610Salfred		/* XXX forward */
1991184610Salfred		break;
1992184610Salfred
1993184610Salfred	case UT_WRITE_CLASS_DEVICE:
1994184610Salfred		switch (std->req.bRequest) {
1995184610Salfred		case UR_CLEAR_FEATURE:
1996184610Salfred			goto tr_valid;
1997184610Salfred		case UR_SET_DESCRIPTOR:
1998184610Salfred		case UR_SET_FEATURE:
1999184610Salfred			break;
2000184610Salfred		default:
2001184610Salfred			goto tr_stalled;
2002184610Salfred		}
2003184610Salfred		break;
2004184610Salfred
2005184610Salfred	case UT_WRITE_CLASS_OTHER:
2006184610Salfred		switch (std->req.bRequest) {
2007184610Salfred		case UR_CLEAR_FEATURE:
2008184610Salfred			goto tr_handle_clear_port_feature;
2009184610Salfred		case UR_SET_FEATURE:
2010184610Salfred			goto tr_handle_set_port_feature;
2011184610Salfred		case UR_CLEAR_TT_BUFFER:
2012184610Salfred		case UR_RESET_TT:
2013184610Salfred		case UR_STOP_TT:
2014184610Salfred			goto tr_valid;
2015184610Salfred
2016184610Salfred		default:
2017184610Salfred			goto tr_stalled;
2018184610Salfred		}
2019184610Salfred		break;
2020184610Salfred
2021184610Salfred	case UT_READ_CLASS_OTHER:
2022184610Salfred		switch (std->req.bRequest) {
2023184610Salfred		case UR_GET_TT_STATE:
2024184610Salfred			goto tr_handle_get_tt_state;
2025184610Salfred		case UR_GET_STATUS:
2026184610Salfred			goto tr_handle_get_port_status;
2027184610Salfred		default:
2028184610Salfred			goto tr_stalled;
2029184610Salfred		}
2030184610Salfred		break;
2031184610Salfred
2032184610Salfred	case UT_READ_CLASS_DEVICE:
2033184610Salfred		switch (std->req.bRequest) {
2034184610Salfred		case UR_GET_DESCRIPTOR:
2035184610Salfred			goto tr_handle_get_class_descriptor;
2036184610Salfred		case UR_GET_STATUS:
2037184610Salfred			goto tr_handle_get_class_status;
2038184610Salfred
2039184610Salfred		default:
2040184610Salfred			goto tr_stalled;
2041184610Salfred		}
2042184610Salfred		break;
2043184610Salfred	default:
2044184610Salfred		goto tr_stalled;
2045184610Salfred	}
2046184610Salfred	goto tr_valid;
2047184610Salfred
2048184610Salfredtr_handle_get_descriptor:
2049184610Salfred	switch (value >> 8) {
2050184610Salfred	case UDESC_DEVICE:
2051184610Salfred		if (value & 0xff) {
2052184610Salfred			goto tr_stalled;
2053184610Salfred		}
2054184610Salfred		std->len = sizeof(uss820dci_devd);
2055184610Salfred		std->ptr = USB_ADD_BYTES(&uss820dci_devd, 0);
2056184610Salfred		goto tr_valid;
2057184610Salfred	case UDESC_CONFIG:
2058184610Salfred		if (value & 0xff) {
2059184610Salfred			goto tr_stalled;
2060184610Salfred		}
2061184610Salfred		std->len = sizeof(uss820dci_confd);
2062184610Salfred		std->ptr = USB_ADD_BYTES(&uss820dci_confd, 0);
2063184610Salfred		goto tr_valid;
2064184610Salfred	case UDESC_STRING:
2065184610Salfred		switch (value & 0xff) {
2066184610Salfred		case 0:		/* Language table */
2067184610Salfred			std->len = sizeof(uss820dci_langtab);
2068184610Salfred			std->ptr = USB_ADD_BYTES(&uss820dci_langtab, 0);
2069184610Salfred			goto tr_valid;
2070184610Salfred
2071184610Salfred		case 1:		/* Vendor */
2072184610Salfred			std->len = sizeof(uss820dci_vendor);
2073184610Salfred			std->ptr = USB_ADD_BYTES(&uss820dci_vendor, 0);
2074184610Salfred			goto tr_valid;
2075184610Salfred
2076184610Salfred		case 2:		/* Product */
2077184610Salfred			std->len = sizeof(uss820dci_product);
2078184610Salfred			std->ptr = USB_ADD_BYTES(&uss820dci_product, 0);
2079184610Salfred			goto tr_valid;
2080184610Salfred		default:
2081184610Salfred			break;
2082184610Salfred		}
2083184610Salfred		break;
2084184610Salfred	default:
2085184610Salfred		goto tr_stalled;
2086184610Salfred	}
2087184610Salfred	goto tr_stalled;
2088184610Salfred
2089184610Salfredtr_handle_get_config:
2090184610Salfred	std->len = 1;
2091184610Salfred	sc->sc_hub_temp.wValue[0] = sc->sc_conf;
2092184610Salfred	goto tr_valid;
2093184610Salfred
2094184610Salfredtr_handle_get_status:
2095184610Salfred	std->len = 2;
2096184610Salfred	USETW(sc->sc_hub_temp.wValue, UDS_SELF_POWERED);
2097184610Salfred	goto tr_valid;
2098184610Salfred
2099184610Salfredtr_handle_set_address:
2100184610Salfred	if (value & 0xFF00) {
2101184610Salfred		goto tr_stalled;
2102184610Salfred	}
2103184610Salfred	sc->sc_rt_addr = value;
2104184610Salfred	goto tr_valid;
2105184610Salfred
2106184610Salfredtr_handle_set_config:
2107184610Salfred	if (value >= 2) {
2108184610Salfred		goto tr_stalled;
2109184610Salfred	}
2110184610Salfred	sc->sc_conf = value;
2111184610Salfred	goto tr_valid;
2112184610Salfred
2113184610Salfredtr_handle_get_interface:
2114184610Salfred	std->len = 1;
2115184610Salfred	sc->sc_hub_temp.wValue[0] = 0;
2116184610Salfred	goto tr_valid;
2117184610Salfred
2118184610Salfredtr_handle_get_tt_state:
2119184610Salfredtr_handle_get_class_status:
2120184610Salfredtr_handle_get_iface_status:
2121184610Salfredtr_handle_get_ep_status:
2122184610Salfred	std->len = 2;
2123184610Salfred	USETW(sc->sc_hub_temp.wValue, 0);
2124184610Salfred	goto tr_valid;
2125184610Salfred
2126184610Salfredtr_handle_set_halt:
2127184610Salfredtr_handle_set_interface:
2128184610Salfredtr_handle_set_wakeup:
2129184610Salfredtr_handle_clear_wakeup:
2130184610Salfredtr_handle_clear_halt:
2131184610Salfred	goto tr_valid;
2132184610Salfred
2133184610Salfredtr_handle_clear_port_feature:
2134184610Salfred	if (index != 1) {
2135184610Salfred		goto tr_stalled;
2136184610Salfred	}
2137184610Salfred	DPRINTFN(9, "UR_CLEAR_PORT_FEATURE on port %d\n", index);
2138184610Salfred
2139184610Salfred	switch (value) {
2140184610Salfred	case UHF_PORT_SUSPEND:
2141184610Salfred		uss820dci_wakeup_peer(sc);
2142184610Salfred		break;
2143184610Salfred
2144184610Salfred	case UHF_PORT_ENABLE:
2145184610Salfred		sc->sc_flags.port_enabled = 0;
2146184610Salfred		break;
2147184610Salfred
2148184610Salfred	case UHF_PORT_TEST:
2149184610Salfred	case UHF_PORT_INDICATOR:
2150184610Salfred	case UHF_C_PORT_ENABLE:
2151184610Salfred	case UHF_C_PORT_OVER_CURRENT:
2152184610Salfred	case UHF_C_PORT_RESET:
2153184610Salfred		/* nops */
2154184610Salfred		break;
2155184610Salfred	case UHF_PORT_POWER:
2156184610Salfred		sc->sc_flags.port_powered = 0;
2157184610Salfred		uss820dci_pull_down(sc);
2158184610Salfred		break;
2159184610Salfred	case UHF_C_PORT_CONNECTION:
2160184610Salfred		sc->sc_flags.change_connect = 0;
2161184610Salfred		break;
2162184610Salfred	case UHF_C_PORT_SUSPEND:
2163184610Salfred		sc->sc_flags.change_suspend = 0;
2164184610Salfred		break;
2165184610Salfred	default:
2166184610Salfred		std->err = USB_ERR_IOERROR;
2167184610Salfred		goto done;
2168184610Salfred	}
2169184610Salfred	goto tr_valid;
2170184610Salfred
2171184610Salfredtr_handle_set_port_feature:
2172184610Salfred	if (index != 1) {
2173184610Salfred		goto tr_stalled;
2174184610Salfred	}
2175184610Salfred	DPRINTFN(9, "UR_SET_PORT_FEATURE\n");
2176184610Salfred
2177184610Salfred	switch (value) {
2178184610Salfred	case UHF_PORT_ENABLE:
2179184610Salfred		sc->sc_flags.port_enabled = 1;
2180184610Salfred		break;
2181184610Salfred	case UHF_PORT_SUSPEND:
2182184610Salfred	case UHF_PORT_RESET:
2183184610Salfred	case UHF_PORT_TEST:
2184184610Salfred	case UHF_PORT_INDICATOR:
2185184610Salfred		/* nops */
2186184610Salfred		break;
2187184610Salfred	case UHF_PORT_POWER:
2188184610Salfred		sc->sc_flags.port_powered = 1;
2189184610Salfred		break;
2190184610Salfred	default:
2191184610Salfred		std->err = USB_ERR_IOERROR;
2192184610Salfred		goto done;
2193184610Salfred	}
2194184610Salfred	goto tr_valid;
2195184610Salfred
2196184610Salfredtr_handle_get_port_status:
2197184610Salfred
2198184610Salfred	DPRINTFN(9, "UR_GET_PORT_STATUS\n");
2199184610Salfred
2200184610Salfred	if (index != 1) {
2201184610Salfred		goto tr_stalled;
2202184610Salfred	}
2203184610Salfred	if (sc->sc_flags.status_vbus) {
2204184610Salfred		uss820dci_pull_up(sc);
2205184610Salfred	} else {
2206184610Salfred		uss820dci_pull_down(sc);
2207184610Salfred	}
2208184610Salfred
2209184610Salfred	/* Select FULL-speed and Device Side Mode */
2210184610Salfred
2211184610Salfred	value = UPS_PORT_MODE_DEVICE;
2212184610Salfred
2213184610Salfred	if (sc->sc_flags.port_powered) {
2214184610Salfred		value |= UPS_PORT_POWER;
2215184610Salfred	}
2216184610Salfred	if (sc->sc_flags.port_enabled) {
2217184610Salfred		value |= UPS_PORT_ENABLED;
2218184610Salfred	}
2219184610Salfred	if (sc->sc_flags.status_vbus &&
2220184610Salfred	    sc->sc_flags.status_bus_reset) {
2221184610Salfred		value |= UPS_CURRENT_CONNECT_STATUS;
2222184610Salfred	}
2223184610Salfred	if (sc->sc_flags.status_suspend) {
2224184610Salfred		value |= UPS_SUSPEND;
2225184610Salfred	}
2226184610Salfred	USETW(sc->sc_hub_temp.ps.wPortStatus, value);
2227184610Salfred
2228184610Salfred	value = 0;
2229184610Salfred
2230184610Salfred	if (sc->sc_flags.change_connect) {
2231184610Salfred		value |= UPS_C_CONNECT_STATUS;
2232184610Salfred	}
2233184610Salfred	if (sc->sc_flags.change_suspend) {
2234184610Salfred		value |= UPS_C_SUSPEND;
2235184610Salfred	}
2236184610Salfred	USETW(sc->sc_hub_temp.ps.wPortChange, value);
2237184610Salfred	std->len = sizeof(sc->sc_hub_temp.ps);
2238184610Salfred	goto tr_valid;
2239184610Salfred
2240184610Salfredtr_handle_get_class_descriptor:
2241184610Salfred	if (value & 0xFF) {
2242184610Salfred		goto tr_stalled;
2243184610Salfred	}
2244184610Salfred	std->ptr = USB_ADD_BYTES(&uss820dci_hubd, 0);
2245184610Salfred	std->len = sizeof(uss820dci_hubd);
2246184610Salfred	goto tr_valid;
2247184610Salfred
2248184610Salfredtr_stalled:
2249184610Salfred	std->err = USB_ERR_STALLED;
2250184610Salfredtr_valid:
2251184610Salfreddone:
2252184610Salfred	return;
2253184610Salfred}
2254184610Salfred
2255184610Salfredstatic void
2256184610Salfreduss820dci_root_ctrl_poll(struct uss820dci_softc *sc)
2257184610Salfred{
2258184610Salfred	usb2_sw_transfer(&sc->sc_root_ctrl,
2259184610Salfred	    &uss820dci_root_ctrl_done);
2260184610Salfred}
2261184610Salfred
2262184610Salfredstruct usb2_pipe_methods uss820dci_root_ctrl_methods =
2263184610Salfred{
2264184610Salfred	.open = uss820dci_root_ctrl_open,
2265184610Salfred	.close = uss820dci_root_ctrl_close,
2266184610Salfred	.enter = uss820dci_root_ctrl_enter,
2267184610Salfred	.start = uss820dci_root_ctrl_start,
2268184610Salfred	.enter_is_cancelable = 1,
2269184610Salfred	.start_is_cancelable = 0,
2270184610Salfred};
2271184610Salfred
2272184610Salfred/*------------------------------------------------------------------------*
2273184610Salfred * at91dci root interrupt support
2274184610Salfred *------------------------------------------------------------------------*/
2275184610Salfredstatic void
2276184610Salfreduss820dci_root_intr_open(struct usb2_xfer *xfer)
2277184610Salfred{
2278184610Salfred	return;
2279184610Salfred}
2280184610Salfred
2281184610Salfredstatic void
2282184610Salfreduss820dci_root_intr_close(struct usb2_xfer *xfer)
2283184610Salfred{
2284187173Sthompsa	struct uss820dci_softc *sc = USS820_DCI_BUS2SC(xfer->xroot->bus);
2285184610Salfred
2286184610Salfred	if (sc->sc_root_intr.xfer == xfer) {
2287184610Salfred		sc->sc_root_intr.xfer = NULL;
2288184610Salfred	}
2289184610Salfred	uss820dci_device_done(xfer, USB_ERR_CANCELLED);
2290184610Salfred}
2291184610Salfred
2292184610Salfredstatic void
2293184610Salfreduss820dci_root_intr_enter(struct usb2_xfer *xfer)
2294184610Salfred{
2295184610Salfred	return;
2296184610Salfred}
2297184610Salfred
2298184610Salfredstatic void
2299184610Salfreduss820dci_root_intr_start(struct usb2_xfer *xfer)
2300184610Salfred{
2301187173Sthompsa	struct uss820dci_softc *sc = USS820_DCI_BUS2SC(xfer->xroot->bus);
2302184610Salfred
2303184610Salfred	sc->sc_root_intr.xfer = xfer;
2304184610Salfred}
2305184610Salfred
2306184610Salfredstruct usb2_pipe_methods uss820dci_root_intr_methods =
2307184610Salfred{
2308184610Salfred	.open = uss820dci_root_intr_open,
2309184610Salfred	.close = uss820dci_root_intr_close,
2310184610Salfred	.enter = uss820dci_root_intr_enter,
2311184610Salfred	.start = uss820dci_root_intr_start,
2312184610Salfred	.enter_is_cancelable = 1,
2313184610Salfred	.start_is_cancelable = 1,
2314184610Salfred};
2315184610Salfred
2316184610Salfredstatic void
2317184610Salfreduss820dci_xfer_setup(struct usb2_setup_params *parm)
2318184610Salfred{
2319184610Salfred	const struct usb2_hw_ep_profile *pf;
2320184610Salfred	struct uss820dci_softc *sc;
2321184610Salfred	struct usb2_xfer *xfer;
2322184610Salfred	void *last_obj;
2323184610Salfred	uint32_t ntd;
2324184610Salfred	uint32_t n;
2325184610Salfred	uint8_t ep_no;
2326184610Salfred
2327184610Salfred	sc = USS820_DCI_BUS2SC(parm->udev->bus);
2328184610Salfred	xfer = parm->curr_xfer;
2329184610Salfred
2330184610Salfred	/*
2331184610Salfred	 * NOTE: This driver does not use any of the parameters that
2332184610Salfred	 * are computed from the following values. Just set some
2333184610Salfred	 * reasonable dummies:
2334184610Salfred	 */
2335184610Salfred	parm->hc_max_packet_size = 0x500;
2336184610Salfred	parm->hc_max_packet_count = 1;
2337184610Salfred	parm->hc_max_frame_size = 0x500;
2338184610Salfred
2339184610Salfred	usb2_transfer_setup_sub(parm);
2340184610Salfred
2341184610Salfred	/*
2342184610Salfred	 * compute maximum number of TDs
2343184610Salfred	 */
2344184610Salfred	if (parm->methods == &uss820dci_device_ctrl_methods) {
2345184610Salfred
2346184610Salfred		ntd = xfer->nframes + 1 /* STATUS */ + 1 /* SYNC */ ;
2347184610Salfred
2348184610Salfred	} else if (parm->methods == &uss820dci_device_bulk_methods) {
2349184610Salfred
2350184610Salfred		ntd = xfer->nframes + 1 /* SYNC */ ;
2351184610Salfred
2352184610Salfred	} else if (parm->methods == &uss820dci_device_intr_methods) {
2353184610Salfred
2354184610Salfred		ntd = xfer->nframes + 1 /* SYNC */ ;
2355184610Salfred
2356184610Salfred	} else if (parm->methods == &uss820dci_device_isoc_fs_methods) {
2357184610Salfred
2358184610Salfred		ntd = xfer->nframes + 1 /* SYNC */ ;
2359184610Salfred
2360184610Salfred	} else {
2361184610Salfred
2362184610Salfred		ntd = 0;
2363184610Salfred	}
2364184610Salfred
2365184610Salfred	/*
2366184610Salfred	 * check if "usb2_transfer_setup_sub" set an error
2367184610Salfred	 */
2368184610Salfred	if (parm->err) {
2369184610Salfred		return;
2370184610Salfred	}
2371184610Salfred	/*
2372184610Salfred	 * allocate transfer descriptors
2373184610Salfred	 */
2374184610Salfred	last_obj = NULL;
2375184610Salfred
2376184610Salfred	/*
2377184610Salfred	 * get profile stuff
2378184610Salfred	 */
2379184610Salfred	if (ntd) {
2380184610Salfred
2381184610Salfred		ep_no = xfer->endpoint & UE_ADDR;
2382184610Salfred		uss820dci_get_hw_ep_profile(parm->udev, &pf, ep_no);
2383184610Salfred
2384184610Salfred		if (pf == NULL) {
2385184610Salfred			/* should not happen */
2386184610Salfred			parm->err = USB_ERR_INVAL;
2387184610Salfred			return;
2388184610Salfred		}
2389184610Salfred	} else {
2390184610Salfred		ep_no = 0;
2391184610Salfred		pf = NULL;
2392184610Salfred	}
2393184610Salfred
2394184610Salfred	/* align data */
2395184610Salfred	parm->size[0] += ((-parm->size[0]) & (USB_HOST_ALIGN - 1));
2396184610Salfred
2397184610Salfred	for (n = 0; n != ntd; n++) {
2398184610Salfred
2399184610Salfred		struct uss820dci_td *td;
2400184610Salfred
2401184610Salfred		if (parm->buf) {
2402184610Salfred
2403184610Salfred			td = USB_ADD_BYTES(parm->buf, parm->size[0]);
2404184610Salfred
2405184610Salfred			/* init TD */
2406184610Salfred			td->io_tag = sc->sc_io_tag;
2407184610Salfred			td->io_hdl = sc->sc_io_hdl;
2408184610Salfred			td->max_packet_size = xfer->max_packet_size;
2409184610Salfred			td->rx_stat_reg = USS820_GET_REG(sc, USS820_RXSTAT);
2410184610Salfred			td->tx_stat_reg = USS820_GET_REG(sc, USS820_TXSTAT);
2411184610Salfred			td->rx_flag_reg = USS820_GET_REG(sc, USS820_RXFLG);
2412184610Salfred			td->tx_flag_reg = USS820_GET_REG(sc, USS820_TXFLG);
2413184610Salfred			td->rx_fifo_reg = USS820_GET_REG(sc, USS820_RXDAT);
2414184610Salfred			td->tx_fifo_reg = USS820_GET_REG(sc, USS820_TXDAT);
2415184610Salfred			td->rx_count_low_reg = USS820_GET_REG(sc, USS820_RXCNTL);
2416184610Salfred			td->rx_count_high_reg = USS820_GET_REG(sc, USS820_RXCNTH);
2417184610Salfred			td->tx_count_low_reg = USS820_GET_REG(sc, USS820_TXCNTL);
2418184610Salfred			td->tx_count_high_reg = USS820_GET_REG(sc, USS820_TXCNTH);
2419184610Salfred			td->rx_cntl_reg = USS820_GET_REG(sc, USS820_RXCON);
2420184610Salfred			td->tx_cntl_reg = USS820_GET_REG(sc, USS820_TXCON);
2421184610Salfred			td->pend_reg = USS820_GET_REG(sc, USS820_PEND);
2422184610Salfred			td->ep_reg = USS820_GET_REG(sc, USS820_EPINDEX);
2423184610Salfred			td->ep_index = ep_no;
2424184610Salfred			if (pf->support_multi_buffer &&
2425184610Salfred			    (parm->methods != &uss820dci_device_ctrl_methods)) {
2426184610Salfred				td->support_multi_buffer = 1;
2427184610Salfred			}
2428184610Salfred			td->obj_next = last_obj;
2429184610Salfred
2430184610Salfred			last_obj = td;
2431184610Salfred		}
2432184610Salfred		parm->size[0] += sizeof(*td);
2433184610Salfred	}
2434184610Salfred
2435184610Salfred	xfer->td_start[0] = last_obj;
2436184610Salfred}
2437184610Salfred
2438184610Salfredstatic void
2439184610Salfreduss820dci_xfer_unsetup(struct usb2_xfer *xfer)
2440184610Salfred{
2441184610Salfred	return;
2442184610Salfred}
2443184610Salfred
2444184610Salfredstatic void
2445184610Salfreduss820dci_pipe_init(struct usb2_device *udev, struct usb2_endpoint_descriptor *edesc,
2446184610Salfred    struct usb2_pipe *pipe)
2447184610Salfred{
2448184610Salfred	struct uss820dci_softc *sc = USS820_DCI_BUS2SC(udev->bus);
2449184610Salfred
2450184610Salfred	DPRINTFN(2, "pipe=%p, addr=%d, endpt=%d, mode=%d (%d)\n",
2451184610Salfred	    pipe, udev->address,
2452184610Salfred	    edesc->bEndpointAddress, udev->flags.usb2_mode,
2453184610Salfred	    sc->sc_rt_addr);
2454184610Salfred
2455184610Salfred	if (udev->device_index == sc->sc_rt_addr) {
2456184610Salfred
2457184610Salfred		if (udev->flags.usb2_mode != USB_MODE_HOST) {
2458184610Salfred			/* not supported */
2459184610Salfred			return;
2460184610Salfred		}
2461184610Salfred		switch (edesc->bEndpointAddress) {
2462184610Salfred		case USB_CONTROL_ENDPOINT:
2463184610Salfred			pipe->methods = &uss820dci_root_ctrl_methods;
2464184610Salfred			break;
2465184610Salfred		case UE_DIR_IN | USS820_DCI_INTR_ENDPT:
2466184610Salfred			pipe->methods = &uss820dci_root_intr_methods;
2467184610Salfred			break;
2468184610Salfred		default:
2469184610Salfred			/* do nothing */
2470184610Salfred			break;
2471184610Salfred		}
2472184610Salfred	} else {
2473184610Salfred
2474184610Salfred		if (udev->flags.usb2_mode != USB_MODE_DEVICE) {
2475184610Salfred			/* not supported */
2476184610Salfred			return;
2477184610Salfred		}
2478184610Salfred		if (udev->speed != USB_SPEED_FULL) {
2479184610Salfred			/* not supported */
2480184610Salfred			return;
2481184610Salfred		}
2482184610Salfred		switch (edesc->bmAttributes & UE_XFERTYPE) {
2483184610Salfred		case UE_CONTROL:
2484184610Salfred			pipe->methods = &uss820dci_device_ctrl_methods;
2485184610Salfred			break;
2486184610Salfred		case UE_INTERRUPT:
2487184610Salfred			pipe->methods = &uss820dci_device_intr_methods;
2488184610Salfred			break;
2489184610Salfred		case UE_ISOCHRONOUS:
2490184610Salfred			pipe->methods = &uss820dci_device_isoc_fs_methods;
2491184610Salfred			break;
2492184610Salfred		case UE_BULK:
2493184610Salfred			pipe->methods = &uss820dci_device_bulk_methods;
2494184610Salfred			break;
2495184610Salfred		default:
2496184610Salfred			/* do nothing */
2497184610Salfred			break;
2498184610Salfred		}
2499184610Salfred	}
2500184610Salfred}
2501184610Salfred
2502184610Salfredstruct usb2_bus_methods uss820dci_bus_methods =
2503184610Salfred{
2504184610Salfred	.pipe_init = &uss820dci_pipe_init,
2505184610Salfred	.xfer_setup = &uss820dci_xfer_setup,
2506184610Salfred	.xfer_unsetup = &uss820dci_xfer_unsetup,
2507184610Salfred	.get_hw_ep_profile = &uss820dci_get_hw_ep_profile,
2508184610Salfred	.set_stall = &uss820dci_set_stall,
2509184610Salfred	.clear_stall = &uss820dci_clear_stall,
2510187172Sthompsa	.roothub_exec = &uss820dci_root_ctrl_task,
2511184610Salfred};
2512