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