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