at91dci.c revision 199673
1184610Salfred#include <sys/cdefs.h>
2184610Salfred__FBSDID("$FreeBSD: head/sys/dev/usb/controller/at91dci.c 199673 2009-11-22 21:19:01Z thompsa $");
3184610Salfred
4184610Salfred/*-
5184610Salfred * Copyright (c) 2007-2008 Hans Petter Selasky. All rights reserved.
6184610Salfred *
7184610Salfred * Redistribution and use in source and binary forms, with or without
8184610Salfred * modification, are permitted provided that the following conditions
9184610Salfred * are met:
10184610Salfred * 1. Redistributions of source code must retain the above copyright
11184610Salfred *    notice, this list of conditions and the following disclaimer.
12184610Salfred * 2. Redistributions in binary form must reproduce the above copyright
13184610Salfred *    notice, this list of conditions and the following disclaimer in the
14184610Salfred *    documentation and/or other materials provided with the distribution.
15184610Salfred *
16184610Salfred * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
17184610Salfred * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18184610Salfred * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19184610Salfred * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
20184610Salfred * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21184610Salfred * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22184610Salfred * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23184610Salfred * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24184610Salfred * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25184610Salfred * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26184610Salfred * SUCH DAMAGE.
27184610Salfred */
28184610Salfred
29184610Salfred/*
30184610Salfred * This file contains the driver for the AT91 series USB Device
31184610Salfred * Controller
32184610Salfred */
33184610Salfred
34184610Salfred/*
35184610Salfred * Thanks to "David Brownell" for helping out regarding the hardware
36184610Salfred * endpoint profiles.
37184610Salfred */
38184610Salfred
39184610Salfred/*
40184610Salfred * NOTE: The "fifo_bank" is not reset in hardware when the endpoint is
41190754Sthompsa * reset.
42184610Salfred *
43184610Salfred * NOTE: When the chip detects BUS-reset it will also reset the
44184610Salfred * endpoints, Function-address and more.
45184610Salfred */
46184610Salfred
47194677Sthompsa#include <sys/stdint.h>
48194677Sthompsa#include <sys/stddef.h>
49194677Sthompsa#include <sys/param.h>
50194677Sthompsa#include <sys/queue.h>
51194677Sthompsa#include <sys/types.h>
52194677Sthompsa#include <sys/systm.h>
53194677Sthompsa#include <sys/kernel.h>
54194677Sthompsa#include <sys/bus.h>
55194677Sthompsa#include <sys/linker_set.h>
56194677Sthompsa#include <sys/module.h>
57194677Sthompsa#include <sys/lock.h>
58194677Sthompsa#include <sys/mutex.h>
59194677Sthompsa#include <sys/condvar.h>
60194677Sthompsa#include <sys/sysctl.h>
61194677Sthompsa#include <sys/sx.h>
62194677Sthompsa#include <sys/unistd.h>
63194677Sthompsa#include <sys/callout.h>
64194677Sthompsa#include <sys/malloc.h>
65194677Sthompsa#include <sys/priv.h>
66194677Sthompsa
67188942Sthompsa#include <dev/usb/usb.h>
68194677Sthompsa#include <dev/usb/usbdi.h>
69184610Salfred
70184610Salfred#define	USB_DEBUG_VAR at91dcidebug
71184610Salfred
72188942Sthompsa#include <dev/usb/usb_core.h>
73188942Sthompsa#include <dev/usb/usb_debug.h>
74188942Sthompsa#include <dev/usb/usb_busdma.h>
75188942Sthompsa#include <dev/usb/usb_process.h>
76188942Sthompsa#include <dev/usb/usb_transfer.h>
77188942Sthompsa#include <dev/usb/usb_device.h>
78188942Sthompsa#include <dev/usb/usb_hub.h>
79188942Sthompsa#include <dev/usb/usb_util.h>
80184610Salfred
81188942Sthompsa#include <dev/usb/usb_controller.h>
82188942Sthompsa#include <dev/usb/usb_bus.h>
83188942Sthompsa#include <dev/usb/controller/at91dci.h>
84184610Salfred
85184610Salfred#define	AT9100_DCI_BUS2SC(bus) \
86184610Salfred   ((struct at91dci_softc *)(((uint8_t *)(bus)) - \
87190181Sthompsa    ((uint8_t *)&(((struct at91dci_softc *)0)->sc_bus))))
88184610Salfred
89184610Salfred#define	AT9100_DCI_PC2SC(pc) \
90190180Sthompsa   AT9100_DCI_BUS2SC(USB_DMATAG_TO_XROOT((pc)->tag_parent)->bus)
91184610Salfred
92194677Sthompsa#ifdef USB_DEBUG
93184610Salfredstatic int at91dcidebug = 0;
94184610Salfred
95192502SthompsaSYSCTL_NODE(_hw_usb, OID_AUTO, at91dci, CTLFLAG_RW, 0, "USB at91dci");
96192502SthompsaSYSCTL_INT(_hw_usb_at91dci, OID_AUTO, debug, CTLFLAG_RW,
97184610Salfred    &at91dcidebug, 0, "at91dci debug level");
98184610Salfred#endif
99184610Salfred
100184610Salfred#define	AT9100_DCI_INTR_ENDPT 1
101184610Salfred
102184610Salfred/* prototypes */
103184610Salfred
104192984Sthompsastruct usb_bus_methods at91dci_bus_methods;
105192984Sthompsastruct usb_pipe_methods at91dci_device_bulk_methods;
106192984Sthompsastruct usb_pipe_methods at91dci_device_ctrl_methods;
107192984Sthompsastruct usb_pipe_methods at91dci_device_intr_methods;
108192984Sthompsastruct usb_pipe_methods at91dci_device_isoc_fs_methods;
109184610Salfred
110184610Salfredstatic at91dci_cmd_t at91dci_setup_rx;
111184610Salfredstatic at91dci_cmd_t at91dci_data_rx;
112184610Salfredstatic at91dci_cmd_t at91dci_data_tx;
113184610Salfredstatic at91dci_cmd_t at91dci_data_tx_sync;
114193045Sthompsastatic void	at91dci_device_done(struct usb_xfer *, usb_error_t);
115192984Sthompsastatic void	at91dci_do_poll(struct usb_bus *);
116192984Sthompsastatic void	at91dci_standard_done(struct usb_xfer *);
117190735Sthompsastatic void	at91dci_root_intr(struct at91dci_softc *sc);
118184610Salfred
119184610Salfred/*
120184610Salfred * NOTE: Some of the bits in the CSR register have inverse meaning so
121184610Salfred * we need a helper macro when acknowledging events:
122184610Salfred */
123184610Salfred#define	AT91_CSR_ACK(csr, what) do {		\
124184610Salfred  (csr) &= ~((AT91_UDP_CSR_FORCESTALL|		\
125184610Salfred	      AT91_UDP_CSR_TXPKTRDY|		\
126184610Salfred	      AT91_UDP_CSR_RXBYTECNT) ^ (what));\
127184610Salfred  (csr) |= ((AT91_UDP_CSR_RX_DATA_BK0|		\
128184610Salfred	     AT91_UDP_CSR_RX_DATA_BK1|		\
129184610Salfred	     AT91_UDP_CSR_TXCOMP|		\
130184610Salfred	     AT91_UDP_CSR_RXSETUP|		\
131184610Salfred	     AT91_UDP_CSR_STALLSENT) ^ (what));	\
132184610Salfred} while (0)
133184610Salfred
134184610Salfred/*
135184610Salfred * Here is a list of what the chip supports.
136184610Salfred * Probably it supports more than listed here!
137184610Salfred */
138192984Sthompsastatic const struct usb_hw_ep_profile
139184610Salfred	at91dci_ep_profile[AT91_UDP_EP_MAX] = {
140184610Salfred
141184610Salfred	[0] = {
142184610Salfred		.max_in_frame_size = 8,
143184610Salfred		.max_out_frame_size = 8,
144184610Salfred		.is_simplex = 1,
145184610Salfred		.support_control = 1,
146184610Salfred	},
147184610Salfred	[1] = {
148184610Salfred		.max_in_frame_size = 64,
149184610Salfred		.max_out_frame_size = 64,
150184610Salfred		.is_simplex = 1,
151184610Salfred		.support_multi_buffer = 1,
152184610Salfred		.support_bulk = 1,
153184610Salfred		.support_interrupt = 1,
154184610Salfred		.support_isochronous = 1,
155184610Salfred		.support_in = 1,
156184610Salfred		.support_out = 1,
157184610Salfred	},
158184610Salfred	[2] = {
159184610Salfred		.max_in_frame_size = 64,
160184610Salfred		.max_out_frame_size = 64,
161184610Salfred		.is_simplex = 1,
162184610Salfred		.support_multi_buffer = 1,
163184610Salfred		.support_bulk = 1,
164184610Salfred		.support_interrupt = 1,
165184610Salfred		.support_isochronous = 1,
166184610Salfred		.support_in = 1,
167184610Salfred		.support_out = 1,
168184610Salfred	},
169184610Salfred	[3] = {
170184610Salfred		/* can also do BULK */
171184610Salfred		.max_in_frame_size = 8,
172184610Salfred		.max_out_frame_size = 8,
173184610Salfred		.is_simplex = 1,
174184610Salfred		.support_interrupt = 1,
175184610Salfred		.support_in = 1,
176184610Salfred		.support_out = 1,
177184610Salfred	},
178184610Salfred	[4] = {
179184610Salfred		.max_in_frame_size = 256,
180184610Salfred		.max_out_frame_size = 256,
181184610Salfred		.is_simplex = 1,
182184610Salfred		.support_multi_buffer = 1,
183184610Salfred		.support_bulk = 1,
184184610Salfred		.support_interrupt = 1,
185184610Salfred		.support_isochronous = 1,
186184610Salfred		.support_in = 1,
187184610Salfred		.support_out = 1,
188184610Salfred	},
189184610Salfred	[5] = {
190184610Salfred		.max_in_frame_size = 256,
191184610Salfred		.max_out_frame_size = 256,
192184610Salfred		.is_simplex = 1,
193184610Salfred		.support_multi_buffer = 1,
194184610Salfred		.support_bulk = 1,
195184610Salfred		.support_interrupt = 1,
196184610Salfred		.support_isochronous = 1,
197184610Salfred		.support_in = 1,
198184610Salfred		.support_out = 1,
199184610Salfred	},
200184610Salfred};
201184610Salfred
202184610Salfredstatic void
203192984Sthompsaat91dci_get_hw_ep_profile(struct usb_device *udev,
204192984Sthompsa    const struct usb_hw_ep_profile **ppf, uint8_t ep_addr)
205184610Salfred{
206184610Salfred	if (ep_addr < AT91_UDP_EP_MAX) {
207184610Salfred		*ppf = (at91dci_ep_profile + ep_addr);
208184610Salfred	} else {
209184610Salfred		*ppf = NULL;
210184610Salfred	}
211184610Salfred}
212184610Salfred
213184610Salfredstatic void
214184610Salfredat91dci_clocks_on(struct at91dci_softc *sc)
215184610Salfred{
216184610Salfred	if (sc->sc_flags.clocks_off &&
217184610Salfred	    sc->sc_flags.port_powered) {
218184610Salfred
219184610Salfred		DPRINTFN(5, "\n");
220184610Salfred
221184610Salfred		if (sc->sc_clocks_on) {
222184610Salfred			(sc->sc_clocks_on) (sc->sc_clocks_arg);
223184610Salfred		}
224184610Salfred		sc->sc_flags.clocks_off = 0;
225184610Salfred
226184610Salfred		/* enable Transceiver */
227184610Salfred		AT91_UDP_WRITE_4(sc, AT91_UDP_TXVC, 0);
228184610Salfred	}
229184610Salfred}
230184610Salfred
231184610Salfredstatic void
232184610Salfredat91dci_clocks_off(struct at91dci_softc *sc)
233184610Salfred{
234184610Salfred	if (!sc->sc_flags.clocks_off) {
235184610Salfred
236184610Salfred		DPRINTFN(5, "\n");
237184610Salfred
238184610Salfred		/* disable Transceiver */
239184610Salfred		AT91_UDP_WRITE_4(sc, AT91_UDP_TXVC, AT91_UDP_TXVC_DIS);
240184610Salfred
241184610Salfred		if (sc->sc_clocks_off) {
242184610Salfred			(sc->sc_clocks_off) (sc->sc_clocks_arg);
243184610Salfred		}
244184610Salfred		sc->sc_flags.clocks_off = 1;
245184610Salfred	}
246184610Salfred}
247184610Salfred
248184610Salfredstatic void
249184610Salfredat91dci_pull_up(struct at91dci_softc *sc)
250184610Salfred{
251184610Salfred	/* pullup D+, if possible */
252184610Salfred
253184610Salfred	if (!sc->sc_flags.d_pulled_up &&
254184610Salfred	    sc->sc_flags.port_powered) {
255184610Salfred		sc->sc_flags.d_pulled_up = 1;
256184610Salfred		(sc->sc_pull_up) (sc->sc_pull_arg);
257184610Salfred	}
258184610Salfred}
259184610Salfred
260184610Salfredstatic void
261184610Salfredat91dci_pull_down(struct at91dci_softc *sc)
262184610Salfred{
263184610Salfred	/* pulldown D+, if possible */
264184610Salfred
265184610Salfred	if (sc->sc_flags.d_pulled_up) {
266184610Salfred		sc->sc_flags.d_pulled_up = 0;
267184610Salfred		(sc->sc_pull_down) (sc->sc_pull_arg);
268184610Salfred	}
269184610Salfred}
270184610Salfred
271184610Salfredstatic void
272190735Sthompsaat91dci_wakeup_peer(struct at91dci_softc *sc)
273184610Salfred{
274184610Salfred	if (!(sc->sc_flags.status_suspend)) {
275184610Salfred		return;
276184610Salfred	}
277184610Salfred
278186730Salfred	AT91_UDP_WRITE_4(sc, AT91_UDP_GSTATE, AT91_UDP_GSTATE_ESR);
279184610Salfred
280186730Salfred	/* wait 8 milliseconds */
281188983Sthompsa	/* Wait for reset to complete. */
282194228Sthompsa	usb_pause_mtx(&sc->sc_bus.bus_mtx, hz / 125);
283184610Salfred
284186730Salfred	AT91_UDP_WRITE_4(sc, AT91_UDP_GSTATE, 0);
285184610Salfred}
286184610Salfred
287184610Salfredstatic void
288184610Salfredat91dci_set_address(struct at91dci_softc *sc, uint8_t addr)
289184610Salfred{
290184610Salfred	DPRINTFN(5, "addr=%d\n", addr);
291184610Salfred
292184610Salfred	AT91_UDP_WRITE_4(sc, AT91_UDP_FADDR, addr |
293184610Salfred	    AT91_UDP_FADDR_EN);
294184610Salfred}
295184610Salfred
296184610Salfredstatic uint8_t
297184610Salfredat91dci_setup_rx(struct at91dci_td *td)
298184610Salfred{
299184610Salfred	struct at91dci_softc *sc;
300192984Sthompsa	struct usb_device_request req;
301184610Salfred	uint32_t csr;
302184610Salfred	uint32_t temp;
303184610Salfred	uint16_t count;
304184610Salfred
305184610Salfred	/* read out FIFO status */
306184610Salfred	csr = bus_space_read_4(td->io_tag, td->io_hdl,
307184610Salfred	    td->status_reg);
308184610Salfred
309184610Salfred	DPRINTFN(5, "csr=0x%08x rem=%u\n", csr, td->remainder);
310184610Salfred
311184610Salfred	temp = csr;
312184610Salfred	temp &= (AT91_UDP_CSR_RX_DATA_BK0 |
313184610Salfred	    AT91_UDP_CSR_RX_DATA_BK1 |
314184610Salfred	    AT91_UDP_CSR_STALLSENT |
315184610Salfred	    AT91_UDP_CSR_RXSETUP |
316184610Salfred	    AT91_UDP_CSR_TXCOMP);
317184610Salfred
318184610Salfred	if (!(csr & AT91_UDP_CSR_RXSETUP)) {
319184610Salfred		goto not_complete;
320184610Salfred	}
321190721Sthompsa	/* clear did stall */
322190721Sthompsa	td->did_stall = 0;
323190721Sthompsa
324184610Salfred	/* get the packet byte count */
325184610Salfred	count = (csr & AT91_UDP_CSR_RXBYTECNT) >> 16;
326184610Salfred
327184610Salfred	/* verify data length */
328184610Salfred	if (count != td->remainder) {
329184610Salfred		DPRINTFN(0, "Invalid SETUP packet "
330184610Salfred		    "length, %d bytes\n", count);
331184610Salfred		goto not_complete;
332184610Salfred	}
333184610Salfred	if (count != sizeof(req)) {
334184610Salfred		DPRINTFN(0, "Unsupported SETUP packet "
335184610Salfred		    "length, %d bytes\n", count);
336184610Salfred		goto not_complete;
337184610Salfred	}
338184610Salfred	/* receive data */
339184610Salfred	bus_space_read_multi_1(td->io_tag, td->io_hdl,
340184610Salfred	    td->fifo_reg, (void *)&req, sizeof(req));
341184610Salfred
342184610Salfred	/* copy data into real buffer */
343194228Sthompsa	usbd_copy_in(td->pc, 0, &req, sizeof(req));
344184610Salfred
345184610Salfred	td->offset = sizeof(req);
346184610Salfred	td->remainder = 0;
347184610Salfred
348184610Salfred	/* get pointer to softc */
349184610Salfred	sc = AT9100_DCI_PC2SC(td->pc);
350184610Salfred
351184610Salfred	/* sneak peek the set address */
352184610Salfred	if ((req.bmRequestType == UT_WRITE_DEVICE) &&
353184610Salfred	    (req.bRequest == UR_SET_ADDRESS)) {
354184610Salfred		sc->sc_dv_addr = req.wValue[0] & 0x7F;
355184610Salfred	} else {
356184610Salfred		sc->sc_dv_addr = 0xFF;
357184610Salfred	}
358184610Salfred
359184610Salfred	/* sneak peek the endpoint direction */
360184610Salfred	if (req.bmRequestType & UE_DIR_IN) {
361184610Salfred		csr |= AT91_UDP_CSR_DIR;
362184610Salfred	} else {
363184610Salfred		csr &= ~AT91_UDP_CSR_DIR;
364184610Salfred	}
365184610Salfred
366184610Salfred	/* write the direction of the control transfer */
367184610Salfred	AT91_CSR_ACK(csr, temp);
368184610Salfred	bus_space_write_4(td->io_tag, td->io_hdl,
369184610Salfred	    td->status_reg, csr);
370184610Salfred	return (0);			/* complete */
371184610Salfred
372184610Salfrednot_complete:
373190721Sthompsa	/* abort any ongoing transfer */
374190721Sthompsa	if (!td->did_stall) {
375190721Sthompsa		DPRINTFN(5, "stalling\n");
376190721Sthompsa		temp |= AT91_UDP_CSR_FORCESTALL;
377190721Sthompsa		td->did_stall = 1;
378190721Sthompsa	}
379190721Sthompsa
380184610Salfred	/* clear interrupts, if any */
381184610Salfred	if (temp) {
382184610Salfred		DPRINTFN(5, "clearing 0x%08x\n", temp);
383184610Salfred		AT91_CSR_ACK(csr, temp);
384184610Salfred		bus_space_write_4(td->io_tag, td->io_hdl,
385184610Salfred		    td->status_reg, csr);
386184610Salfred	}
387184610Salfred	return (1);			/* not complete */
388184610Salfred
389184610Salfred}
390184610Salfred
391184610Salfredstatic uint8_t
392184610Salfredat91dci_data_rx(struct at91dci_td *td)
393184610Salfred{
394192984Sthompsa	struct usb_page_search buf_res;
395184610Salfred	uint32_t csr;
396184610Salfred	uint32_t temp;
397184610Salfred	uint16_t count;
398184610Salfred	uint8_t to;
399184610Salfred	uint8_t got_short;
400184610Salfred
401184610Salfred	to = 2;				/* don't loop forever! */
402184610Salfred	got_short = 0;
403184610Salfred
404184610Salfred	/* check if any of the FIFO banks have data */
405184610Salfredrepeat:
406184610Salfred	/* read out FIFO status */
407184610Salfred	csr = bus_space_read_4(td->io_tag, td->io_hdl,
408184610Salfred	    td->status_reg);
409184610Salfred
410184610Salfred	DPRINTFN(5, "csr=0x%08x rem=%u\n", csr, td->remainder);
411184610Salfred
412184610Salfred	if (csr & AT91_UDP_CSR_RXSETUP) {
413184610Salfred		if (td->remainder == 0) {
414184610Salfred			/*
415184610Salfred			 * We are actually complete and have
416184610Salfred			 * received the next SETUP
417184610Salfred			 */
418184610Salfred			DPRINTFN(5, "faking complete\n");
419184610Salfred			return (0);	/* complete */
420184610Salfred		}
421184610Salfred		/*
422184610Salfred	         * USB Host Aborted the transfer.
423184610Salfred	         */
424184610Salfred		td->error = 1;
425184610Salfred		return (0);		/* complete */
426184610Salfred	}
427184610Salfred	/* Make sure that "STALLSENT" gets cleared */
428184610Salfred	temp = csr;
429184610Salfred	temp &= AT91_UDP_CSR_STALLSENT;
430184610Salfred
431184610Salfred	/* check status */
432184610Salfred	if (!(csr & (AT91_UDP_CSR_RX_DATA_BK0 |
433184610Salfred	    AT91_UDP_CSR_RX_DATA_BK1))) {
434184610Salfred		if (temp) {
435184610Salfred			/* write command */
436184610Salfred			AT91_CSR_ACK(csr, temp);
437184610Salfred			bus_space_write_4(td->io_tag, td->io_hdl,
438184610Salfred			    td->status_reg, csr);
439184610Salfred		}
440184610Salfred		return (1);		/* not complete */
441184610Salfred	}
442184610Salfred	/* get the packet byte count */
443184610Salfred	count = (csr & AT91_UDP_CSR_RXBYTECNT) >> 16;
444184610Salfred
445184610Salfred	/* verify the packet byte count */
446184610Salfred	if (count != td->max_packet_size) {
447184610Salfred		if (count < td->max_packet_size) {
448184610Salfred			/* we have a short packet */
449184610Salfred			td->short_pkt = 1;
450184610Salfred			got_short = 1;
451184610Salfred		} else {
452184610Salfred			/* invalid USB packet */
453184610Salfred			td->error = 1;
454184610Salfred			return (0);	/* we are complete */
455184610Salfred		}
456184610Salfred	}
457184610Salfred	/* verify the packet byte count */
458184610Salfred	if (count > td->remainder) {
459184610Salfred		/* invalid USB packet */
460184610Salfred		td->error = 1;
461184610Salfred		return (0);		/* we are complete */
462184610Salfred	}
463184610Salfred	while (count > 0) {
464194228Sthompsa		usbd_get_page(td->pc, td->offset, &buf_res);
465184610Salfred
466184610Salfred		/* get correct length */
467184610Salfred		if (buf_res.length > count) {
468184610Salfred			buf_res.length = count;
469184610Salfred		}
470184610Salfred		/* receive data */
471184610Salfred		bus_space_read_multi_1(td->io_tag, td->io_hdl,
472184610Salfred		    td->fifo_reg, buf_res.buffer, buf_res.length);
473184610Salfred
474184610Salfred		/* update counters */
475184610Salfred		count -= buf_res.length;
476184610Salfred		td->offset += buf_res.length;
477184610Salfred		td->remainder -= buf_res.length;
478184610Salfred	}
479184610Salfred
480184610Salfred	/* clear status bits */
481184610Salfred	if (td->support_multi_buffer) {
482184610Salfred		if (td->fifo_bank) {
483184610Salfred			td->fifo_bank = 0;
484184610Salfred			temp |= AT91_UDP_CSR_RX_DATA_BK1;
485184610Salfred		} else {
486184610Salfred			td->fifo_bank = 1;
487184610Salfred			temp |= AT91_UDP_CSR_RX_DATA_BK0;
488184610Salfred		}
489184610Salfred	} else {
490184610Salfred		temp |= (AT91_UDP_CSR_RX_DATA_BK0 |
491184610Salfred		    AT91_UDP_CSR_RX_DATA_BK1);
492184610Salfred	}
493184610Salfred
494184610Salfred	/* write command */
495184610Salfred	AT91_CSR_ACK(csr, temp);
496184610Salfred	bus_space_write_4(td->io_tag, td->io_hdl,
497184610Salfred	    td->status_reg, csr);
498184610Salfred
499184610Salfred	/*
500184610Salfred	 * NOTE: We may have to delay a little bit before
501184610Salfred	 * proceeding after clearing the DATA_BK bits.
502184610Salfred	 */
503184610Salfred
504184610Salfred	/* check if we are complete */
505184610Salfred	if ((td->remainder == 0) || got_short) {
506184610Salfred		if (td->short_pkt) {
507184610Salfred			/* we are complete */
508184610Salfred			return (0);
509184610Salfred		}
510184610Salfred		/* else need to receive a zero length packet */
511184610Salfred	}
512184610Salfred	if (--to) {
513184610Salfred		goto repeat;
514184610Salfred	}
515184610Salfred	return (1);			/* not complete */
516184610Salfred}
517184610Salfred
518184610Salfredstatic uint8_t
519184610Salfredat91dci_data_tx(struct at91dci_td *td)
520184610Salfred{
521192984Sthompsa	struct usb_page_search buf_res;
522184610Salfred	uint32_t csr;
523184610Salfred	uint32_t temp;
524184610Salfred	uint16_t count;
525184610Salfred	uint8_t to;
526184610Salfred
527184610Salfred	to = 2;				/* don't loop forever! */
528184610Salfred
529184610Salfredrepeat:
530184610Salfred
531184610Salfred	/* read out FIFO status */
532184610Salfred	csr = bus_space_read_4(td->io_tag, td->io_hdl,
533184610Salfred	    td->status_reg);
534184610Salfred
535184610Salfred	DPRINTFN(5, "csr=0x%08x rem=%u\n", csr, td->remainder);
536184610Salfred
537184610Salfred	if (csr & AT91_UDP_CSR_RXSETUP) {
538184610Salfred		/*
539184610Salfred	         * The current transfer was aborted
540184610Salfred	         * by the USB Host
541184610Salfred	         */
542184610Salfred		td->error = 1;
543184610Salfred		return (0);		/* complete */
544184610Salfred	}
545184610Salfred	/* Make sure that "STALLSENT" gets cleared */
546184610Salfred	temp = csr;
547184610Salfred	temp &= AT91_UDP_CSR_STALLSENT;
548184610Salfred
549184610Salfred	if (csr & AT91_UDP_CSR_TXPKTRDY) {
550184610Salfred		if (temp) {
551184610Salfred			/* write command */
552184610Salfred			AT91_CSR_ACK(csr, temp);
553184610Salfred			bus_space_write_4(td->io_tag, td->io_hdl,
554184610Salfred			    td->status_reg, csr);
555184610Salfred		}
556184610Salfred		return (1);		/* not complete */
557184610Salfred	} else {
558184610Salfred		/* clear TXCOMP and set TXPKTRDY */
559184610Salfred		temp |= (AT91_UDP_CSR_TXCOMP |
560184610Salfred		    AT91_UDP_CSR_TXPKTRDY);
561184610Salfred	}
562184610Salfred
563184610Salfred	count = td->max_packet_size;
564184610Salfred	if (td->remainder < count) {
565184610Salfred		/* we have a short packet */
566184610Salfred		td->short_pkt = 1;
567184610Salfred		count = td->remainder;
568184610Salfred	}
569184610Salfred	while (count > 0) {
570184610Salfred
571194228Sthompsa		usbd_get_page(td->pc, td->offset, &buf_res);
572184610Salfred
573184610Salfred		/* get correct length */
574184610Salfred		if (buf_res.length > count) {
575184610Salfred			buf_res.length = count;
576184610Salfred		}
577184610Salfred		/* transmit data */
578184610Salfred		bus_space_write_multi_1(td->io_tag, td->io_hdl,
579184610Salfred		    td->fifo_reg, buf_res.buffer, buf_res.length);
580184610Salfred
581184610Salfred		/* update counters */
582184610Salfred		count -= buf_res.length;
583184610Salfred		td->offset += buf_res.length;
584184610Salfred		td->remainder -= buf_res.length;
585184610Salfred	}
586184610Salfred
587184610Salfred	/* write command */
588184610Salfred	AT91_CSR_ACK(csr, temp);
589184610Salfred	bus_space_write_4(td->io_tag, td->io_hdl,
590184610Salfred	    td->status_reg, csr);
591184610Salfred
592184610Salfred	/* check remainder */
593184610Salfred	if (td->remainder == 0) {
594184610Salfred		if (td->short_pkt) {
595184610Salfred			return (0);	/* complete */
596184610Salfred		}
597184610Salfred		/* else we need to transmit a short packet */
598184610Salfred	}
599184610Salfred	if (--to) {
600184610Salfred		goto repeat;
601184610Salfred	}
602184610Salfred	return (1);			/* not complete */
603184610Salfred}
604184610Salfred
605184610Salfredstatic uint8_t
606184610Salfredat91dci_data_tx_sync(struct at91dci_td *td)
607184610Salfred{
608184610Salfred	struct at91dci_softc *sc;
609184610Salfred	uint32_t csr;
610184610Salfred	uint32_t temp;
611184610Salfred
612184610Salfred#if 0
613184610Salfredrepeat:
614184610Salfred#endif
615184610Salfred
616184610Salfred	/* read out FIFO status */
617184610Salfred	csr = bus_space_read_4(td->io_tag, td->io_hdl,
618184610Salfred	    td->status_reg);
619184610Salfred
620184610Salfred	DPRINTFN(5, "csr=0x%08x\n", csr);
621184610Salfred
622184610Salfred	if (csr & AT91_UDP_CSR_RXSETUP) {
623184610Salfred		DPRINTFN(5, "faking complete\n");
624184610Salfred		/* Race condition */
625184610Salfred		return (0);		/* complete */
626184610Salfred	}
627184610Salfred	temp = csr;
628184610Salfred	temp &= (AT91_UDP_CSR_STALLSENT |
629184610Salfred	    AT91_UDP_CSR_TXCOMP);
630184610Salfred
631184610Salfred	/* check status */
632184610Salfred	if (csr & AT91_UDP_CSR_TXPKTRDY) {
633184610Salfred		goto not_complete;
634184610Salfred	}
635184610Salfred	if (!(csr & AT91_UDP_CSR_TXCOMP)) {
636184610Salfred		goto not_complete;
637184610Salfred	}
638184610Salfred	sc = AT9100_DCI_PC2SC(td->pc);
639184610Salfred	if (sc->sc_dv_addr != 0xFF) {
640184610Salfred		/*
641184610Salfred		 * The AT91 has a special requirement with regard to
642184610Salfred		 * setting the address and that is to write the new
643184610Salfred		 * address before clearing TXCOMP:
644184610Salfred		 */
645184610Salfred		at91dci_set_address(sc, sc->sc_dv_addr);
646184610Salfred	}
647184610Salfred	/* write command */
648184610Salfred	AT91_CSR_ACK(csr, temp);
649184610Salfred	bus_space_write_4(td->io_tag, td->io_hdl,
650184610Salfred	    td->status_reg, csr);
651184610Salfred
652184610Salfred	return (0);			/* complete */
653184610Salfred
654184610Salfrednot_complete:
655184610Salfred	if (temp) {
656184610Salfred		/* write command */
657184610Salfred		AT91_CSR_ACK(csr, temp);
658184610Salfred		bus_space_write_4(td->io_tag, td->io_hdl,
659184610Salfred		    td->status_reg, csr);
660184610Salfred	}
661184610Salfred	return (1);			/* not complete */
662184610Salfred}
663184610Salfred
664184610Salfredstatic uint8_t
665192984Sthompsaat91dci_xfer_do_fifo(struct usb_xfer *xfer)
666184610Salfred{
667184610Salfred	struct at91dci_softc *sc;
668184610Salfred	struct at91dci_td *td;
669184610Salfred	uint8_t temp;
670184610Salfred
671184610Salfred	DPRINTFN(9, "\n");
672184610Salfred
673184610Salfred	td = xfer->td_transfer_cache;
674184610Salfred	while (1) {
675184610Salfred		if ((td->func) (td)) {
676184610Salfred			/* operation in progress */
677184610Salfred			break;
678184610Salfred		}
679184610Salfred		if (((void *)td) == xfer->td_transfer_last) {
680184610Salfred			goto done;
681184610Salfred		}
682184610Salfred		if (td->error) {
683184610Salfred			goto done;
684184610Salfred		} else if (td->remainder > 0) {
685184610Salfred			/*
686184610Salfred			 * We had a short transfer. If there is no alternate
687184610Salfred			 * next, stop processing !
688184610Salfred			 */
689184610Salfred			if (!td->alt_next) {
690184610Salfred				goto done;
691184610Salfred			}
692184610Salfred		}
693184610Salfred		/*
694184610Salfred		 * Fetch the next transfer descriptor and transfer
695184610Salfred		 * some flags to the next transfer descriptor
696184610Salfred		 */
697184610Salfred		temp = 0;
698184610Salfred		if (td->fifo_bank)
699184610Salfred			temp |= 1;
700184610Salfred		td = td->obj_next;
701184610Salfred		xfer->td_transfer_cache = td;
702184610Salfred		if (temp & 1)
703184610Salfred			td->fifo_bank = 1;
704184610Salfred	}
705184610Salfred	return (1);			/* not complete */
706184610Salfred
707184610Salfreddone:
708187173Sthompsa	sc = AT9100_DCI_BUS2SC(xfer->xroot->bus);
709193644Sthompsa	temp = (xfer->endpointno & UE_ADDR);
710184610Salfred
711184610Salfred	/* update FIFO bank flag and multi buffer */
712184610Salfred	if (td->fifo_bank) {
713184610Salfred		sc->sc_ep_flags[temp].fifo_bank = 1;
714184610Salfred	} else {
715184610Salfred		sc->sc_ep_flags[temp].fifo_bank = 0;
716184610Salfred	}
717184610Salfred
718184610Salfred	/* compute all actual lengths */
719184610Salfred
720184610Salfred	at91dci_standard_done(xfer);
721184610Salfred
722184610Salfred	return (0);			/* complete */
723184610Salfred}
724184610Salfred
725184610Salfredstatic void
726184610Salfredat91dci_interrupt_poll(struct at91dci_softc *sc)
727184610Salfred{
728192984Sthompsa	struct usb_xfer *xfer;
729184610Salfred
730184610Salfredrepeat:
731184610Salfred	TAILQ_FOREACH(xfer, &sc->sc_bus.intr_q.head, wait_entry) {
732184610Salfred		if (!at91dci_xfer_do_fifo(xfer)) {
733184610Salfred			/* queue has been modified */
734184610Salfred			goto repeat;
735184610Salfred		}
736184610Salfred	}
737184610Salfred}
738184610Salfred
739187175Sthompsavoid
740187175Sthompsaat91dci_vbus_interrupt(struct at91dci_softc *sc, uint8_t is_on)
741184610Salfred{
742184610Salfred	DPRINTFN(5, "vbus = %u\n", is_on);
743184610Salfred
744184824Sthompsa	USB_BUS_LOCK(&sc->sc_bus);
745184610Salfred	if (is_on) {
746184610Salfred		if (!sc->sc_flags.status_vbus) {
747184610Salfred			sc->sc_flags.status_vbus = 1;
748184610Salfred
749184610Salfred			/* complete root HUB interrupt endpoint */
750190735Sthompsa			at91dci_root_intr(sc);
751184610Salfred		}
752184610Salfred	} else {
753184610Salfred		if (sc->sc_flags.status_vbus) {
754184610Salfred			sc->sc_flags.status_vbus = 0;
755184610Salfred			sc->sc_flags.status_bus_reset = 0;
756184610Salfred			sc->sc_flags.status_suspend = 0;
757184610Salfred			sc->sc_flags.change_suspend = 0;
758184610Salfred			sc->sc_flags.change_connect = 1;
759184610Salfred
760184610Salfred			/* complete root HUB interrupt endpoint */
761190735Sthompsa			at91dci_root_intr(sc);
762184610Salfred		}
763184610Salfred	}
764184824Sthompsa	USB_BUS_UNLOCK(&sc->sc_bus);
765184610Salfred}
766184610Salfred
767184610Salfredvoid
768184610Salfredat91dci_interrupt(struct at91dci_softc *sc)
769184610Salfred{
770184610Salfred	uint32_t status;
771184610Salfred
772184824Sthompsa	USB_BUS_LOCK(&sc->sc_bus);
773184610Salfred
774184610Salfred	status = AT91_UDP_READ_4(sc, AT91_UDP_ISR);
775184610Salfred	status &= AT91_UDP_INT_DEFAULT;
776184610Salfred
777184610Salfred	if (!status) {
778184824Sthompsa		USB_BUS_UNLOCK(&sc->sc_bus);
779184610Salfred		return;
780184610Salfred	}
781184610Salfred	/* acknowledge interrupts */
782184610Salfred
783184610Salfred	AT91_UDP_WRITE_4(sc, AT91_UDP_ICR, status);
784184610Salfred
785184610Salfred	/* check for any bus state change interrupts */
786184610Salfred
787184610Salfred	if (status & AT91_UDP_INT_BUS) {
788184610Salfred
789184610Salfred		DPRINTFN(5, "real bus interrupt 0x%08x\n", status);
790184610Salfred
791184610Salfred		if (status & AT91_UDP_INT_END_BR) {
792184610Salfred
793184610Salfred			/* set correct state */
794184610Salfred			sc->sc_flags.status_bus_reset = 1;
795184610Salfred			sc->sc_flags.status_suspend = 0;
796184610Salfred			sc->sc_flags.change_suspend = 0;
797184610Salfred			sc->sc_flags.change_connect = 1;
798184610Salfred
799184610Salfred			/* disable resume interrupt */
800184610Salfred			AT91_UDP_WRITE_4(sc, AT91_UDP_IDR,
801184610Salfred			    AT91_UDP_INT_RXRSM);
802184610Salfred			/* enable suspend interrupt */
803184610Salfred			AT91_UDP_WRITE_4(sc, AT91_UDP_IER,
804184610Salfred			    AT91_UDP_INT_RXSUSP);
805184610Salfred		}
806184610Salfred		/*
807184610Salfred	         * If RXRSM and RXSUSP is set at the same time we interpret
808184610Salfred	         * that like RESUME. Resume is set when there is at least 3
809184610Salfred	         * milliseconds of inactivity on the USB BUS.
810184610Salfred	         */
811184610Salfred		if (status & AT91_UDP_INT_RXRSM) {
812184610Salfred			if (sc->sc_flags.status_suspend) {
813184610Salfred				sc->sc_flags.status_suspend = 0;
814184610Salfred				sc->sc_flags.change_suspend = 1;
815184610Salfred
816184610Salfred				/* disable resume interrupt */
817184610Salfred				AT91_UDP_WRITE_4(sc, AT91_UDP_IDR,
818184610Salfred				    AT91_UDP_INT_RXRSM);
819184610Salfred				/* enable suspend interrupt */
820184610Salfred				AT91_UDP_WRITE_4(sc, AT91_UDP_IER,
821184610Salfred				    AT91_UDP_INT_RXSUSP);
822184610Salfred			}
823184610Salfred		} else if (status & AT91_UDP_INT_RXSUSP) {
824184610Salfred			if (!sc->sc_flags.status_suspend) {
825184610Salfred				sc->sc_flags.status_suspend = 1;
826184610Salfred				sc->sc_flags.change_suspend = 1;
827184610Salfred
828184610Salfred				/* disable suspend interrupt */
829184610Salfred				AT91_UDP_WRITE_4(sc, AT91_UDP_IDR,
830184610Salfred				    AT91_UDP_INT_RXSUSP);
831184610Salfred
832184610Salfred				/* enable resume interrupt */
833184610Salfred				AT91_UDP_WRITE_4(sc, AT91_UDP_IER,
834184610Salfred				    AT91_UDP_INT_RXRSM);
835184610Salfred			}
836184610Salfred		}
837184610Salfred		/* complete root HUB interrupt endpoint */
838190735Sthompsa		at91dci_root_intr(sc);
839184610Salfred	}
840184610Salfred	/* check for any endpoint interrupts */
841184610Salfred
842184610Salfred	if (status & AT91_UDP_INT_EPS) {
843184610Salfred
844184610Salfred		DPRINTFN(5, "real endpoint interrupt 0x%08x\n", status);
845184610Salfred
846184610Salfred		at91dci_interrupt_poll(sc);
847184610Salfred	}
848184824Sthompsa	USB_BUS_UNLOCK(&sc->sc_bus);
849184610Salfred}
850184610Salfred
851184610Salfredstatic void
852184610Salfredat91dci_setup_standard_chain_sub(struct at91dci_std_temp *temp)
853184610Salfred{
854184610Salfred	struct at91dci_td *td;
855184610Salfred
856184610Salfred	/* get current Transfer Descriptor */
857184610Salfred	td = temp->td_next;
858184610Salfred	temp->td = td;
859184610Salfred
860184610Salfred	/* prepare for next TD */
861184610Salfred	temp->td_next = td->obj_next;
862184610Salfred
863184610Salfred	/* fill out the Transfer Descriptor */
864184610Salfred	td->func = temp->func;
865184610Salfred	td->pc = temp->pc;
866184610Salfred	td->offset = temp->offset;
867184610Salfred	td->remainder = temp->len;
868184610Salfred	td->fifo_bank = 0;
869184610Salfred	td->error = 0;
870192552Sthompsa	td->did_stall = temp->did_stall;
871184610Salfred	td->short_pkt = temp->short_pkt;
872184610Salfred	td->alt_next = temp->setup_alt_next;
873184610Salfred}
874184610Salfred
875184610Salfredstatic void
876192984Sthompsaat91dci_setup_standard_chain(struct usb_xfer *xfer)
877184610Salfred{
878184610Salfred	struct at91dci_std_temp temp;
879184610Salfred	struct at91dci_softc *sc;
880184610Salfred	struct at91dci_td *td;
881184610Salfred	uint32_t x;
882184610Salfred	uint8_t ep_no;
883184610Salfred	uint8_t need_sync;
884184610Salfred
885184610Salfred	DPRINTFN(9, "addr=%d endpt=%d sumlen=%d speed=%d\n",
886193644Sthompsa	    xfer->address, UE_GET_ADDR(xfer->endpointno),
887194228Sthompsa	    xfer->sumlen, usbd_get_speed(xfer->xroot->udev));
888184610Salfred
889184610Salfred	temp.max_frame_size = xfer->max_frame_size;
890184610Salfred
891184610Salfred	td = xfer->td_start[0];
892184610Salfred	xfer->td_transfer_first = td;
893184610Salfred	xfer->td_transfer_cache = td;
894184610Salfred
895184610Salfred	/* setup temp */
896184610Salfred
897199673Sthompsa	temp.pc = NULL;
898184610Salfred	temp.td = NULL;
899184610Salfred	temp.td_next = xfer->td_start[0];
900190183Sthompsa	temp.offset = 0;
901184610Salfred	temp.setup_alt_next = xfer->flags_int.short_frames_ok;
902192552Sthompsa	temp.did_stall = !xfer->flags_int.control_stall;
903184610Salfred
904187173Sthompsa	sc = AT9100_DCI_BUS2SC(xfer->xroot->bus);
905193644Sthompsa	ep_no = (xfer->endpointno & UE_ADDR);
906184610Salfred
907184610Salfred	/* check if we should prepend a setup message */
908184610Salfred
909184610Salfred	if (xfer->flags_int.control_xfr) {
910184610Salfred		if (xfer->flags_int.control_hdr) {
911184610Salfred
912184610Salfred			temp.func = &at91dci_setup_rx;
913184610Salfred			temp.len = xfer->frlengths[0];
914184610Salfred			temp.pc = xfer->frbuffers + 0;
915184610Salfred			temp.short_pkt = temp.len ? 1 : 0;
916190183Sthompsa			/* check for last frame */
917190183Sthompsa			if (xfer->nframes == 1) {
918190183Sthompsa				/* no STATUS stage yet, SETUP is last */
919190183Sthompsa				if (xfer->flags_int.control_act)
920190183Sthompsa					temp.setup_alt_next = 0;
921190183Sthompsa			}
922184610Salfred
923184610Salfred			at91dci_setup_standard_chain_sub(&temp);
924184610Salfred		}
925184610Salfred		x = 1;
926184610Salfred	} else {
927184610Salfred		x = 0;
928184610Salfred	}
929184610Salfred
930184610Salfred	if (x != xfer->nframes) {
931193644Sthompsa		if (xfer->endpointno & UE_DIR_IN) {
932184610Salfred			temp.func = &at91dci_data_tx;
933184610Salfred			need_sync = 1;
934184610Salfred		} else {
935184610Salfred			temp.func = &at91dci_data_rx;
936184610Salfred			need_sync = 0;
937184610Salfred		}
938184610Salfred
939184610Salfred		/* setup "pc" pointer */
940184610Salfred		temp.pc = xfer->frbuffers + x;
941184610Salfred	} else {
942184610Salfred		need_sync = 0;
943184610Salfred	}
944184610Salfred	while (x != xfer->nframes) {
945184610Salfred
946184610Salfred		/* DATA0 / DATA1 message */
947184610Salfred
948184610Salfred		temp.len = xfer->frlengths[x];
949184610Salfred
950184610Salfred		x++;
951184610Salfred
952184610Salfred		if (x == xfer->nframes) {
953190183Sthompsa			if (xfer->flags_int.control_xfr) {
954190183Sthompsa				if (xfer->flags_int.control_act) {
955190183Sthompsa					temp.setup_alt_next = 0;
956190183Sthompsa				}
957190183Sthompsa			} else {
958190183Sthompsa				temp.setup_alt_next = 0;
959190183Sthompsa			}
960184610Salfred		}
961184610Salfred		if (temp.len == 0) {
962184610Salfred
963184610Salfred			/* make sure that we send an USB packet */
964184610Salfred
965184610Salfred			temp.short_pkt = 0;
966184610Salfred
967184610Salfred		} else {
968184610Salfred
969184610Salfred			/* regular data transfer */
970184610Salfred
971184610Salfred			temp.short_pkt = (xfer->flags.force_short_xfer) ? 0 : 1;
972184610Salfred		}
973184610Salfred
974184610Salfred		at91dci_setup_standard_chain_sub(&temp);
975184610Salfred
976184610Salfred		if (xfer->flags_int.isochronous_xfr) {
977184610Salfred			temp.offset += temp.len;
978184610Salfred		} else {
979184610Salfred			/* get next Page Cache pointer */
980184610Salfred			temp.pc = xfer->frbuffers + x;
981184610Salfred		}
982184610Salfred	}
983184610Salfred
984190183Sthompsa	/* check for control transfer */
985190183Sthompsa	if (xfer->flags_int.control_xfr) {
986184610Salfred
987190183Sthompsa		/* always setup a valid "pc" pointer for status and sync */
988190183Sthompsa		temp.pc = xfer->frbuffers + 0;
989184610Salfred		temp.len = 0;
990184610Salfred		temp.short_pkt = 0;
991190183Sthompsa		temp.setup_alt_next = 0;
992184610Salfred
993190183Sthompsa		/* check if we need to sync */
994184610Salfred		if (need_sync) {
995184610Salfred			/* we need a SYNC point after TX */
996184610Salfred			temp.func = &at91dci_data_tx_sync;
997190183Sthompsa			at91dci_setup_standard_chain_sub(&temp);
998190183Sthompsa		}
999184610Salfred
1000190183Sthompsa		/* check if we should append a status stage */
1001190183Sthompsa		if (!xfer->flags_int.control_act) {
1002190183Sthompsa
1003190183Sthompsa			/*
1004190183Sthompsa			 * Send a DATA1 message and invert the current
1005190183Sthompsa			 * endpoint direction.
1006190183Sthompsa			 */
1007193644Sthompsa			if (xfer->endpointno & UE_DIR_IN) {
1008190183Sthompsa				temp.func = &at91dci_data_rx;
1009190183Sthompsa				need_sync = 0;
1010190183Sthompsa			} else {
1011190183Sthompsa				temp.func = &at91dci_data_tx;
1012190183Sthompsa				need_sync = 1;
1013190183Sthompsa			}
1014190183Sthompsa
1015184610Salfred			at91dci_setup_standard_chain_sub(&temp);
1016190183Sthompsa			if (need_sync) {
1017190183Sthompsa				/* we need a SYNC point after TX */
1018190183Sthompsa				temp.func = &at91dci_data_tx_sync;
1019190183Sthompsa				at91dci_setup_standard_chain_sub(&temp);
1020190183Sthompsa			}
1021184610Salfred		}
1022184610Salfred	}
1023190183Sthompsa
1024184610Salfred	/* must have at least one frame! */
1025184610Salfred	td = temp.td;
1026184610Salfred	xfer->td_transfer_last = td;
1027184610Salfred
1028184610Salfred	/* setup the correct fifo bank */
1029184610Salfred	if (sc->sc_ep_flags[ep_no].fifo_bank) {
1030184610Salfred		td = xfer->td_transfer_first;
1031184610Salfred		td->fifo_bank = 1;
1032184610Salfred	}
1033184610Salfred}
1034184610Salfred
1035184610Salfredstatic void
1036184610Salfredat91dci_timeout(void *arg)
1037184610Salfred{
1038192984Sthompsa	struct usb_xfer *xfer = arg;
1039184610Salfred
1040184610Salfred	DPRINTF("xfer=%p\n", xfer);
1041184610Salfred
1042187177Sthompsa	USB_BUS_LOCK_ASSERT(xfer->xroot->bus, MA_OWNED);
1043184610Salfred
1044184610Salfred	/* transfer is transferred */
1045184610Salfred	at91dci_device_done(xfer, USB_ERR_TIMEOUT);
1046184610Salfred}
1047184610Salfred
1048184610Salfredstatic void
1049192984Sthompsaat91dci_start_standard_chain(struct usb_xfer *xfer)
1050184610Salfred{
1051184610Salfred	DPRINTFN(9, "\n");
1052184610Salfred
1053184610Salfred	/* poll one time */
1054184610Salfred	if (at91dci_xfer_do_fifo(xfer)) {
1055184610Salfred
1056187173Sthompsa		struct at91dci_softc *sc = AT9100_DCI_BUS2SC(xfer->xroot->bus);
1057193644Sthompsa		uint8_t ep_no = xfer->endpointno & UE_ADDR;
1058184610Salfred
1059184610Salfred		/*
1060184610Salfred		 * Only enable the endpoint interrupt when we are actually
1061184610Salfred		 * waiting for data, hence we are dealing with level
1062184610Salfred		 * triggered interrupts !
1063184610Salfred		 */
1064184610Salfred		AT91_UDP_WRITE_4(sc, AT91_UDP_IER, AT91_UDP_INT_EP(ep_no));
1065184610Salfred
1066184610Salfred		DPRINTFN(15, "enable interrupts on endpoint %d\n", ep_no);
1067184610Salfred
1068184610Salfred		/* put transfer on interrupt queue */
1069194228Sthompsa		usbd_transfer_enqueue(&xfer->xroot->bus->intr_q, xfer);
1070184610Salfred
1071184610Salfred		/* start timeout, if any */
1072184610Salfred		if (xfer->timeout != 0) {
1073194228Sthompsa			usbd_transfer_timeout_ms(xfer,
1074184610Salfred			    &at91dci_timeout, xfer->timeout);
1075184610Salfred		}
1076184610Salfred	}
1077184610Salfred}
1078184610Salfred
1079184610Salfredstatic void
1080190735Sthompsaat91dci_root_intr(struct at91dci_softc *sc)
1081184610Salfred{
1082184610Salfred	DPRINTFN(9, "\n");
1083184610Salfred
1084184824Sthompsa	USB_BUS_LOCK_ASSERT(&sc->sc_bus, MA_OWNED);
1085184610Salfred
1086184610Salfred	/* set port bit */
1087184610Salfred	sc->sc_hub_idata[0] = 0x02;	/* we only have one port */
1088184610Salfred
1089190735Sthompsa	uhub_root_intr(&sc->sc_bus, sc->sc_hub_idata,
1090190735Sthompsa	    sizeof(sc->sc_hub_idata));
1091184610Salfred}
1092184610Salfred
1093193045Sthompsastatic usb_error_t
1094192984Sthompsaat91dci_standard_done_sub(struct usb_xfer *xfer)
1095184610Salfred{
1096184610Salfred	struct at91dci_td *td;
1097184610Salfred	uint32_t len;
1098184610Salfred	uint8_t error;
1099184610Salfred
1100184610Salfred	DPRINTFN(9, "\n");
1101184610Salfred
1102184610Salfred	td = xfer->td_transfer_cache;
1103184610Salfred
1104184610Salfred	do {
1105184610Salfred		len = td->remainder;
1106184610Salfred
1107184610Salfred		if (xfer->aframes != xfer->nframes) {
1108184610Salfred			/*
1109184610Salfred		         * Verify the length and subtract
1110184610Salfred		         * the remainder from "frlengths[]":
1111184610Salfred		         */
1112184610Salfred			if (len > xfer->frlengths[xfer->aframes]) {
1113184610Salfred				td->error = 1;
1114184610Salfred			} else {
1115184610Salfred				xfer->frlengths[xfer->aframes] -= len;
1116184610Salfred			}
1117184610Salfred		}
1118184610Salfred		/* Check for transfer error */
1119184610Salfred		if (td->error) {
1120184610Salfred			/* the transfer is finished */
1121184610Salfred			error = 1;
1122184610Salfred			td = NULL;
1123184610Salfred			break;
1124184610Salfred		}
1125184610Salfred		/* Check for short transfer */
1126184610Salfred		if (len > 0) {
1127184610Salfred			if (xfer->flags_int.short_frames_ok) {
1128184610Salfred				/* follow alt next */
1129184610Salfred				if (td->alt_next) {
1130184610Salfred					td = td->obj_next;
1131184610Salfred				} else {
1132184610Salfred					td = NULL;
1133184610Salfred				}
1134184610Salfred			} else {
1135184610Salfred				/* the transfer is finished */
1136184610Salfred				td = NULL;
1137184610Salfred			}
1138184610Salfred			error = 0;
1139184610Salfred			break;
1140184610Salfred		}
1141184610Salfred		td = td->obj_next;
1142184610Salfred
1143184610Salfred		/* this USB frame is complete */
1144184610Salfred		error = 0;
1145184610Salfred		break;
1146184610Salfred
1147184610Salfred	} while (0);
1148184610Salfred
1149184610Salfred	/* update transfer cache */
1150184610Salfred
1151184610Salfred	xfer->td_transfer_cache = td;
1152184610Salfred
1153184610Salfred	return (error ?
1154184610Salfred	    USB_ERR_STALLED : USB_ERR_NORMAL_COMPLETION);
1155184610Salfred}
1156184610Salfred
1157184610Salfredstatic void
1158192984Sthompsaat91dci_standard_done(struct usb_xfer *xfer)
1159184610Salfred{
1160193045Sthompsa	usb_error_t err = 0;
1161184610Salfred
1162193644Sthompsa	DPRINTFN(13, "xfer=%p endpoint=%p transfer done\n",
1163193644Sthompsa	    xfer, xfer->endpoint);
1164184610Salfred
1165184610Salfred	/* reset scanner */
1166184610Salfred
1167184610Salfred	xfer->td_transfer_cache = xfer->td_transfer_first;
1168184610Salfred
1169184610Salfred	if (xfer->flags_int.control_xfr) {
1170184610Salfred
1171184610Salfred		if (xfer->flags_int.control_hdr) {
1172184610Salfred
1173184610Salfred			err = at91dci_standard_done_sub(xfer);
1174184610Salfred		}
1175184610Salfred		xfer->aframes = 1;
1176184610Salfred
1177184610Salfred		if (xfer->td_transfer_cache == NULL) {
1178184610Salfred			goto done;
1179184610Salfred		}
1180184610Salfred	}
1181184610Salfred	while (xfer->aframes != xfer->nframes) {
1182184610Salfred
1183184610Salfred		err = at91dci_standard_done_sub(xfer);
1184184610Salfred		xfer->aframes++;
1185184610Salfred
1186184610Salfred		if (xfer->td_transfer_cache == NULL) {
1187184610Salfred			goto done;
1188184610Salfred		}
1189184610Salfred	}
1190184610Salfred
1191184610Salfred	if (xfer->flags_int.control_xfr &&
1192184610Salfred	    !xfer->flags_int.control_act) {
1193184610Salfred
1194184610Salfred		err = at91dci_standard_done_sub(xfer);
1195184610Salfred	}
1196184610Salfreddone:
1197184610Salfred	at91dci_device_done(xfer, err);
1198184610Salfred}
1199184610Salfred
1200184610Salfred/*------------------------------------------------------------------------*
1201184610Salfred *	at91dci_device_done
1202184610Salfred *
1203184610Salfred * NOTE: this function can be called more than one time on the
1204184610Salfred * same USB transfer!
1205184610Salfred *------------------------------------------------------------------------*/
1206184610Salfredstatic void
1207193045Sthompsaat91dci_device_done(struct usb_xfer *xfer, usb_error_t error)
1208184610Salfred{
1209187173Sthompsa	struct at91dci_softc *sc = AT9100_DCI_BUS2SC(xfer->xroot->bus);
1210184610Salfred	uint8_t ep_no;
1211184610Salfred
1212184824Sthompsa	USB_BUS_LOCK_ASSERT(&sc->sc_bus, MA_OWNED);
1213184610Salfred
1214193644Sthompsa	DPRINTFN(2, "xfer=%p, endpoint=%p, error=%d\n",
1215193644Sthompsa	    xfer, xfer->endpoint, error);
1216184610Salfred
1217192499Sthompsa	if (xfer->flags_int.usb_mode == USB_MODE_DEVICE) {
1218193644Sthompsa		ep_no = (xfer->endpointno & UE_ADDR);
1219184610Salfred
1220184610Salfred		/* disable endpoint interrupt */
1221184610Salfred		AT91_UDP_WRITE_4(sc, AT91_UDP_IDR, AT91_UDP_INT_EP(ep_no));
1222184610Salfred
1223184610Salfred		DPRINTFN(15, "disable interrupts on endpoint %d\n", ep_no);
1224184610Salfred	}
1225184610Salfred	/* dequeue transfer and start next transfer */
1226194228Sthompsa	usbd_transfer_done(xfer, error);
1227184610Salfred}
1228184610Salfred
1229184610Salfredstatic void
1230192984Sthompsaat91dci_set_stall(struct usb_device *udev, struct usb_xfer *xfer,
1231195121Sthompsa    struct usb_endpoint *ep, uint8_t *did_stall)
1232184610Salfred{
1233184610Salfred	struct at91dci_softc *sc;
1234184610Salfred	uint32_t csr_val;
1235184610Salfred	uint8_t csr_reg;
1236184610Salfred
1237184824Sthompsa	USB_BUS_LOCK_ASSERT(udev->bus, MA_OWNED);
1238184610Salfred
1239193644Sthompsa	DPRINTFN(5, "endpoint=%p\n", ep);
1240184610Salfred
1241184610Salfred	if (xfer) {
1242184610Salfred		/* cancel any ongoing transfers */
1243184610Salfred		at91dci_device_done(xfer, USB_ERR_STALLED);
1244184610Salfred	}
1245184610Salfred	/* set FORCESTALL */
1246184610Salfred	sc = AT9100_DCI_BUS2SC(udev->bus);
1247193644Sthompsa	csr_reg = (ep->edesc->bEndpointAddress & UE_ADDR);
1248184610Salfred	csr_reg = AT91_UDP_CSR(csr_reg);
1249184610Salfred	csr_val = AT91_UDP_READ_4(sc, csr_reg);
1250184610Salfred	AT91_CSR_ACK(csr_val, AT91_UDP_CSR_FORCESTALL);
1251184610Salfred	AT91_UDP_WRITE_4(sc, csr_reg, csr_val);
1252184610Salfred}
1253184610Salfred
1254184610Salfredstatic void
1255184610Salfredat91dci_clear_stall_sub(struct at91dci_softc *sc, uint8_t ep_no,
1256184610Salfred    uint8_t ep_type, uint8_t ep_dir)
1257184610Salfred{
1258192984Sthompsa	const struct usb_hw_ep_profile *pf;
1259184610Salfred	uint32_t csr_val;
1260184610Salfred	uint32_t temp;
1261184610Salfred	uint8_t csr_reg;
1262184610Salfred	uint8_t to;
1263184610Salfred
1264184610Salfred	if (ep_type == UE_CONTROL) {
1265184610Salfred		/* clearing stall is not needed */
1266184610Salfred		return;
1267184610Salfred	}
1268184610Salfred	/* compute CSR register offset */
1269184610Salfred	csr_reg = AT91_UDP_CSR(ep_no);
1270184610Salfred
1271184610Salfred	/* compute default CSR value */
1272184610Salfred	csr_val = 0;
1273184610Salfred	AT91_CSR_ACK(csr_val, 0);
1274184610Salfred
1275184610Salfred	/* disable endpoint */
1276184610Salfred	AT91_UDP_WRITE_4(sc, csr_reg, csr_val);
1277184610Salfred
1278184610Salfred	/* get endpoint profile */
1279184610Salfred	at91dci_get_hw_ep_profile(NULL, &pf, ep_no);
1280184610Salfred
1281184610Salfred	/* reset FIFO */
1282184610Salfred	AT91_UDP_WRITE_4(sc, AT91_UDP_RST, AT91_UDP_RST_EP(ep_no));
1283184610Salfred	AT91_UDP_WRITE_4(sc, AT91_UDP_RST, 0);
1284184610Salfred
1285184610Salfred	/*
1286184610Salfred	 * NOTE: One would assume that a FIFO reset would release the
1287184610Salfred	 * FIFO banks aswell, but it doesn't! We have to do this
1288184610Salfred	 * manually!
1289184610Salfred	 */
1290184610Salfred
1291184610Salfred	/* release FIFO banks, if any */
1292184610Salfred	for (to = 0; to != 2; to++) {
1293184610Salfred
1294184610Salfred		/* get csr value */
1295184610Salfred		csr_val = AT91_UDP_READ_4(sc, csr_reg);
1296184610Salfred
1297184610Salfred		if (csr_val & (AT91_UDP_CSR_RX_DATA_BK0 |
1298184610Salfred		    AT91_UDP_CSR_RX_DATA_BK1)) {
1299184610Salfred			/* clear status bits */
1300184610Salfred			if (pf->support_multi_buffer) {
1301184610Salfred				if (sc->sc_ep_flags[ep_no].fifo_bank) {
1302184610Salfred					sc->sc_ep_flags[ep_no].fifo_bank = 0;
1303184610Salfred					temp = AT91_UDP_CSR_RX_DATA_BK1;
1304184610Salfred				} else {
1305184610Salfred					sc->sc_ep_flags[ep_no].fifo_bank = 1;
1306184610Salfred					temp = AT91_UDP_CSR_RX_DATA_BK0;
1307184610Salfred				}
1308184610Salfred			} else {
1309184610Salfred				temp = (AT91_UDP_CSR_RX_DATA_BK0 |
1310184610Salfred				    AT91_UDP_CSR_RX_DATA_BK1);
1311184610Salfred			}
1312184610Salfred		} else {
1313184610Salfred			temp = 0;
1314184610Salfred		}
1315184610Salfred
1316184610Salfred		/* clear FORCESTALL */
1317184610Salfred		temp |= AT91_UDP_CSR_STALLSENT;
1318184610Salfred
1319184610Salfred		AT91_CSR_ACK(csr_val, temp);
1320184610Salfred		AT91_UDP_WRITE_4(sc, csr_reg, csr_val);
1321184610Salfred	}
1322184610Salfred
1323184610Salfred	/* compute default CSR value */
1324184610Salfred	csr_val = 0;
1325184610Salfred	AT91_CSR_ACK(csr_val, 0);
1326184610Salfred
1327184610Salfred	/* enable endpoint */
1328184610Salfred	csr_val &= ~AT91_UDP_CSR_ET_MASK;
1329184610Salfred	csr_val |= AT91_UDP_CSR_EPEDS;
1330184610Salfred
1331184610Salfred	if (ep_type == UE_CONTROL) {
1332184610Salfred		csr_val |= AT91_UDP_CSR_ET_CTRL;
1333184610Salfred	} else {
1334184610Salfred		if (ep_type == UE_BULK) {
1335184610Salfred			csr_val |= AT91_UDP_CSR_ET_BULK;
1336184610Salfred		} else if (ep_type == UE_INTERRUPT) {
1337184610Salfred			csr_val |= AT91_UDP_CSR_ET_INT;
1338184610Salfred		} else {
1339184610Salfred			csr_val |= AT91_UDP_CSR_ET_ISO;
1340184610Salfred		}
1341184610Salfred		if (ep_dir & UE_DIR_IN) {
1342184610Salfred			csr_val |= AT91_UDP_CSR_ET_DIR_IN;
1343184610Salfred		}
1344184610Salfred	}
1345184610Salfred
1346184610Salfred	/* enable endpoint */
1347184610Salfred	AT91_UDP_WRITE_4(sc, AT91_UDP_CSR(ep_no), csr_val);
1348184610Salfred}
1349184610Salfred
1350184610Salfredstatic void
1351193644Sthompsaat91dci_clear_stall(struct usb_device *udev, struct usb_endpoint *ep)
1352184610Salfred{
1353184610Salfred	struct at91dci_softc *sc;
1354192984Sthompsa	struct usb_endpoint_descriptor *ed;
1355184610Salfred
1356193644Sthompsa	DPRINTFN(5, "endpoint=%p\n", ep);
1357184610Salfred
1358184824Sthompsa	USB_BUS_LOCK_ASSERT(udev->bus, MA_OWNED);
1359184610Salfred
1360184610Salfred	/* check mode */
1361192499Sthompsa	if (udev->flags.usb_mode != USB_MODE_DEVICE) {
1362184610Salfred		/* not supported */
1363184610Salfred		return;
1364184610Salfred	}
1365184610Salfred	/* get softc */
1366184610Salfred	sc = AT9100_DCI_BUS2SC(udev->bus);
1367184610Salfred
1368184610Salfred	/* get endpoint descriptor */
1369193644Sthompsa	ed = ep->edesc;
1370184610Salfred
1371184610Salfred	/* reset endpoint */
1372184610Salfred	at91dci_clear_stall_sub(sc,
1373184610Salfred	    (ed->bEndpointAddress & UE_ADDR),
1374184610Salfred	    (ed->bmAttributes & UE_XFERTYPE),
1375184610Salfred	    (ed->bEndpointAddress & (UE_DIR_IN | UE_DIR_OUT)));
1376184610Salfred}
1377184610Salfred
1378193045Sthompsausb_error_t
1379184610Salfredat91dci_init(struct at91dci_softc *sc)
1380184610Salfred{
1381184610Salfred	uint32_t csr_val;
1382184610Salfred	uint8_t n;
1383184610Salfred
1384184610Salfred	DPRINTF("start\n");
1385184610Salfred
1386184610Salfred	/* set up the bus structure */
1387184610Salfred	sc->sc_bus.usbrev = USB_REV_1_1;
1388184610Salfred	sc->sc_bus.methods = &at91dci_bus_methods;
1389184610Salfred
1390184824Sthompsa	USB_BUS_LOCK(&sc->sc_bus);
1391184610Salfred
1392184610Salfred	/* turn on clocks */
1393184610Salfred
1394184610Salfred	if (sc->sc_clocks_on) {
1395184610Salfred		(sc->sc_clocks_on) (sc->sc_clocks_arg);
1396184610Salfred	}
1397184610Salfred	/* wait a little for things to stabilise */
1398194228Sthompsa	usb_pause_mtx(&sc->sc_bus.bus_mtx, hz / 1000);
1399184610Salfred
1400184610Salfred	/* disable and clear all interrupts */
1401184610Salfred
1402184610Salfred	AT91_UDP_WRITE_4(sc, AT91_UDP_IDR, 0xFFFFFFFF);
1403184610Salfred	AT91_UDP_WRITE_4(sc, AT91_UDP_ICR, 0xFFFFFFFF);
1404184610Salfred
1405184610Salfred	/* compute default CSR value */
1406184610Salfred
1407184610Salfred	csr_val = 0;
1408184610Salfred	AT91_CSR_ACK(csr_val, 0);
1409184610Salfred
1410184610Salfred	/* disable all endpoints */
1411184610Salfred
1412184610Salfred	for (n = 0; n != AT91_UDP_EP_MAX; n++) {
1413184610Salfred
1414184610Salfred		/* disable endpoint */
1415184610Salfred		AT91_UDP_WRITE_4(sc, AT91_UDP_CSR(n), csr_val);
1416184610Salfred	}
1417184610Salfred
1418184610Salfred	/* enable the control endpoint */
1419184610Salfred
1420184610Salfred	AT91_CSR_ACK(csr_val, AT91_UDP_CSR_ET_CTRL |
1421184610Salfred	    AT91_UDP_CSR_EPEDS);
1422184610Salfred
1423184610Salfred	/* write to FIFO control register */
1424184610Salfred
1425184610Salfred	AT91_UDP_WRITE_4(sc, AT91_UDP_CSR(0), csr_val);
1426184610Salfred
1427184610Salfred	/* enable the interrupts we want */
1428184610Salfred
1429184610Salfred	AT91_UDP_WRITE_4(sc, AT91_UDP_IER, AT91_UDP_INT_BUS);
1430184610Salfred
1431184610Salfred	/* turn off clocks */
1432184610Salfred
1433184610Salfred	at91dci_clocks_off(sc);
1434184610Salfred
1435184824Sthompsa	USB_BUS_UNLOCK(&sc->sc_bus);
1436184610Salfred
1437184610Salfred	/* catch any lost interrupts */
1438184610Salfred
1439184610Salfred	at91dci_do_poll(&sc->sc_bus);
1440184610Salfred
1441184610Salfred	return (0);			/* success */
1442184610Salfred}
1443184610Salfred
1444184610Salfredvoid
1445184610Salfredat91dci_uninit(struct at91dci_softc *sc)
1446184610Salfred{
1447184824Sthompsa	USB_BUS_LOCK(&sc->sc_bus);
1448184610Salfred
1449184610Salfred	/* disable and clear all interrupts */
1450184610Salfred	AT91_UDP_WRITE_4(sc, AT91_UDP_IDR, 0xFFFFFFFF);
1451184610Salfred	AT91_UDP_WRITE_4(sc, AT91_UDP_ICR, 0xFFFFFFFF);
1452184610Salfred
1453184610Salfred	sc->sc_flags.port_powered = 0;
1454184610Salfred	sc->sc_flags.status_vbus = 0;
1455184610Salfred	sc->sc_flags.status_bus_reset = 0;
1456184610Salfred	sc->sc_flags.status_suspend = 0;
1457184610Salfred	sc->sc_flags.change_suspend = 0;
1458184610Salfred	sc->sc_flags.change_connect = 1;
1459184610Salfred
1460184610Salfred	at91dci_pull_down(sc);
1461184610Salfred	at91dci_clocks_off(sc);
1462184824Sthompsa	USB_BUS_UNLOCK(&sc->sc_bus);
1463184610Salfred}
1464184610Salfred
1465184610Salfredvoid
1466184610Salfredat91dci_suspend(struct at91dci_softc *sc)
1467184610Salfred{
1468184610Salfred	return;
1469184610Salfred}
1470184610Salfred
1471184610Salfredvoid
1472184610Salfredat91dci_resume(struct at91dci_softc *sc)
1473184610Salfred{
1474184610Salfred	return;
1475184610Salfred}
1476184610Salfred
1477184610Salfredstatic void
1478192984Sthompsaat91dci_do_poll(struct usb_bus *bus)
1479184610Salfred{
1480184610Salfred	struct at91dci_softc *sc = AT9100_DCI_BUS2SC(bus);
1481184610Salfred
1482184824Sthompsa	USB_BUS_LOCK(&sc->sc_bus);
1483184610Salfred	at91dci_interrupt_poll(sc);
1484184824Sthompsa	USB_BUS_UNLOCK(&sc->sc_bus);
1485184610Salfred}
1486184610Salfred
1487184610Salfred/*------------------------------------------------------------------------*
1488184610Salfred * at91dci bulk support
1489184610Salfred *------------------------------------------------------------------------*/
1490184610Salfredstatic void
1491192984Sthompsaat91dci_device_bulk_open(struct usb_xfer *xfer)
1492184610Salfred{
1493184610Salfred	return;
1494184610Salfred}
1495184610Salfred
1496184610Salfredstatic void
1497192984Sthompsaat91dci_device_bulk_close(struct usb_xfer *xfer)
1498184610Salfred{
1499184610Salfred	at91dci_device_done(xfer, USB_ERR_CANCELLED);
1500184610Salfred}
1501184610Salfred
1502184610Salfredstatic void
1503192984Sthompsaat91dci_device_bulk_enter(struct usb_xfer *xfer)
1504184610Salfred{
1505184610Salfred	return;
1506184610Salfred}
1507184610Salfred
1508184610Salfredstatic void
1509192984Sthompsaat91dci_device_bulk_start(struct usb_xfer *xfer)
1510184610Salfred{
1511184610Salfred	/* setup TDs */
1512184610Salfred	at91dci_setup_standard_chain(xfer);
1513184610Salfred	at91dci_start_standard_chain(xfer);
1514184610Salfred}
1515184610Salfred
1516192984Sthompsastruct usb_pipe_methods at91dci_device_bulk_methods =
1517184610Salfred{
1518184610Salfred	.open = at91dci_device_bulk_open,
1519184610Salfred	.close = at91dci_device_bulk_close,
1520184610Salfred	.enter = at91dci_device_bulk_enter,
1521184610Salfred	.start = at91dci_device_bulk_start,
1522184610Salfred};
1523184610Salfred
1524184610Salfred/*------------------------------------------------------------------------*
1525184610Salfred * at91dci control support
1526184610Salfred *------------------------------------------------------------------------*/
1527184610Salfredstatic void
1528192984Sthompsaat91dci_device_ctrl_open(struct usb_xfer *xfer)
1529184610Salfred{
1530184610Salfred	return;
1531184610Salfred}
1532184610Salfred
1533184610Salfredstatic void
1534192984Sthompsaat91dci_device_ctrl_close(struct usb_xfer *xfer)
1535184610Salfred{
1536184610Salfred	at91dci_device_done(xfer, USB_ERR_CANCELLED);
1537184610Salfred}
1538184610Salfred
1539184610Salfredstatic void
1540192984Sthompsaat91dci_device_ctrl_enter(struct usb_xfer *xfer)
1541184610Salfred{
1542184610Salfred	return;
1543184610Salfred}
1544184610Salfred
1545184610Salfredstatic void
1546192984Sthompsaat91dci_device_ctrl_start(struct usb_xfer *xfer)
1547184610Salfred{
1548184610Salfred	/* setup TDs */
1549184610Salfred	at91dci_setup_standard_chain(xfer);
1550184610Salfred	at91dci_start_standard_chain(xfer);
1551184610Salfred}
1552184610Salfred
1553192984Sthompsastruct usb_pipe_methods at91dci_device_ctrl_methods =
1554184610Salfred{
1555184610Salfred	.open = at91dci_device_ctrl_open,
1556184610Salfred	.close = at91dci_device_ctrl_close,
1557184610Salfred	.enter = at91dci_device_ctrl_enter,
1558184610Salfred	.start = at91dci_device_ctrl_start,
1559184610Salfred};
1560184610Salfred
1561184610Salfred/*------------------------------------------------------------------------*
1562184610Salfred * at91dci interrupt support
1563184610Salfred *------------------------------------------------------------------------*/
1564184610Salfredstatic void
1565192984Sthompsaat91dci_device_intr_open(struct usb_xfer *xfer)
1566184610Salfred{
1567184610Salfred	return;
1568184610Salfred}
1569184610Salfred
1570184610Salfredstatic void
1571192984Sthompsaat91dci_device_intr_close(struct usb_xfer *xfer)
1572184610Salfred{
1573184610Salfred	at91dci_device_done(xfer, USB_ERR_CANCELLED);
1574184610Salfred}
1575184610Salfred
1576184610Salfredstatic void
1577192984Sthompsaat91dci_device_intr_enter(struct usb_xfer *xfer)
1578184610Salfred{
1579184610Salfred	return;
1580184610Salfred}
1581184610Salfred
1582184610Salfredstatic void
1583192984Sthompsaat91dci_device_intr_start(struct usb_xfer *xfer)
1584184610Salfred{
1585184610Salfred	/* setup TDs */
1586184610Salfred	at91dci_setup_standard_chain(xfer);
1587184610Salfred	at91dci_start_standard_chain(xfer);
1588184610Salfred}
1589184610Salfred
1590192984Sthompsastruct usb_pipe_methods at91dci_device_intr_methods =
1591184610Salfred{
1592184610Salfred	.open = at91dci_device_intr_open,
1593184610Salfred	.close = at91dci_device_intr_close,
1594184610Salfred	.enter = at91dci_device_intr_enter,
1595184610Salfred	.start = at91dci_device_intr_start,
1596184610Salfred};
1597184610Salfred
1598184610Salfred/*------------------------------------------------------------------------*
1599184610Salfred * at91dci full speed isochronous support
1600184610Salfred *------------------------------------------------------------------------*/
1601184610Salfredstatic void
1602192984Sthompsaat91dci_device_isoc_fs_open(struct usb_xfer *xfer)
1603184610Salfred{
1604184610Salfred	return;
1605184610Salfred}
1606184610Salfred
1607184610Salfredstatic void
1608192984Sthompsaat91dci_device_isoc_fs_close(struct usb_xfer *xfer)
1609184610Salfred{
1610184610Salfred	at91dci_device_done(xfer, USB_ERR_CANCELLED);
1611184610Salfred}
1612184610Salfred
1613184610Salfredstatic void
1614192984Sthompsaat91dci_device_isoc_fs_enter(struct usb_xfer *xfer)
1615184610Salfred{
1616187173Sthompsa	struct at91dci_softc *sc = AT9100_DCI_BUS2SC(xfer->xroot->bus);
1617184610Salfred	uint32_t temp;
1618184610Salfred	uint32_t nframes;
1619184610Salfred
1620184610Salfred	DPRINTFN(6, "xfer=%p next=%d nframes=%d\n",
1621193644Sthompsa	    xfer, xfer->endpoint->isoc_next, xfer->nframes);
1622184610Salfred
1623184610Salfred	/* get the current frame index */
1624184610Salfred
1625184610Salfred	nframes = AT91_UDP_READ_4(sc, AT91_UDP_FRM);
1626184610Salfred
1627184610Salfred	/*
1628184610Salfred	 * check if the frame index is within the window where the frames
1629184610Salfred	 * will be inserted
1630184610Salfred	 */
1631193644Sthompsa	temp = (nframes - xfer->endpoint->isoc_next) & AT91_UDP_FRM_MASK;
1632184610Salfred
1633193644Sthompsa	if ((xfer->endpoint->is_synced == 0) ||
1634184610Salfred	    (temp < xfer->nframes)) {
1635184610Salfred		/*
1636193644Sthompsa		 * If there is data underflow or the endpoint queue is
1637184610Salfred		 * empty we schedule the transfer a few frames ahead
1638184610Salfred		 * of the current frame position. Else two isochronous
1639184610Salfred		 * transfers might overlap.
1640184610Salfred		 */
1641193644Sthompsa		xfer->endpoint->isoc_next = (nframes + 3) & AT91_UDP_FRM_MASK;
1642193644Sthompsa		xfer->endpoint->is_synced = 1;
1643193644Sthompsa		DPRINTFN(3, "start next=%d\n", xfer->endpoint->isoc_next);
1644184610Salfred	}
1645184610Salfred	/*
1646184610Salfred	 * compute how many milliseconds the insertion is ahead of the
1647184610Salfred	 * current frame position:
1648184610Salfred	 */
1649193644Sthompsa	temp = (xfer->endpoint->isoc_next - nframes) & AT91_UDP_FRM_MASK;
1650184610Salfred
1651184610Salfred	/*
1652184610Salfred	 * pre-compute when the isochronous transfer will be finished:
1653184610Salfred	 */
1654184610Salfred	xfer->isoc_time_complete =
1655194228Sthompsa	    usb_isoc_time_expand(&sc->sc_bus, nframes) + temp +
1656184610Salfred	    xfer->nframes;
1657184610Salfred
1658184610Salfred	/* compute frame number for next insertion */
1659193644Sthompsa	xfer->endpoint->isoc_next += xfer->nframes;
1660184610Salfred
1661184610Salfred	/* setup TDs */
1662184610Salfred	at91dci_setup_standard_chain(xfer);
1663184610Salfred}
1664184610Salfred
1665184610Salfredstatic void
1666192984Sthompsaat91dci_device_isoc_fs_start(struct usb_xfer *xfer)
1667184610Salfred{
1668184610Salfred	/* start TD chain */
1669184610Salfred	at91dci_start_standard_chain(xfer);
1670184610Salfred}
1671184610Salfred
1672192984Sthompsastruct usb_pipe_methods at91dci_device_isoc_fs_methods =
1673184610Salfred{
1674184610Salfred	.open = at91dci_device_isoc_fs_open,
1675184610Salfred	.close = at91dci_device_isoc_fs_close,
1676184610Salfred	.enter = at91dci_device_isoc_fs_enter,
1677184610Salfred	.start = at91dci_device_isoc_fs_start,
1678184610Salfred};
1679184610Salfred
1680184610Salfred/*------------------------------------------------------------------------*
1681184610Salfred * at91dci root control support
1682184610Salfred *------------------------------------------------------------------------*
1683190735Sthompsa * Simulate a hardware HUB by handling all the necessary requests.
1684184610Salfred *------------------------------------------------------------------------*/
1685184610Salfred
1686192984Sthompsastatic const struct usb_device_descriptor at91dci_devd = {
1687192984Sthompsa	.bLength = sizeof(struct usb_device_descriptor),
1688184610Salfred	.bDescriptorType = UDESC_DEVICE,
1689184610Salfred	.bcdUSB = {0x00, 0x02},
1690184610Salfred	.bDeviceClass = UDCLASS_HUB,
1691184610Salfred	.bDeviceSubClass = UDSUBCLASS_HUB,
1692184610Salfred	.bDeviceProtocol = UDPROTO_HSHUBSTT,
1693184610Salfred	.bMaxPacketSize = 64,
1694184610Salfred	.bcdDevice = {0x00, 0x01},
1695184610Salfred	.iManufacturer = 1,
1696184610Salfred	.iProduct = 2,
1697184610Salfred	.bNumConfigurations = 1,
1698184610Salfred};
1699184610Salfred
1700192984Sthompsastatic const struct usb_device_qualifier at91dci_odevd = {
1701192984Sthompsa	.bLength = sizeof(struct usb_device_qualifier),
1702184610Salfred	.bDescriptorType = UDESC_DEVICE_QUALIFIER,
1703184610Salfred	.bcdUSB = {0x00, 0x02},
1704184610Salfred	.bDeviceClass = UDCLASS_HUB,
1705184610Salfred	.bDeviceSubClass = UDSUBCLASS_HUB,
1706184610Salfred	.bDeviceProtocol = UDPROTO_FSHUB,
1707184610Salfred	.bMaxPacketSize0 = 0,
1708184610Salfred	.bNumConfigurations = 0,
1709184610Salfred};
1710184610Salfred
1711184610Salfredstatic const struct at91dci_config_desc at91dci_confd = {
1712184610Salfred	.confd = {
1713192984Sthompsa		.bLength = sizeof(struct usb_config_descriptor),
1714184610Salfred		.bDescriptorType = UDESC_CONFIG,
1715184610Salfred		.wTotalLength[0] = sizeof(at91dci_confd),
1716184610Salfred		.bNumInterface = 1,
1717184610Salfred		.bConfigurationValue = 1,
1718184610Salfred		.iConfiguration = 0,
1719184610Salfred		.bmAttributes = UC_SELF_POWERED,
1720184610Salfred		.bMaxPower = 0,
1721184610Salfred	},
1722184610Salfred	.ifcd = {
1723192984Sthompsa		.bLength = sizeof(struct usb_interface_descriptor),
1724184610Salfred		.bDescriptorType = UDESC_INTERFACE,
1725184610Salfred		.bNumEndpoints = 1,
1726184610Salfred		.bInterfaceClass = UICLASS_HUB,
1727184610Salfred		.bInterfaceSubClass = UISUBCLASS_HUB,
1728184610Salfred		.bInterfaceProtocol = UIPROTO_HSHUBSTT,
1729184610Salfred	},
1730184610Salfred	.endpd = {
1731192984Sthompsa		.bLength = sizeof(struct usb_endpoint_descriptor),
1732184610Salfred		.bDescriptorType = UDESC_ENDPOINT,
1733184610Salfred		.bEndpointAddress = (UE_DIR_IN | AT9100_DCI_INTR_ENDPT),
1734184610Salfred		.bmAttributes = UE_INTERRUPT,
1735184610Salfred		.wMaxPacketSize[0] = 8,
1736184610Salfred		.bInterval = 255,
1737184610Salfred	},
1738184610Salfred};
1739184610Salfred
1740192984Sthompsastatic const struct usb_hub_descriptor_min at91dci_hubd = {
1741184610Salfred	.bDescLength = sizeof(at91dci_hubd),
1742184610Salfred	.bDescriptorType = UDESC_HUB,
1743184610Salfred	.bNbrPorts = 1,
1744184610Salfred	.wHubCharacteristics[0] =
1745184610Salfred	(UHD_PWR_NO_SWITCH | UHD_OC_INDIVIDUAL) & 0xFF,
1746184610Salfred	.wHubCharacteristics[1] =
1747187183Sthompsa	(UHD_PWR_NO_SWITCH | UHD_OC_INDIVIDUAL) >> 8,
1748184610Salfred	.bPwrOn2PwrGood = 50,
1749184610Salfred	.bHubContrCurrent = 0,
1750184610Salfred	.DeviceRemovable = {0},		/* port is removable */
1751184610Salfred};
1752184610Salfred
1753184610Salfred#define	STRING_LANG \
1754184610Salfred  0x09, 0x04,				/* American English */
1755184610Salfred
1756184610Salfred#define	STRING_VENDOR \
1757184610Salfred  'A', 0, 'T', 0, 'M', 0, 'E', 0, 'L', 0
1758184610Salfred
1759184610Salfred#define	STRING_PRODUCT \
1760184610Salfred  'D', 0, 'C', 0, 'I', 0, ' ', 0, 'R', 0, \
1761184610Salfred  'o', 0, 'o', 0, 't', 0, ' ', 0, 'H', 0, \
1762184610Salfred  'U', 0, 'B', 0,
1763184610Salfred
1764184610SalfredUSB_MAKE_STRING_DESC(STRING_LANG, at91dci_langtab);
1765184610SalfredUSB_MAKE_STRING_DESC(STRING_VENDOR, at91dci_vendor);
1766184610SalfredUSB_MAKE_STRING_DESC(STRING_PRODUCT, at91dci_product);
1767184610Salfred
1768193045Sthompsastatic usb_error_t
1769192984Sthompsaat91dci_roothub_exec(struct usb_device *udev,
1770192984Sthompsa    struct usb_device_request *req, const void **pptr, uint16_t *plength)
1771184610Salfred{
1772191402Sthompsa	struct at91dci_softc *sc = AT9100_DCI_BUS2SC(udev->bus);
1773191402Sthompsa	const void *ptr;
1774191402Sthompsa	uint16_t len;
1775184610Salfred	uint16_t value;
1776184610Salfred	uint16_t index;
1777193045Sthompsa	usb_error_t err;
1778184610Salfred
1779184824Sthompsa	USB_BUS_LOCK_ASSERT(&sc->sc_bus, MA_OWNED);
1780184610Salfred
1781184610Salfred	/* buffer reset */
1782191402Sthompsa	ptr = (const void *)&sc->sc_hub_temp;
1783191402Sthompsa	len = 0;
1784191402Sthompsa	err = 0;
1785184610Salfred
1786191402Sthompsa	value = UGETW(req->wValue);
1787191402Sthompsa	index = UGETW(req->wIndex);
1788184610Salfred
1789184610Salfred	/* demultiplex the control request */
1790184610Salfred
1791191402Sthompsa	switch (req->bmRequestType) {
1792184610Salfred	case UT_READ_DEVICE:
1793191402Sthompsa		switch (req->bRequest) {
1794184610Salfred		case UR_GET_DESCRIPTOR:
1795184610Salfred			goto tr_handle_get_descriptor;
1796184610Salfred		case UR_GET_CONFIG:
1797184610Salfred			goto tr_handle_get_config;
1798184610Salfred		case UR_GET_STATUS:
1799184610Salfred			goto tr_handle_get_status;
1800184610Salfred		default:
1801184610Salfred			goto tr_stalled;
1802184610Salfred		}
1803184610Salfred		break;
1804184610Salfred
1805184610Salfred	case UT_WRITE_DEVICE:
1806191402Sthompsa		switch (req->bRequest) {
1807184610Salfred		case UR_SET_ADDRESS:
1808184610Salfred			goto tr_handle_set_address;
1809184610Salfred		case UR_SET_CONFIG:
1810184610Salfred			goto tr_handle_set_config;
1811184610Salfred		case UR_CLEAR_FEATURE:
1812184610Salfred			goto tr_valid;	/* nop */
1813184610Salfred		case UR_SET_DESCRIPTOR:
1814184610Salfred			goto tr_valid;	/* nop */
1815184610Salfred		case UR_SET_FEATURE:
1816184610Salfred		default:
1817184610Salfred			goto tr_stalled;
1818184610Salfred		}
1819184610Salfred		break;
1820184610Salfred
1821184610Salfred	case UT_WRITE_ENDPOINT:
1822191402Sthompsa		switch (req->bRequest) {
1823184610Salfred		case UR_CLEAR_FEATURE:
1824191402Sthompsa			switch (UGETW(req->wValue)) {
1825184610Salfred			case UF_ENDPOINT_HALT:
1826184610Salfred				goto tr_handle_clear_halt;
1827184610Salfred			case UF_DEVICE_REMOTE_WAKEUP:
1828184610Salfred				goto tr_handle_clear_wakeup;
1829184610Salfred			default:
1830184610Salfred				goto tr_stalled;
1831184610Salfred			}
1832184610Salfred			break;
1833184610Salfred		case UR_SET_FEATURE:
1834191402Sthompsa			switch (UGETW(req->wValue)) {
1835184610Salfred			case UF_ENDPOINT_HALT:
1836184610Salfred				goto tr_handle_set_halt;
1837184610Salfred			case UF_DEVICE_REMOTE_WAKEUP:
1838184610Salfred				goto tr_handle_set_wakeup;
1839184610Salfred			default:
1840184610Salfred				goto tr_stalled;
1841184610Salfred			}
1842184610Salfred			break;
1843184610Salfred		case UR_SYNCH_FRAME:
1844184610Salfred			goto tr_valid;	/* nop */
1845184610Salfred		default:
1846184610Salfred			goto tr_stalled;
1847184610Salfred		}
1848184610Salfred		break;
1849184610Salfred
1850184610Salfred	case UT_READ_ENDPOINT:
1851191402Sthompsa		switch (req->bRequest) {
1852184610Salfred		case UR_GET_STATUS:
1853184610Salfred			goto tr_handle_get_ep_status;
1854184610Salfred		default:
1855184610Salfred			goto tr_stalled;
1856184610Salfred		}
1857184610Salfred		break;
1858184610Salfred
1859184610Salfred	case UT_WRITE_INTERFACE:
1860191402Sthompsa		switch (req->bRequest) {
1861184610Salfred		case UR_SET_INTERFACE:
1862184610Salfred			goto tr_handle_set_interface;
1863184610Salfred		case UR_CLEAR_FEATURE:
1864184610Salfred			goto tr_valid;	/* nop */
1865184610Salfred		case UR_SET_FEATURE:
1866184610Salfred		default:
1867184610Salfred			goto tr_stalled;
1868184610Salfred		}
1869184610Salfred		break;
1870184610Salfred
1871184610Salfred	case UT_READ_INTERFACE:
1872191402Sthompsa		switch (req->bRequest) {
1873184610Salfred		case UR_GET_INTERFACE:
1874184610Salfred			goto tr_handle_get_interface;
1875184610Salfred		case UR_GET_STATUS:
1876184610Salfred			goto tr_handle_get_iface_status;
1877184610Salfred		default:
1878184610Salfred			goto tr_stalled;
1879184610Salfred		}
1880184610Salfred		break;
1881184610Salfred
1882184610Salfred	case UT_WRITE_CLASS_INTERFACE:
1883184610Salfred	case UT_WRITE_VENDOR_INTERFACE:
1884184610Salfred		/* XXX forward */
1885184610Salfred		break;
1886184610Salfred
1887184610Salfred	case UT_READ_CLASS_INTERFACE:
1888184610Salfred	case UT_READ_VENDOR_INTERFACE:
1889184610Salfred		/* XXX forward */
1890184610Salfred		break;
1891184610Salfred
1892184610Salfred	case UT_WRITE_CLASS_DEVICE:
1893191402Sthompsa		switch (req->bRequest) {
1894184610Salfred		case UR_CLEAR_FEATURE:
1895184610Salfred			goto tr_valid;
1896184610Salfred		case UR_SET_DESCRIPTOR:
1897184610Salfred		case UR_SET_FEATURE:
1898184610Salfred			break;
1899184610Salfred		default:
1900184610Salfred			goto tr_stalled;
1901184610Salfred		}
1902184610Salfred		break;
1903184610Salfred
1904184610Salfred	case UT_WRITE_CLASS_OTHER:
1905191402Sthompsa		switch (req->bRequest) {
1906184610Salfred		case UR_CLEAR_FEATURE:
1907184610Salfred			goto tr_handle_clear_port_feature;
1908184610Salfred		case UR_SET_FEATURE:
1909184610Salfred			goto tr_handle_set_port_feature;
1910184610Salfred		case UR_CLEAR_TT_BUFFER:
1911184610Salfred		case UR_RESET_TT:
1912184610Salfred		case UR_STOP_TT:
1913184610Salfred			goto tr_valid;
1914184610Salfred
1915184610Salfred		default:
1916184610Salfred			goto tr_stalled;
1917184610Salfred		}
1918184610Salfred		break;
1919184610Salfred
1920184610Salfred	case UT_READ_CLASS_OTHER:
1921191402Sthompsa		switch (req->bRequest) {
1922184610Salfred		case UR_GET_TT_STATE:
1923184610Salfred			goto tr_handle_get_tt_state;
1924184610Salfred		case UR_GET_STATUS:
1925184610Salfred			goto tr_handle_get_port_status;
1926184610Salfred		default:
1927184610Salfred			goto tr_stalled;
1928184610Salfred		}
1929184610Salfred		break;
1930184610Salfred
1931184610Salfred	case UT_READ_CLASS_DEVICE:
1932191402Sthompsa		switch (req->bRequest) {
1933184610Salfred		case UR_GET_DESCRIPTOR:
1934184610Salfred			goto tr_handle_get_class_descriptor;
1935184610Salfred		case UR_GET_STATUS:
1936184610Salfred			goto tr_handle_get_class_status;
1937184610Salfred
1938184610Salfred		default:
1939184610Salfred			goto tr_stalled;
1940184610Salfred		}
1941184610Salfred		break;
1942184610Salfred	default:
1943184610Salfred		goto tr_stalled;
1944184610Salfred	}
1945184610Salfred	goto tr_valid;
1946184610Salfred
1947184610Salfredtr_handle_get_descriptor:
1948184610Salfred	switch (value >> 8) {
1949184610Salfred	case UDESC_DEVICE:
1950184610Salfred		if (value & 0xff) {
1951184610Salfred			goto tr_stalled;
1952184610Salfred		}
1953191402Sthompsa		len = sizeof(at91dci_devd);
1954191402Sthompsa		ptr = (const void *)&at91dci_devd;
1955184610Salfred		goto tr_valid;
1956184610Salfred	case UDESC_CONFIG:
1957184610Salfred		if (value & 0xff) {
1958184610Salfred			goto tr_stalled;
1959184610Salfred		}
1960191402Sthompsa		len = sizeof(at91dci_confd);
1961191402Sthompsa		ptr = (const void *)&at91dci_confd;
1962184610Salfred		goto tr_valid;
1963184610Salfred	case UDESC_STRING:
1964184610Salfred		switch (value & 0xff) {
1965184610Salfred		case 0:		/* Language table */
1966191402Sthompsa			len = sizeof(at91dci_langtab);
1967191402Sthompsa			ptr = (const void *)&at91dci_langtab;
1968184610Salfred			goto tr_valid;
1969184610Salfred
1970184610Salfred		case 1:		/* Vendor */
1971191402Sthompsa			len = sizeof(at91dci_vendor);
1972191402Sthompsa			ptr = (const void *)&at91dci_vendor;
1973184610Salfred			goto tr_valid;
1974184610Salfred
1975184610Salfred		case 2:		/* Product */
1976191402Sthompsa			len = sizeof(at91dci_product);
1977191402Sthompsa			ptr = (const void *)&at91dci_product;
1978184610Salfred			goto tr_valid;
1979184610Salfred		default:
1980184610Salfred			break;
1981184610Salfred		}
1982184610Salfred		break;
1983184610Salfred	default:
1984184610Salfred		goto tr_stalled;
1985184610Salfred	}
1986184610Salfred	goto tr_stalled;
1987184610Salfred
1988184610Salfredtr_handle_get_config:
1989191402Sthompsa	len = 1;
1990184610Salfred	sc->sc_hub_temp.wValue[0] = sc->sc_conf;
1991184610Salfred	goto tr_valid;
1992184610Salfred
1993184610Salfredtr_handle_get_status:
1994191402Sthompsa	len = 2;
1995184610Salfred	USETW(sc->sc_hub_temp.wValue, UDS_SELF_POWERED);
1996184610Salfred	goto tr_valid;
1997184610Salfred
1998184610Salfredtr_handle_set_address:
1999184610Salfred	if (value & 0xFF00) {
2000184610Salfred		goto tr_stalled;
2001184610Salfred	}
2002184610Salfred	sc->sc_rt_addr = value;
2003184610Salfred	goto tr_valid;
2004184610Salfred
2005184610Salfredtr_handle_set_config:
2006184610Salfred	if (value >= 2) {
2007184610Salfred		goto tr_stalled;
2008184610Salfred	}
2009184610Salfred	sc->sc_conf = value;
2010184610Salfred	goto tr_valid;
2011184610Salfred
2012184610Salfredtr_handle_get_interface:
2013191402Sthompsa	len = 1;
2014184610Salfred	sc->sc_hub_temp.wValue[0] = 0;
2015184610Salfred	goto tr_valid;
2016184610Salfred
2017184610Salfredtr_handle_get_tt_state:
2018184610Salfredtr_handle_get_class_status:
2019184610Salfredtr_handle_get_iface_status:
2020184610Salfredtr_handle_get_ep_status:
2021191402Sthompsa	len = 2;
2022184610Salfred	USETW(sc->sc_hub_temp.wValue, 0);
2023184610Salfred	goto tr_valid;
2024184610Salfred
2025184610Salfredtr_handle_set_halt:
2026184610Salfredtr_handle_set_interface:
2027184610Salfredtr_handle_set_wakeup:
2028184610Salfredtr_handle_clear_wakeup:
2029184610Salfredtr_handle_clear_halt:
2030184610Salfred	goto tr_valid;
2031184610Salfred
2032184610Salfredtr_handle_clear_port_feature:
2033184610Salfred	if (index != 1) {
2034184610Salfred		goto tr_stalled;
2035184610Salfred	}
2036184610Salfred	DPRINTFN(9, "UR_CLEAR_PORT_FEATURE on port %d\n", index);
2037184610Salfred
2038184610Salfred	switch (value) {
2039184610Salfred	case UHF_PORT_SUSPEND:
2040190735Sthompsa		at91dci_wakeup_peer(sc);
2041184610Salfred		break;
2042184610Salfred
2043184610Salfred	case UHF_PORT_ENABLE:
2044184610Salfred		sc->sc_flags.port_enabled = 0;
2045184610Salfred		break;
2046184610Salfred
2047184610Salfred	case UHF_PORT_TEST:
2048184610Salfred	case UHF_PORT_INDICATOR:
2049184610Salfred	case UHF_C_PORT_ENABLE:
2050184610Salfred	case UHF_C_PORT_OVER_CURRENT:
2051184610Salfred	case UHF_C_PORT_RESET:
2052184610Salfred		/* nops */
2053184610Salfred		break;
2054184610Salfred	case UHF_PORT_POWER:
2055184610Salfred		sc->sc_flags.port_powered = 0;
2056184610Salfred		at91dci_pull_down(sc);
2057184610Salfred		at91dci_clocks_off(sc);
2058184610Salfred		break;
2059184610Salfred	case UHF_C_PORT_CONNECTION:
2060184610Salfred		sc->sc_flags.change_connect = 0;
2061184610Salfred		break;
2062184610Salfred	case UHF_C_PORT_SUSPEND:
2063184610Salfred		sc->sc_flags.change_suspend = 0;
2064184610Salfred		break;
2065184610Salfred	default:
2066191402Sthompsa		err = USB_ERR_IOERROR;
2067184610Salfred		goto done;
2068184610Salfred	}
2069184610Salfred	goto tr_valid;
2070184610Salfred
2071184610Salfredtr_handle_set_port_feature:
2072184610Salfred	if (index != 1) {
2073184610Salfred		goto tr_stalled;
2074184610Salfred	}
2075184610Salfred	DPRINTFN(9, "UR_SET_PORT_FEATURE\n");
2076184610Salfred
2077184610Salfred	switch (value) {
2078184610Salfred	case UHF_PORT_ENABLE:
2079184610Salfred		sc->sc_flags.port_enabled = 1;
2080184610Salfred		break;
2081184610Salfred	case UHF_PORT_SUSPEND:
2082184610Salfred	case UHF_PORT_RESET:
2083184610Salfred	case UHF_PORT_TEST:
2084184610Salfred	case UHF_PORT_INDICATOR:
2085184610Salfred		/* nops */
2086184610Salfred		break;
2087184610Salfred	case UHF_PORT_POWER:
2088184610Salfred		sc->sc_flags.port_powered = 1;
2089184610Salfred		break;
2090184610Salfred	default:
2091191402Sthompsa		err = USB_ERR_IOERROR;
2092184610Salfred		goto done;
2093184610Salfred	}
2094184610Salfred	goto tr_valid;
2095184610Salfred
2096184610Salfredtr_handle_get_port_status:
2097184610Salfred
2098184610Salfred	DPRINTFN(9, "UR_GET_PORT_STATUS\n");
2099184610Salfred
2100184610Salfred	if (index != 1) {
2101184610Salfred		goto tr_stalled;
2102184610Salfred	}
2103184610Salfred	if (sc->sc_flags.status_vbus) {
2104184610Salfred		at91dci_clocks_on(sc);
2105184610Salfred		at91dci_pull_up(sc);
2106184610Salfred	} else {
2107184610Salfred		at91dci_pull_down(sc);
2108184610Salfred		at91dci_clocks_off(sc);
2109184610Salfred	}
2110184610Salfred
2111184610Salfred	/* Select FULL-speed and Device Side Mode */
2112184610Salfred
2113184610Salfred	value = UPS_PORT_MODE_DEVICE;
2114184610Salfred
2115184610Salfred	if (sc->sc_flags.port_powered) {
2116184610Salfred		value |= UPS_PORT_POWER;
2117184610Salfred	}
2118184610Salfred	if (sc->sc_flags.port_enabled) {
2119184610Salfred		value |= UPS_PORT_ENABLED;
2120184610Salfred	}
2121184610Salfred	if (sc->sc_flags.status_vbus &&
2122184610Salfred	    sc->sc_flags.status_bus_reset) {
2123184610Salfred		value |= UPS_CURRENT_CONNECT_STATUS;
2124184610Salfred	}
2125184610Salfred	if (sc->sc_flags.status_suspend) {
2126184610Salfred		value |= UPS_SUSPEND;
2127184610Salfred	}
2128184610Salfred	USETW(sc->sc_hub_temp.ps.wPortStatus, value);
2129184610Salfred
2130184610Salfred	value = 0;
2131184610Salfred
2132184610Salfred	if (sc->sc_flags.change_connect) {
2133184610Salfred		value |= UPS_C_CONNECT_STATUS;
2134184610Salfred
2135184610Salfred		if (sc->sc_flags.status_vbus &&
2136184610Salfred		    sc->sc_flags.status_bus_reset) {
2137184610Salfred			/* reset endpoint flags */
2138184610Salfred			bzero(sc->sc_ep_flags, sizeof(sc->sc_ep_flags));
2139184610Salfred		}
2140184610Salfred	}
2141184610Salfred	if (sc->sc_flags.change_suspend) {
2142184610Salfred		value |= UPS_C_SUSPEND;
2143184610Salfred	}
2144184610Salfred	USETW(sc->sc_hub_temp.ps.wPortChange, value);
2145191402Sthompsa	len = sizeof(sc->sc_hub_temp.ps);
2146184610Salfred	goto tr_valid;
2147184610Salfred
2148184610Salfredtr_handle_get_class_descriptor:
2149184610Salfred	if (value & 0xFF) {
2150184610Salfred		goto tr_stalled;
2151184610Salfred	}
2152191402Sthompsa	ptr = (const void *)&at91dci_hubd;
2153191402Sthompsa	len = sizeof(at91dci_hubd);
2154184610Salfred	goto tr_valid;
2155184610Salfred
2156184610Salfredtr_stalled:
2157191402Sthompsa	err = USB_ERR_STALLED;
2158184610Salfredtr_valid:
2159184610Salfreddone:
2160191402Sthompsa	*plength = len;
2161191402Sthompsa	*pptr = ptr;
2162191402Sthompsa	return (err);
2163184610Salfred}
2164184610Salfred
2165184610Salfredstatic void
2166192984Sthompsaat91dci_xfer_setup(struct usb_setup_params *parm)
2167184610Salfred{
2168192984Sthompsa	const struct usb_hw_ep_profile *pf;
2169184610Salfred	struct at91dci_softc *sc;
2170192984Sthompsa	struct usb_xfer *xfer;
2171184610Salfred	void *last_obj;
2172184610Salfred	uint32_t ntd;
2173184610Salfred	uint32_t n;
2174184610Salfred	uint8_t ep_no;
2175184610Salfred
2176184610Salfred	sc = AT9100_DCI_BUS2SC(parm->udev->bus);
2177184610Salfred	xfer = parm->curr_xfer;
2178184610Salfred
2179184610Salfred	/*
2180184610Salfred	 * NOTE: This driver does not use any of the parameters that
2181184610Salfred	 * are computed from the following values. Just set some
2182184610Salfred	 * reasonable dummies:
2183184610Salfred	 */
2184184610Salfred	parm->hc_max_packet_size = 0x500;
2185184610Salfred	parm->hc_max_packet_count = 1;
2186184610Salfred	parm->hc_max_frame_size = 0x500;
2187184610Salfred
2188194228Sthompsa	usbd_transfer_setup_sub(parm);
2189184610Salfred
2190184610Salfred	/*
2191184610Salfred	 * compute maximum number of TDs
2192184610Salfred	 */
2193184610Salfred	if (parm->methods == &at91dci_device_ctrl_methods) {
2194184610Salfred
2195184610Salfred		ntd = xfer->nframes + 1 /* STATUS */ + 1	/* SYNC 1 */
2196184610Salfred		    + 1 /* SYNC 2 */ ;
2197184610Salfred
2198184610Salfred	} else if (parm->methods == &at91dci_device_bulk_methods) {
2199184610Salfred
2200184610Salfred		ntd = xfer->nframes + 1 /* SYNC */ ;
2201184610Salfred
2202184610Salfred	} else if (parm->methods == &at91dci_device_intr_methods) {
2203184610Salfred
2204184610Salfred		ntd = xfer->nframes + 1 /* SYNC */ ;
2205184610Salfred
2206184610Salfred	} else if (parm->methods == &at91dci_device_isoc_fs_methods) {
2207184610Salfred
2208184610Salfred		ntd = xfer->nframes + 1 /* SYNC */ ;
2209184610Salfred
2210184610Salfred	} else {
2211184610Salfred
2212184610Salfred		ntd = 0;
2213184610Salfred	}
2214184610Salfred
2215184610Salfred	/*
2216194228Sthompsa	 * check if "usbd_transfer_setup_sub" set an error
2217184610Salfred	 */
2218184610Salfred	if (parm->err) {
2219184610Salfred		return;
2220184610Salfred	}
2221184610Salfred	/*
2222184610Salfred	 * allocate transfer descriptors
2223184610Salfred	 */
2224184610Salfred	last_obj = NULL;
2225184610Salfred
2226184610Salfred	/*
2227184610Salfred	 * get profile stuff
2228184610Salfred	 */
2229184610Salfred	if (ntd) {
2230184610Salfred
2231193644Sthompsa		ep_no = xfer->endpointno & UE_ADDR;
2232184610Salfred		at91dci_get_hw_ep_profile(parm->udev, &pf, ep_no);
2233184610Salfred
2234184610Salfred		if (pf == NULL) {
2235184610Salfred			/* should not happen */
2236184610Salfred			parm->err = USB_ERR_INVAL;
2237184610Salfred			return;
2238184610Salfred		}
2239184610Salfred	} else {
2240184610Salfred		ep_no = 0;
2241184610Salfred		pf = NULL;
2242184610Salfred	}
2243184610Salfred
2244184610Salfred	/* align data */
2245184610Salfred	parm->size[0] += ((-parm->size[0]) & (USB_HOST_ALIGN - 1));
2246184610Salfred
2247184610Salfred	for (n = 0; n != ntd; n++) {
2248184610Salfred
2249184610Salfred		struct at91dci_td *td;
2250184610Salfred
2251184610Salfred		if (parm->buf) {
2252184610Salfred
2253184610Salfred			td = USB_ADD_BYTES(parm->buf, parm->size[0]);
2254184610Salfred
2255184610Salfred			/* init TD */
2256184610Salfred			td->io_tag = sc->sc_io_tag;
2257184610Salfred			td->io_hdl = sc->sc_io_hdl;
2258184610Salfred			td->max_packet_size = xfer->max_packet_size;
2259184610Salfred			td->status_reg = AT91_UDP_CSR(ep_no);
2260184610Salfred			td->fifo_reg = AT91_UDP_FDR(ep_no);
2261184610Salfred			if (pf->support_multi_buffer) {
2262184610Salfred				td->support_multi_buffer = 1;
2263184610Salfred			}
2264184610Salfred			td->obj_next = last_obj;
2265184610Salfred
2266184610Salfred			last_obj = td;
2267184610Salfred		}
2268184610Salfred		parm->size[0] += sizeof(*td);
2269184610Salfred	}
2270184610Salfred
2271184610Salfred	xfer->td_start[0] = last_obj;
2272184610Salfred}
2273184610Salfred
2274184610Salfredstatic void
2275192984Sthompsaat91dci_xfer_unsetup(struct usb_xfer *xfer)
2276184610Salfred{
2277184610Salfred	return;
2278184610Salfred}
2279184610Salfred
2280184610Salfredstatic void
2281193644Sthompsaat91dci_ep_init(struct usb_device *udev, struct usb_endpoint_descriptor *edesc,
2282193644Sthompsa    struct usb_endpoint *ep)
2283184610Salfred{
2284184610Salfred	struct at91dci_softc *sc = AT9100_DCI_BUS2SC(udev->bus);
2285184610Salfred
2286193644Sthompsa	DPRINTFN(2, "endpoint=%p, addr=%d, endpt=%d, mode=%d (%d)\n",
2287193644Sthompsa	    ep, udev->address,
2288192499Sthompsa	    edesc->bEndpointAddress, udev->flags.usb_mode,
2289184610Salfred	    sc->sc_rt_addr);
2290184610Salfred
2291190735Sthompsa	if (udev->device_index != sc->sc_rt_addr) {
2292184610Salfred
2293192499Sthompsa		if (udev->flags.usb_mode != USB_MODE_DEVICE) {
2294184610Salfred			/* not supported */
2295184610Salfred			return;
2296184610Salfred		}
2297184610Salfred		if (udev->speed != USB_SPEED_FULL) {
2298184610Salfred			/* not supported */
2299184610Salfred			return;
2300184610Salfred		}
2301184610Salfred		switch (edesc->bmAttributes & UE_XFERTYPE) {
2302184610Salfred		case UE_CONTROL:
2303193644Sthompsa			ep->methods = &at91dci_device_ctrl_methods;
2304184610Salfred			break;
2305184610Salfred		case UE_INTERRUPT:
2306193644Sthompsa			ep->methods = &at91dci_device_intr_methods;
2307184610Salfred			break;
2308184610Salfred		case UE_ISOCHRONOUS:
2309193644Sthompsa			ep->methods = &at91dci_device_isoc_fs_methods;
2310184610Salfred			break;
2311184610Salfred		case UE_BULK:
2312193644Sthompsa			ep->methods = &at91dci_device_bulk_methods;
2313184610Salfred			break;
2314184610Salfred		default:
2315184610Salfred			/* do nothing */
2316184610Salfred			break;
2317184610Salfred		}
2318184610Salfred	}
2319184610Salfred}
2320184610Salfred
2321192984Sthompsastruct usb_bus_methods at91dci_bus_methods =
2322184610Salfred{
2323193644Sthompsa	.endpoint_init = &at91dci_ep_init,
2324184610Salfred	.xfer_setup = &at91dci_xfer_setup,
2325184610Salfred	.xfer_unsetup = &at91dci_xfer_unsetup,
2326184610Salfred	.get_hw_ep_profile = &at91dci_get_hw_ep_profile,
2327184610Salfred	.set_stall = &at91dci_set_stall,
2328184610Salfred	.clear_stall = &at91dci_clear_stall,
2329190735Sthompsa	.roothub_exec = &at91dci_roothub_exec,
2330195960Salfred	.xfer_poll = &at91dci_do_poll,
2331184610Salfred};
2332