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