uss820dci.c revision 330897
1/* $FreeBSD: stable/11/sys/dev/usb/controller/uss820dci.c 330897 2018-03-14 03:19:51Z eadler $ */
2/*-
3 * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
4 *
5 * Copyright (c) 2008 Hans Petter Selasky <hselasky@FreeBSD.org>
6 * All rights reserved.
7 *
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
10 * are met:
11 * 1. Redistributions of source code must retain the above copyright
12 *    notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 *    notice, this list of conditions and the following disclaimer in the
15 *    documentation and/or other materials provided with the distribution.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
18 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20 * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
21 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27 * SUCH DAMAGE.
28 */
29
30/*
31 * This file contains the driver for the USS820 series USB Device
32 * Controller
33 *
34 * NOTE: The datasheet does not document everything.
35 */
36
37#ifdef USB_GLOBAL_INCLUDE_FILE
38#include USB_GLOBAL_INCLUDE_FILE
39#else
40#include <sys/stdint.h>
41#include <sys/stddef.h>
42#include <sys/param.h>
43#include <sys/queue.h>
44#include <sys/types.h>
45#include <sys/systm.h>
46#include <sys/kernel.h>
47#include <sys/bus.h>
48#include <sys/module.h>
49#include <sys/lock.h>
50#include <sys/mutex.h>
51#include <sys/condvar.h>
52#include <sys/sysctl.h>
53#include <sys/sx.h>
54#include <sys/unistd.h>
55#include <sys/callout.h>
56#include <sys/malloc.h>
57#include <sys/priv.h>
58
59#include <dev/usb/usb.h>
60#include <dev/usb/usbdi.h>
61
62#define	USB_DEBUG_VAR uss820dcidebug
63
64#include <dev/usb/usb_core.h>
65#include <dev/usb/usb_debug.h>
66#include <dev/usb/usb_busdma.h>
67#include <dev/usb/usb_process.h>
68#include <dev/usb/usb_transfer.h>
69#include <dev/usb/usb_device.h>
70#include <dev/usb/usb_hub.h>
71#include <dev/usb/usb_util.h>
72
73#include <dev/usb/usb_controller.h>
74#include <dev/usb/usb_bus.h>
75#endif			/* USB_GLOBAL_INCLUDE_FILE */
76
77#include <dev/usb/controller/uss820dci.h>
78
79#define	USS820_DCI_BUS2SC(bus) \
80   ((struct uss820dci_softc *)(((uint8_t *)(bus)) - \
81    ((uint8_t *)&(((struct uss820dci_softc *)0)->sc_bus))))
82
83#define	USS820_DCI_PC2SC(pc) \
84   USS820_DCI_BUS2SC(USB_DMATAG_TO_XROOT((pc)->tag_parent)->bus)
85
86#define	USS820_DCI_THREAD_IRQ \
87    (USS820_SSR_SUSPEND | USS820_SSR_RESUME | USS820_SSR_RESET)
88
89#ifdef USB_DEBUG
90static int uss820dcidebug = 0;
91
92static SYSCTL_NODE(_hw_usb, OID_AUTO, uss820dci, CTLFLAG_RW, 0,
93    "USB uss820dci");
94SYSCTL_INT(_hw_usb_uss820dci, OID_AUTO, debug, CTLFLAG_RWTUN,
95    &uss820dcidebug, 0, "uss820dci debug level");
96#endif
97
98#define	USS820_DCI_INTR_ENDPT 1
99
100/* prototypes */
101
102static const struct usb_bus_methods uss820dci_bus_methods;
103static const struct usb_pipe_methods uss820dci_device_bulk_methods;
104static const struct usb_pipe_methods uss820dci_device_ctrl_methods;
105static const struct usb_pipe_methods uss820dci_device_intr_methods;
106static const struct usb_pipe_methods uss820dci_device_isoc_fs_methods;
107
108static uss820dci_cmd_t uss820dci_setup_rx;
109static uss820dci_cmd_t uss820dci_data_rx;
110static uss820dci_cmd_t uss820dci_data_tx;
111static uss820dci_cmd_t uss820dci_data_tx_sync;
112static void	uss820dci_device_done(struct usb_xfer *, usb_error_t);
113static void	uss820dci_do_poll(struct usb_bus *);
114static void	uss820dci_standard_done(struct usb_xfer *);
115static void	uss820dci_intr_set(struct usb_xfer *, uint8_t);
116static void	uss820dci_update_shared_1(struct uss820dci_softc *, uint8_t,
117		    uint8_t, uint8_t);
118static void	uss820dci_root_intr(struct uss820dci_softc *);
119
120/*
121 * Here is a list of what the USS820D chip can support. The main
122 * limitation is that the sum of the buffer sizes must be less than
123 * 1120 bytes.
124 */
125static const struct usb_hw_ep_profile
126	uss820dci_ep_profile[] = {
127
128	[0] = {
129		.max_in_frame_size = 32,
130		.max_out_frame_size = 32,
131		.is_simplex = 0,
132		.support_control = 1,
133	},
134	[1] = {
135		.max_in_frame_size = 64,
136		.max_out_frame_size = 64,
137		.is_simplex = 0,
138		.support_multi_buffer = 1,
139		.support_bulk = 1,
140		.support_interrupt = 1,
141		.support_in = 1,
142		.support_out = 1,
143	},
144	[2] = {
145		.max_in_frame_size = 8,
146		.max_out_frame_size = 8,
147		.is_simplex = 0,
148		.support_multi_buffer = 1,
149		.support_bulk = 1,
150		.support_interrupt = 1,
151		.support_in = 1,
152		.support_out = 1,
153	},
154	[3] = {
155		.max_in_frame_size = 256,
156		.max_out_frame_size = 256,
157		.is_simplex = 0,
158		.support_multi_buffer = 1,
159		.support_isochronous = 1,
160		.support_in = 1,
161		.support_out = 1,
162	},
163};
164
165static void
166uss820dci_update_shared_1(struct uss820dci_softc *sc, uint8_t reg,
167    uint8_t keep_mask, uint8_t set_mask)
168{
169	uint8_t temp;
170
171	USS820_WRITE_1(sc, USS820_PEND, 1);
172	temp = USS820_READ_1(sc, reg);
173	temp &= (keep_mask);
174	temp |= (set_mask);
175	USS820_WRITE_1(sc, reg, temp);
176	USS820_WRITE_1(sc, USS820_PEND, 0);
177}
178
179static void
180uss820dci_get_hw_ep_profile(struct usb_device *udev,
181    const struct usb_hw_ep_profile **ppf, uint8_t ep_addr)
182{
183	if (ep_addr == 0) {
184		*ppf = uss820dci_ep_profile + 0;
185	} else if (ep_addr < 5) {
186		*ppf = uss820dci_ep_profile + 1;
187	} else if (ep_addr < 7) {
188		*ppf = uss820dci_ep_profile + 2;
189	} else if (ep_addr == 7) {
190		*ppf = uss820dci_ep_profile + 3;
191	} else {
192		*ppf = NULL;
193	}
194}
195
196static void
197uss820dci_pull_up(struct uss820dci_softc *sc)
198{
199	uint8_t temp;
200
201	/* pullup D+, if possible */
202
203	if (!sc->sc_flags.d_pulled_up &&
204	    sc->sc_flags.port_powered) {
205		sc->sc_flags.d_pulled_up = 1;
206
207		DPRINTF("\n");
208
209		temp = USS820_READ_1(sc, USS820_MCSR);
210		temp |= USS820_MCSR_DPEN;
211		USS820_WRITE_1(sc, USS820_MCSR, temp);
212	}
213}
214
215static void
216uss820dci_pull_down(struct uss820dci_softc *sc)
217{
218	uint8_t temp;
219
220	/* pulldown D+, if possible */
221
222	if (sc->sc_flags.d_pulled_up) {
223		sc->sc_flags.d_pulled_up = 0;
224
225		DPRINTF("\n");
226
227		temp = USS820_READ_1(sc, USS820_MCSR);
228		temp &= ~USS820_MCSR_DPEN;
229		USS820_WRITE_1(sc, USS820_MCSR, temp);
230	}
231}
232
233static void
234uss820dci_wakeup_peer(struct uss820dci_softc *sc)
235{
236	if (!(sc->sc_flags.status_suspend)) {
237		return;
238	}
239	DPRINTFN(0, "not supported\n");
240}
241
242static void
243uss820dci_set_address(struct uss820dci_softc *sc, uint8_t addr)
244{
245	DPRINTFN(5, "addr=%d\n", addr);
246
247	USS820_WRITE_1(sc, USS820_FADDR, addr);
248}
249
250static uint8_t
251uss820dci_setup_rx(struct uss820dci_softc *sc, struct uss820dci_td *td)
252{
253	struct usb_device_request req;
254	uint16_t count;
255	uint8_t rx_stat;
256	uint8_t temp;
257
258	/* select the correct endpoint */
259	USS820_WRITE_1(sc, USS820_EPINDEX, td->ep_index);
260
261	/* read out FIFO status */
262	rx_stat = USS820_READ_1(sc, USS820_RXSTAT);
263
264	DPRINTFN(5, "rx_stat=0x%02x rem=%u\n", rx_stat, td->remainder);
265
266	if (!(rx_stat & USS820_RXSTAT_RXSETUP)) {
267		goto not_complete;
268	}
269	/* clear did stall */
270	td->did_stall = 0;
271
272	/* clear stall and all I/O */
273	uss820dci_update_shared_1(sc, USS820_EPCON,
274	    0xFF ^ (USS820_EPCON_TXSTL |
275	    USS820_EPCON_RXSTL |
276	    USS820_EPCON_RXIE |
277	    USS820_EPCON_TXOE), 0);
278
279	/* clear end overwrite flag */
280	uss820dci_update_shared_1(sc, USS820_RXSTAT,
281	    0xFF ^ USS820_RXSTAT_EDOVW, 0);
282
283	/* get the packet byte count */
284	count = USS820_READ_1(sc, USS820_RXCNTL);
285	count |= (USS820_READ_1(sc, USS820_RXCNTH) << 8);
286	count &= 0x3FF;
287
288	/* verify data length */
289	if (count != td->remainder) {
290		DPRINTFN(0, "Invalid SETUP packet "
291		    "length, %d bytes\n", count);
292		goto setup_not_complete;
293	}
294	if (count != sizeof(req)) {
295		DPRINTFN(0, "Unsupported SETUP packet "
296		    "length, %d bytes\n", count);
297		goto setup_not_complete;
298	}
299	/* receive data */
300	bus_space_read_multi_1(sc->sc_io_tag, sc->sc_io_hdl,
301	    USS820_RXDAT * USS820_REG_STRIDE, (void *)&req, sizeof(req));
302
303	/* read out FIFO status */
304	rx_stat = USS820_READ_1(sc, USS820_RXSTAT);
305
306	if (rx_stat & (USS820_RXSTAT_EDOVW |
307	    USS820_RXSTAT_STOVW)) {
308		DPRINTF("new SETUP packet received\n");
309		return (1);		/* not complete */
310	}
311	/* clear receive setup bit */
312	uss820dci_update_shared_1(sc, USS820_RXSTAT,
313	    0xFF ^ (USS820_RXSTAT_RXSETUP |
314	    USS820_RXSTAT_EDOVW |
315	    USS820_RXSTAT_STOVW), 0);
316
317	/* set RXFFRC bit */
318	temp = USS820_READ_1(sc, USS820_RXCON);
319	temp |= USS820_RXCON_RXFFRC;
320	USS820_WRITE_1(sc, USS820_RXCON, temp);
321
322	/* copy data into real buffer */
323	usbd_copy_in(td->pc, 0, &req, sizeof(req));
324
325	td->offset = sizeof(req);
326	td->remainder = 0;
327
328	/* sneak peek the set address */
329	if ((req.bmRequestType == UT_WRITE_DEVICE) &&
330	    (req.bRequest == UR_SET_ADDRESS)) {
331		sc->sc_dv_addr = req.wValue[0] & 0x7F;
332	} else {
333		sc->sc_dv_addr = 0xFF;
334	}
335
336	/* reset TX FIFO */
337	temp = USS820_READ_1(sc, USS820_TXCON);
338	temp |= USS820_TXCON_TXCLR;
339	USS820_WRITE_1(sc, USS820_TXCON, temp);
340	temp &= ~USS820_TXCON_TXCLR;
341	USS820_WRITE_1(sc, USS820_TXCON, temp);
342
343	return (0);			/* complete */
344
345setup_not_complete:
346
347	/* set RXFFRC bit */
348	temp = USS820_READ_1(sc, USS820_RXCON);
349	temp |= USS820_RXCON_RXFFRC;
350	USS820_WRITE_1(sc, USS820_RXCON, temp);
351
352	/* FALLTHROUGH */
353
354not_complete:
355	/* abort any ongoing transfer */
356	if (!td->did_stall) {
357		DPRINTFN(5, "stalling\n");
358		/* set stall */
359		uss820dci_update_shared_1(sc, USS820_EPCON, 0xFF,
360		    (USS820_EPCON_TXSTL | USS820_EPCON_RXSTL));
361
362		td->did_stall = 1;
363	}
364
365	/* clear end overwrite flag, if any */
366	if (rx_stat & USS820_RXSTAT_RXSETUP) {
367		uss820dci_update_shared_1(sc, USS820_RXSTAT,
368		    0xFF ^ (USS820_RXSTAT_EDOVW |
369		    USS820_RXSTAT_STOVW |
370		    USS820_RXSTAT_RXSETUP), 0);
371	}
372	return (1);			/* not complete */
373}
374
375static uint8_t
376uss820dci_data_rx(struct uss820dci_softc *sc, struct uss820dci_td *td)
377{
378	struct usb_page_search buf_res;
379	uint16_t count;
380	uint8_t rx_flag;
381	uint8_t rx_stat;
382	uint8_t rx_cntl;
383	uint8_t to;
384	uint8_t got_short;
385
386	to = 2;				/* don't loop forever! */
387	got_short = 0;
388
389	/* select the correct endpoint */
390	USS820_WRITE_1(sc, USS820_EPINDEX, td->ep_index);
391
392	/* check if any of the FIFO banks have data */
393repeat:
394	/* read out FIFO flag */
395	rx_flag = USS820_READ_1(sc, USS820_RXFLG);
396	/* read out FIFO status */
397	rx_stat = USS820_READ_1(sc, USS820_RXSTAT);
398
399	DPRINTFN(5, "rx_stat=0x%02x rx_flag=0x%02x rem=%u\n",
400	    rx_stat, rx_flag, td->remainder);
401
402	if (rx_stat & (USS820_RXSTAT_RXSETUP |
403	    USS820_RXSTAT_RXSOVW |
404	    USS820_RXSTAT_EDOVW)) {
405		if (td->remainder == 0 && td->ep_index == 0) {
406			/*
407			 * We are actually complete and have
408			 * received the next SETUP
409			 */
410			DPRINTFN(5, "faking complete\n");
411			return (0);	/* complete */
412		}
413		/*
414	         * USB Host Aborted the transfer.
415	         */
416		td->error = 1;
417		return (0);		/* complete */
418	}
419	/* check for errors */
420	if (rx_flag & (USS820_RXFLG_RXOVF |
421	    USS820_RXFLG_RXURF)) {
422		DPRINTFN(5, "overflow or underflow\n");
423		/* should not happen */
424		td->error = 1;
425		return (0);		/* complete */
426	}
427	/* check status */
428	if (!(rx_flag & (USS820_RXFLG_RXFIF0 |
429	    USS820_RXFLG_RXFIF1))) {
430
431		/* read out EPCON register */
432		/* enable RX input */
433		if (!td->did_enable) {
434			uss820dci_update_shared_1(USS820_DCI_PC2SC(td->pc),
435			    USS820_EPCON, 0xFF, USS820_EPCON_RXIE);
436			td->did_enable = 1;
437		}
438		return (1);		/* not complete */
439	}
440	/* get the packet byte count */
441	count = USS820_READ_1(sc, USS820_RXCNTL);
442	count |= (USS820_READ_1(sc, USS820_RXCNTH) << 8);
443	count &= 0x3FF;
444
445	DPRINTFN(5, "count=0x%04x\n", count);
446
447	/* verify the packet byte count */
448	if (count != td->max_packet_size) {
449		if (count < td->max_packet_size) {
450			/* we have a short packet */
451			td->short_pkt = 1;
452			got_short = 1;
453		} else {
454			/* invalid USB packet */
455			td->error = 1;
456			return (0);	/* we are complete */
457		}
458	}
459	/* verify the packet byte count */
460	if (count > td->remainder) {
461		/* invalid USB packet */
462		td->error = 1;
463		return (0);		/* we are complete */
464	}
465	while (count > 0) {
466		usbd_get_page(td->pc, td->offset, &buf_res);
467
468		/* get correct length */
469		if (buf_res.length > count) {
470			buf_res.length = count;
471		}
472		/* receive data */
473		bus_space_read_multi_1(sc->sc_io_tag, sc->sc_io_hdl,
474		    USS820_RXDAT * USS820_REG_STRIDE, buf_res.buffer, buf_res.length);
475
476		/* update counters */
477		count -= buf_res.length;
478		td->offset += buf_res.length;
479		td->remainder -= buf_res.length;
480	}
481
482	/* set RXFFRC bit */
483	rx_cntl = USS820_READ_1(sc, USS820_RXCON);
484	rx_cntl |= USS820_RXCON_RXFFRC;
485	USS820_WRITE_1(sc, USS820_RXCON, rx_cntl);
486
487	/* check if we are complete */
488	if ((td->remainder == 0) || got_short) {
489		if (td->short_pkt) {
490			/* we are complete */
491			return (0);
492		}
493		/* else need to receive a zero length packet */
494	}
495	if (--to) {
496		goto repeat;
497	}
498	return (1);			/* not complete */
499}
500
501static uint8_t
502uss820dci_data_tx(struct uss820dci_softc *sc, struct uss820dci_td *td)
503{
504	struct usb_page_search buf_res;
505	uint16_t count;
506	uint16_t count_copy;
507	uint8_t rx_stat;
508	uint8_t tx_flag;
509	uint8_t to;
510
511	/* select the correct endpoint */
512	USS820_WRITE_1(sc, USS820_EPINDEX, td->ep_index);
513
514	to = 2;				/* don't loop forever! */
515
516repeat:
517	/* read out TX FIFO flags */
518	tx_flag = USS820_READ_1(sc, USS820_TXFLG);
519
520	DPRINTFN(5, "tx_flag=0x%02x rem=%u\n", tx_flag, td->remainder);
521
522	if (td->ep_index == 0) {
523		/* read out RX FIFO status last */
524		rx_stat = USS820_READ_1(sc, USS820_RXSTAT);
525
526		DPRINTFN(5, "rx_stat=0x%02x\n", rx_stat);
527
528		if (rx_stat & (USS820_RXSTAT_RXSETUP |
529		    USS820_RXSTAT_RXSOVW |
530		    USS820_RXSTAT_EDOVW)) {
531			/*
532			 * The current transfer was aborted by the USB
533			 * Host:
534			 */
535			td->error = 1;
536			return (0);		/* complete */
537		}
538	}
539	if (tx_flag & (USS820_TXFLG_TXOVF |
540	    USS820_TXFLG_TXURF)) {
541		td->error = 1;
542		return (0);		/* complete */
543	}
544	if (tx_flag & USS820_TXFLG_TXFIF0) {
545		if (tx_flag & USS820_TXFLG_TXFIF1) {
546			return (1);	/* not complete */
547		}
548	}
549	if ((!td->support_multi_buffer) &&
550	    (tx_flag & (USS820_TXFLG_TXFIF0 |
551	    USS820_TXFLG_TXFIF1))) {
552		return (1);		/* not complete */
553	}
554	count = td->max_packet_size;
555	if (td->remainder < count) {
556		/* we have a short packet */
557		td->short_pkt = 1;
558		count = td->remainder;
559	}
560	count_copy = count;
561	while (count > 0) {
562
563		usbd_get_page(td->pc, td->offset, &buf_res);
564
565		/* get correct length */
566		if (buf_res.length > count) {
567			buf_res.length = count;
568		}
569		/* transmit data */
570		bus_space_write_multi_1(sc->sc_io_tag, sc->sc_io_hdl,
571		    USS820_TXDAT * USS820_REG_STRIDE, buf_res.buffer, buf_res.length);
572
573		/* update counters */
574		count -= buf_res.length;
575		td->offset += buf_res.length;
576		td->remainder -= buf_res.length;
577	}
578
579	/* post-write high packet byte count first */
580	USS820_WRITE_1(sc, USS820_TXCNTH, count_copy >> 8);
581
582	/* post-write low packet byte count last */
583	USS820_WRITE_1(sc, USS820_TXCNTL, count_copy);
584
585	/*
586	 * Enable TX output, which must happen after that we have written
587	 * data into the FIFO. This is undocumented.
588	 */
589	if (!td->did_enable) {
590		uss820dci_update_shared_1(USS820_DCI_PC2SC(td->pc),
591		    USS820_EPCON, 0xFF, USS820_EPCON_TXOE);
592		td->did_enable = 1;
593	}
594	/* check remainder */
595	if (td->remainder == 0) {
596		if (td->short_pkt) {
597			return (0);	/* complete */
598		}
599		/* else we need to transmit a short packet */
600	}
601	if (--to) {
602		goto repeat;
603	}
604	return (1);			/* not complete */
605}
606
607static uint8_t
608uss820dci_data_tx_sync(struct uss820dci_softc *sc, struct uss820dci_td *td)
609{
610	uint8_t rx_stat;
611	uint8_t tx_flag;
612
613	/* select the correct endpoint */
614	USS820_WRITE_1(sc, USS820_EPINDEX, td->ep_index);
615
616	/* read out TX FIFO flag */
617	tx_flag = USS820_READ_1(sc, USS820_TXFLG);
618
619	if (td->ep_index == 0) {
620		/* read out RX FIFO status last */
621		rx_stat = USS820_READ_1(sc, USS820_RXSTAT);
622
623		DPRINTFN(5, "rx_stat=0x%02x rem=%u\n", rx_stat, td->remainder);
624
625		if (rx_stat & (USS820_RXSTAT_RXSETUP |
626		    USS820_RXSTAT_RXSOVW |
627		    USS820_RXSTAT_EDOVW)) {
628			DPRINTFN(5, "faking complete\n");
629			/* Race condition */
630			return (0);		/* complete */
631		}
632	}
633	DPRINTFN(5, "tx_flag=0x%02x rem=%u\n", tx_flag, td->remainder);
634
635	if (tx_flag & (USS820_TXFLG_TXOVF |
636	    USS820_TXFLG_TXURF)) {
637		td->error = 1;
638		return (0);		/* complete */
639	}
640	if (tx_flag & (USS820_TXFLG_TXFIF0 |
641	    USS820_TXFLG_TXFIF1)) {
642		return (1);		/* not complete */
643	}
644	if (td->ep_index == 0 && sc->sc_dv_addr != 0xFF) {
645		/* write function address */
646		uss820dci_set_address(sc, sc->sc_dv_addr);
647	}
648	return (0);			/* complete */
649}
650
651static void
652uss820dci_xfer_do_fifo(struct usb_xfer *xfer)
653{
654	struct uss820dci_softc *sc = USS820_DCI_BUS2SC(xfer->xroot->bus);
655	struct uss820dci_td *td;
656
657	DPRINTFN(9, "\n");
658
659	td = xfer->td_transfer_cache;
660	if (td == NULL)
661		return;
662
663	while (1) {
664		if ((td->func) (sc, td)) {
665			/* operation in progress */
666			break;
667		}
668		if (((void *)td) == xfer->td_transfer_last) {
669			goto done;
670		}
671		if (td->error) {
672			goto done;
673		} else if (td->remainder > 0) {
674			/*
675			 * We had a short transfer. If there is no alternate
676			 * next, stop processing !
677			 */
678			if (!td->alt_next) {
679				goto done;
680			}
681		}
682		/*
683		 * Fetch the next transfer descriptor.
684		 */
685		td = td->obj_next;
686		xfer->td_transfer_cache = td;
687	}
688	return;
689
690done:
691	/* compute all actual lengths */
692	xfer->td_transfer_cache = NULL;
693	sc->sc_xfer_complete = 1;
694}
695
696static uint8_t
697uss820dci_xfer_do_complete(struct usb_xfer *xfer)
698{
699	struct uss820dci_td *td;
700
701	DPRINTFN(9, "\n");
702
703	td = xfer->td_transfer_cache;
704	if (td == NULL) {
705		/* compute all actual lengths */
706		uss820dci_standard_done(xfer);
707		return(1);
708	}
709	return (0);
710}
711
712static void
713uss820dci_interrupt_poll_locked(struct uss820dci_softc *sc)
714{
715	struct usb_xfer *xfer;
716
717	TAILQ_FOREACH(xfer, &sc->sc_bus.intr_q.head, wait_entry)
718		uss820dci_xfer_do_fifo(xfer);
719}
720
721static void
722uss820dci_interrupt_complete_locked(struct uss820dci_softc *sc)
723{
724	struct usb_xfer *xfer;
725repeat:
726	TAILQ_FOREACH(xfer, &sc->sc_bus.intr_q.head, wait_entry) {
727		if (uss820dci_xfer_do_complete(xfer))
728			goto repeat;
729	}
730}
731
732static void
733uss820dci_wait_suspend(struct uss820dci_softc *sc, uint8_t on)
734{
735	uint8_t scr;
736	uint8_t scratch;
737
738	scr = USS820_READ_1(sc, USS820_SCR);
739	scratch = USS820_READ_1(sc, USS820_SCRATCH);
740
741	if (on) {
742		scr |= USS820_SCR_IE_SUSP;
743		scratch &= ~USS820_SCRATCH_IE_RESUME;
744	} else {
745		scr &= ~USS820_SCR_IE_SUSP;
746		scratch |= USS820_SCRATCH_IE_RESUME;
747	}
748
749	USS820_WRITE_1(sc, USS820_SCR, scr);
750	USS820_WRITE_1(sc, USS820_SCRATCH, scratch);
751}
752
753int
754uss820dci_filter_interrupt(void *arg)
755{
756	struct uss820dci_softc *sc = arg;
757	int retval = FILTER_HANDLED;
758	uint8_t ssr;
759
760	USB_BUS_SPIN_LOCK(&sc->sc_bus);
761
762	ssr = USS820_READ_1(sc, USS820_SSR);
763	uss820dci_update_shared_1(sc, USS820_SSR, USS820_DCI_THREAD_IRQ, 0);
764
765	if (ssr & USS820_DCI_THREAD_IRQ)
766		retval = FILTER_SCHEDULE_THREAD;
767
768	/* poll FIFOs, if any */
769	uss820dci_interrupt_poll_locked(sc);
770
771	if (sc->sc_xfer_complete != 0)
772		retval = FILTER_SCHEDULE_THREAD;
773
774	USB_BUS_SPIN_UNLOCK(&sc->sc_bus);
775
776	return (retval);
777}
778
779void
780uss820dci_interrupt(void *arg)
781{
782	struct uss820dci_softc *sc = arg;
783	uint8_t ssr;
784	uint8_t event;
785
786	USB_BUS_LOCK(&sc->sc_bus);
787	USB_BUS_SPIN_LOCK(&sc->sc_bus);
788
789	ssr = USS820_READ_1(sc, USS820_SSR);
790
791	/* acknowledge all interrupts */
792
793	uss820dci_update_shared_1(sc, USS820_SSR, ~USS820_DCI_THREAD_IRQ, 0);
794
795	/* check for any bus state change interrupts */
796
797	if (ssr & USS820_DCI_THREAD_IRQ) {
798
799		event = 0;
800
801		if (ssr & USS820_SSR_RESET) {
802			sc->sc_flags.status_bus_reset = 1;
803			sc->sc_flags.status_suspend = 0;
804			sc->sc_flags.change_suspend = 0;
805			sc->sc_flags.change_connect = 1;
806
807			/* disable resume interrupt */
808			uss820dci_wait_suspend(sc, 1);
809
810			event = 1;
811		}
812		/*
813	         * If "RESUME" and "SUSPEND" is set at the same time
814	         * we interpret that like "RESUME". Resume is set when
815	         * there is at least 3 milliseconds of inactivity on
816	         * the USB BUS.
817	         */
818		if (ssr & USS820_SSR_RESUME) {
819			if (sc->sc_flags.status_suspend) {
820				sc->sc_flags.status_suspend = 0;
821				sc->sc_flags.change_suspend = 1;
822				/* disable resume interrupt */
823				uss820dci_wait_suspend(sc, 1);
824				event = 1;
825			}
826		} else if (ssr & USS820_SSR_SUSPEND) {
827			if (!sc->sc_flags.status_suspend) {
828				sc->sc_flags.status_suspend = 1;
829				sc->sc_flags.change_suspend = 1;
830				/* enable resume interrupt */
831				uss820dci_wait_suspend(sc, 0);
832				event = 1;
833			}
834		}
835		if (event) {
836
837			DPRINTF("real bus interrupt 0x%02x\n", ssr);
838
839			/* complete root HUB interrupt endpoint */
840			uss820dci_root_intr(sc);
841		}
842	}
843	/* acknowledge all SBI interrupts */
844	uss820dci_update_shared_1(sc, USS820_SBI, 0, 0);
845
846	/* acknowledge all SBI1 interrupts */
847	uss820dci_update_shared_1(sc, USS820_SBI1, 0, 0);
848
849	if (sc->sc_xfer_complete != 0) {
850		sc->sc_xfer_complete = 0;
851
852		/* complete FIFOs, if any */
853		uss820dci_interrupt_complete_locked(sc);
854	}
855	USB_BUS_SPIN_UNLOCK(&sc->sc_bus);
856	USB_BUS_UNLOCK(&sc->sc_bus);
857}
858
859static void
860uss820dci_setup_standard_chain_sub(struct uss820_std_temp *temp)
861{
862	struct uss820dci_td *td;
863
864	/* get current Transfer Descriptor */
865	td = temp->td_next;
866	temp->td = td;
867
868	/* prepare for next TD */
869	temp->td_next = td->obj_next;
870
871	/* fill out the Transfer Descriptor */
872	td->func = temp->func;
873	td->pc = temp->pc;
874	td->offset = temp->offset;
875	td->remainder = temp->len;
876	td->error = 0;
877	td->did_enable = 0;
878	td->did_stall = temp->did_stall;
879	td->short_pkt = temp->short_pkt;
880	td->alt_next = temp->setup_alt_next;
881}
882
883static void
884uss820dci_setup_standard_chain(struct usb_xfer *xfer)
885{
886	struct uss820_std_temp temp;
887	struct uss820dci_softc *sc;
888	struct uss820dci_td *td;
889	uint32_t x;
890	uint8_t ep_no;
891
892	DPRINTFN(9, "addr=%d endpt=%d sumlen=%d speed=%d\n",
893	    xfer->address, UE_GET_ADDR(xfer->endpointno),
894	    xfer->sumlen, usbd_get_speed(xfer->xroot->udev));
895
896	temp.max_frame_size = xfer->max_frame_size;
897
898	td = xfer->td_start[0];
899	xfer->td_transfer_first = td;
900	xfer->td_transfer_cache = td;
901
902	/* setup temp */
903
904	temp.pc = NULL;
905	temp.td = NULL;
906	temp.td_next = xfer->td_start[0];
907	temp.offset = 0;
908	temp.setup_alt_next = xfer->flags_int.short_frames_ok ||
909	    xfer->flags_int.isochronous_xfr;
910	temp.did_stall = !xfer->flags_int.control_stall;
911
912	sc = USS820_DCI_BUS2SC(xfer->xroot->bus);
913	ep_no = (xfer->endpointno & UE_ADDR);
914
915	/* check if we should prepend a setup message */
916
917	if (xfer->flags_int.control_xfr) {
918		if (xfer->flags_int.control_hdr) {
919
920			temp.func = &uss820dci_setup_rx;
921			temp.len = xfer->frlengths[0];
922			temp.pc = xfer->frbuffers + 0;
923			temp.short_pkt = temp.len ? 1 : 0;
924			/* check for last frame */
925			if (xfer->nframes == 1) {
926				/* no STATUS stage yet, SETUP is last */
927				if (xfer->flags_int.control_act)
928					temp.setup_alt_next = 0;
929			}
930
931			uss820dci_setup_standard_chain_sub(&temp);
932		}
933		x = 1;
934	} else {
935		x = 0;
936	}
937
938	if (x != xfer->nframes) {
939		if (xfer->endpointno & UE_DIR_IN) {
940			temp.func = &uss820dci_data_tx;
941		} else {
942			temp.func = &uss820dci_data_rx;
943		}
944
945		/* setup "pc" pointer */
946		temp.pc = xfer->frbuffers + x;
947	}
948	while (x != xfer->nframes) {
949
950		/* DATA0 / DATA1 message */
951
952		temp.len = xfer->frlengths[x];
953
954		x++;
955
956		if (x == xfer->nframes) {
957			if (xfer->flags_int.control_xfr) {
958				if (xfer->flags_int.control_act) {
959					temp.setup_alt_next = 0;
960				}
961			} else {
962				temp.setup_alt_next = 0;
963			}
964		}
965		if (temp.len == 0) {
966
967			/* make sure that we send an USB packet */
968
969			temp.short_pkt = 0;
970
971		} else {
972
973			/* regular data transfer */
974
975			temp.short_pkt = (xfer->flags.force_short_xfer) ? 0 : 1;
976		}
977
978		uss820dci_setup_standard_chain_sub(&temp);
979
980		if (xfer->flags_int.isochronous_xfr) {
981			temp.offset += temp.len;
982		} else {
983			/* get next Page Cache pointer */
984			temp.pc = xfer->frbuffers + x;
985		}
986	}
987
988	/* check for control transfer */
989	if (xfer->flags_int.control_xfr) {
990		uint8_t need_sync;
991
992		/* always setup a valid "pc" pointer for status and sync */
993		temp.pc = xfer->frbuffers + 0;
994		temp.len = 0;
995		temp.short_pkt = 0;
996		temp.setup_alt_next = 0;
997
998		/* check if we should append a status stage */
999		if (!xfer->flags_int.control_act) {
1000
1001			/*
1002			 * Send a DATA1 message and invert the current
1003			 * endpoint direction.
1004			 */
1005			if (xfer->endpointno & UE_DIR_IN) {
1006				temp.func = &uss820dci_data_rx;
1007				need_sync = 0;
1008			} else {
1009				temp.func = &uss820dci_data_tx;
1010				need_sync = 1;
1011			}
1012			temp.len = 0;
1013			temp.short_pkt = 0;
1014
1015			uss820dci_setup_standard_chain_sub(&temp);
1016			if (need_sync) {
1017				/* we need a SYNC point after TX */
1018				temp.func = &uss820dci_data_tx_sync;
1019				uss820dci_setup_standard_chain_sub(&temp);
1020			}
1021		}
1022	}
1023	/* must have at least one frame! */
1024	td = temp.td;
1025	xfer->td_transfer_last = td;
1026}
1027
1028static void
1029uss820dci_timeout(void *arg)
1030{
1031	struct usb_xfer *xfer = arg;
1032
1033	DPRINTF("xfer=%p\n", xfer);
1034
1035	USB_BUS_LOCK_ASSERT(xfer->xroot->bus, MA_OWNED);
1036
1037	/* transfer is transferred */
1038	uss820dci_device_done(xfer, USB_ERR_TIMEOUT);
1039}
1040
1041static void
1042uss820dci_intr_set(struct usb_xfer *xfer, uint8_t set)
1043{
1044	struct uss820dci_softc *sc = USS820_DCI_BUS2SC(xfer->xroot->bus);
1045	uint8_t ep_no = (xfer->endpointno & UE_ADDR);
1046	uint8_t ep_reg;
1047	uint8_t temp;
1048
1049	DPRINTFN(15, "endpoint 0x%02x\n", xfer->endpointno);
1050
1051	if (ep_no > 3) {
1052		ep_reg = USS820_SBIE1;
1053	} else {
1054		ep_reg = USS820_SBIE;
1055	}
1056
1057	ep_no &= 3;
1058	ep_no = 1 << (2 * ep_no);
1059
1060	if (xfer->flags_int.control_xfr) {
1061		if (xfer->flags_int.control_hdr) {
1062			ep_no <<= 1;	/* RX interrupt only */
1063		} else {
1064			ep_no |= (ep_no << 1);	/* RX and TX interrupt */
1065		}
1066	} else {
1067		if (!(xfer->endpointno & UE_DIR_IN)) {
1068			ep_no <<= 1;
1069		}
1070	}
1071	temp = USS820_READ_1(sc, ep_reg);
1072	if (set) {
1073		temp |= ep_no;
1074	} else {
1075		temp &= ~ep_no;
1076	}
1077	USS820_WRITE_1(sc, ep_reg, temp);
1078}
1079
1080static void
1081uss820dci_start_standard_chain(struct usb_xfer *xfer)
1082{
1083	struct uss820dci_softc *sc = USS820_DCI_BUS2SC(xfer->xroot->bus);
1084
1085	DPRINTFN(9, "\n");
1086
1087	USB_BUS_SPIN_LOCK(&sc->sc_bus);
1088
1089	/* poll one time */
1090	uss820dci_xfer_do_fifo(xfer);
1091
1092	if (uss820dci_xfer_do_complete(xfer) == 0) {
1093		/*
1094		 * Only enable the endpoint interrupt when we are
1095		 * actually waiting for data, hence we are dealing
1096		 * with level triggered interrupts !
1097		 */
1098		uss820dci_intr_set(xfer, 1);
1099
1100		/* put transfer on interrupt queue */
1101		usbd_transfer_enqueue(&xfer->xroot->bus->intr_q, xfer);
1102
1103		/* start timeout, if any */
1104		if (xfer->timeout != 0) {
1105			usbd_transfer_timeout_ms(xfer,
1106			    &uss820dci_timeout, xfer->timeout);
1107		}
1108	}
1109	USB_BUS_SPIN_UNLOCK(&sc->sc_bus);
1110}
1111
1112static void
1113uss820dci_root_intr(struct uss820dci_softc *sc)
1114{
1115	DPRINTFN(9, "\n");
1116
1117	USB_BUS_LOCK_ASSERT(&sc->sc_bus, MA_OWNED);
1118
1119	/* set port bit */
1120	sc->sc_hub_idata[0] = 0x02;	/* we only have one port */
1121
1122	uhub_root_intr(&sc->sc_bus, sc->sc_hub_idata,
1123	    sizeof(sc->sc_hub_idata));
1124}
1125
1126static usb_error_t
1127uss820dci_standard_done_sub(struct usb_xfer *xfer)
1128{
1129	struct uss820dci_td *td;
1130	uint32_t len;
1131	uint8_t error;
1132
1133	DPRINTFN(9, "\n");
1134
1135	td = xfer->td_transfer_cache;
1136
1137	do {
1138		len = td->remainder;
1139
1140		if (xfer->aframes != xfer->nframes) {
1141			/*
1142		         * Verify the length and subtract
1143		         * the remainder from "frlengths[]":
1144		         */
1145			if (len > xfer->frlengths[xfer->aframes]) {
1146				td->error = 1;
1147			} else {
1148				xfer->frlengths[xfer->aframes] -= len;
1149			}
1150		}
1151		/* Check for transfer error */
1152		if (td->error) {
1153			/* the transfer is finished */
1154			error = 1;
1155			td = NULL;
1156			break;
1157		}
1158		/* Check for short transfer */
1159		if (len > 0) {
1160			if (xfer->flags_int.short_frames_ok ||
1161			    xfer->flags_int.isochronous_xfr) {
1162				/* follow alt next */
1163				if (td->alt_next) {
1164					td = td->obj_next;
1165				} else {
1166					td = NULL;
1167				}
1168			} else {
1169				/* the transfer is finished */
1170				td = NULL;
1171			}
1172			error = 0;
1173			break;
1174		}
1175		td = td->obj_next;
1176
1177		/* this USB frame is complete */
1178		error = 0;
1179		break;
1180
1181	} while (0);
1182
1183	/* update transfer cache */
1184
1185	xfer->td_transfer_cache = td;
1186
1187	return (error ?
1188	    USB_ERR_STALLED : USB_ERR_NORMAL_COMPLETION);
1189}
1190
1191static void
1192uss820dci_standard_done(struct usb_xfer *xfer)
1193{
1194	usb_error_t err = 0;
1195
1196	DPRINTFN(13, "xfer=%p endpoint=%p transfer done\n",
1197	    xfer, xfer->endpoint);
1198
1199	/* reset scanner */
1200
1201	xfer->td_transfer_cache = xfer->td_transfer_first;
1202
1203	if (xfer->flags_int.control_xfr) {
1204
1205		if (xfer->flags_int.control_hdr) {
1206
1207			err = uss820dci_standard_done_sub(xfer);
1208		}
1209		xfer->aframes = 1;
1210
1211		if (xfer->td_transfer_cache == NULL) {
1212			goto done;
1213		}
1214	}
1215	while (xfer->aframes != xfer->nframes) {
1216
1217		err = uss820dci_standard_done_sub(xfer);
1218		xfer->aframes++;
1219
1220		if (xfer->td_transfer_cache == NULL) {
1221			goto done;
1222		}
1223	}
1224
1225	if (xfer->flags_int.control_xfr &&
1226	    !xfer->flags_int.control_act) {
1227
1228		err = uss820dci_standard_done_sub(xfer);
1229	}
1230done:
1231	uss820dci_device_done(xfer, err);
1232}
1233
1234/*------------------------------------------------------------------------*
1235 *	uss820dci_device_done
1236 *
1237 * NOTE: this function can be called more than one time on the
1238 * same USB transfer!
1239 *------------------------------------------------------------------------*/
1240static void
1241uss820dci_device_done(struct usb_xfer *xfer, usb_error_t error)
1242{
1243	struct uss820dci_softc *sc = USS820_DCI_BUS2SC(xfer->xroot->bus);
1244
1245	USB_BUS_LOCK_ASSERT(xfer->xroot->bus, MA_OWNED);
1246
1247	DPRINTFN(2, "xfer=%p, endpoint=%p, error=%d\n",
1248	    xfer, xfer->endpoint, error);
1249
1250	USB_BUS_SPIN_LOCK(&sc->sc_bus);
1251
1252	if (xfer->flags_int.usb_mode == USB_MODE_DEVICE) {
1253		uss820dci_intr_set(xfer, 0);
1254	}
1255	/* dequeue transfer and start next transfer */
1256	usbd_transfer_done(xfer, error);
1257
1258	USB_BUS_SPIN_UNLOCK(&sc->sc_bus);
1259}
1260
1261static void
1262uss820dci_xfer_stall(struct usb_xfer *xfer)
1263{
1264	uss820dci_device_done(xfer, USB_ERR_STALLED);
1265}
1266
1267static void
1268uss820dci_set_stall(struct usb_device *udev,
1269    struct usb_endpoint *ep, uint8_t *did_stall)
1270{
1271	struct uss820dci_softc *sc;
1272	uint8_t ep_no;
1273	uint8_t ep_type;
1274	uint8_t ep_dir;
1275	uint8_t temp;
1276
1277	USB_BUS_LOCK_ASSERT(udev->bus, MA_OWNED);
1278
1279	DPRINTFN(5, "endpoint=%p\n", ep);
1280
1281	/* set FORCESTALL */
1282	sc = USS820_DCI_BUS2SC(udev->bus);
1283	ep_no = (ep->edesc->bEndpointAddress & UE_ADDR);
1284	ep_dir = (ep->edesc->bEndpointAddress & (UE_DIR_IN | UE_DIR_OUT));
1285	ep_type = (ep->edesc->bmAttributes & UE_XFERTYPE);
1286
1287	if (ep_type == UE_CONTROL) {
1288		/* should not happen */
1289		return;
1290	}
1291	USB_BUS_SPIN_LOCK(&sc->sc_bus);
1292	USS820_WRITE_1(sc, USS820_EPINDEX, ep_no);
1293
1294	if (ep_dir == UE_DIR_IN) {
1295		temp = USS820_EPCON_TXSTL;
1296	} else {
1297		temp = USS820_EPCON_RXSTL;
1298	}
1299	uss820dci_update_shared_1(sc, USS820_EPCON, 0xFF, temp);
1300	USB_BUS_SPIN_UNLOCK(&sc->sc_bus);
1301}
1302
1303static void
1304uss820dci_clear_stall_sub(struct uss820dci_softc *sc,
1305    uint8_t ep_no, uint8_t ep_type, uint8_t ep_dir)
1306{
1307	uint8_t temp;
1308
1309	if (ep_type == UE_CONTROL) {
1310		/* clearing stall is not needed */
1311		return;
1312	}
1313	USB_BUS_SPIN_LOCK(&sc->sc_bus);
1314
1315	/* select endpoint index */
1316	USS820_WRITE_1(sc, USS820_EPINDEX, ep_no);
1317
1318	/* clear stall and disable I/O transfers */
1319	if (ep_dir == UE_DIR_IN) {
1320		temp = 0xFF ^ (USS820_EPCON_TXOE |
1321		    USS820_EPCON_TXSTL);
1322	} else {
1323		temp = 0xFF ^ (USS820_EPCON_RXIE |
1324		    USS820_EPCON_RXSTL);
1325	}
1326	uss820dci_update_shared_1(sc, USS820_EPCON, temp, 0);
1327
1328	if (ep_dir == UE_DIR_IN) {
1329		/* reset data toggle */
1330		USS820_WRITE_1(sc, USS820_TXSTAT,
1331		    USS820_TXSTAT_TXSOVW);
1332
1333		/* reset FIFO */
1334		temp = USS820_READ_1(sc, USS820_TXCON);
1335		temp |= USS820_TXCON_TXCLR;
1336		USS820_WRITE_1(sc, USS820_TXCON, temp);
1337		temp &= ~USS820_TXCON_TXCLR;
1338		USS820_WRITE_1(sc, USS820_TXCON, temp);
1339	} else {
1340
1341		/* reset data toggle */
1342		uss820dci_update_shared_1(sc, USS820_RXSTAT,
1343		    0, USS820_RXSTAT_RXSOVW);
1344
1345		/* reset FIFO */
1346		temp = USS820_READ_1(sc, USS820_RXCON);
1347		temp |= USS820_RXCON_RXCLR;
1348		temp &= ~USS820_RXCON_RXFFRC;
1349		USS820_WRITE_1(sc, USS820_RXCON, temp);
1350		temp &= ~USS820_RXCON_RXCLR;
1351		USS820_WRITE_1(sc, USS820_RXCON, temp);
1352	}
1353	USB_BUS_SPIN_UNLOCK(&sc->sc_bus);
1354}
1355
1356static void
1357uss820dci_clear_stall(struct usb_device *udev, struct usb_endpoint *ep)
1358{
1359	struct uss820dci_softc *sc;
1360	struct usb_endpoint_descriptor *ed;
1361
1362	USB_BUS_LOCK_ASSERT(udev->bus, MA_OWNED);
1363
1364	DPRINTFN(5, "endpoint=%p\n", ep);
1365
1366	/* check mode */
1367	if (udev->flags.usb_mode != USB_MODE_DEVICE) {
1368		/* not supported */
1369		return;
1370	}
1371	/* get softc */
1372	sc = USS820_DCI_BUS2SC(udev->bus);
1373
1374	/* get endpoint descriptor */
1375	ed = ep->edesc;
1376
1377	/* reset endpoint */
1378	uss820dci_clear_stall_sub(sc,
1379	    (ed->bEndpointAddress & UE_ADDR),
1380	    (ed->bmAttributes & UE_XFERTYPE),
1381	    (ed->bEndpointAddress & (UE_DIR_IN | UE_DIR_OUT)));
1382}
1383
1384usb_error_t
1385uss820dci_init(struct uss820dci_softc *sc)
1386{
1387	const struct usb_hw_ep_profile *pf;
1388	uint8_t n;
1389	uint8_t temp;
1390
1391	DPRINTF("start\n");
1392
1393	/* set up the bus structure */
1394	sc->sc_bus.usbrev = USB_REV_1_1;
1395	sc->sc_bus.methods = &uss820dci_bus_methods;
1396
1397	USB_BUS_LOCK(&sc->sc_bus);
1398
1399	/* we always have VBUS */
1400	sc->sc_flags.status_vbus = 1;
1401
1402	/* reset the chip */
1403	USS820_WRITE_1(sc, USS820_SCR, USS820_SCR_SRESET);
1404	DELAY(100);
1405	USS820_WRITE_1(sc, USS820_SCR, 0);
1406
1407	/* wait for reset to complete */
1408	for (n = 0;; n++) {
1409
1410		temp = USS820_READ_1(sc, USS820_MCSR);
1411
1412		if (temp & USS820_MCSR_INIT) {
1413			break;
1414		}
1415		if (n == 100) {
1416			USB_BUS_UNLOCK(&sc->sc_bus);
1417			return (USB_ERR_INVAL);
1418		}
1419		/* wait a little for things to stabilise */
1420		DELAY(100);
1421	}
1422
1423	/* do a pulldown */
1424	uss820dci_pull_down(sc);
1425
1426	/* wait 10ms for pulldown to stabilise */
1427	usb_pause_mtx(&sc->sc_bus.bus_mtx, hz / 100);
1428
1429	/* check hardware revision */
1430	temp = USS820_READ_1(sc, USS820_REV);
1431
1432	if (temp < 0x13) {
1433		USB_BUS_UNLOCK(&sc->sc_bus);
1434		return (USB_ERR_INVAL);
1435	}
1436	/* enable interrupts */
1437	USS820_WRITE_1(sc, USS820_SCR,
1438	    USS820_SCR_T_IRQ |
1439	    USS820_SCR_IE_RESET |
1440	/* USS820_SCR_RWUPE | */
1441	    USS820_SCR_IE_SUSP |
1442	    USS820_SCR_IRQPOL);
1443
1444	/* enable interrupts */
1445	USS820_WRITE_1(sc, USS820_SCRATCH,
1446	    USS820_SCRATCH_IE_RESUME);
1447
1448	/* enable features */
1449	USS820_WRITE_1(sc, USS820_MCSR,
1450	    USS820_MCSR_BDFEAT |
1451	    USS820_MCSR_FEAT);
1452
1453	sc->sc_flags.mcsr_feat = 1;
1454
1455	/* disable interrupts */
1456	USS820_WRITE_1(sc, USS820_SBIE, 0);
1457
1458	/* disable interrupts */
1459	USS820_WRITE_1(sc, USS820_SBIE1, 0);
1460
1461	/* disable all endpoints */
1462	for (n = 0; n != USS820_EP_MAX; n++) {
1463
1464		/* select endpoint */
1465		USS820_WRITE_1(sc, USS820_EPINDEX, n);
1466
1467		/* disable endpoint */
1468		uss820dci_update_shared_1(sc, USS820_EPCON, 0, 0);
1469	}
1470
1471	/*
1472	 * Initialise default values for some registers that cannot be
1473	 * changed during operation!
1474	 */
1475	for (n = 0; n != USS820_EP_MAX; n++) {
1476
1477		uss820dci_get_hw_ep_profile(NULL, &pf, n);
1478
1479		/* the maximum frame sizes should be the same */
1480		if (pf->max_in_frame_size != pf->max_out_frame_size) {
1481			DPRINTF("Max frame size mismatch %u != %u\n",
1482			    pf->max_in_frame_size, pf->max_out_frame_size);
1483		}
1484		if (pf->support_isochronous) {
1485			if (pf->max_in_frame_size <= 64) {
1486				temp = (USS820_TXCON_FFSZ_16_64 |
1487				    USS820_TXCON_TXISO |
1488				    USS820_TXCON_ATM);
1489			} else if (pf->max_in_frame_size <= 256) {
1490				temp = (USS820_TXCON_FFSZ_64_256 |
1491				    USS820_TXCON_TXISO |
1492				    USS820_TXCON_ATM);
1493			} else if (pf->max_in_frame_size <= 512) {
1494				temp = (USS820_TXCON_FFSZ_8_512 |
1495				    USS820_TXCON_TXISO |
1496				    USS820_TXCON_ATM);
1497			} else {	/* 1024 bytes */
1498				temp = (USS820_TXCON_FFSZ_32_1024 |
1499				    USS820_TXCON_TXISO |
1500				    USS820_TXCON_ATM);
1501			}
1502		} else {
1503			if ((pf->max_in_frame_size <= 8) &&
1504			    (sc->sc_flags.mcsr_feat)) {
1505				temp = (USS820_TXCON_FFSZ_8_512 |
1506				    USS820_TXCON_ATM);
1507			} else if (pf->max_in_frame_size <= 16) {
1508				temp = (USS820_TXCON_FFSZ_16_64 |
1509				    USS820_TXCON_ATM);
1510			} else if ((pf->max_in_frame_size <= 32) &&
1511			    (sc->sc_flags.mcsr_feat)) {
1512				temp = (USS820_TXCON_FFSZ_32_1024 |
1513				    USS820_TXCON_ATM);
1514			} else {	/* 64 bytes */
1515				temp = (USS820_TXCON_FFSZ_64_256 |
1516				    USS820_TXCON_ATM);
1517			}
1518		}
1519
1520		/* need to configure the chip early */
1521
1522		USS820_WRITE_1(sc, USS820_EPINDEX, n);
1523		USS820_WRITE_1(sc, USS820_TXCON, temp);
1524		USS820_WRITE_1(sc, USS820_RXCON, temp);
1525
1526		if (pf->support_control) {
1527			temp = USS820_EPCON_CTLEP |
1528			    USS820_EPCON_RXSPM |
1529			    USS820_EPCON_RXIE |
1530			    USS820_EPCON_RXEPEN |
1531			    USS820_EPCON_TXOE |
1532			    USS820_EPCON_TXEPEN;
1533		} else {
1534			temp = USS820_EPCON_RXEPEN | USS820_EPCON_TXEPEN;
1535		}
1536
1537		uss820dci_update_shared_1(sc, USS820_EPCON, 0, temp);
1538	}
1539
1540	USB_BUS_UNLOCK(&sc->sc_bus);
1541
1542	/* catch any lost interrupts */
1543
1544	uss820dci_do_poll(&sc->sc_bus);
1545
1546	return (0);			/* success */
1547}
1548
1549void
1550uss820dci_uninit(struct uss820dci_softc *sc)
1551{
1552	uint8_t temp;
1553
1554	USB_BUS_LOCK(&sc->sc_bus);
1555
1556	/* disable all interrupts */
1557	temp = USS820_READ_1(sc, USS820_SCR);
1558	temp &= ~USS820_SCR_T_IRQ;
1559	USS820_WRITE_1(sc, USS820_SCR, temp);
1560
1561	sc->sc_flags.port_powered = 0;
1562	sc->sc_flags.status_vbus = 0;
1563	sc->sc_flags.status_bus_reset = 0;
1564	sc->sc_flags.status_suspend = 0;
1565	sc->sc_flags.change_suspend = 0;
1566	sc->sc_flags.change_connect = 1;
1567
1568	uss820dci_pull_down(sc);
1569	USB_BUS_UNLOCK(&sc->sc_bus);
1570}
1571
1572static void
1573uss820dci_suspend(struct uss820dci_softc *sc)
1574{
1575	/* TODO */
1576}
1577
1578static void
1579uss820dci_resume(struct uss820dci_softc *sc)
1580{
1581	/* TODO */
1582}
1583
1584static void
1585uss820dci_do_poll(struct usb_bus *bus)
1586{
1587	struct uss820dci_softc *sc = USS820_DCI_BUS2SC(bus);
1588
1589	USB_BUS_LOCK(&sc->sc_bus);
1590	USB_BUS_SPIN_LOCK(&sc->sc_bus);
1591	uss820dci_interrupt_poll_locked(sc);
1592	uss820dci_interrupt_complete_locked(sc);
1593	USB_BUS_SPIN_UNLOCK(&sc->sc_bus);
1594	USB_BUS_UNLOCK(&sc->sc_bus);
1595}
1596
1597/*------------------------------------------------------------------------*
1598 * uss820dci bulk support
1599 *------------------------------------------------------------------------*/
1600static void
1601uss820dci_device_bulk_open(struct usb_xfer *xfer)
1602{
1603	return;
1604}
1605
1606static void
1607uss820dci_device_bulk_close(struct usb_xfer *xfer)
1608{
1609	uss820dci_device_done(xfer, USB_ERR_CANCELLED);
1610}
1611
1612static void
1613uss820dci_device_bulk_enter(struct usb_xfer *xfer)
1614{
1615	return;
1616}
1617
1618static void
1619uss820dci_device_bulk_start(struct usb_xfer *xfer)
1620{
1621	/* setup TDs */
1622	uss820dci_setup_standard_chain(xfer);
1623	uss820dci_start_standard_chain(xfer);
1624}
1625
1626static const struct usb_pipe_methods uss820dci_device_bulk_methods =
1627{
1628	.open = uss820dci_device_bulk_open,
1629	.close = uss820dci_device_bulk_close,
1630	.enter = uss820dci_device_bulk_enter,
1631	.start = uss820dci_device_bulk_start,
1632};
1633
1634/*------------------------------------------------------------------------*
1635 * uss820dci control support
1636 *------------------------------------------------------------------------*/
1637static void
1638uss820dci_device_ctrl_open(struct usb_xfer *xfer)
1639{
1640	return;
1641}
1642
1643static void
1644uss820dci_device_ctrl_close(struct usb_xfer *xfer)
1645{
1646	uss820dci_device_done(xfer, USB_ERR_CANCELLED);
1647}
1648
1649static void
1650uss820dci_device_ctrl_enter(struct usb_xfer *xfer)
1651{
1652	return;
1653}
1654
1655static void
1656uss820dci_device_ctrl_start(struct usb_xfer *xfer)
1657{
1658	/* setup TDs */
1659	uss820dci_setup_standard_chain(xfer);
1660	uss820dci_start_standard_chain(xfer);
1661}
1662
1663static const struct usb_pipe_methods uss820dci_device_ctrl_methods =
1664{
1665	.open = uss820dci_device_ctrl_open,
1666	.close = uss820dci_device_ctrl_close,
1667	.enter = uss820dci_device_ctrl_enter,
1668	.start = uss820dci_device_ctrl_start,
1669};
1670
1671/*------------------------------------------------------------------------*
1672 * uss820dci interrupt support
1673 *------------------------------------------------------------------------*/
1674static void
1675uss820dci_device_intr_open(struct usb_xfer *xfer)
1676{
1677	return;
1678}
1679
1680static void
1681uss820dci_device_intr_close(struct usb_xfer *xfer)
1682{
1683	uss820dci_device_done(xfer, USB_ERR_CANCELLED);
1684}
1685
1686static void
1687uss820dci_device_intr_enter(struct usb_xfer *xfer)
1688{
1689	return;
1690}
1691
1692static void
1693uss820dci_device_intr_start(struct usb_xfer *xfer)
1694{
1695	/* setup TDs */
1696	uss820dci_setup_standard_chain(xfer);
1697	uss820dci_start_standard_chain(xfer);
1698}
1699
1700static const struct usb_pipe_methods uss820dci_device_intr_methods =
1701{
1702	.open = uss820dci_device_intr_open,
1703	.close = uss820dci_device_intr_close,
1704	.enter = uss820dci_device_intr_enter,
1705	.start = uss820dci_device_intr_start,
1706};
1707
1708/*------------------------------------------------------------------------*
1709 * uss820dci full speed isochronous support
1710 *------------------------------------------------------------------------*/
1711static void
1712uss820dci_device_isoc_fs_open(struct usb_xfer *xfer)
1713{
1714	return;
1715}
1716
1717static void
1718uss820dci_device_isoc_fs_close(struct usb_xfer *xfer)
1719{
1720	uss820dci_device_done(xfer, USB_ERR_CANCELLED);
1721}
1722
1723static void
1724uss820dci_device_isoc_fs_enter(struct usb_xfer *xfer)
1725{
1726	struct uss820dci_softc *sc = USS820_DCI_BUS2SC(xfer->xroot->bus);
1727	uint32_t temp;
1728	uint32_t nframes;
1729
1730	DPRINTFN(6, "xfer=%p next=%d nframes=%d\n",
1731	    xfer, xfer->endpoint->isoc_next, xfer->nframes);
1732
1733	/* get the current frame index - we don't need the high bits */
1734
1735	nframes = USS820_READ_1(sc, USS820_SOFL);
1736
1737	/*
1738	 * check if the frame index is within the window where the
1739	 * frames will be inserted
1740	 */
1741	temp = (nframes - xfer->endpoint->isoc_next) & USS820_SOFL_MASK;
1742
1743	if ((xfer->endpoint->is_synced == 0) ||
1744	    (temp < xfer->nframes)) {
1745		/*
1746		 * If there is data underflow or the pipe queue is
1747		 * empty we schedule the transfer a few frames ahead
1748		 * of the current frame position. Else two isochronous
1749		 * transfers might overlap.
1750		 */
1751		xfer->endpoint->isoc_next = (nframes + 3) & USS820_SOFL_MASK;
1752		xfer->endpoint->is_synced = 1;
1753		DPRINTFN(3, "start next=%d\n", xfer->endpoint->isoc_next);
1754	}
1755	/*
1756	 * compute how many milliseconds the insertion is ahead of the
1757	 * current frame position:
1758	 */
1759	temp = (xfer->endpoint->isoc_next - nframes) & USS820_SOFL_MASK;
1760
1761	/*
1762	 * pre-compute when the isochronous transfer will be finished:
1763	 */
1764	xfer->isoc_time_complete =
1765	    usb_isoc_time_expand(&sc->sc_bus, nframes) + temp +
1766	    xfer->nframes;
1767
1768	/* compute frame number for next insertion */
1769	xfer->endpoint->isoc_next += xfer->nframes;
1770
1771	/* setup TDs */
1772	uss820dci_setup_standard_chain(xfer);
1773}
1774
1775static void
1776uss820dci_device_isoc_fs_start(struct usb_xfer *xfer)
1777{
1778	/* start TD chain */
1779	uss820dci_start_standard_chain(xfer);
1780}
1781
1782static const struct usb_pipe_methods uss820dci_device_isoc_fs_methods =
1783{
1784	.open = uss820dci_device_isoc_fs_open,
1785	.close = uss820dci_device_isoc_fs_close,
1786	.enter = uss820dci_device_isoc_fs_enter,
1787	.start = uss820dci_device_isoc_fs_start,
1788};
1789
1790/*------------------------------------------------------------------------*
1791 * uss820dci root control support
1792 *------------------------------------------------------------------------*
1793 * Simulate a hardware HUB by handling all the necessary requests.
1794 *------------------------------------------------------------------------*/
1795
1796static const struct usb_device_descriptor uss820dci_devd = {
1797	.bLength = sizeof(struct usb_device_descriptor),
1798	.bDescriptorType = UDESC_DEVICE,
1799	.bcdUSB = {0x00, 0x02},
1800	.bDeviceClass = UDCLASS_HUB,
1801	.bDeviceSubClass = UDSUBCLASS_HUB,
1802	.bDeviceProtocol = UDPROTO_FSHUB,
1803	.bMaxPacketSize = 64,
1804	.bcdDevice = {0x00, 0x01},
1805	.iManufacturer = 1,
1806	.iProduct = 2,
1807	.bNumConfigurations = 1,
1808};
1809
1810static const struct usb_device_qualifier uss820dci_odevd = {
1811	.bLength = sizeof(struct usb_device_qualifier),
1812	.bDescriptorType = UDESC_DEVICE_QUALIFIER,
1813	.bcdUSB = {0x00, 0x02},
1814	.bDeviceClass = UDCLASS_HUB,
1815	.bDeviceSubClass = UDSUBCLASS_HUB,
1816	.bDeviceProtocol = UDPROTO_FSHUB,
1817	.bMaxPacketSize0 = 0,
1818	.bNumConfigurations = 0,
1819};
1820
1821static const struct uss820dci_config_desc uss820dci_confd = {
1822	.confd = {
1823		.bLength = sizeof(struct usb_config_descriptor),
1824		.bDescriptorType = UDESC_CONFIG,
1825		.wTotalLength[0] = sizeof(uss820dci_confd),
1826		.bNumInterface = 1,
1827		.bConfigurationValue = 1,
1828		.iConfiguration = 0,
1829		.bmAttributes = UC_SELF_POWERED,
1830		.bMaxPower = 0,
1831	},
1832	.ifcd = {
1833		.bLength = sizeof(struct usb_interface_descriptor),
1834		.bDescriptorType = UDESC_INTERFACE,
1835		.bNumEndpoints = 1,
1836		.bInterfaceClass = UICLASS_HUB,
1837		.bInterfaceSubClass = UISUBCLASS_HUB,
1838		.bInterfaceProtocol = 0,
1839	},
1840
1841	.endpd = {
1842		.bLength = sizeof(struct usb_endpoint_descriptor),
1843		.bDescriptorType = UDESC_ENDPOINT,
1844		.bEndpointAddress = (UE_DIR_IN | USS820_DCI_INTR_ENDPT),
1845		.bmAttributes = UE_INTERRUPT,
1846		.wMaxPacketSize[0] = 8,
1847		.bInterval = 255,
1848	},
1849};
1850
1851#define	HSETW(ptr, val) ptr = { (uint8_t)(val), (uint8_t)((val) >> 8) }
1852
1853static const struct usb_hub_descriptor_min uss820dci_hubd = {
1854	.bDescLength = sizeof(uss820dci_hubd),
1855	.bDescriptorType = UDESC_HUB,
1856	.bNbrPorts = 1,
1857	HSETW(.wHubCharacteristics, (UHD_PWR_NO_SWITCH | UHD_OC_INDIVIDUAL)),
1858	.bPwrOn2PwrGood = 50,
1859	.bHubContrCurrent = 0,
1860	.DeviceRemovable = {0},		/* port is removable */
1861};
1862
1863#define	STRING_VENDOR \
1864  "A\0G\0E\0R\0E"
1865
1866#define	STRING_PRODUCT \
1867  "D\0C\0I\0 \0R\0o\0o\0t\0 \0H\0U\0B"
1868
1869USB_MAKE_STRING_DESC(STRING_VENDOR, uss820dci_vendor);
1870USB_MAKE_STRING_DESC(STRING_PRODUCT, uss820dci_product);
1871
1872static usb_error_t
1873uss820dci_roothub_exec(struct usb_device *udev,
1874    struct usb_device_request *req, const void **pptr, uint16_t *plength)
1875{
1876	struct uss820dci_softc *sc = USS820_DCI_BUS2SC(udev->bus);
1877	const void *ptr;
1878	uint16_t len;
1879	uint16_t value;
1880	uint16_t index;
1881	usb_error_t err;
1882
1883	USB_BUS_LOCK_ASSERT(&sc->sc_bus, MA_OWNED);
1884
1885	/* buffer reset */
1886	ptr = (const void *)&sc->sc_hub_temp;
1887	len = 0;
1888	err = 0;
1889
1890	value = UGETW(req->wValue);
1891	index = UGETW(req->wIndex);
1892
1893	/* demultiplex the control request */
1894
1895	switch (req->bmRequestType) {
1896	case UT_READ_DEVICE:
1897		switch (req->bRequest) {
1898		case UR_GET_DESCRIPTOR:
1899			goto tr_handle_get_descriptor;
1900		case UR_GET_CONFIG:
1901			goto tr_handle_get_config;
1902		case UR_GET_STATUS:
1903			goto tr_handle_get_status;
1904		default:
1905			goto tr_stalled;
1906		}
1907		break;
1908
1909	case UT_WRITE_DEVICE:
1910		switch (req->bRequest) {
1911		case UR_SET_ADDRESS:
1912			goto tr_handle_set_address;
1913		case UR_SET_CONFIG:
1914			goto tr_handle_set_config;
1915		case UR_CLEAR_FEATURE:
1916			goto tr_valid;	/* nop */
1917		case UR_SET_DESCRIPTOR:
1918			goto tr_valid;	/* nop */
1919		case UR_SET_FEATURE:
1920		default:
1921			goto tr_stalled;
1922		}
1923		break;
1924
1925	case UT_WRITE_ENDPOINT:
1926		switch (req->bRequest) {
1927		case UR_CLEAR_FEATURE:
1928			switch (UGETW(req->wValue)) {
1929			case UF_ENDPOINT_HALT:
1930				goto tr_handle_clear_halt;
1931			case UF_DEVICE_REMOTE_WAKEUP:
1932				goto tr_handle_clear_wakeup;
1933			default:
1934				goto tr_stalled;
1935			}
1936			break;
1937		case UR_SET_FEATURE:
1938			switch (UGETW(req->wValue)) {
1939			case UF_ENDPOINT_HALT:
1940				goto tr_handle_set_halt;
1941			case UF_DEVICE_REMOTE_WAKEUP:
1942				goto tr_handle_set_wakeup;
1943			default:
1944				goto tr_stalled;
1945			}
1946			break;
1947		case UR_SYNCH_FRAME:
1948			goto tr_valid;	/* nop */
1949		default:
1950			goto tr_stalled;
1951		}
1952		break;
1953
1954	case UT_READ_ENDPOINT:
1955		switch (req->bRequest) {
1956		case UR_GET_STATUS:
1957			goto tr_handle_get_ep_status;
1958		default:
1959			goto tr_stalled;
1960		}
1961		break;
1962
1963	case UT_WRITE_INTERFACE:
1964		switch (req->bRequest) {
1965		case UR_SET_INTERFACE:
1966			goto tr_handle_set_interface;
1967		case UR_CLEAR_FEATURE:
1968			goto tr_valid;	/* nop */
1969		case UR_SET_FEATURE:
1970		default:
1971			goto tr_stalled;
1972		}
1973		break;
1974
1975	case UT_READ_INTERFACE:
1976		switch (req->bRequest) {
1977		case UR_GET_INTERFACE:
1978			goto tr_handle_get_interface;
1979		case UR_GET_STATUS:
1980			goto tr_handle_get_iface_status;
1981		default:
1982			goto tr_stalled;
1983		}
1984		break;
1985
1986	case UT_WRITE_CLASS_INTERFACE:
1987	case UT_WRITE_VENDOR_INTERFACE:
1988		/* XXX forward */
1989		break;
1990
1991	case UT_READ_CLASS_INTERFACE:
1992	case UT_READ_VENDOR_INTERFACE:
1993		/* XXX forward */
1994		break;
1995
1996	case UT_WRITE_CLASS_DEVICE:
1997		switch (req->bRequest) {
1998		case UR_CLEAR_FEATURE:
1999			goto tr_valid;
2000		case UR_SET_DESCRIPTOR:
2001		case UR_SET_FEATURE:
2002			break;
2003		default:
2004			goto tr_stalled;
2005		}
2006		break;
2007
2008	case UT_WRITE_CLASS_OTHER:
2009		switch (req->bRequest) {
2010		case UR_CLEAR_FEATURE:
2011			goto tr_handle_clear_port_feature;
2012		case UR_SET_FEATURE:
2013			goto tr_handle_set_port_feature;
2014		case UR_CLEAR_TT_BUFFER:
2015		case UR_RESET_TT:
2016		case UR_STOP_TT:
2017			goto tr_valid;
2018
2019		default:
2020			goto tr_stalled;
2021		}
2022		break;
2023
2024	case UT_READ_CLASS_OTHER:
2025		switch (req->bRequest) {
2026		case UR_GET_TT_STATE:
2027			goto tr_handle_get_tt_state;
2028		case UR_GET_STATUS:
2029			goto tr_handle_get_port_status;
2030		default:
2031			goto tr_stalled;
2032		}
2033		break;
2034
2035	case UT_READ_CLASS_DEVICE:
2036		switch (req->bRequest) {
2037		case UR_GET_DESCRIPTOR:
2038			goto tr_handle_get_class_descriptor;
2039		case UR_GET_STATUS:
2040			goto tr_handle_get_class_status;
2041
2042		default:
2043			goto tr_stalled;
2044		}
2045		break;
2046	default:
2047		goto tr_stalled;
2048	}
2049	goto tr_valid;
2050
2051tr_handle_get_descriptor:
2052	switch (value >> 8) {
2053	case UDESC_DEVICE:
2054		if (value & 0xff) {
2055			goto tr_stalled;
2056		}
2057		len = sizeof(uss820dci_devd);
2058		ptr = (const void *)&uss820dci_devd;
2059		goto tr_valid;
2060	case UDESC_DEVICE_QUALIFIER:
2061		if (value & 0xff) {
2062			goto tr_stalled;
2063		}
2064		len = sizeof(uss820dci_odevd);
2065		ptr = (const void *)&uss820dci_odevd;
2066		goto tr_valid;
2067	case UDESC_CONFIG:
2068		if (value & 0xff) {
2069			goto tr_stalled;
2070		}
2071		len = sizeof(uss820dci_confd);
2072		ptr = (const void *)&uss820dci_confd;
2073		goto tr_valid;
2074	case UDESC_STRING:
2075		switch (value & 0xff) {
2076		case 0:		/* Language table */
2077			len = sizeof(usb_string_lang_en);
2078			ptr = (const void *)&usb_string_lang_en;
2079			goto tr_valid;
2080
2081		case 1:		/* Vendor */
2082			len = sizeof(uss820dci_vendor);
2083			ptr = (const void *)&uss820dci_vendor;
2084			goto tr_valid;
2085
2086		case 2:		/* Product */
2087			len = sizeof(uss820dci_product);
2088			ptr = (const void *)&uss820dci_product;
2089			goto tr_valid;
2090		default:
2091			break;
2092		}
2093		break;
2094	default:
2095		goto tr_stalled;
2096	}
2097	goto tr_stalled;
2098
2099tr_handle_get_config:
2100	len = 1;
2101	sc->sc_hub_temp.wValue[0] = sc->sc_conf;
2102	goto tr_valid;
2103
2104tr_handle_get_status:
2105	len = 2;
2106	USETW(sc->sc_hub_temp.wValue, UDS_SELF_POWERED);
2107	goto tr_valid;
2108
2109tr_handle_set_address:
2110	if (value & 0xFF00) {
2111		goto tr_stalled;
2112	}
2113	sc->sc_rt_addr = value;
2114	goto tr_valid;
2115
2116tr_handle_set_config:
2117	if (value >= 2) {
2118		goto tr_stalled;
2119	}
2120	sc->sc_conf = value;
2121	goto tr_valid;
2122
2123tr_handle_get_interface:
2124	len = 1;
2125	sc->sc_hub_temp.wValue[0] = 0;
2126	goto tr_valid;
2127
2128tr_handle_get_tt_state:
2129tr_handle_get_class_status:
2130tr_handle_get_iface_status:
2131tr_handle_get_ep_status:
2132	len = 2;
2133	USETW(sc->sc_hub_temp.wValue, 0);
2134	goto tr_valid;
2135
2136tr_handle_set_halt:
2137tr_handle_set_interface:
2138tr_handle_set_wakeup:
2139tr_handle_clear_wakeup:
2140tr_handle_clear_halt:
2141	goto tr_valid;
2142
2143tr_handle_clear_port_feature:
2144	if (index != 1) {
2145		goto tr_stalled;
2146	}
2147	DPRINTFN(9, "UR_CLEAR_PORT_FEATURE on port %d\n", index);
2148
2149	switch (value) {
2150	case UHF_PORT_SUSPEND:
2151		uss820dci_wakeup_peer(sc);
2152		break;
2153
2154	case UHF_PORT_ENABLE:
2155		sc->sc_flags.port_enabled = 0;
2156		break;
2157
2158	case UHF_PORT_TEST:
2159	case UHF_PORT_INDICATOR:
2160	case UHF_C_PORT_ENABLE:
2161	case UHF_C_PORT_OVER_CURRENT:
2162	case UHF_C_PORT_RESET:
2163		/* nops */
2164		break;
2165	case UHF_PORT_POWER:
2166		sc->sc_flags.port_powered = 0;
2167		uss820dci_pull_down(sc);
2168		break;
2169	case UHF_C_PORT_CONNECTION:
2170		sc->sc_flags.change_connect = 0;
2171		break;
2172	case UHF_C_PORT_SUSPEND:
2173		sc->sc_flags.change_suspend = 0;
2174		break;
2175	default:
2176		err = USB_ERR_IOERROR;
2177		goto done;
2178	}
2179	goto tr_valid;
2180
2181tr_handle_set_port_feature:
2182	if (index != 1) {
2183		goto tr_stalled;
2184	}
2185	DPRINTFN(9, "UR_SET_PORT_FEATURE\n");
2186
2187	switch (value) {
2188	case UHF_PORT_ENABLE:
2189		sc->sc_flags.port_enabled = 1;
2190		break;
2191	case UHF_PORT_SUSPEND:
2192	case UHF_PORT_RESET:
2193	case UHF_PORT_TEST:
2194	case UHF_PORT_INDICATOR:
2195		/* nops */
2196		break;
2197	case UHF_PORT_POWER:
2198		sc->sc_flags.port_powered = 1;
2199		break;
2200	default:
2201		err = USB_ERR_IOERROR;
2202		goto done;
2203	}
2204	goto tr_valid;
2205
2206tr_handle_get_port_status:
2207
2208	DPRINTFN(9, "UR_GET_PORT_STATUS\n");
2209
2210	if (index != 1) {
2211		goto tr_stalled;
2212	}
2213	if (sc->sc_flags.status_vbus) {
2214		uss820dci_pull_up(sc);
2215	} else {
2216		uss820dci_pull_down(sc);
2217	}
2218
2219	/* Select FULL-speed and Device Side Mode */
2220
2221	value = UPS_PORT_MODE_DEVICE;
2222
2223	if (sc->sc_flags.port_powered) {
2224		value |= UPS_PORT_POWER;
2225	}
2226	if (sc->sc_flags.port_enabled) {
2227		value |= UPS_PORT_ENABLED;
2228	}
2229	if (sc->sc_flags.status_vbus &&
2230	    sc->sc_flags.status_bus_reset) {
2231		value |= UPS_CURRENT_CONNECT_STATUS;
2232	}
2233	if (sc->sc_flags.status_suspend) {
2234		value |= UPS_SUSPEND;
2235	}
2236	USETW(sc->sc_hub_temp.ps.wPortStatus, value);
2237
2238	value = 0;
2239
2240	if (sc->sc_flags.change_connect) {
2241		value |= UPS_C_CONNECT_STATUS;
2242	}
2243	if (sc->sc_flags.change_suspend) {
2244		value |= UPS_C_SUSPEND;
2245	}
2246	USETW(sc->sc_hub_temp.ps.wPortChange, value);
2247	len = sizeof(sc->sc_hub_temp.ps);
2248	goto tr_valid;
2249
2250tr_handle_get_class_descriptor:
2251	if (value & 0xFF) {
2252		goto tr_stalled;
2253	}
2254	ptr = (const void *)&uss820dci_hubd;
2255	len = sizeof(uss820dci_hubd);
2256	goto tr_valid;
2257
2258tr_stalled:
2259	err = USB_ERR_STALLED;
2260tr_valid:
2261done:
2262	*plength = len;
2263	*pptr = ptr;
2264	return (err);
2265}
2266
2267static void
2268uss820dci_xfer_setup(struct usb_setup_params *parm)
2269{
2270	const struct usb_hw_ep_profile *pf;
2271	struct uss820dci_softc *sc;
2272	struct usb_xfer *xfer;
2273	void *last_obj;
2274	uint32_t ntd;
2275	uint32_t n;
2276	uint8_t ep_no;
2277
2278	sc = USS820_DCI_BUS2SC(parm->udev->bus);
2279	xfer = parm->curr_xfer;
2280
2281	/*
2282	 * NOTE: This driver does not use any of the parameters that
2283	 * are computed from the following values. Just set some
2284	 * reasonable dummies:
2285	 */
2286	parm->hc_max_packet_size = 0x500;
2287	parm->hc_max_packet_count = 1;
2288	parm->hc_max_frame_size = 0x500;
2289
2290	usbd_transfer_setup_sub(parm);
2291
2292	/*
2293	 * compute maximum number of TDs
2294	 */
2295	if (parm->methods == &uss820dci_device_ctrl_methods) {
2296
2297		ntd = xfer->nframes + 1 /* STATUS */ + 1 /* SYNC */ ;
2298
2299	} else if (parm->methods == &uss820dci_device_bulk_methods) {
2300
2301		ntd = xfer->nframes + 1 /* SYNC */ ;
2302
2303	} else if (parm->methods == &uss820dci_device_intr_methods) {
2304
2305		ntd = xfer->nframes + 1 /* SYNC */ ;
2306
2307	} else if (parm->methods == &uss820dci_device_isoc_fs_methods) {
2308
2309		ntd = xfer->nframes + 1 /* SYNC */ ;
2310
2311	} else {
2312
2313		ntd = 0;
2314	}
2315
2316	/*
2317	 * check if "usbd_transfer_setup_sub" set an error
2318	 */
2319	if (parm->err) {
2320		return;
2321	}
2322	/*
2323	 * allocate transfer descriptors
2324	 */
2325	last_obj = NULL;
2326
2327	/*
2328	 * get profile stuff
2329	 */
2330	if (ntd) {
2331
2332		ep_no = xfer->endpointno & UE_ADDR;
2333		uss820dci_get_hw_ep_profile(parm->udev, &pf, ep_no);
2334
2335		if (pf == NULL) {
2336			/* should not happen */
2337			parm->err = USB_ERR_INVAL;
2338			return;
2339		}
2340	} else {
2341		ep_no = 0;
2342		pf = NULL;
2343	}
2344
2345	/* align data */
2346	parm->size[0] += ((-parm->size[0]) & (USB_HOST_ALIGN - 1));
2347
2348	for (n = 0; n != ntd; n++) {
2349
2350		struct uss820dci_td *td;
2351
2352		if (parm->buf) {
2353
2354			td = USB_ADD_BYTES(parm->buf, parm->size[0]);
2355
2356			/* init TD */
2357			td->max_packet_size = xfer->max_packet_size;
2358			td->ep_index = ep_no;
2359			if (pf->support_multi_buffer &&
2360			    (parm->methods != &uss820dci_device_ctrl_methods)) {
2361				td->support_multi_buffer = 1;
2362			}
2363			td->obj_next = last_obj;
2364
2365			last_obj = td;
2366		}
2367		parm->size[0] += sizeof(*td);
2368	}
2369
2370	xfer->td_start[0] = last_obj;
2371}
2372
2373static void
2374uss820dci_xfer_unsetup(struct usb_xfer *xfer)
2375{
2376	return;
2377}
2378
2379static void
2380uss820dci_ep_init(struct usb_device *udev, struct usb_endpoint_descriptor *edesc,
2381    struct usb_endpoint *ep)
2382{
2383	struct uss820dci_softc *sc = USS820_DCI_BUS2SC(udev->bus);
2384
2385	DPRINTFN(2, "endpoint=%p, addr=%d, endpt=%d, mode=%d (%d)\n",
2386	    ep, udev->address,
2387	    edesc->bEndpointAddress, udev->flags.usb_mode,
2388	    sc->sc_rt_addr);
2389
2390	if (udev->device_index != sc->sc_rt_addr) {
2391
2392		if (udev->speed != USB_SPEED_FULL) {
2393			/* not supported */
2394			return;
2395		}
2396		switch (edesc->bmAttributes & UE_XFERTYPE) {
2397		case UE_CONTROL:
2398			ep->methods = &uss820dci_device_ctrl_methods;
2399			break;
2400		case UE_INTERRUPT:
2401			ep->methods = &uss820dci_device_intr_methods;
2402			break;
2403		case UE_ISOCHRONOUS:
2404			ep->methods = &uss820dci_device_isoc_fs_methods;
2405			break;
2406		case UE_BULK:
2407			ep->methods = &uss820dci_device_bulk_methods;
2408			break;
2409		default:
2410			/* do nothing */
2411			break;
2412		}
2413	}
2414}
2415
2416static void
2417uss820dci_set_hw_power_sleep(struct usb_bus *bus, uint32_t state)
2418{
2419	struct uss820dci_softc *sc = USS820_DCI_BUS2SC(bus);
2420
2421	switch (state) {
2422	case USB_HW_POWER_SUSPEND:
2423		uss820dci_suspend(sc);
2424		break;
2425	case USB_HW_POWER_SHUTDOWN:
2426		uss820dci_uninit(sc);
2427		break;
2428	case USB_HW_POWER_RESUME:
2429		uss820dci_resume(sc);
2430		break;
2431	default:
2432		break;
2433	}
2434}
2435
2436static const struct usb_bus_methods uss820dci_bus_methods =
2437{
2438	.endpoint_init = &uss820dci_ep_init,
2439	.xfer_setup = &uss820dci_xfer_setup,
2440	.xfer_unsetup = &uss820dci_xfer_unsetup,
2441	.get_hw_ep_profile = &uss820dci_get_hw_ep_profile,
2442	.xfer_stall = &uss820dci_xfer_stall,
2443	.set_stall = &uss820dci_set_stall,
2444	.clear_stall = &uss820dci_clear_stall,
2445	.roothub_exec = &uss820dci_roothub_exec,
2446	.xfer_poll = &uss820dci_do_poll,
2447	.set_hw_power_sleep = uss820dci_set_hw_power_sleep,
2448};
2449