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