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