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