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