1246122Shselasky/* $FreeBSD$ */
2187160Sthompsa/*-
3187160Sthompsa * Copyright (c) 2009 Hans Petter Selasky. All rights reserved.
4187160Sthompsa *
5187160Sthompsa * Redistribution and use in source and binary forms, with or without
6187160Sthompsa * modification, are permitted provided that the following conditions
7187160Sthompsa * are met:
8187160Sthompsa * 1. Redistributions of source code must retain the above copyright
9187160Sthompsa *    notice, this list of conditions and the following disclaimer.
10187160Sthompsa * 2. Redistributions in binary form must reproduce the above copyright
11187160Sthompsa *    notice, this list of conditions and the following disclaimer in the
12187160Sthompsa *    documentation and/or other materials provided with the distribution.
13187160Sthompsa *
14187160Sthompsa * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15187160Sthompsa * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16187160Sthompsa * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17187160Sthompsa * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18187160Sthompsa * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19187160Sthompsa * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20187160Sthompsa * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21187160Sthompsa * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22187160Sthompsa * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23187160Sthompsa * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24187160Sthompsa * SUCH DAMAGE.
25187160Sthompsa */
26187160Sthompsa
27187160Sthompsa/*
28190754Sthompsa * This file contains the driver for the ATMEGA series USB OTG Controller. This
29190754Sthompsa * driver currently only supports the DCI mode of the USB hardware.
30187160Sthompsa */
31187160Sthompsa
32187160Sthompsa/*
33187160Sthompsa * NOTE: When the chip detects BUS-reset it will also reset the
34187160Sthompsa * endpoints, Function-address and more.
35187160Sthompsa */
36187160Sthompsa
37246122Shselasky#ifdef USB_GLOBAL_INCLUDE_FILE
38246122Shselasky#include USB_GLOBAL_INCLUDE_FILE
39246122Shselasky#else
40194677Sthompsa#include <sys/stdint.h>
41194677Sthompsa#include <sys/stddef.h>
42194677Sthompsa#include <sys/param.h>
43194677Sthompsa#include <sys/queue.h>
44194677Sthompsa#include <sys/types.h>
45194677Sthompsa#include <sys/systm.h>
46194677Sthompsa#include <sys/kernel.h>
47194677Sthompsa#include <sys/bus.h>
48194677Sthompsa#include <sys/module.h>
49194677Sthompsa#include <sys/lock.h>
50194677Sthompsa#include <sys/mutex.h>
51194677Sthompsa#include <sys/condvar.h>
52194677Sthompsa#include <sys/sysctl.h>
53194677Sthompsa#include <sys/sx.h>
54194677Sthompsa#include <sys/unistd.h>
55194677Sthompsa#include <sys/callout.h>
56194677Sthompsa#include <sys/malloc.h>
57194677Sthompsa#include <sys/priv.h>
58194677Sthompsa
59188942Sthompsa#include <dev/usb/usb.h>
60194677Sthompsa#include <dev/usb/usbdi.h>
61187160Sthompsa
62187160Sthompsa#define	USB_DEBUG_VAR atmegadci_debug
63187160Sthompsa
64188942Sthompsa#include <dev/usb/usb_core.h>
65188942Sthompsa#include <dev/usb/usb_debug.h>
66188942Sthompsa#include <dev/usb/usb_busdma.h>
67188942Sthompsa#include <dev/usb/usb_process.h>
68188942Sthompsa#include <dev/usb/usb_transfer.h>
69188942Sthompsa#include <dev/usb/usb_device.h>
70188942Sthompsa#include <dev/usb/usb_hub.h>
71188942Sthompsa#include <dev/usb/usb_util.h>
72187160Sthompsa
73188942Sthompsa#include <dev/usb/usb_controller.h>
74188942Sthompsa#include <dev/usb/usb_bus.h>
75246122Shselasky#endif			/* USB_GLOBAL_INCLUDE_FILE */
76246122Shselasky
77188942Sthompsa#include <dev/usb/controller/atmegadci.h>
78187160Sthompsa
79187160Sthompsa#define	ATMEGA_BUS2SC(bus) \
80187160Sthompsa   ((struct atmegadci_softc *)(((uint8_t *)(bus)) - \
81190181Sthompsa    ((uint8_t *)&(((struct atmegadci_softc *)0)->sc_bus))))
82187160Sthompsa
83187160Sthompsa#define	ATMEGA_PC2SC(pc) \
84190180Sthompsa   ATMEGA_BUS2SC(USB_DMATAG_TO_XROOT((pc)->tag_parent)->bus)
85187160Sthompsa
86194677Sthompsa#ifdef USB_DEBUG
87187160Sthompsastatic int atmegadci_debug = 0;
88187160Sthompsa
89227309Sedstatic SYSCTL_NODE(_hw_usb, OID_AUTO, atmegadci, CTLFLAG_RW, 0,
90227309Sed    "USB ATMEGA DCI");
91192502SthompsaSYSCTL_INT(_hw_usb_atmegadci, OID_AUTO, debug, CTLFLAG_RW,
92187160Sthompsa    &atmegadci_debug, 0, "ATMEGA DCI debug level");
93187160Sthompsa#endif
94187160Sthompsa
95187160Sthompsa#define	ATMEGA_INTR_ENDPT 1
96187160Sthompsa
97187160Sthompsa/* prototypes */
98187160Sthompsa
99192984Sthompsastruct usb_bus_methods atmegadci_bus_methods;
100192984Sthompsastruct usb_pipe_methods atmegadci_device_non_isoc_methods;
101192984Sthompsastruct usb_pipe_methods atmegadci_device_isoc_fs_methods;
102187160Sthompsa
103187160Sthompsastatic atmegadci_cmd_t atmegadci_setup_rx;
104187160Sthompsastatic atmegadci_cmd_t atmegadci_data_rx;
105187160Sthompsastatic atmegadci_cmd_t atmegadci_data_tx;
106187160Sthompsastatic atmegadci_cmd_t atmegadci_data_tx_sync;
107193045Sthompsastatic void atmegadci_device_done(struct usb_xfer *, usb_error_t);
108192984Sthompsastatic void atmegadci_do_poll(struct usb_bus *);
109192984Sthompsastatic void atmegadci_standard_done(struct usb_xfer *);
110190735Sthompsastatic void atmegadci_root_intr(struct atmegadci_softc *sc);
111187160Sthompsa
112187160Sthompsa/*
113187160Sthompsa * Here is a list of what the chip supports:
114187160Sthompsa */
115192984Sthompsastatic const struct usb_hw_ep_profile
116187160Sthompsa	atmegadci_ep_profile[2] = {
117187160Sthompsa
118187160Sthompsa	[0] = {
119187160Sthompsa		.max_in_frame_size = 64,
120187160Sthompsa		.max_out_frame_size = 64,
121187160Sthompsa		.is_simplex = 1,
122187160Sthompsa		.support_control = 1,
123187160Sthompsa	},
124187160Sthompsa	[1] = {
125187160Sthompsa		.max_in_frame_size = 64,
126187160Sthompsa		.max_out_frame_size = 64,
127187160Sthompsa		.is_simplex = 1,
128187160Sthompsa		.support_bulk = 1,
129187160Sthompsa		.support_interrupt = 1,
130187160Sthompsa		.support_isochronous = 1,
131187160Sthompsa		.support_in = 1,
132187160Sthompsa		.support_out = 1,
133187160Sthompsa	},
134187160Sthompsa};
135187160Sthompsa
136187160Sthompsastatic void
137192984Sthompsaatmegadci_get_hw_ep_profile(struct usb_device *udev,
138192984Sthompsa    const struct usb_hw_ep_profile **ppf, uint8_t ep_addr)
139187160Sthompsa{
140187160Sthompsa	if (ep_addr == 0)
141187160Sthompsa		*ppf = atmegadci_ep_profile;
142187160Sthompsa	else if (ep_addr < ATMEGA_EP_MAX)
143187160Sthompsa		*ppf = atmegadci_ep_profile + 1;
144187160Sthompsa	else
145187160Sthompsa		*ppf = NULL;
146187160Sthompsa}
147187160Sthompsa
148187160Sthompsastatic void
149187160Sthompsaatmegadci_clocks_on(struct atmegadci_softc *sc)
150187160Sthompsa{
151187160Sthompsa	if (sc->sc_flags.clocks_off &&
152187160Sthompsa	    sc->sc_flags.port_powered) {
153187160Sthompsa
154187160Sthompsa		DPRINTFN(5, "\n");
155187160Sthompsa
156187160Sthompsa		/* turn on clocks */
157187160Sthompsa		(sc->sc_clocks_on) (&sc->sc_bus);
158187160Sthompsa
159187160Sthompsa		ATMEGA_WRITE_1(sc, ATMEGA_USBCON,
160187160Sthompsa		    ATMEGA_USBCON_USBE |
161187160Sthompsa		    ATMEGA_USBCON_OTGPADE |
162187160Sthompsa		    ATMEGA_USBCON_VBUSTE);
163187160Sthompsa
164187160Sthompsa		sc->sc_flags.clocks_off = 0;
165187160Sthompsa
166187160Sthompsa		/* enable transceiver ? */
167187160Sthompsa	}
168187160Sthompsa}
169187160Sthompsa
170187160Sthompsastatic void
171187160Sthompsaatmegadci_clocks_off(struct atmegadci_softc *sc)
172187160Sthompsa{
173187160Sthompsa	if (!sc->sc_flags.clocks_off) {
174187160Sthompsa
175187160Sthompsa		DPRINTFN(5, "\n");
176187160Sthompsa
177187160Sthompsa		/* disable Transceiver ? */
178187160Sthompsa
179187160Sthompsa		ATMEGA_WRITE_1(sc, ATMEGA_USBCON,
180187160Sthompsa		    ATMEGA_USBCON_USBE |
181187160Sthompsa		    ATMEGA_USBCON_OTGPADE |
182187160Sthompsa		    ATMEGA_USBCON_FRZCLK |
183187160Sthompsa		    ATMEGA_USBCON_VBUSTE);
184187160Sthompsa
185187160Sthompsa		/* turn clocks off */
186187160Sthompsa		(sc->sc_clocks_off) (&sc->sc_bus);
187187160Sthompsa
188187160Sthompsa		sc->sc_flags.clocks_off = 1;
189187160Sthompsa	}
190187160Sthompsa}
191187160Sthompsa
192187160Sthompsastatic void
193187160Sthompsaatmegadci_pull_up(struct atmegadci_softc *sc)
194187160Sthompsa{
195187160Sthompsa	/* pullup D+, if possible */
196187160Sthompsa
197187160Sthompsa	if (!sc->sc_flags.d_pulled_up &&
198187160Sthompsa	    sc->sc_flags.port_powered) {
199187160Sthompsa		sc->sc_flags.d_pulled_up = 1;
200187160Sthompsa		ATMEGA_WRITE_1(sc, ATMEGA_UDCON, 0);
201187160Sthompsa	}
202187160Sthompsa}
203187160Sthompsa
204187160Sthompsastatic void
205187160Sthompsaatmegadci_pull_down(struct atmegadci_softc *sc)
206187160Sthompsa{
207187160Sthompsa	/* pulldown D+, if possible */
208187160Sthompsa
209187160Sthompsa	if (sc->sc_flags.d_pulled_up) {
210187160Sthompsa		sc->sc_flags.d_pulled_up = 0;
211187160Sthompsa		ATMEGA_WRITE_1(sc, ATMEGA_UDCON, ATMEGA_UDCON_DETACH);
212187160Sthompsa	}
213187160Sthompsa}
214187160Sthompsa
215187160Sthompsastatic void
216190735Sthompsaatmegadci_wakeup_peer(struct atmegadci_softc *sc)
217187160Sthompsa{
218187160Sthompsa	uint8_t temp;
219187160Sthompsa
220187160Sthompsa	if (!sc->sc_flags.status_suspend) {
221187160Sthompsa		return;
222187160Sthompsa	}
223187160Sthompsa
224187160Sthompsa	temp = ATMEGA_READ_1(sc, ATMEGA_UDCON);
225187160Sthompsa	ATMEGA_WRITE_1(sc, ATMEGA_UDCON, temp | ATMEGA_UDCON_RMWKUP);
226187160Sthompsa
227187160Sthompsa	/* wait 8 milliseconds */
228188983Sthompsa	/* Wait for reset to complete. */
229194228Sthompsa	usb_pause_mtx(&sc->sc_bus.bus_mtx, hz / 125);
230187160Sthompsa
231187160Sthompsa	/* hardware should have cleared RMWKUP bit */
232187160Sthompsa}
233187160Sthompsa
234187160Sthompsastatic void
235187160Sthompsaatmegadci_set_address(struct atmegadci_softc *sc, uint8_t addr)
236187160Sthompsa{
237187160Sthompsa	DPRINTFN(5, "addr=%d\n", addr);
238187160Sthompsa
239187160Sthompsa	addr |= ATMEGA_UDADDR_ADDEN;
240187160Sthompsa
241187160Sthompsa	ATMEGA_WRITE_1(sc, ATMEGA_UDADDR, addr);
242187160Sthompsa}
243187160Sthompsa
244187160Sthompsastatic uint8_t
245187160Sthompsaatmegadci_setup_rx(struct atmegadci_td *td)
246187160Sthompsa{
247187160Sthompsa	struct atmegadci_softc *sc;
248192984Sthompsa	struct usb_device_request req;
249187160Sthompsa	uint16_t count;
250187160Sthompsa	uint8_t temp;
251187160Sthompsa
252187160Sthompsa	/* get pointer to softc */
253187160Sthompsa	sc = ATMEGA_PC2SC(td->pc);
254187160Sthompsa
255187160Sthompsa	/* select endpoint number */
256187160Sthompsa	ATMEGA_WRITE_1(sc, ATMEGA_UENUM, td->ep_no);
257187160Sthompsa
258187160Sthompsa	/* check endpoint status */
259187160Sthompsa	temp = ATMEGA_READ_1(sc, ATMEGA_UEINTX);
260187160Sthompsa
261187160Sthompsa	DPRINTFN(5, "UEINTX=0x%02x\n", temp);
262187160Sthompsa
263187160Sthompsa	if (!(temp & ATMEGA_UEINTX_RXSTPI)) {
264187160Sthompsa		goto not_complete;
265187160Sthompsa	}
266190721Sthompsa	/* clear did stall */
267190721Sthompsa	td->did_stall = 0;
268187160Sthompsa	/* get the packet byte count */
269187160Sthompsa	count =
270187160Sthompsa	    (ATMEGA_READ_1(sc, ATMEGA_UEBCHX) << 8) |
271187160Sthompsa	    (ATMEGA_READ_1(sc, ATMEGA_UEBCLX));
272187160Sthompsa
273187160Sthompsa	/* mask away undefined bits */
274187160Sthompsa	count &= 0x7FF;
275187160Sthompsa
276187160Sthompsa	/* verify data length */
277187160Sthompsa	if (count != td->remainder) {
278187160Sthompsa		DPRINTFN(0, "Invalid SETUP packet "
279187160Sthompsa		    "length, %d bytes\n", count);
280187160Sthompsa		goto not_complete;
281187160Sthompsa	}
282187160Sthompsa	if (count != sizeof(req)) {
283187160Sthompsa		DPRINTFN(0, "Unsupported SETUP packet "
284187160Sthompsa		    "length, %d bytes\n", count);
285187160Sthompsa		goto not_complete;
286187160Sthompsa	}
287187160Sthompsa	/* receive data */
288187160Sthompsa	ATMEGA_READ_MULTI_1(sc, ATMEGA_UEDATX,
289187160Sthompsa	    (void *)&req, sizeof(req));
290187160Sthompsa
291187160Sthompsa	/* copy data into real buffer */
292194228Sthompsa	usbd_copy_in(td->pc, 0, &req, sizeof(req));
293187160Sthompsa
294187160Sthompsa	td->offset = sizeof(req);
295187160Sthompsa	td->remainder = 0;
296187160Sthompsa
297187160Sthompsa	/* sneak peek the set address */
298187160Sthompsa	if ((req.bmRequestType == UT_WRITE_DEVICE) &&
299187160Sthompsa	    (req.bRequest == UR_SET_ADDRESS)) {
300187160Sthompsa		sc->sc_dv_addr = req.wValue[0] & 0x7F;
301189677Sthompsa		/* must write address before ZLP */
302189677Sthompsa		ATMEGA_WRITE_1(sc, ATMEGA_UDADDR, sc->sc_dv_addr);
303187160Sthompsa	} else {
304187160Sthompsa		sc->sc_dv_addr = 0xFF;
305187160Sthompsa	}
306187160Sthompsa
307197556Sthompsa	/* Clear SETUP packet interrupt and all other previous interrupts */
308197556Sthompsa	ATMEGA_WRITE_1(sc, ATMEGA_UEINTX, 0);
309187160Sthompsa	return (0);			/* complete */
310187160Sthompsa
311187160Sthompsanot_complete:
312190721Sthompsa	/* abort any ongoing transfer */
313190721Sthompsa	if (!td->did_stall) {
314190721Sthompsa		DPRINTFN(5, "stalling\n");
315190721Sthompsa		ATMEGA_WRITE_1(sc, ATMEGA_UECONX,
316190721Sthompsa		    ATMEGA_UECONX_EPEN |
317190721Sthompsa		    ATMEGA_UECONX_STALLRQ);
318190721Sthompsa		td->did_stall = 1;
319190721Sthompsa	}
320190722Sthompsa	if (temp & ATMEGA_UEINTX_RXSTPI) {
321190722Sthompsa		/* clear SETUP packet interrupt */
322190722Sthompsa		ATMEGA_WRITE_1(sc, ATMEGA_UEINTX, ~ATMEGA_UEINTX_RXSTPI);
323190722Sthompsa	}
324187160Sthompsa	/* we only want to know if there is a SETUP packet */
325187160Sthompsa	ATMEGA_WRITE_1(sc, ATMEGA_UEIENX, ATMEGA_UEIENX_RXSTPE);
326187160Sthompsa	return (1);			/* not complete */
327187160Sthompsa}
328187160Sthompsa
329187160Sthompsastatic uint8_t
330187160Sthompsaatmegadci_data_rx(struct atmegadci_td *td)
331187160Sthompsa{
332187160Sthompsa	struct atmegadci_softc *sc;
333192984Sthompsa	struct usb_page_search buf_res;
334187160Sthompsa	uint16_t count;
335187160Sthompsa	uint8_t temp;
336187160Sthompsa	uint8_t to;
337187160Sthompsa	uint8_t got_short;
338187160Sthompsa
339187160Sthompsa	to = 3;				/* don't loop forever! */
340187160Sthompsa	got_short = 0;
341187160Sthompsa
342187160Sthompsa	/* get pointer to softc */
343187160Sthompsa	sc = ATMEGA_PC2SC(td->pc);
344187160Sthompsa
345187160Sthompsa	/* select endpoint number */
346187160Sthompsa	ATMEGA_WRITE_1(sc, ATMEGA_UENUM, td->ep_no);
347187160Sthompsa
348187160Sthompsarepeat:
349187160Sthompsa	/* check if any of the FIFO banks have data */
350187160Sthompsa	/* check endpoint status */
351187160Sthompsa	temp = ATMEGA_READ_1(sc, ATMEGA_UEINTX);
352187160Sthompsa
353187160Sthompsa	DPRINTFN(5, "temp=0x%02x rem=%u\n", temp, td->remainder);
354187160Sthompsa
355187160Sthompsa	if (temp & ATMEGA_UEINTX_RXSTPI) {
356187160Sthompsa		if (td->remainder == 0) {
357187160Sthompsa			/*
358187160Sthompsa			 * We are actually complete and have
359187160Sthompsa			 * received the next SETUP
360187160Sthompsa			 */
361187160Sthompsa			DPRINTFN(5, "faking complete\n");
362187160Sthompsa			return (0);	/* complete */
363187160Sthompsa		}
364187160Sthompsa		/*
365187160Sthompsa	         * USB Host Aborted the transfer.
366187160Sthompsa	         */
367187160Sthompsa		td->error = 1;
368187160Sthompsa		return (0);		/* complete */
369187160Sthompsa	}
370187160Sthompsa	/* check status */
371187160Sthompsa	if (!(temp & (ATMEGA_UEINTX_FIFOCON |
372187160Sthompsa	    ATMEGA_UEINTX_RXOUTI))) {
373187160Sthompsa		/* no data */
374187160Sthompsa		goto not_complete;
375187160Sthompsa	}
376187160Sthompsa	/* get the packet byte count */
377187160Sthompsa	count =
378187160Sthompsa	    (ATMEGA_READ_1(sc, ATMEGA_UEBCHX) << 8) |
379187160Sthompsa	    (ATMEGA_READ_1(sc, ATMEGA_UEBCLX));
380187160Sthompsa
381187160Sthompsa	/* mask away undefined bits */
382187160Sthompsa	count &= 0x7FF;
383187160Sthompsa
384187160Sthompsa	/* verify the packet byte count */
385187160Sthompsa	if (count != td->max_packet_size) {
386187160Sthompsa		if (count < td->max_packet_size) {
387187160Sthompsa			/* we have a short packet */
388187160Sthompsa			td->short_pkt = 1;
389187160Sthompsa			got_short = 1;
390187160Sthompsa		} else {
391187160Sthompsa			/* invalid USB packet */
392187160Sthompsa			td->error = 1;
393187160Sthompsa			return (0);	/* we are complete */
394187160Sthompsa		}
395187160Sthompsa	}
396187160Sthompsa	/* verify the packet byte count */
397187160Sthompsa	if (count > td->remainder) {
398187160Sthompsa		/* invalid USB packet */
399187160Sthompsa		td->error = 1;
400187160Sthompsa		return (0);		/* we are complete */
401187160Sthompsa	}
402187160Sthompsa	while (count > 0) {
403194228Sthompsa		usbd_get_page(td->pc, td->offset, &buf_res);
404187160Sthompsa
405187160Sthompsa		/* get correct length */
406187160Sthompsa		if (buf_res.length > count) {
407187160Sthompsa			buf_res.length = count;
408187160Sthompsa		}
409187160Sthompsa		/* receive data */
410187160Sthompsa		ATMEGA_READ_MULTI_1(sc, ATMEGA_UEDATX,
411187160Sthompsa		    buf_res.buffer, buf_res.length);
412187160Sthompsa
413187160Sthompsa		/* update counters */
414187160Sthompsa		count -= buf_res.length;
415187160Sthompsa		td->offset += buf_res.length;
416187160Sthompsa		td->remainder -= buf_res.length;
417187160Sthompsa	}
418187160Sthompsa
419187160Sthompsa	/* clear OUT packet interrupt */
420187160Sthompsa	ATMEGA_WRITE_1(sc, ATMEGA_UEINTX, ATMEGA_UEINTX_RXOUTI ^ 0xFF);
421187160Sthompsa
422187160Sthompsa	/* release FIFO bank */
423187160Sthompsa	ATMEGA_WRITE_1(sc, ATMEGA_UEINTX, ATMEGA_UEINTX_FIFOCON ^ 0xFF);
424187160Sthompsa
425187160Sthompsa	/* check if we are complete */
426187160Sthompsa	if ((td->remainder == 0) || got_short) {
427187160Sthompsa		if (td->short_pkt) {
428187160Sthompsa			/* we are complete */
429187160Sthompsa			return (0);
430187160Sthompsa		}
431187160Sthompsa		/* else need to receive a zero length packet */
432187160Sthompsa	}
433187160Sthompsa	if (--to) {
434187160Sthompsa		goto repeat;
435187160Sthompsa	}
436187160Sthompsanot_complete:
437187160Sthompsa	/* we only want to know if there is a SETUP packet or OUT packet */
438187160Sthompsa	ATMEGA_WRITE_1(sc, ATMEGA_UEIENX,
439187160Sthompsa	    ATMEGA_UEIENX_RXSTPE | ATMEGA_UEIENX_RXOUTE);
440187160Sthompsa	return (1);			/* not complete */
441187160Sthompsa}
442187160Sthompsa
443187160Sthompsastatic uint8_t
444187160Sthompsaatmegadci_data_tx(struct atmegadci_td *td)
445187160Sthompsa{
446187160Sthompsa	struct atmegadci_softc *sc;
447192984Sthompsa	struct usb_page_search buf_res;
448187160Sthompsa	uint16_t count;
449187160Sthompsa	uint8_t to;
450187160Sthompsa	uint8_t temp;
451187160Sthompsa
452187160Sthompsa	to = 3;				/* don't loop forever! */
453187160Sthompsa
454187160Sthompsa	/* get pointer to softc */
455187160Sthompsa	sc = ATMEGA_PC2SC(td->pc);
456187160Sthompsa
457187160Sthompsa	/* select endpoint number */
458187160Sthompsa	ATMEGA_WRITE_1(sc, ATMEGA_UENUM, td->ep_no);
459187160Sthompsa
460187160Sthompsarepeat:
461187160Sthompsa
462187160Sthompsa	/* check endpoint status */
463187160Sthompsa	temp = ATMEGA_READ_1(sc, ATMEGA_UEINTX);
464187160Sthompsa
465187160Sthompsa	DPRINTFN(5, "temp=0x%02x rem=%u\n", temp, td->remainder);
466187160Sthompsa
467187160Sthompsa	if (temp & ATMEGA_UEINTX_RXSTPI) {
468187160Sthompsa		/*
469187160Sthompsa	         * The current transfer was aborted
470187160Sthompsa	         * by the USB Host
471187160Sthompsa	         */
472187160Sthompsa		td->error = 1;
473187160Sthompsa		return (0);		/* complete */
474187160Sthompsa	}
475191401Sthompsa
476191401Sthompsa	temp = ATMEGA_READ_1(sc, ATMEGA_UESTA0X);
477191401Sthompsa	if (temp & 3) {
478191401Sthompsa		/* cannot write any data - a bank is busy */
479187160Sthompsa		goto not_complete;
480187160Sthompsa	}
481191401Sthompsa
482187160Sthompsa	count = td->max_packet_size;
483187160Sthompsa	if (td->remainder < count) {
484187160Sthompsa		/* we have a short packet */
485187160Sthompsa		td->short_pkt = 1;
486187160Sthompsa		count = td->remainder;
487187160Sthompsa	}
488187160Sthompsa	while (count > 0) {
489187160Sthompsa
490194228Sthompsa		usbd_get_page(td->pc, td->offset, &buf_res);
491187160Sthompsa
492187160Sthompsa		/* get correct length */
493187160Sthompsa		if (buf_res.length > count) {
494187160Sthompsa			buf_res.length = count;
495187160Sthompsa		}
496187160Sthompsa		/* transmit data */
497187160Sthompsa		ATMEGA_WRITE_MULTI_1(sc, ATMEGA_UEDATX,
498187160Sthompsa		    buf_res.buffer, buf_res.length);
499187160Sthompsa
500187160Sthompsa		/* update counters */
501187160Sthompsa		count -= buf_res.length;
502187160Sthompsa		td->offset += buf_res.length;
503187160Sthompsa		td->remainder -= buf_res.length;
504187160Sthompsa	}
505187160Sthompsa
506187160Sthompsa	/* clear IN packet interrupt */
507187160Sthompsa	ATMEGA_WRITE_1(sc, ATMEGA_UEINTX, 0xFF ^ ATMEGA_UEINTX_TXINI);
508187160Sthompsa
509187160Sthompsa	/* allocate FIFO bank */
510187160Sthompsa	ATMEGA_WRITE_1(sc, ATMEGA_UEINTX, 0xFF ^ ATMEGA_UEINTX_FIFOCON);
511187160Sthompsa
512187160Sthompsa	/* check remainder */
513187160Sthompsa	if (td->remainder == 0) {
514187160Sthompsa		if (td->short_pkt) {
515187160Sthompsa			return (0);	/* complete */
516187160Sthompsa		}
517187160Sthompsa		/* else we need to transmit a short packet */
518187160Sthompsa	}
519187160Sthompsa	if (--to) {
520187160Sthompsa		goto repeat;
521187160Sthompsa	}
522187160Sthompsanot_complete:
523187160Sthompsa	/* we only want to know if there is a SETUP packet or free IN packet */
524187160Sthompsa	ATMEGA_WRITE_1(sc, ATMEGA_UEIENX,
525187160Sthompsa	    ATMEGA_UEIENX_RXSTPE | ATMEGA_UEIENX_TXINE);
526187160Sthompsa	return (1);			/* not complete */
527187160Sthompsa}
528187160Sthompsa
529187160Sthompsastatic uint8_t
530187160Sthompsaatmegadci_data_tx_sync(struct atmegadci_td *td)
531187160Sthompsa{
532187160Sthompsa	struct atmegadci_softc *sc;
533187160Sthompsa	uint8_t temp;
534187160Sthompsa
535187160Sthompsa	/* get pointer to softc */
536187160Sthompsa	sc = ATMEGA_PC2SC(td->pc);
537187160Sthompsa
538187160Sthompsa	/* select endpoint number */
539187160Sthompsa	ATMEGA_WRITE_1(sc, ATMEGA_UENUM, td->ep_no);
540187160Sthompsa
541187160Sthompsa	/* check endpoint status */
542187160Sthompsa	temp = ATMEGA_READ_1(sc, ATMEGA_UEINTX);
543187160Sthompsa
544187160Sthompsa	DPRINTFN(5, "temp=0x%02x\n", temp);
545187160Sthompsa
546187160Sthompsa	if (temp & ATMEGA_UEINTX_RXSTPI) {
547187160Sthompsa		DPRINTFN(5, "faking complete\n");
548187160Sthompsa		/* Race condition */
549187160Sthompsa		return (0);		/* complete */
550187160Sthompsa	}
551187160Sthompsa	/*
552187160Sthompsa	 * The control endpoint has only got one bank, so if that bank
553187160Sthompsa	 * is free the packet has been transferred!
554187160Sthompsa	 */
555191401Sthompsa	temp = ATMEGA_READ_1(sc, ATMEGA_UESTA0X);
556191401Sthompsa	if (temp & 3) {
557191401Sthompsa		/* cannot write any data - a bank is busy */
558187160Sthompsa		goto not_complete;
559187160Sthompsa	}
560187160Sthompsa	if (sc->sc_dv_addr != 0xFF) {
561187160Sthompsa		/* set new address */
562187160Sthompsa		atmegadci_set_address(sc, sc->sc_dv_addr);
563187160Sthompsa	}
564187160Sthompsa	return (0);			/* complete */
565187160Sthompsa
566187160Sthompsanot_complete:
567187160Sthompsa	/* we only want to know if there is a SETUP packet or free IN packet */
568187160Sthompsa	ATMEGA_WRITE_1(sc, ATMEGA_UEIENX,
569187160Sthompsa	    ATMEGA_UEIENX_RXSTPE | ATMEGA_UEIENX_TXINE);
570187160Sthompsa	return (1);			/* not complete */
571187160Sthompsa}
572187160Sthompsa
573187160Sthompsastatic uint8_t
574192984Sthompsaatmegadci_xfer_do_fifo(struct usb_xfer *xfer)
575187160Sthompsa{
576187160Sthompsa	struct atmegadci_td *td;
577187160Sthompsa
578187160Sthompsa	DPRINTFN(9, "\n");
579187160Sthompsa
580187160Sthompsa	td = xfer->td_transfer_cache;
581187160Sthompsa	while (1) {
582187160Sthompsa		if ((td->func) (td)) {
583187160Sthompsa			/* operation in progress */
584187160Sthompsa			break;
585187160Sthompsa		}
586187160Sthompsa		if (((void *)td) == xfer->td_transfer_last) {
587187160Sthompsa			goto done;
588187160Sthompsa		}
589187160Sthompsa		if (td->error) {
590187160Sthompsa			goto done;
591187160Sthompsa		} else if (td->remainder > 0) {
592187160Sthompsa			/*
593187160Sthompsa			 * We had a short transfer. If there is no alternate
594187160Sthompsa			 * next, stop processing !
595187160Sthompsa			 */
596187160Sthompsa			if (!td->alt_next) {
597187160Sthompsa				goto done;
598187160Sthompsa			}
599187160Sthompsa		}
600187160Sthompsa		/*
601187160Sthompsa		 * Fetch the next transfer descriptor and transfer
602187160Sthompsa		 * some flags to the next transfer descriptor
603187160Sthompsa		 */
604187160Sthompsa		td = td->obj_next;
605187160Sthompsa		xfer->td_transfer_cache = td;
606187160Sthompsa	}
607187160Sthompsa	return (1);			/* not complete */
608187160Sthompsa
609187160Sthompsadone:
610187160Sthompsa	/* compute all actual lengths */
611187160Sthompsa
612187160Sthompsa	atmegadci_standard_done(xfer);
613187160Sthompsa	return (0);			/* complete */
614187160Sthompsa}
615187160Sthompsa
616187160Sthompsastatic void
617187160Sthompsaatmegadci_interrupt_poll(struct atmegadci_softc *sc)
618187160Sthompsa{
619192984Sthompsa	struct usb_xfer *xfer;
620187160Sthompsa
621187160Sthompsarepeat:
622187160Sthompsa	TAILQ_FOREACH(xfer, &sc->sc_bus.intr_q.head, wait_entry) {
623187160Sthompsa		if (!atmegadci_xfer_do_fifo(xfer)) {
624187160Sthompsa			/* queue has been modified */
625187160Sthompsa			goto repeat;
626187160Sthompsa		}
627187160Sthompsa	}
628187160Sthompsa}
629187160Sthompsa
630187160Sthompsastatic void
631187160Sthompsaatmegadci_vbus_interrupt(struct atmegadci_softc *sc, uint8_t is_on)
632187160Sthompsa{
633187160Sthompsa	DPRINTFN(5, "vbus = %u\n", is_on);
634187160Sthompsa
635187160Sthompsa	if (is_on) {
636187160Sthompsa		if (!sc->sc_flags.status_vbus) {
637187160Sthompsa			sc->sc_flags.status_vbus = 1;
638187160Sthompsa
639187160Sthompsa			/* complete root HUB interrupt endpoint */
640187160Sthompsa
641190735Sthompsa			atmegadci_root_intr(sc);
642187160Sthompsa		}
643187160Sthompsa	} else {
644187160Sthompsa		if (sc->sc_flags.status_vbus) {
645187160Sthompsa			sc->sc_flags.status_vbus = 0;
646187160Sthompsa			sc->sc_flags.status_bus_reset = 0;
647187160Sthompsa			sc->sc_flags.status_suspend = 0;
648187160Sthompsa			sc->sc_flags.change_suspend = 0;
649187160Sthompsa			sc->sc_flags.change_connect = 1;
650187160Sthompsa
651187160Sthompsa			/* complete root HUB interrupt endpoint */
652187160Sthompsa
653190735Sthompsa			atmegadci_root_intr(sc);
654187160Sthompsa		}
655187160Sthompsa	}
656187160Sthompsa}
657187160Sthompsa
658187160Sthompsavoid
659187160Sthompsaatmegadci_interrupt(struct atmegadci_softc *sc)
660187160Sthompsa{
661187160Sthompsa	uint8_t status;
662187160Sthompsa
663187160Sthompsa	USB_BUS_LOCK(&sc->sc_bus);
664187160Sthompsa
665187160Sthompsa	/* read interrupt status */
666187160Sthompsa	status = ATMEGA_READ_1(sc, ATMEGA_UDINT);
667187160Sthompsa
668187160Sthompsa	/* clear all set interrupts */
669190720Sthompsa	ATMEGA_WRITE_1(sc, ATMEGA_UDINT, (~status) & 0x7D);
670187160Sthompsa
671189677Sthompsa	DPRINTFN(14, "UDINT=0x%02x\n", status);
672189677Sthompsa
673187160Sthompsa	/* check for any bus state change interrupts */
674187160Sthompsa	if (status & ATMEGA_UDINT_EORSTI) {
675187160Sthompsa
676187160Sthompsa		DPRINTFN(5, "end of reset\n");
677187160Sthompsa
678187160Sthompsa		/* set correct state */
679187160Sthompsa		sc->sc_flags.status_bus_reset = 1;
680187160Sthompsa		sc->sc_flags.status_suspend = 0;
681187160Sthompsa		sc->sc_flags.change_suspend = 0;
682187160Sthompsa		sc->sc_flags.change_connect = 1;
683187160Sthompsa
684187160Sthompsa		/* disable resume interrupt */
685187160Sthompsa		ATMEGA_WRITE_1(sc, ATMEGA_UDIEN,
686187160Sthompsa		    ATMEGA_UDINT_SUSPE |
687187160Sthompsa		    ATMEGA_UDINT_EORSTE);
688187160Sthompsa
689187160Sthompsa		/* complete root HUB interrupt endpoint */
690190735Sthompsa		atmegadci_root_intr(sc);
691187160Sthompsa	}
692187160Sthompsa	/*
693187160Sthompsa	 * If resume and suspend is set at the same time we interpret
694187160Sthompsa	 * that like RESUME. Resume is set when there is at least 3
695187160Sthompsa	 * milliseconds of inactivity on the USB BUS.
696187160Sthompsa	 */
697192446Sthompsa	if (status & ATMEGA_UDINT_WAKEUPI) {
698187160Sthompsa
699187160Sthompsa		DPRINTFN(5, "resume interrupt\n");
700187160Sthompsa
701187160Sthompsa		if (sc->sc_flags.status_suspend) {
702187160Sthompsa			/* update status bits */
703187160Sthompsa			sc->sc_flags.status_suspend = 0;
704187160Sthompsa			sc->sc_flags.change_suspend = 1;
705187160Sthompsa
706187160Sthompsa			/* disable resume interrupt */
707187160Sthompsa			ATMEGA_WRITE_1(sc, ATMEGA_UDIEN,
708187160Sthompsa			    ATMEGA_UDINT_SUSPE |
709187160Sthompsa			    ATMEGA_UDINT_EORSTE);
710187160Sthompsa
711187160Sthompsa			/* complete root HUB interrupt endpoint */
712190735Sthompsa			atmegadci_root_intr(sc);
713187160Sthompsa		}
714187160Sthompsa	} else if (status & ATMEGA_UDINT_SUSPI) {
715187160Sthompsa
716187160Sthompsa		DPRINTFN(5, "suspend interrupt\n");
717187160Sthompsa
718187160Sthompsa		if (!sc->sc_flags.status_suspend) {
719187160Sthompsa			/* update status bits */
720187160Sthompsa			sc->sc_flags.status_suspend = 1;
721187160Sthompsa			sc->sc_flags.change_suspend = 1;
722187160Sthompsa
723187160Sthompsa			/* disable suspend interrupt */
724187160Sthompsa			ATMEGA_WRITE_1(sc, ATMEGA_UDIEN,
725192446Sthompsa			    ATMEGA_UDINT_WAKEUPE |
726187160Sthompsa			    ATMEGA_UDINT_EORSTE);
727187160Sthompsa
728187160Sthompsa			/* complete root HUB interrupt endpoint */
729190735Sthompsa			atmegadci_root_intr(sc);
730187160Sthompsa		}
731187160Sthompsa	}
732187160Sthompsa	/* check VBUS */
733187160Sthompsa	status = ATMEGA_READ_1(sc, ATMEGA_USBINT);
734187160Sthompsa
735187160Sthompsa	/* clear all set interrupts */
736190720Sthompsa	ATMEGA_WRITE_1(sc, ATMEGA_USBINT, (~status) & 0x03);
737187160Sthompsa
738187160Sthompsa	if (status & ATMEGA_USBINT_VBUSTI) {
739187160Sthompsa		uint8_t temp;
740187160Sthompsa
741189677Sthompsa		DPRINTFN(5, "USBINT=0x%02x\n", status);
742189677Sthompsa
743187160Sthompsa		temp = ATMEGA_READ_1(sc, ATMEGA_USBSTA);
744187160Sthompsa		atmegadci_vbus_interrupt(sc, temp & ATMEGA_USBSTA_VBUS);
745187160Sthompsa	}
746187160Sthompsa	/* check for any endpoint interrupts */
747187160Sthompsa	status = ATMEGA_READ_1(sc, ATMEGA_UEINT);
748190720Sthompsa	/* the hardware will clear the UEINT bits automatically */
749187160Sthompsa	if (status) {
750187160Sthompsa
751189677Sthompsa		DPRINTFN(5, "real endpoint interrupt UEINT=0x%02x\n", status);
752187160Sthompsa
753187160Sthompsa		atmegadci_interrupt_poll(sc);
754187160Sthompsa	}
755187160Sthompsa	USB_BUS_UNLOCK(&sc->sc_bus);
756187160Sthompsa}
757187160Sthompsa
758187160Sthompsastatic void
759187160Sthompsaatmegadci_setup_standard_chain_sub(struct atmegadci_std_temp *temp)
760187160Sthompsa{
761187160Sthompsa	struct atmegadci_td *td;
762187160Sthompsa
763187160Sthompsa	/* get current Transfer Descriptor */
764187160Sthompsa	td = temp->td_next;
765187160Sthompsa	temp->td = td;
766187160Sthompsa
767187160Sthompsa	/* prepare for next TD */
768187160Sthompsa	temp->td_next = td->obj_next;
769187160Sthompsa
770187160Sthompsa	/* fill out the Transfer Descriptor */
771187160Sthompsa	td->func = temp->func;
772187160Sthompsa	td->pc = temp->pc;
773187160Sthompsa	td->offset = temp->offset;
774187160Sthompsa	td->remainder = temp->len;
775187160Sthompsa	td->error = 0;
776192552Sthompsa	td->did_stall = temp->did_stall;
777187160Sthompsa	td->short_pkt = temp->short_pkt;
778187160Sthompsa	td->alt_next = temp->setup_alt_next;
779187160Sthompsa}
780187160Sthompsa
781187160Sthompsastatic void
782192984Sthompsaatmegadci_setup_standard_chain(struct usb_xfer *xfer)
783187160Sthompsa{
784187160Sthompsa	struct atmegadci_std_temp temp;
785187160Sthompsa	struct atmegadci_softc *sc;
786187160Sthompsa	struct atmegadci_td *td;
787187160Sthompsa	uint32_t x;
788187160Sthompsa	uint8_t ep_no;
789187160Sthompsa	uint8_t need_sync;
790187160Sthompsa
791187160Sthompsa	DPRINTFN(9, "addr=%d endpt=%d sumlen=%d speed=%d\n",
792193644Sthompsa	    xfer->address, UE_GET_ADDR(xfer->endpointno),
793194228Sthompsa	    xfer->sumlen, usbd_get_speed(xfer->xroot->udev));
794187160Sthompsa
795187160Sthompsa	temp.max_frame_size = xfer->max_frame_size;
796187160Sthompsa
797187160Sthompsa	td = xfer->td_start[0];
798187160Sthompsa	xfer->td_transfer_first = td;
799187160Sthompsa	xfer->td_transfer_cache = td;
800187160Sthompsa
801187160Sthompsa	/* setup temp */
802187160Sthompsa
803199673Sthompsa	temp.pc = NULL;
804187160Sthompsa	temp.td = NULL;
805187160Sthompsa	temp.td_next = xfer->td_start[0];
806190183Sthompsa	temp.offset = 0;
807187160Sthompsa	temp.setup_alt_next = xfer->flags_int.short_frames_ok;
808192552Sthompsa	temp.did_stall = !xfer->flags_int.control_stall;
809187160Sthompsa
810187160Sthompsa	sc = ATMEGA_BUS2SC(xfer->xroot->bus);
811193644Sthompsa	ep_no = (xfer->endpointno & UE_ADDR);
812187160Sthompsa
813187160Sthompsa	/* check if we should prepend a setup message */
814187160Sthompsa
815187160Sthompsa	if (xfer->flags_int.control_xfr) {
816187160Sthompsa		if (xfer->flags_int.control_hdr) {
817187160Sthompsa
818187160Sthompsa			temp.func = &atmegadci_setup_rx;
819187160Sthompsa			temp.len = xfer->frlengths[0];
820187160Sthompsa			temp.pc = xfer->frbuffers + 0;
821187160Sthompsa			temp.short_pkt = temp.len ? 1 : 0;
822190183Sthompsa			/* check for last frame */
823190183Sthompsa			if (xfer->nframes == 1) {
824190183Sthompsa				/* no STATUS stage yet, SETUP is last */
825190183Sthompsa				if (xfer->flags_int.control_act)
826190183Sthompsa					temp.setup_alt_next = 0;
827190183Sthompsa			}
828187160Sthompsa
829187160Sthompsa			atmegadci_setup_standard_chain_sub(&temp);
830187160Sthompsa		}
831187160Sthompsa		x = 1;
832187160Sthompsa	} else {
833187160Sthompsa		x = 0;
834187160Sthompsa	}
835187160Sthompsa
836187160Sthompsa	if (x != xfer->nframes) {
837193644Sthompsa		if (xfer->endpointno & UE_DIR_IN) {
838187160Sthompsa			temp.func = &atmegadci_data_tx;
839187160Sthompsa			need_sync = 1;
840187160Sthompsa		} else {
841187160Sthompsa			temp.func = &atmegadci_data_rx;
842187160Sthompsa			need_sync = 0;
843187160Sthompsa		}
844187160Sthompsa
845187160Sthompsa		/* setup "pc" pointer */
846187160Sthompsa		temp.pc = xfer->frbuffers + x;
847187160Sthompsa	} else {
848187160Sthompsa		need_sync = 0;
849187160Sthompsa	}
850187160Sthompsa	while (x != xfer->nframes) {
851187160Sthompsa
852187160Sthompsa		/* DATA0 / DATA1 message */
853187160Sthompsa
854187160Sthompsa		temp.len = xfer->frlengths[x];
855187160Sthompsa
856187160Sthompsa		x++;
857187160Sthompsa
858187160Sthompsa		if (x == xfer->nframes) {
859190183Sthompsa			if (xfer->flags_int.control_xfr) {
860190183Sthompsa				if (xfer->flags_int.control_act) {
861190183Sthompsa					temp.setup_alt_next = 0;
862190183Sthompsa				}
863190183Sthompsa			} else {
864190183Sthompsa				temp.setup_alt_next = 0;
865190183Sthompsa			}
866187160Sthompsa		}
867187160Sthompsa		if (temp.len == 0) {
868187160Sthompsa
869187160Sthompsa			/* make sure that we send an USB packet */
870187160Sthompsa
871187160Sthompsa			temp.short_pkt = 0;
872187160Sthompsa
873187160Sthompsa		} else {
874187160Sthompsa
875187160Sthompsa			/* regular data transfer */
876187160Sthompsa
877187160Sthompsa			temp.short_pkt = (xfer->flags.force_short_xfer) ? 0 : 1;
878187160Sthompsa		}
879187160Sthompsa
880187160Sthompsa		atmegadci_setup_standard_chain_sub(&temp);
881187160Sthompsa
882187160Sthompsa		if (xfer->flags_int.isochronous_xfr) {
883187160Sthompsa			temp.offset += temp.len;
884187160Sthompsa		} else {
885187160Sthompsa			/* get next Page Cache pointer */
886187160Sthompsa			temp.pc = xfer->frbuffers + x;
887187160Sthompsa		}
888187160Sthompsa	}
889187160Sthompsa
890190183Sthompsa	if (xfer->flags_int.control_xfr) {
891187160Sthompsa
892190183Sthompsa		/* always setup a valid "pc" pointer for status and sync */
893190183Sthompsa		temp.pc = xfer->frbuffers + 0;
894187160Sthompsa		temp.len = 0;
895187160Sthompsa		temp.short_pkt = 0;
896190183Sthompsa		temp.setup_alt_next = 0;
897187160Sthompsa
898190183Sthompsa		/* check if we need to sync */
899187160Sthompsa		if (need_sync) {
900187160Sthompsa			/* we need a SYNC point after TX */
901187160Sthompsa			temp.func = &atmegadci_data_tx_sync;
902190183Sthompsa			atmegadci_setup_standard_chain_sub(&temp);
903190183Sthompsa		}
904187160Sthompsa
905190183Sthompsa		/* check if we should append a status stage */
906190183Sthompsa		if (!xfer->flags_int.control_act) {
907190183Sthompsa
908190183Sthompsa			/*
909190183Sthompsa			 * Send a DATA1 message and invert the current
910190183Sthompsa			 * endpoint direction.
911190183Sthompsa			 */
912193644Sthompsa			if (xfer->endpointno & UE_DIR_IN) {
913190183Sthompsa				temp.func = &atmegadci_data_rx;
914190183Sthompsa				need_sync = 0;
915190183Sthompsa			} else {
916190183Sthompsa				temp.func = &atmegadci_data_tx;
917190183Sthompsa				need_sync = 1;
918190183Sthompsa			}
919190183Sthompsa
920187160Sthompsa			atmegadci_setup_standard_chain_sub(&temp);
921190183Sthompsa			if (need_sync) {
922190183Sthompsa				/* we need a SYNC point after TX */
923190183Sthompsa				temp.func = &atmegadci_data_tx_sync;
924190183Sthompsa				atmegadci_setup_standard_chain_sub(&temp);
925190183Sthompsa			}
926187160Sthompsa		}
927187160Sthompsa	}
928187160Sthompsa	/* must have at least one frame! */
929187160Sthompsa	td = temp.td;
930187160Sthompsa	xfer->td_transfer_last = td;
931187160Sthompsa}
932187160Sthompsa
933187160Sthompsastatic void
934187160Sthompsaatmegadci_timeout(void *arg)
935187160Sthompsa{
936192984Sthompsa	struct usb_xfer *xfer = arg;
937187160Sthompsa
938187160Sthompsa	DPRINTF("xfer=%p\n", xfer);
939187160Sthompsa
940187160Sthompsa	USB_BUS_LOCK_ASSERT(xfer->xroot->bus, MA_OWNED);
941187160Sthompsa
942187160Sthompsa	/* transfer is transferred */
943187160Sthompsa	atmegadci_device_done(xfer, USB_ERR_TIMEOUT);
944187160Sthompsa}
945187160Sthompsa
946187160Sthompsastatic void
947192984Sthompsaatmegadci_start_standard_chain(struct usb_xfer *xfer)
948187160Sthompsa{
949187160Sthompsa	DPRINTFN(9, "\n");
950187160Sthompsa
951187160Sthompsa	/* poll one time - will turn on interrupts */
952187160Sthompsa	if (atmegadci_xfer_do_fifo(xfer)) {
953187160Sthompsa
954187160Sthompsa		/* put transfer on interrupt queue */
955194228Sthompsa		usbd_transfer_enqueue(&xfer->xroot->bus->intr_q, xfer);
956187160Sthompsa
957187160Sthompsa		/* start timeout, if any */
958187160Sthompsa		if (xfer->timeout != 0) {
959194228Sthompsa			usbd_transfer_timeout_ms(xfer,
960187160Sthompsa			    &atmegadci_timeout, xfer->timeout);
961187160Sthompsa		}
962187160Sthompsa	}
963187160Sthompsa}
964187160Sthompsa
965187160Sthompsastatic void
966190735Sthompsaatmegadci_root_intr(struct atmegadci_softc *sc)
967187160Sthompsa{
968187160Sthompsa	DPRINTFN(9, "\n");
969187160Sthompsa
970187160Sthompsa	USB_BUS_LOCK_ASSERT(&sc->sc_bus, MA_OWNED);
971187160Sthompsa
972187160Sthompsa	/* set port bit */
973187160Sthompsa	sc->sc_hub_idata[0] = 0x02;	/* we only have one port */
974187160Sthompsa
975190735Sthompsa	uhub_root_intr(&sc->sc_bus, sc->sc_hub_idata,
976190735Sthompsa	    sizeof(sc->sc_hub_idata));
977190735Sthompsa }
978187160Sthompsa
979193045Sthompsastatic usb_error_t
980192984Sthompsaatmegadci_standard_done_sub(struct usb_xfer *xfer)
981187160Sthompsa{
982187160Sthompsa	struct atmegadci_td *td;
983187160Sthompsa	uint32_t len;
984187160Sthompsa	uint8_t error;
985187160Sthompsa
986187160Sthompsa	DPRINTFN(9, "\n");
987187160Sthompsa
988187160Sthompsa	td = xfer->td_transfer_cache;
989187160Sthompsa
990187160Sthompsa	do {
991187160Sthompsa		len = td->remainder;
992187160Sthompsa
993187160Sthompsa		if (xfer->aframes != xfer->nframes) {
994187160Sthompsa			/*
995187160Sthompsa		         * Verify the length and subtract
996187160Sthompsa		         * the remainder from "frlengths[]":
997187160Sthompsa		         */
998187160Sthompsa			if (len > xfer->frlengths[xfer->aframes]) {
999187160Sthompsa				td->error = 1;
1000187160Sthompsa			} else {
1001187160Sthompsa				xfer->frlengths[xfer->aframes] -= len;
1002187160Sthompsa			}
1003187160Sthompsa		}
1004187160Sthompsa		/* Check for transfer error */
1005187160Sthompsa		if (td->error) {
1006187160Sthompsa			/* the transfer is finished */
1007187160Sthompsa			error = 1;
1008187160Sthompsa			td = NULL;
1009187160Sthompsa			break;
1010187160Sthompsa		}
1011187160Sthompsa		/* Check for short transfer */
1012187160Sthompsa		if (len > 0) {
1013187160Sthompsa			if (xfer->flags_int.short_frames_ok) {
1014187160Sthompsa				/* follow alt next */
1015187160Sthompsa				if (td->alt_next) {
1016187160Sthompsa					td = td->obj_next;
1017187160Sthompsa				} else {
1018187160Sthompsa					td = NULL;
1019187160Sthompsa				}
1020187160Sthompsa			} else {
1021187160Sthompsa				/* the transfer is finished */
1022187160Sthompsa				td = NULL;
1023187160Sthompsa			}
1024187160Sthompsa			error = 0;
1025187160Sthompsa			break;
1026187160Sthompsa		}
1027187160Sthompsa		td = td->obj_next;
1028187160Sthompsa
1029187160Sthompsa		/* this USB frame is complete */
1030187160Sthompsa		error = 0;
1031187160Sthompsa		break;
1032187160Sthompsa
1033187160Sthompsa	} while (0);
1034187160Sthompsa
1035187160Sthompsa	/* update transfer cache */
1036187160Sthompsa
1037187160Sthompsa	xfer->td_transfer_cache = td;
1038187160Sthompsa
1039187160Sthompsa	return (error ?
1040187160Sthompsa	    USB_ERR_STALLED : USB_ERR_NORMAL_COMPLETION);
1041187160Sthompsa}
1042187160Sthompsa
1043187160Sthompsastatic void
1044192984Sthompsaatmegadci_standard_done(struct usb_xfer *xfer)
1045187160Sthompsa{
1046193045Sthompsa	usb_error_t err = 0;
1047187160Sthompsa
1048193644Sthompsa	DPRINTFN(13, "xfer=%p endpoint=%p transfer done\n",
1049193644Sthompsa	    xfer, xfer->endpoint);
1050187160Sthompsa
1051187160Sthompsa	/* reset scanner */
1052187160Sthompsa
1053187160Sthompsa	xfer->td_transfer_cache = xfer->td_transfer_first;
1054187160Sthompsa
1055187160Sthompsa	if (xfer->flags_int.control_xfr) {
1056187160Sthompsa
1057187160Sthompsa		if (xfer->flags_int.control_hdr) {
1058187160Sthompsa
1059187160Sthompsa			err = atmegadci_standard_done_sub(xfer);
1060187160Sthompsa		}
1061187160Sthompsa		xfer->aframes = 1;
1062187160Sthompsa
1063187160Sthompsa		if (xfer->td_transfer_cache == NULL) {
1064187160Sthompsa			goto done;
1065187160Sthompsa		}
1066187160Sthompsa	}
1067187160Sthompsa	while (xfer->aframes != xfer->nframes) {
1068187160Sthompsa
1069187160Sthompsa		err = atmegadci_standard_done_sub(xfer);
1070187160Sthompsa		xfer->aframes++;
1071187160Sthompsa
1072187160Sthompsa		if (xfer->td_transfer_cache == NULL) {
1073187160Sthompsa			goto done;
1074187160Sthompsa		}
1075187160Sthompsa	}
1076187160Sthompsa
1077187160Sthompsa	if (xfer->flags_int.control_xfr &&
1078187160Sthompsa	    !xfer->flags_int.control_act) {
1079187160Sthompsa
1080187160Sthompsa		err = atmegadci_standard_done_sub(xfer);
1081187160Sthompsa	}
1082187160Sthompsadone:
1083187160Sthompsa	atmegadci_device_done(xfer, err);
1084187160Sthompsa}
1085187160Sthompsa
1086187160Sthompsa/*------------------------------------------------------------------------*
1087187160Sthompsa *	atmegadci_device_done
1088187160Sthompsa *
1089187160Sthompsa * NOTE: this function can be called more than one time on the
1090187160Sthompsa * same USB transfer!
1091187160Sthompsa *------------------------------------------------------------------------*/
1092187160Sthompsastatic void
1093193045Sthompsaatmegadci_device_done(struct usb_xfer *xfer, usb_error_t error)
1094187160Sthompsa{
1095187160Sthompsa	struct atmegadci_softc *sc = ATMEGA_BUS2SC(xfer->xroot->bus);
1096187160Sthompsa	uint8_t ep_no;
1097187160Sthompsa
1098187160Sthompsa	USB_BUS_LOCK_ASSERT(&sc->sc_bus, MA_OWNED);
1099187160Sthompsa
1100193644Sthompsa	DPRINTFN(9, "xfer=%p, endpoint=%p, error=%d\n",
1101193644Sthompsa	    xfer, xfer->endpoint, error);
1102187160Sthompsa
1103192499Sthompsa	if (xfer->flags_int.usb_mode == USB_MODE_DEVICE) {
1104193644Sthompsa		ep_no = (xfer->endpointno & UE_ADDR);
1105187160Sthompsa
1106187160Sthompsa		/* select endpoint number */
1107187160Sthompsa		ATMEGA_WRITE_1(sc, ATMEGA_UENUM, ep_no);
1108187160Sthompsa
1109187160Sthompsa		/* disable endpoint interrupt */
1110187160Sthompsa		ATMEGA_WRITE_1(sc, ATMEGA_UEIENX, 0);
1111187160Sthompsa
1112187160Sthompsa		DPRINTFN(15, "disabled interrupts!\n");
1113187160Sthompsa	}
1114187160Sthompsa	/* dequeue transfer and start next transfer */
1115194228Sthompsa	usbd_transfer_done(xfer, error);
1116187160Sthompsa}
1117187160Sthompsa
1118187160Sthompsastatic void
1119239214Shselaskyatmegadci_xfer_stall(struct usb_xfer *xfer)
1120239214Shselasky{
1121239214Shselasky	atmegadci_device_done(xfer, USB_ERR_STALLED);
1122239214Shselasky}
1123239214Shselasky
1124239214Shselaskystatic void
1125239214Shselaskyatmegadci_set_stall(struct usb_device *udev,
1126195121Sthompsa    struct usb_endpoint *ep, uint8_t *did_stall)
1127187160Sthompsa{
1128187160Sthompsa	struct atmegadci_softc *sc;
1129187160Sthompsa	uint8_t ep_no;
1130187160Sthompsa
1131187160Sthompsa	USB_BUS_LOCK_ASSERT(udev->bus, MA_OWNED);
1132187160Sthompsa
1133193644Sthompsa	DPRINTFN(5, "endpoint=%p\n", ep);
1134187160Sthompsa
1135187160Sthompsa	sc = ATMEGA_BUS2SC(udev->bus);
1136187160Sthompsa	/* get endpoint number */
1137193644Sthompsa	ep_no = (ep->edesc->bEndpointAddress & UE_ADDR);
1138187160Sthompsa	/* select endpoint number */
1139187160Sthompsa	ATMEGA_WRITE_1(sc, ATMEGA_UENUM, ep_no);
1140187160Sthompsa	/* set stall */
1141187160Sthompsa	ATMEGA_WRITE_1(sc, ATMEGA_UECONX,
1142187160Sthompsa	    ATMEGA_UECONX_EPEN |
1143187160Sthompsa	    ATMEGA_UECONX_STALLRQ);
1144187160Sthompsa}
1145187160Sthompsa
1146187160Sthompsastatic void
1147187160Sthompsaatmegadci_clear_stall_sub(struct atmegadci_softc *sc, uint8_t ep_no,
1148187160Sthompsa    uint8_t ep_type, uint8_t ep_dir)
1149187160Sthompsa{
1150187160Sthompsa	uint8_t temp;
1151187160Sthompsa
1152187160Sthompsa	if (ep_type == UE_CONTROL) {
1153187160Sthompsa		/* clearing stall is not needed */
1154187160Sthompsa		return;
1155187160Sthompsa	}
1156187160Sthompsa	/* select endpoint number */
1157187160Sthompsa	ATMEGA_WRITE_1(sc, ATMEGA_UENUM, ep_no);
1158187160Sthompsa
1159187160Sthompsa	/* set endpoint reset */
1160187160Sthompsa	ATMEGA_WRITE_1(sc, ATMEGA_UERST, ATMEGA_UERST_MASK(ep_no));
1161187160Sthompsa
1162187160Sthompsa	/* clear endpoint reset */
1163187160Sthompsa	ATMEGA_WRITE_1(sc, ATMEGA_UERST, 0);
1164187160Sthompsa
1165187160Sthompsa	/* set stall */
1166187160Sthompsa	ATMEGA_WRITE_1(sc, ATMEGA_UECONX,
1167187160Sthompsa	    ATMEGA_UECONX_EPEN |
1168187160Sthompsa	    ATMEGA_UECONX_STALLRQ);
1169187160Sthompsa
1170187160Sthompsa	/* reset data toggle */
1171187160Sthompsa	ATMEGA_WRITE_1(sc, ATMEGA_UECONX,
1172187160Sthompsa	    ATMEGA_UECONX_EPEN |
1173187160Sthompsa	    ATMEGA_UECONX_RSTDT);
1174187160Sthompsa
1175187160Sthompsa	/* clear stall */
1176187160Sthompsa	ATMEGA_WRITE_1(sc, ATMEGA_UECONX,
1177187160Sthompsa	    ATMEGA_UECONX_EPEN |
1178187160Sthompsa	    ATMEGA_UECONX_STALLRQC);
1179187160Sthompsa
1180189677Sthompsa	do {
1181187160Sthompsa		if (ep_type == UE_BULK) {
1182192446Sthompsa			temp = ATMEGA_UECFG0X_EPTYPE2;
1183187160Sthompsa		} else if (ep_type == UE_INTERRUPT) {
1184192446Sthompsa			temp = ATMEGA_UECFG0X_EPTYPE3;
1185187160Sthompsa		} else {
1186192446Sthompsa			temp = ATMEGA_UECFG0X_EPTYPE1;
1187187160Sthompsa		}
1188187160Sthompsa		if (ep_dir & UE_DIR_IN) {
1189187160Sthompsa			temp |= ATMEGA_UECFG0X_EPDIR;
1190187160Sthompsa		}
1191187160Sthompsa		/* two banks, 64-bytes wMaxPacket */
1192187160Sthompsa		ATMEGA_WRITE_1(sc, ATMEGA_UECFG0X, temp);
1193187160Sthompsa		ATMEGA_WRITE_1(sc, ATMEGA_UECFG1X,
1194187160Sthompsa		    ATMEGA_UECFG1X_ALLOC |
1195191401Sthompsa		    ATMEGA_UECFG1X_EPBK0 |	/* one bank */
1196189677Sthompsa		    ATMEGA_UECFG1X_EPSIZE(3));
1197187160Sthompsa
1198187160Sthompsa		temp = ATMEGA_READ_1(sc, ATMEGA_UESTA0X);
1199187160Sthompsa		if (!(temp & ATMEGA_UESTA0X_CFGOK)) {
1200199816Sthompsa			device_printf(sc->sc_bus.bdev,
1201199816Sthompsa			    "Chip rejected configuration\n");
1202187160Sthompsa		}
1203189677Sthompsa	} while (0);
1204187160Sthompsa}
1205187160Sthompsa
1206187160Sthompsastatic void
1207193644Sthompsaatmegadci_clear_stall(struct usb_device *udev, struct usb_endpoint *ep)
1208187160Sthompsa{
1209187160Sthompsa	struct atmegadci_softc *sc;
1210192984Sthompsa	struct usb_endpoint_descriptor *ed;
1211187160Sthompsa
1212193644Sthompsa	DPRINTFN(5, "endpoint=%p\n", ep);
1213187160Sthompsa
1214187160Sthompsa	USB_BUS_LOCK_ASSERT(udev->bus, MA_OWNED);
1215187160Sthompsa
1216187160Sthompsa	/* check mode */
1217192499Sthompsa	if (udev->flags.usb_mode != USB_MODE_DEVICE) {
1218187160Sthompsa		/* not supported */
1219187160Sthompsa		return;
1220187160Sthompsa	}
1221187160Sthompsa	/* get softc */
1222187160Sthompsa	sc = ATMEGA_BUS2SC(udev->bus);
1223187160Sthompsa
1224187160Sthompsa	/* get endpoint descriptor */
1225193644Sthompsa	ed = ep->edesc;
1226187160Sthompsa
1227187160Sthompsa	/* reset endpoint */
1228187160Sthompsa	atmegadci_clear_stall_sub(sc,
1229187160Sthompsa	    (ed->bEndpointAddress & UE_ADDR),
1230187160Sthompsa	    (ed->bmAttributes & UE_XFERTYPE),
1231187160Sthompsa	    (ed->bEndpointAddress & (UE_DIR_IN | UE_DIR_OUT)));
1232187160Sthompsa}
1233187160Sthompsa
1234193045Sthompsausb_error_t
1235187160Sthompsaatmegadci_init(struct atmegadci_softc *sc)
1236187160Sthompsa{
1237187160Sthompsa	uint8_t n;
1238187160Sthompsa
1239187160Sthompsa	DPRINTF("start\n");
1240187160Sthompsa
1241187160Sthompsa	/* set up the bus structure */
1242187160Sthompsa	sc->sc_bus.usbrev = USB_REV_1_1;
1243187160Sthompsa	sc->sc_bus.methods = &atmegadci_bus_methods;
1244187160Sthompsa
1245187160Sthompsa	USB_BUS_LOCK(&sc->sc_bus);
1246187160Sthompsa
1247192446Sthompsa	/* make sure USB is enabled */
1248192446Sthompsa	ATMEGA_WRITE_1(sc, ATMEGA_USBCON,
1249192446Sthompsa	    ATMEGA_USBCON_USBE |
1250192446Sthompsa	    ATMEGA_USBCON_FRZCLK);
1251192446Sthompsa
1252187160Sthompsa	/* enable USB PAD regulator */
1253187160Sthompsa	ATMEGA_WRITE_1(sc, ATMEGA_UHWCON,
1254192446Sthompsa	    ATMEGA_UHWCON_UVREGE |
1255192446Sthompsa	    ATMEGA_UHWCON_UIMOD);
1256192446Sthompsa
1257192446Sthompsa	/* the following register sets up the USB PLL, assuming 16MHz X-tal */
1258192446Sthompsa	ATMEGA_WRITE_1(sc, 0x49 /* PLLCSR */, 0x14 | 0x02);
1259192446Sthompsa
1260192446Sthompsa	/* wait for PLL to lock */
1261192446Sthompsa	for (n = 0; n != 20; n++) {
1262192446Sthompsa		if (ATMEGA_READ_1(sc, 0x49) & 0x01)
1263192446Sthompsa			break;
1264192446Sthompsa		/* wait a little bit for PLL to start */
1265194228Sthompsa		usb_pause_mtx(&sc->sc_bus.bus_mtx, hz / 100);
1266192446Sthompsa	}
1267192446Sthompsa
1268190720Sthompsa	/* make sure USB is enabled */
1269190720Sthompsa	ATMEGA_WRITE_1(sc, ATMEGA_USBCON,
1270190720Sthompsa	    ATMEGA_USBCON_USBE |
1271190720Sthompsa	    ATMEGA_USBCON_OTGPADE |
1272190720Sthompsa	    ATMEGA_USBCON_VBUSTE);
1273190720Sthompsa
1274187160Sthompsa	/* turn on clocks */
1275187160Sthompsa	(sc->sc_clocks_on) (&sc->sc_bus);
1276187160Sthompsa
1277189677Sthompsa	/* make sure device is re-enumerated */
1278189677Sthompsa	ATMEGA_WRITE_1(sc, ATMEGA_UDCON, ATMEGA_UDCON_DETACH);
1279189677Sthompsa
1280187160Sthompsa	/* wait a little for things to stabilise */
1281194228Sthompsa	usb_pause_mtx(&sc->sc_bus.bus_mtx, hz / 20);
1282187160Sthompsa
1283187160Sthompsa	/* enable interrupts */
1284187160Sthompsa	ATMEGA_WRITE_1(sc, ATMEGA_UDIEN,
1285187160Sthompsa	    ATMEGA_UDINT_SUSPE |
1286187160Sthompsa	    ATMEGA_UDINT_EORSTE);
1287187160Sthompsa
1288187160Sthompsa	/* reset all endpoints */
1289187160Sthompsa	ATMEGA_WRITE_1(sc, ATMEGA_UERST,
1290187160Sthompsa	    (1 << ATMEGA_EP_MAX) - 1);
1291187160Sthompsa
1292187160Sthompsa	/* disable reset */
1293187160Sthompsa	ATMEGA_WRITE_1(sc, ATMEGA_UERST, 0);
1294187160Sthompsa
1295187160Sthompsa	/* disable all endpoints */
1296189677Sthompsa	for (n = 0; n != ATMEGA_EP_MAX; n++) {
1297187160Sthompsa
1298187160Sthompsa		/* select endpoint */
1299187160Sthompsa		ATMEGA_WRITE_1(sc, ATMEGA_UENUM, n);
1300187160Sthompsa
1301187160Sthompsa		/* disable endpoint interrupt */
1302187160Sthompsa		ATMEGA_WRITE_1(sc, ATMEGA_UEIENX, 0);
1303187160Sthompsa
1304187160Sthompsa		/* disable endpoint */
1305187160Sthompsa		ATMEGA_WRITE_1(sc, ATMEGA_UECONX, 0);
1306187160Sthompsa	}
1307187160Sthompsa
1308187160Sthompsa	/* turn off clocks */
1309187160Sthompsa
1310187160Sthompsa	atmegadci_clocks_off(sc);
1311187160Sthompsa
1312189677Sthompsa	/* read initial VBUS state */
1313189677Sthompsa
1314189677Sthompsa	n = ATMEGA_READ_1(sc, ATMEGA_USBSTA);
1315189677Sthompsa	atmegadci_vbus_interrupt(sc, n & ATMEGA_USBSTA_VBUS);
1316189677Sthompsa
1317187160Sthompsa	USB_BUS_UNLOCK(&sc->sc_bus);
1318187160Sthompsa
1319187160Sthompsa	/* catch any lost interrupts */
1320187160Sthompsa
1321187160Sthompsa	atmegadci_do_poll(&sc->sc_bus);
1322187160Sthompsa
1323187160Sthompsa	return (0);			/* success */
1324187160Sthompsa}
1325187160Sthompsa
1326187160Sthompsavoid
1327187160Sthompsaatmegadci_uninit(struct atmegadci_softc *sc)
1328187160Sthompsa{
1329187160Sthompsa	USB_BUS_LOCK(&sc->sc_bus);
1330187160Sthompsa
1331187160Sthompsa	/* turn on clocks */
1332187160Sthompsa	(sc->sc_clocks_on) (&sc->sc_bus);
1333187160Sthompsa
1334187160Sthompsa	/* disable interrupts */
1335187160Sthompsa	ATMEGA_WRITE_1(sc, ATMEGA_UDIEN, 0);
1336187160Sthompsa
1337187160Sthompsa	/* reset all endpoints */
1338187160Sthompsa	ATMEGA_WRITE_1(sc, ATMEGA_UERST,
1339187160Sthompsa	    (1 << ATMEGA_EP_MAX) - 1);
1340187160Sthompsa
1341187160Sthompsa	/* disable reset */
1342187160Sthompsa	ATMEGA_WRITE_1(sc, ATMEGA_UERST, 0);
1343187160Sthompsa
1344187160Sthompsa	sc->sc_flags.port_powered = 0;
1345187160Sthompsa	sc->sc_flags.status_vbus = 0;
1346187160Sthompsa	sc->sc_flags.status_bus_reset = 0;
1347187160Sthompsa	sc->sc_flags.status_suspend = 0;
1348187160Sthompsa	sc->sc_flags.change_suspend = 0;
1349187160Sthompsa	sc->sc_flags.change_connect = 1;
1350187160Sthompsa
1351187160Sthompsa	atmegadci_pull_down(sc);
1352187160Sthompsa	atmegadci_clocks_off(sc);
1353187160Sthompsa
1354187160Sthompsa	/* disable USB PAD regulator */
1355187160Sthompsa	ATMEGA_WRITE_1(sc, ATMEGA_UHWCON, 0);
1356187160Sthompsa
1357187160Sthompsa	USB_BUS_UNLOCK(&sc->sc_bus);
1358187160Sthompsa}
1359187160Sthompsa
1360228483Shselaskystatic void
1361187160Sthompsaatmegadci_suspend(struct atmegadci_softc *sc)
1362187160Sthompsa{
1363228483Shselasky	/* TODO */
1364187160Sthompsa}
1365187160Sthompsa
1366228483Shselaskystatic void
1367187160Sthompsaatmegadci_resume(struct atmegadci_softc *sc)
1368187160Sthompsa{
1369228483Shselasky	/* TODO */
1370187160Sthompsa}
1371187160Sthompsa
1372187160Sthompsastatic void
1373192984Sthompsaatmegadci_do_poll(struct usb_bus *bus)
1374187160Sthompsa{
1375187160Sthompsa	struct atmegadci_softc *sc = ATMEGA_BUS2SC(bus);
1376187160Sthompsa
1377187160Sthompsa	USB_BUS_LOCK(&sc->sc_bus);
1378187160Sthompsa	atmegadci_interrupt_poll(sc);
1379187160Sthompsa	USB_BUS_UNLOCK(&sc->sc_bus);
1380187160Sthompsa}
1381187160Sthompsa
1382187160Sthompsa/*------------------------------------------------------------------------*
1383187160Sthompsa * at91dci bulk support
1384187160Sthompsa * at91dci control support
1385187160Sthompsa * at91dci interrupt support
1386187160Sthompsa *------------------------------------------------------------------------*/
1387187160Sthompsastatic void
1388192984Sthompsaatmegadci_device_non_isoc_open(struct usb_xfer *xfer)
1389187160Sthompsa{
1390187160Sthompsa	return;
1391187160Sthompsa}
1392187160Sthompsa
1393187160Sthompsastatic void
1394192984Sthompsaatmegadci_device_non_isoc_close(struct usb_xfer *xfer)
1395187160Sthompsa{
1396187160Sthompsa	atmegadci_device_done(xfer, USB_ERR_CANCELLED);
1397187160Sthompsa}
1398187160Sthompsa
1399187160Sthompsastatic void
1400192984Sthompsaatmegadci_device_non_isoc_enter(struct usb_xfer *xfer)
1401187160Sthompsa{
1402187160Sthompsa	return;
1403187160Sthompsa}
1404187160Sthompsa
1405187160Sthompsastatic void
1406192984Sthompsaatmegadci_device_non_isoc_start(struct usb_xfer *xfer)
1407187160Sthompsa{
1408187160Sthompsa	/* setup TDs */
1409187160Sthompsa	atmegadci_setup_standard_chain(xfer);
1410187160Sthompsa	atmegadci_start_standard_chain(xfer);
1411187160Sthompsa}
1412187160Sthompsa
1413192984Sthompsastruct usb_pipe_methods atmegadci_device_non_isoc_methods =
1414187160Sthompsa{
1415190737Sthompsa	.open = atmegadci_device_non_isoc_open,
1416190737Sthompsa	.close = atmegadci_device_non_isoc_close,
1417190737Sthompsa	.enter = atmegadci_device_non_isoc_enter,
1418190737Sthompsa	.start = atmegadci_device_non_isoc_start,
1419187160Sthompsa};
1420187160Sthompsa
1421187160Sthompsa/*------------------------------------------------------------------------*
1422187160Sthompsa * at91dci full speed isochronous support
1423187160Sthompsa *------------------------------------------------------------------------*/
1424187160Sthompsastatic void
1425192984Sthompsaatmegadci_device_isoc_fs_open(struct usb_xfer *xfer)
1426187160Sthompsa{
1427187160Sthompsa	return;
1428187160Sthompsa}
1429187160Sthompsa
1430187160Sthompsastatic void
1431192984Sthompsaatmegadci_device_isoc_fs_close(struct usb_xfer *xfer)
1432187160Sthompsa{
1433187160Sthompsa	atmegadci_device_done(xfer, USB_ERR_CANCELLED);
1434187160Sthompsa}
1435187160Sthompsa
1436187160Sthompsastatic void
1437192984Sthompsaatmegadci_device_isoc_fs_enter(struct usb_xfer *xfer)
1438187160Sthompsa{
1439187160Sthompsa	struct atmegadci_softc *sc = ATMEGA_BUS2SC(xfer->xroot->bus);
1440187160Sthompsa	uint32_t temp;
1441187160Sthompsa	uint32_t nframes;
1442187160Sthompsa
1443187160Sthompsa	DPRINTFN(6, "xfer=%p next=%d nframes=%d\n",
1444193644Sthompsa	    xfer, xfer->endpoint->isoc_next, xfer->nframes);
1445187160Sthompsa
1446187160Sthompsa	/* get the current frame index */
1447187160Sthompsa
1448187160Sthompsa	nframes =
1449187160Sthompsa	    (ATMEGA_READ_1(sc, ATMEGA_UDFNUMH) << 8) |
1450187160Sthompsa	    (ATMEGA_READ_1(sc, ATMEGA_UDFNUML));
1451187160Sthompsa
1452187160Sthompsa	nframes &= ATMEGA_FRAME_MASK;
1453187160Sthompsa
1454187160Sthompsa	/*
1455187160Sthompsa	 * check if the frame index is within the window where the frames
1456187160Sthompsa	 * will be inserted
1457187160Sthompsa	 */
1458193644Sthompsa	temp = (nframes - xfer->endpoint->isoc_next) & ATMEGA_FRAME_MASK;
1459187160Sthompsa
1460193644Sthompsa	if ((xfer->endpoint->is_synced == 0) ||
1461187160Sthompsa	    (temp < xfer->nframes)) {
1462187160Sthompsa		/*
1463187160Sthompsa		 * If there is data underflow or the pipe queue is
1464187160Sthompsa		 * empty we schedule the transfer a few frames ahead
1465187160Sthompsa		 * of the current frame position. Else two isochronous
1466187160Sthompsa		 * transfers might overlap.
1467187160Sthompsa		 */
1468193644Sthompsa		xfer->endpoint->isoc_next = (nframes + 3) & ATMEGA_FRAME_MASK;
1469193644Sthompsa		xfer->endpoint->is_synced = 1;
1470193644Sthompsa		DPRINTFN(3, "start next=%d\n", xfer->endpoint->isoc_next);
1471187160Sthompsa	}
1472187160Sthompsa	/*
1473187160Sthompsa	 * compute how many milliseconds the insertion is ahead of the
1474187160Sthompsa	 * current frame position:
1475187160Sthompsa	 */
1476193644Sthompsa	temp = (xfer->endpoint->isoc_next - nframes) & ATMEGA_FRAME_MASK;
1477187160Sthompsa
1478187160Sthompsa	/*
1479187160Sthompsa	 * pre-compute when the isochronous transfer will be finished:
1480187160Sthompsa	 */
1481187160Sthompsa	xfer->isoc_time_complete =
1482194228Sthompsa	    usb_isoc_time_expand(&sc->sc_bus, nframes) + temp +
1483187160Sthompsa	    xfer->nframes;
1484187160Sthompsa
1485187160Sthompsa	/* compute frame number for next insertion */
1486193644Sthompsa	xfer->endpoint->isoc_next += xfer->nframes;
1487187160Sthompsa
1488187160Sthompsa	/* setup TDs */
1489187160Sthompsa	atmegadci_setup_standard_chain(xfer);
1490187160Sthompsa}
1491187160Sthompsa
1492187160Sthompsastatic void
1493192984Sthompsaatmegadci_device_isoc_fs_start(struct usb_xfer *xfer)
1494187160Sthompsa{
1495187160Sthompsa	/* start TD chain */
1496187160Sthompsa	atmegadci_start_standard_chain(xfer);
1497187160Sthompsa}
1498187160Sthompsa
1499192984Sthompsastruct usb_pipe_methods atmegadci_device_isoc_fs_methods =
1500187160Sthompsa{
1501187160Sthompsa	.open = atmegadci_device_isoc_fs_open,
1502187160Sthompsa	.close = atmegadci_device_isoc_fs_close,
1503187160Sthompsa	.enter = atmegadci_device_isoc_fs_enter,
1504187160Sthompsa	.start = atmegadci_device_isoc_fs_start,
1505187160Sthompsa};
1506187160Sthompsa
1507187160Sthompsa/*------------------------------------------------------------------------*
1508187160Sthompsa * at91dci root control support
1509187160Sthompsa *------------------------------------------------------------------------*
1510190735Sthompsa * Simulate a hardware HUB by handling all the necessary requests.
1511187160Sthompsa *------------------------------------------------------------------------*/
1512187160Sthompsa
1513192984Sthompsastatic const struct usb_device_descriptor atmegadci_devd = {
1514192984Sthompsa	.bLength = sizeof(struct usb_device_descriptor),
1515187160Sthompsa	.bDescriptorType = UDESC_DEVICE,
1516187160Sthompsa	.bcdUSB = {0x00, 0x02},
1517187160Sthompsa	.bDeviceClass = UDCLASS_HUB,
1518187160Sthompsa	.bDeviceSubClass = UDSUBCLASS_HUB,
1519213802Shselasky	.bDeviceProtocol = UDPROTO_FSHUB,
1520187160Sthompsa	.bMaxPacketSize = 64,
1521187160Sthompsa	.bcdDevice = {0x00, 0x01},
1522187160Sthompsa	.iManufacturer = 1,
1523187160Sthompsa	.iProduct = 2,
1524187160Sthompsa	.bNumConfigurations = 1,
1525187160Sthompsa};
1526187160Sthompsa
1527187160Sthompsastatic const struct atmegadci_config_desc atmegadci_confd = {
1528187160Sthompsa	.confd = {
1529192984Sthompsa		.bLength = sizeof(struct usb_config_descriptor),
1530187160Sthompsa		.bDescriptorType = UDESC_CONFIG,
1531187160Sthompsa		.wTotalLength[0] = sizeof(atmegadci_confd),
1532187160Sthompsa		.bNumInterface = 1,
1533187160Sthompsa		.bConfigurationValue = 1,
1534187160Sthompsa		.iConfiguration = 0,
1535187160Sthompsa		.bmAttributes = UC_SELF_POWERED,
1536187160Sthompsa		.bMaxPower = 0,
1537187160Sthompsa	},
1538187160Sthompsa	.ifcd = {
1539192984Sthompsa		.bLength = sizeof(struct usb_interface_descriptor),
1540187160Sthompsa		.bDescriptorType = UDESC_INTERFACE,
1541187160Sthompsa		.bNumEndpoints = 1,
1542187160Sthompsa		.bInterfaceClass = UICLASS_HUB,
1543187160Sthompsa		.bInterfaceSubClass = UISUBCLASS_HUB,
1544213802Shselasky		.bInterfaceProtocol = 0,
1545187160Sthompsa	},
1546187160Sthompsa	.endpd = {
1547192984Sthompsa		.bLength = sizeof(struct usb_endpoint_descriptor),
1548187160Sthompsa		.bDescriptorType = UDESC_ENDPOINT,
1549187160Sthompsa		.bEndpointAddress = (UE_DIR_IN | ATMEGA_INTR_ENDPT),
1550187160Sthompsa		.bmAttributes = UE_INTERRUPT,
1551187160Sthompsa		.wMaxPacketSize[0] = 8,
1552187160Sthompsa		.bInterval = 255,
1553187160Sthompsa	},
1554187160Sthompsa};
1555187160Sthompsa
1556233774Shselasky#define	HSETW(ptr, val) ptr = { (uint8_t)(val), (uint8_t)((val) >> 8) }
1557233774Shselasky
1558192984Sthompsastatic const struct usb_hub_descriptor_min atmegadci_hubd = {
1559187160Sthompsa	.bDescLength = sizeof(atmegadci_hubd),
1560187160Sthompsa	.bDescriptorType = UDESC_HUB,
1561187160Sthompsa	.bNbrPorts = 1,
1562233774Shselasky	HSETW(.wHubCharacteristics, (UHD_PWR_NO_SWITCH | UHD_OC_INDIVIDUAL)),
1563187160Sthompsa	.bPwrOn2PwrGood = 50,
1564187160Sthompsa	.bHubContrCurrent = 0,
1565187160Sthompsa	.DeviceRemovable = {0},		/* port is removable */
1566187160Sthompsa};
1567187160Sthompsa
1568187160Sthompsa#define	STRING_VENDOR \
1569246125Shselasky  "A\0T\0M\0E\0G\0A"
1570187160Sthompsa
1571187160Sthompsa#define	STRING_PRODUCT \
1572246125Shselasky  "D\0C\0I\0 \0R\0o\0o\0t\0 \0H\0U\0B"
1573187160Sthompsa
1574187160SthompsaUSB_MAKE_STRING_DESC(STRING_VENDOR, atmegadci_vendor);
1575187160SthompsaUSB_MAKE_STRING_DESC(STRING_PRODUCT, atmegadci_product);
1576187160Sthompsa
1577193045Sthompsastatic usb_error_t
1578192984Sthompsaatmegadci_roothub_exec(struct usb_device *udev,
1579192984Sthompsa    struct usb_device_request *req, const void **pptr, uint16_t *plength)
1580187160Sthompsa{
1581191402Sthompsa	struct atmegadci_softc *sc = ATMEGA_BUS2SC(udev->bus);
1582191402Sthompsa	const void *ptr;
1583191402Sthompsa	uint16_t len;
1584187160Sthompsa	uint16_t value;
1585187160Sthompsa	uint16_t index;
1586189677Sthompsa	uint8_t temp;
1587193045Sthompsa	usb_error_t err;
1588187160Sthompsa
1589187160Sthompsa	USB_BUS_LOCK_ASSERT(&sc->sc_bus, MA_OWNED);
1590187160Sthompsa
1591187160Sthompsa	/* buffer reset */
1592191402Sthompsa	ptr = (const void *)&sc->sc_hub_temp;
1593191402Sthompsa	len = 0;
1594191402Sthompsa	err = 0;
1595187160Sthompsa
1596191402Sthompsa	value = UGETW(req->wValue);
1597191402Sthompsa	index = UGETW(req->wIndex);
1598187160Sthompsa
1599187160Sthompsa	/* demultiplex the control request */
1600187160Sthompsa
1601191402Sthompsa	switch (req->bmRequestType) {
1602187160Sthompsa	case UT_READ_DEVICE:
1603191402Sthompsa		switch (req->bRequest) {
1604187160Sthompsa		case UR_GET_DESCRIPTOR:
1605187160Sthompsa			goto tr_handle_get_descriptor;
1606187160Sthompsa		case UR_GET_CONFIG:
1607187160Sthompsa			goto tr_handle_get_config;
1608187160Sthompsa		case UR_GET_STATUS:
1609187160Sthompsa			goto tr_handle_get_status;
1610187160Sthompsa		default:
1611187160Sthompsa			goto tr_stalled;
1612187160Sthompsa		}
1613187160Sthompsa		break;
1614187160Sthompsa
1615187160Sthompsa	case UT_WRITE_DEVICE:
1616191402Sthompsa		switch (req->bRequest) {
1617187160Sthompsa		case UR_SET_ADDRESS:
1618187160Sthompsa			goto tr_handle_set_address;
1619187160Sthompsa		case UR_SET_CONFIG:
1620187160Sthompsa			goto tr_handle_set_config;
1621187160Sthompsa		case UR_CLEAR_FEATURE:
1622187160Sthompsa			goto tr_valid;	/* nop */
1623187160Sthompsa		case UR_SET_DESCRIPTOR:
1624187160Sthompsa			goto tr_valid;	/* nop */
1625187160Sthompsa		case UR_SET_FEATURE:
1626187160Sthompsa		default:
1627187160Sthompsa			goto tr_stalled;
1628187160Sthompsa		}
1629187160Sthompsa		break;
1630187160Sthompsa
1631187160Sthompsa	case UT_WRITE_ENDPOINT:
1632191402Sthompsa		switch (req->bRequest) {
1633187160Sthompsa		case UR_CLEAR_FEATURE:
1634191402Sthompsa			switch (UGETW(req->wValue)) {
1635187160Sthompsa			case UF_ENDPOINT_HALT:
1636187160Sthompsa				goto tr_handle_clear_halt;
1637187160Sthompsa			case UF_DEVICE_REMOTE_WAKEUP:
1638187160Sthompsa				goto tr_handle_clear_wakeup;
1639187160Sthompsa			default:
1640187160Sthompsa				goto tr_stalled;
1641187160Sthompsa			}
1642187160Sthompsa			break;
1643187160Sthompsa		case UR_SET_FEATURE:
1644191402Sthompsa			switch (UGETW(req->wValue)) {
1645187160Sthompsa			case UF_ENDPOINT_HALT:
1646187160Sthompsa				goto tr_handle_set_halt;
1647187160Sthompsa			case UF_DEVICE_REMOTE_WAKEUP:
1648187160Sthompsa				goto tr_handle_set_wakeup;
1649187160Sthompsa			default:
1650187160Sthompsa				goto tr_stalled;
1651187160Sthompsa			}
1652187160Sthompsa			break;
1653187160Sthompsa		case UR_SYNCH_FRAME:
1654187160Sthompsa			goto tr_valid;	/* nop */
1655187160Sthompsa		default:
1656187160Sthompsa			goto tr_stalled;
1657187160Sthompsa		}
1658187160Sthompsa		break;
1659187160Sthompsa
1660187160Sthompsa	case UT_READ_ENDPOINT:
1661191402Sthompsa		switch (req->bRequest) {
1662187160Sthompsa		case UR_GET_STATUS:
1663187160Sthompsa			goto tr_handle_get_ep_status;
1664187160Sthompsa		default:
1665187160Sthompsa			goto tr_stalled;
1666187160Sthompsa		}
1667187160Sthompsa		break;
1668187160Sthompsa
1669187160Sthompsa	case UT_WRITE_INTERFACE:
1670191402Sthompsa		switch (req->bRequest) {
1671187160Sthompsa		case UR_SET_INTERFACE:
1672187160Sthompsa			goto tr_handle_set_interface;
1673187160Sthompsa		case UR_CLEAR_FEATURE:
1674187160Sthompsa			goto tr_valid;	/* nop */
1675187160Sthompsa		case UR_SET_FEATURE:
1676187160Sthompsa		default:
1677187160Sthompsa			goto tr_stalled;
1678187160Sthompsa		}
1679187160Sthompsa		break;
1680187160Sthompsa
1681187160Sthompsa	case UT_READ_INTERFACE:
1682191402Sthompsa		switch (req->bRequest) {
1683187160Sthompsa		case UR_GET_INTERFACE:
1684187160Sthompsa			goto tr_handle_get_interface;
1685187160Sthompsa		case UR_GET_STATUS:
1686187160Sthompsa			goto tr_handle_get_iface_status;
1687187160Sthompsa		default:
1688187160Sthompsa			goto tr_stalled;
1689187160Sthompsa		}
1690187160Sthompsa		break;
1691187160Sthompsa
1692187160Sthompsa	case UT_WRITE_CLASS_INTERFACE:
1693187160Sthompsa	case UT_WRITE_VENDOR_INTERFACE:
1694187160Sthompsa		/* XXX forward */
1695187160Sthompsa		break;
1696187160Sthompsa
1697187160Sthompsa	case UT_READ_CLASS_INTERFACE:
1698187160Sthompsa	case UT_READ_VENDOR_INTERFACE:
1699187160Sthompsa		/* XXX forward */
1700187160Sthompsa		break;
1701187160Sthompsa
1702187160Sthompsa	case UT_WRITE_CLASS_DEVICE:
1703191402Sthompsa		switch (req->bRequest) {
1704187160Sthompsa		case UR_CLEAR_FEATURE:
1705187160Sthompsa			goto tr_valid;
1706187160Sthompsa		case UR_SET_DESCRIPTOR:
1707187160Sthompsa		case UR_SET_FEATURE:
1708187160Sthompsa			break;
1709187160Sthompsa		default:
1710187160Sthompsa			goto tr_stalled;
1711187160Sthompsa		}
1712187160Sthompsa		break;
1713187160Sthompsa
1714187160Sthompsa	case UT_WRITE_CLASS_OTHER:
1715191402Sthompsa		switch (req->bRequest) {
1716187160Sthompsa		case UR_CLEAR_FEATURE:
1717187160Sthompsa			goto tr_handle_clear_port_feature;
1718187160Sthompsa		case UR_SET_FEATURE:
1719187160Sthompsa			goto tr_handle_set_port_feature;
1720187160Sthompsa		case UR_CLEAR_TT_BUFFER:
1721187160Sthompsa		case UR_RESET_TT:
1722187160Sthompsa		case UR_STOP_TT:
1723187160Sthompsa			goto tr_valid;
1724187160Sthompsa
1725187160Sthompsa		default:
1726187160Sthompsa			goto tr_stalled;
1727187160Sthompsa		}
1728187160Sthompsa		break;
1729187160Sthompsa
1730187160Sthompsa	case UT_READ_CLASS_OTHER:
1731191402Sthompsa		switch (req->bRequest) {
1732187160Sthompsa		case UR_GET_TT_STATE:
1733187160Sthompsa			goto tr_handle_get_tt_state;
1734187160Sthompsa		case UR_GET_STATUS:
1735187160Sthompsa			goto tr_handle_get_port_status;
1736187160Sthompsa		default:
1737187160Sthompsa			goto tr_stalled;
1738187160Sthompsa		}
1739187160Sthompsa		break;
1740187160Sthompsa
1741187160Sthompsa	case UT_READ_CLASS_DEVICE:
1742191402Sthompsa		switch (req->bRequest) {
1743187160Sthompsa		case UR_GET_DESCRIPTOR:
1744187160Sthompsa			goto tr_handle_get_class_descriptor;
1745187160Sthompsa		case UR_GET_STATUS:
1746187160Sthompsa			goto tr_handle_get_class_status;
1747187160Sthompsa
1748187160Sthompsa		default:
1749187160Sthompsa			goto tr_stalled;
1750187160Sthompsa		}
1751187160Sthompsa		break;
1752187160Sthompsa	default:
1753187160Sthompsa		goto tr_stalled;
1754187160Sthompsa	}
1755187160Sthompsa	goto tr_valid;
1756187160Sthompsa
1757187160Sthompsatr_handle_get_descriptor:
1758187160Sthompsa	switch (value >> 8) {
1759187160Sthompsa	case UDESC_DEVICE:
1760187160Sthompsa		if (value & 0xff) {
1761187160Sthompsa			goto tr_stalled;
1762187160Sthompsa		}
1763191402Sthompsa		len = sizeof(atmegadci_devd);
1764191402Sthompsa		ptr = (const void *)&atmegadci_devd;
1765187160Sthompsa		goto tr_valid;
1766187160Sthompsa	case UDESC_CONFIG:
1767187160Sthompsa		if (value & 0xff) {
1768187160Sthompsa			goto tr_stalled;
1769187160Sthompsa		}
1770191402Sthompsa		len = sizeof(atmegadci_confd);
1771191402Sthompsa		ptr = (const void *)&atmegadci_confd;
1772187160Sthompsa		goto tr_valid;
1773187160Sthompsa	case UDESC_STRING:
1774187160Sthompsa		switch (value & 0xff) {
1775187160Sthompsa		case 0:		/* Language table */
1776246123Shselasky			len = sizeof(usb_string_lang_en);
1777246123Shselasky			ptr = (const void *)&usb_string_lang_en;
1778187160Sthompsa			goto tr_valid;
1779187160Sthompsa
1780187160Sthompsa		case 1:		/* Vendor */
1781191402Sthompsa			len = sizeof(atmegadci_vendor);
1782191402Sthompsa			ptr = (const void *)&atmegadci_vendor;
1783187160Sthompsa			goto tr_valid;
1784187160Sthompsa
1785187160Sthompsa		case 2:		/* Product */
1786191402Sthompsa			len = sizeof(atmegadci_product);
1787191402Sthompsa			ptr = (const void *)&atmegadci_product;
1788187160Sthompsa			goto tr_valid;
1789187160Sthompsa		default:
1790187160Sthompsa			break;
1791187160Sthompsa		}
1792187160Sthompsa		break;
1793187160Sthompsa	default:
1794187160Sthompsa		goto tr_stalled;
1795187160Sthompsa	}
1796187160Sthompsa	goto tr_stalled;
1797187160Sthompsa
1798187160Sthompsatr_handle_get_config:
1799191402Sthompsa	len = 1;
1800187160Sthompsa	sc->sc_hub_temp.wValue[0] = sc->sc_conf;
1801187160Sthompsa	goto tr_valid;
1802187160Sthompsa
1803187160Sthompsatr_handle_get_status:
1804191402Sthompsa	len = 2;
1805187160Sthompsa	USETW(sc->sc_hub_temp.wValue, UDS_SELF_POWERED);
1806187160Sthompsa	goto tr_valid;
1807187160Sthompsa
1808187160Sthompsatr_handle_set_address:
1809187160Sthompsa	if (value & 0xFF00) {
1810187160Sthompsa		goto tr_stalled;
1811187160Sthompsa	}
1812187160Sthompsa	sc->sc_rt_addr = value;
1813187160Sthompsa	goto tr_valid;
1814187160Sthompsa
1815187160Sthompsatr_handle_set_config:
1816187160Sthompsa	if (value >= 2) {
1817187160Sthompsa		goto tr_stalled;
1818187160Sthompsa	}
1819187160Sthompsa	sc->sc_conf = value;
1820187160Sthompsa	goto tr_valid;
1821187160Sthompsa
1822187160Sthompsatr_handle_get_interface:
1823191402Sthompsa	len = 1;
1824187160Sthompsa	sc->sc_hub_temp.wValue[0] = 0;
1825187160Sthompsa	goto tr_valid;
1826187160Sthompsa
1827187160Sthompsatr_handle_get_tt_state:
1828187160Sthompsatr_handle_get_class_status:
1829187160Sthompsatr_handle_get_iface_status:
1830187160Sthompsatr_handle_get_ep_status:
1831191402Sthompsa	len = 2;
1832187160Sthompsa	USETW(sc->sc_hub_temp.wValue, 0);
1833187160Sthompsa	goto tr_valid;
1834187160Sthompsa
1835187160Sthompsatr_handle_set_halt:
1836187160Sthompsatr_handle_set_interface:
1837187160Sthompsatr_handle_set_wakeup:
1838187160Sthompsatr_handle_clear_wakeup:
1839187160Sthompsatr_handle_clear_halt:
1840187160Sthompsa	goto tr_valid;
1841187160Sthompsa
1842187160Sthompsatr_handle_clear_port_feature:
1843187160Sthompsa	if (index != 1) {
1844187160Sthompsa		goto tr_stalled;
1845187160Sthompsa	}
1846187160Sthompsa	DPRINTFN(9, "UR_CLEAR_PORT_FEATURE on port %d\n", index);
1847187160Sthompsa
1848187160Sthompsa	switch (value) {
1849187160Sthompsa	case UHF_PORT_SUSPEND:
1850190735Sthompsa		atmegadci_wakeup_peer(sc);
1851187160Sthompsa		break;
1852187160Sthompsa
1853187160Sthompsa	case UHF_PORT_ENABLE:
1854187160Sthompsa		sc->sc_flags.port_enabled = 0;
1855187160Sthompsa		break;
1856187160Sthompsa
1857187160Sthompsa	case UHF_PORT_TEST:
1858187160Sthompsa	case UHF_PORT_INDICATOR:
1859187160Sthompsa	case UHF_C_PORT_ENABLE:
1860187160Sthompsa	case UHF_C_PORT_OVER_CURRENT:
1861187160Sthompsa	case UHF_C_PORT_RESET:
1862187160Sthompsa		/* nops */
1863187160Sthompsa		break;
1864187160Sthompsa	case UHF_PORT_POWER:
1865187160Sthompsa		sc->sc_flags.port_powered = 0;
1866187160Sthompsa		atmegadci_pull_down(sc);
1867187160Sthompsa		atmegadci_clocks_off(sc);
1868187160Sthompsa		break;
1869187160Sthompsa	case UHF_C_PORT_CONNECTION:
1870189677Sthompsa		/* clear connect change flag */
1871187160Sthompsa		sc->sc_flags.change_connect = 0;
1872189677Sthompsa
1873192446Sthompsa		if (!sc->sc_flags.status_bus_reset) {
1874192446Sthompsa			/* we are not connected */
1875192446Sthompsa			break;
1876192446Sthompsa		}
1877192446Sthompsa
1878189677Sthompsa		/* configure the control endpoint */
1879189677Sthompsa
1880189677Sthompsa		/* select endpoint number */
1881189677Sthompsa		ATMEGA_WRITE_1(sc, ATMEGA_UENUM, 0);
1882189677Sthompsa
1883189677Sthompsa		/* set endpoint reset */
1884189677Sthompsa		ATMEGA_WRITE_1(sc, ATMEGA_UERST, ATMEGA_UERST_MASK(0));
1885189677Sthompsa
1886189677Sthompsa		/* clear endpoint reset */
1887189677Sthompsa		ATMEGA_WRITE_1(sc, ATMEGA_UERST, 0);
1888189677Sthompsa
1889189677Sthompsa		/* enable and stall endpoint */
1890189677Sthompsa		ATMEGA_WRITE_1(sc, ATMEGA_UECONX,
1891189677Sthompsa		    ATMEGA_UECONX_EPEN |
1892189677Sthompsa		    ATMEGA_UECONX_STALLRQ);
1893189677Sthompsa
1894189677Sthompsa		/* one bank, 64-bytes wMaxPacket */
1895189677Sthompsa		ATMEGA_WRITE_1(sc, ATMEGA_UECFG0X,
1896189677Sthompsa		    ATMEGA_UECFG0X_EPTYPE0);
1897189677Sthompsa		ATMEGA_WRITE_1(sc, ATMEGA_UECFG1X,
1898189677Sthompsa		    ATMEGA_UECFG1X_ALLOC |
1899189677Sthompsa		    ATMEGA_UECFG1X_EPBK0 |
1900189677Sthompsa		    ATMEGA_UECFG1X_EPSIZE(3));
1901189677Sthompsa
1902189677Sthompsa		/* check valid config */
1903189677Sthompsa		temp = ATMEGA_READ_1(sc, ATMEGA_UESTA0X);
1904189677Sthompsa		if (!(temp & ATMEGA_UESTA0X_CFGOK)) {
1905199816Sthompsa			device_printf(sc->sc_bus.bdev,
1906199816Sthompsa			    "Chip rejected EP0 configuration\n");
1907189677Sthompsa		}
1908187160Sthompsa		break;
1909187160Sthompsa	case UHF_C_PORT_SUSPEND:
1910187160Sthompsa		sc->sc_flags.change_suspend = 0;
1911187160Sthompsa		break;
1912187160Sthompsa	default:
1913191402Sthompsa		err = USB_ERR_IOERROR;
1914187160Sthompsa		goto done;
1915187160Sthompsa	}
1916187160Sthompsa	goto tr_valid;
1917187160Sthompsa
1918187160Sthompsatr_handle_set_port_feature:
1919187160Sthompsa	if (index != 1) {
1920187160Sthompsa		goto tr_stalled;
1921187160Sthompsa	}
1922187160Sthompsa	DPRINTFN(9, "UR_SET_PORT_FEATURE\n");
1923187160Sthompsa
1924187160Sthompsa	switch (value) {
1925187160Sthompsa	case UHF_PORT_ENABLE:
1926187160Sthompsa		sc->sc_flags.port_enabled = 1;
1927187160Sthompsa		break;
1928187160Sthompsa	case UHF_PORT_SUSPEND:
1929187160Sthompsa	case UHF_PORT_RESET:
1930187160Sthompsa	case UHF_PORT_TEST:
1931187160Sthompsa	case UHF_PORT_INDICATOR:
1932187160Sthompsa		/* nops */
1933187160Sthompsa		break;
1934187160Sthompsa	case UHF_PORT_POWER:
1935187160Sthompsa		sc->sc_flags.port_powered = 1;
1936187160Sthompsa		break;
1937187160Sthompsa	default:
1938191402Sthompsa		err = USB_ERR_IOERROR;
1939187160Sthompsa		goto done;
1940187160Sthompsa	}
1941187160Sthompsa	goto tr_valid;
1942187160Sthompsa
1943187160Sthompsatr_handle_get_port_status:
1944187160Sthompsa
1945187160Sthompsa	DPRINTFN(9, "UR_GET_PORT_STATUS\n");
1946187160Sthompsa
1947187160Sthompsa	if (index != 1) {
1948187160Sthompsa		goto tr_stalled;
1949187160Sthompsa	}
1950187160Sthompsa	if (sc->sc_flags.status_vbus) {
1951187160Sthompsa		atmegadci_clocks_on(sc);
1952187160Sthompsa		atmegadci_pull_up(sc);
1953187160Sthompsa	} else {
1954187160Sthompsa		atmegadci_pull_down(sc);
1955187160Sthompsa		atmegadci_clocks_off(sc);
1956187160Sthompsa	}
1957187160Sthompsa
1958187160Sthompsa	/* Select FULL-speed and Device Side Mode */
1959187160Sthompsa
1960187160Sthompsa	value = UPS_PORT_MODE_DEVICE;
1961187160Sthompsa
1962187160Sthompsa	if (sc->sc_flags.port_powered) {
1963187160Sthompsa		value |= UPS_PORT_POWER;
1964187160Sthompsa	}
1965187160Sthompsa	if (sc->sc_flags.port_enabled) {
1966187160Sthompsa		value |= UPS_PORT_ENABLED;
1967187160Sthompsa	}
1968187160Sthompsa	if (sc->sc_flags.status_vbus &&
1969187160Sthompsa	    sc->sc_flags.status_bus_reset) {
1970187160Sthompsa		value |= UPS_CURRENT_CONNECT_STATUS;
1971187160Sthompsa	}
1972187160Sthompsa	if (sc->sc_flags.status_suspend) {
1973187160Sthompsa		value |= UPS_SUSPEND;
1974187160Sthompsa	}
1975187160Sthompsa	USETW(sc->sc_hub_temp.ps.wPortStatus, value);
1976187160Sthompsa
1977187160Sthompsa	value = 0;
1978187160Sthompsa
1979187160Sthompsa	if (sc->sc_flags.change_connect) {
1980187160Sthompsa		value |= UPS_C_CONNECT_STATUS;
1981187160Sthompsa	}
1982187160Sthompsa	if (sc->sc_flags.change_suspend) {
1983187160Sthompsa		value |= UPS_C_SUSPEND;
1984187160Sthompsa	}
1985187160Sthompsa	USETW(sc->sc_hub_temp.ps.wPortChange, value);
1986191402Sthompsa	len = sizeof(sc->sc_hub_temp.ps);
1987187160Sthompsa	goto tr_valid;
1988187160Sthompsa
1989187160Sthompsatr_handle_get_class_descriptor:
1990187160Sthompsa	if (value & 0xFF) {
1991187160Sthompsa		goto tr_stalled;
1992187160Sthompsa	}
1993191402Sthompsa	ptr = (const void *)&atmegadci_hubd;
1994191402Sthompsa	len = sizeof(atmegadci_hubd);
1995187160Sthompsa	goto tr_valid;
1996187160Sthompsa
1997187160Sthompsatr_stalled:
1998191402Sthompsa	err = USB_ERR_STALLED;
1999187160Sthompsatr_valid:
2000187160Sthompsadone:
2001191402Sthompsa	*plength = len;
2002191402Sthompsa	*pptr = ptr;
2003191402Sthompsa	return (err);
2004187160Sthompsa}
2005187160Sthompsa
2006187160Sthompsastatic void
2007192984Sthompsaatmegadci_xfer_setup(struct usb_setup_params *parm)
2008187160Sthompsa{
2009192984Sthompsa	const struct usb_hw_ep_profile *pf;
2010187160Sthompsa	struct atmegadci_softc *sc;
2011192984Sthompsa	struct usb_xfer *xfer;
2012187160Sthompsa	void *last_obj;
2013187160Sthompsa	uint32_t ntd;
2014187160Sthompsa	uint32_t n;
2015187160Sthompsa	uint8_t ep_no;
2016187160Sthompsa
2017187160Sthompsa	sc = ATMEGA_BUS2SC(parm->udev->bus);
2018187160Sthompsa	xfer = parm->curr_xfer;
2019187160Sthompsa
2020187160Sthompsa	/*
2021187160Sthompsa	 * NOTE: This driver does not use any of the parameters that
2022187160Sthompsa	 * are computed from the following values. Just set some
2023187160Sthompsa	 * reasonable dummies:
2024187160Sthompsa	 */
2025187160Sthompsa	parm->hc_max_packet_size = 0x500;
2026187160Sthompsa	parm->hc_max_packet_count = 1;
2027187160Sthompsa	parm->hc_max_frame_size = 0x500;
2028187160Sthompsa
2029194228Sthompsa	usbd_transfer_setup_sub(parm);
2030187160Sthompsa
2031187160Sthompsa	/*
2032187160Sthompsa	 * compute maximum number of TDs
2033187160Sthompsa	 */
2034193644Sthompsa	if ((xfer->endpoint->edesc->bmAttributes & UE_XFERTYPE) == UE_CONTROL) {
2035187160Sthompsa
2036190737Sthompsa		ntd = xfer->nframes + 1 /* STATUS */ + 1 /* SYNC 1 */
2037187160Sthompsa		    + 1 /* SYNC 2 */ ;
2038190737Sthompsa	} else {
2039187160Sthompsa
2040187160Sthompsa		ntd = xfer->nframes + 1 /* SYNC */ ;
2041187160Sthompsa	}
2042187160Sthompsa
2043187160Sthompsa	/*
2044194228Sthompsa	 * check if "usbd_transfer_setup_sub" set an error
2045187160Sthompsa	 */
2046190737Sthompsa	if (parm->err)
2047187160Sthompsa		return;
2048190737Sthompsa
2049187160Sthompsa	/*
2050187160Sthompsa	 * allocate transfer descriptors
2051187160Sthompsa	 */
2052187160Sthompsa	last_obj = NULL;
2053187160Sthompsa
2054187160Sthompsa	/*
2055187160Sthompsa	 * get profile stuff
2056187160Sthompsa	 */
2057193644Sthompsa	ep_no = xfer->endpointno & UE_ADDR;
2058190737Sthompsa	atmegadci_get_hw_ep_profile(parm->udev, &pf, ep_no);
2059187160Sthompsa
2060190737Sthompsa	if (pf == NULL) {
2061190737Sthompsa		/* should not happen */
2062190737Sthompsa		parm->err = USB_ERR_INVAL;
2063190737Sthompsa		return;
2064187160Sthompsa	}
2065187160Sthompsa
2066187160Sthompsa	/* align data */
2067187160Sthompsa	parm->size[0] += ((-parm->size[0]) & (USB_HOST_ALIGN - 1));
2068187160Sthompsa
2069187160Sthompsa	for (n = 0; n != ntd; n++) {
2070187160Sthompsa
2071187160Sthompsa		struct atmegadci_td *td;
2072187160Sthompsa
2073187160Sthompsa		if (parm->buf) {
2074187160Sthompsa
2075187160Sthompsa			td = USB_ADD_BYTES(parm->buf, parm->size[0]);
2076187160Sthompsa
2077187160Sthompsa			/* init TD */
2078187160Sthompsa			td->max_packet_size = xfer->max_packet_size;
2079187160Sthompsa			td->ep_no = ep_no;
2080187160Sthompsa			if (pf->support_multi_buffer) {
2081187160Sthompsa				td->support_multi_buffer = 1;
2082187160Sthompsa			}
2083187160Sthompsa			td->obj_next = last_obj;
2084187160Sthompsa
2085187160Sthompsa			last_obj = td;
2086187160Sthompsa		}
2087187160Sthompsa		parm->size[0] += sizeof(*td);
2088187160Sthompsa	}
2089187160Sthompsa
2090187160Sthompsa	xfer->td_start[0] = last_obj;
2091187160Sthompsa}
2092187160Sthompsa
2093187160Sthompsastatic void
2094192984Sthompsaatmegadci_xfer_unsetup(struct usb_xfer *xfer)
2095187160Sthompsa{
2096187160Sthompsa	return;
2097187160Sthompsa}
2098187160Sthompsa
2099187160Sthompsastatic void
2100193644Sthompsaatmegadci_ep_init(struct usb_device *udev, struct usb_endpoint_descriptor *edesc,
2101193644Sthompsa    struct usb_endpoint *ep)
2102187160Sthompsa{
2103187160Sthompsa	struct atmegadci_softc *sc = ATMEGA_BUS2SC(udev->bus);
2104187160Sthompsa
2105193644Sthompsa	DPRINTFN(2, "endpoint=%p, addr=%d, endpt=%d, mode=%d (%d,%d)\n",
2106193644Sthompsa	    ep, udev->address,
2107192499Sthompsa	    edesc->bEndpointAddress, udev->flags.usb_mode,
2108189677Sthompsa	    sc->sc_rt_addr, udev->device_index);
2109187160Sthompsa
2110190735Sthompsa	if (udev->device_index != sc->sc_rt_addr) {
2111187160Sthompsa
2112187160Sthompsa		if (udev->speed != USB_SPEED_FULL) {
2113187160Sthompsa			/* not supported */
2114187160Sthompsa			return;
2115187160Sthompsa		}
2116190737Sthompsa		if ((edesc->bmAttributes & UE_XFERTYPE) == UE_ISOCHRONOUS)
2117193644Sthompsa			ep->methods = &atmegadci_device_isoc_fs_methods;
2118190737Sthompsa		else
2119193644Sthompsa			ep->methods = &atmegadci_device_non_isoc_methods;
2120187160Sthompsa	}
2121187160Sthompsa}
2122187160Sthompsa
2123228483Shselaskystatic void
2124228483Shselaskyatmegadci_set_hw_power_sleep(struct usb_bus *bus, uint32_t state)
2125228483Shselasky{
2126228483Shselasky	struct atmegadci_softc *sc = ATMEGA_BUS2SC(bus);
2127228483Shselasky
2128228483Shselasky	switch (state) {
2129228483Shselasky	case USB_HW_POWER_SUSPEND:
2130228483Shselasky		atmegadci_suspend(sc);
2131228483Shselasky		break;
2132228483Shselasky	case USB_HW_POWER_SHUTDOWN:
2133228483Shselasky		atmegadci_uninit(sc);
2134228483Shselasky		break;
2135228483Shselasky	case USB_HW_POWER_RESUME:
2136228483Shselasky		atmegadci_resume(sc);
2137228483Shselasky		break;
2138228483Shselasky	default:
2139228483Shselasky		break;
2140228483Shselasky	}
2141228483Shselasky}
2142228483Shselasky
2143192984Sthompsastruct usb_bus_methods atmegadci_bus_methods =
2144187160Sthompsa{
2145193644Sthompsa	.endpoint_init = &atmegadci_ep_init,
2146187160Sthompsa	.xfer_setup = &atmegadci_xfer_setup,
2147187160Sthompsa	.xfer_unsetup = &atmegadci_xfer_unsetup,
2148187160Sthompsa	.get_hw_ep_profile = &atmegadci_get_hw_ep_profile,
2149239214Shselasky	.xfer_stall = &atmegadci_xfer_stall,
2150187160Sthompsa	.set_stall = &atmegadci_set_stall,
2151187160Sthompsa	.clear_stall = &atmegadci_clear_stall,
2152190735Sthompsa	.roothub_exec = &atmegadci_roothub_exec,
2153195960Salfred	.xfer_poll = &atmegadci_do_poll,
2154228483Shselasky	.set_hw_power_sleep = &atmegadci_set_hw_power_sleep,
2155187160Sthompsa};
2156