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