]> CyberLeo.Net >> Repos - FreeBSD/stable/8.git/blob - sys/dev/usb/controller/uss820dci.c
MFC r362623:
[FreeBSD/stable/8.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 static void
1516 uss820dci_suspend(struct uss820dci_softc *sc)
1517 {
1518         /* TODO */
1519 }
1520
1521 static void
1522 uss820dci_resume(struct uss820dci_softc *sc)
1523 {
1524         /* TODO */
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 #define HSETW(ptr, val) ptr = { (uint8_t)(val), (uint8_t)((val) >> 8) }
1792
1793 static const struct usb_hub_descriptor_min uss820dci_hubd = {
1794         .bDescLength = sizeof(uss820dci_hubd),
1795         .bDescriptorType = UDESC_HUB,
1796         .bNbrPorts = 1,
1797         HSETW(.wHubCharacteristics, (UHD_PWR_NO_SWITCH | UHD_OC_INDIVIDUAL)),
1798         .bPwrOn2PwrGood = 50,
1799         .bHubContrCurrent = 0,
1800         .DeviceRemovable = {0},         /* port is removable */
1801 };
1802
1803 #define STRING_LANG \
1804   0x09, 0x04,                           /* American English */
1805
1806 #define STRING_VENDOR \
1807   'A', 0, 'G', 0, 'E', 0, 'R', 0, 'E', 0
1808
1809 #define STRING_PRODUCT \
1810   'D', 0, 'C', 0, 'I', 0, ' ', 0, 'R', 0, \
1811   'o', 0, 'o', 0, 't', 0, ' ', 0, 'H', 0, \
1812   'U', 0, 'B', 0,
1813
1814 USB_MAKE_STRING_DESC(STRING_LANG, uss820dci_langtab);
1815 USB_MAKE_STRING_DESC(STRING_VENDOR, uss820dci_vendor);
1816 USB_MAKE_STRING_DESC(STRING_PRODUCT, uss820dci_product);
1817
1818 static usb_error_t
1819 uss820dci_roothub_exec(struct usb_device *udev,
1820     struct usb_device_request *req, const void **pptr, uint16_t *plength)
1821 {
1822         struct uss820dci_softc *sc = USS820_DCI_BUS2SC(udev->bus);
1823         const void *ptr;
1824         uint16_t len;
1825         uint16_t value;
1826         uint16_t index;
1827         usb_error_t err;
1828
1829         USB_BUS_LOCK_ASSERT(&sc->sc_bus, MA_OWNED);
1830
1831         /* buffer reset */
1832         ptr = (const void *)&sc->sc_hub_temp;
1833         len = 0;
1834         err = 0;
1835
1836         value = UGETW(req->wValue);
1837         index = UGETW(req->wIndex);
1838
1839         /* demultiplex the control request */
1840
1841         switch (req->bmRequestType) {
1842         case UT_READ_DEVICE:
1843                 switch (req->bRequest) {
1844                 case UR_GET_DESCRIPTOR:
1845                         goto tr_handle_get_descriptor;
1846                 case UR_GET_CONFIG:
1847                         goto tr_handle_get_config;
1848                 case UR_GET_STATUS:
1849                         goto tr_handle_get_status;
1850                 default:
1851                         goto tr_stalled;
1852                 }
1853                 break;
1854
1855         case UT_WRITE_DEVICE:
1856                 switch (req->bRequest) {
1857                 case UR_SET_ADDRESS:
1858                         goto tr_handle_set_address;
1859                 case UR_SET_CONFIG:
1860                         goto tr_handle_set_config;
1861                 case UR_CLEAR_FEATURE:
1862                         goto tr_valid;  /* nop */
1863                 case UR_SET_DESCRIPTOR:
1864                         goto tr_valid;  /* nop */
1865                 case UR_SET_FEATURE:
1866                 default:
1867                         goto tr_stalled;
1868                 }
1869                 break;
1870
1871         case UT_WRITE_ENDPOINT:
1872                 switch (req->bRequest) {
1873                 case UR_CLEAR_FEATURE:
1874                         switch (UGETW(req->wValue)) {
1875                         case UF_ENDPOINT_HALT:
1876                                 goto tr_handle_clear_halt;
1877                         case UF_DEVICE_REMOTE_WAKEUP:
1878                                 goto tr_handle_clear_wakeup;
1879                         default:
1880                                 goto tr_stalled;
1881                         }
1882                         break;
1883                 case UR_SET_FEATURE:
1884                         switch (UGETW(req->wValue)) {
1885                         case UF_ENDPOINT_HALT:
1886                                 goto tr_handle_set_halt;
1887                         case UF_DEVICE_REMOTE_WAKEUP:
1888                                 goto tr_handle_set_wakeup;
1889                         default:
1890                                 goto tr_stalled;
1891                         }
1892                         break;
1893                 case UR_SYNCH_FRAME:
1894                         goto tr_valid;  /* nop */
1895                 default:
1896                         goto tr_stalled;
1897                 }
1898                 break;
1899
1900         case UT_READ_ENDPOINT:
1901                 switch (req->bRequest) {
1902                 case UR_GET_STATUS:
1903                         goto tr_handle_get_ep_status;
1904                 default:
1905                         goto tr_stalled;
1906                 }
1907                 break;
1908
1909         case UT_WRITE_INTERFACE:
1910                 switch (req->bRequest) {
1911                 case UR_SET_INTERFACE:
1912                         goto tr_handle_set_interface;
1913                 case UR_CLEAR_FEATURE:
1914                         goto tr_valid;  /* nop */
1915                 case UR_SET_FEATURE:
1916                 default:
1917                         goto tr_stalled;
1918                 }
1919                 break;
1920
1921         case UT_READ_INTERFACE:
1922                 switch (req->bRequest) {
1923                 case UR_GET_INTERFACE:
1924                         goto tr_handle_get_interface;
1925                 case UR_GET_STATUS:
1926                         goto tr_handle_get_iface_status;
1927                 default:
1928                         goto tr_stalled;
1929                 }
1930                 break;
1931
1932         case UT_WRITE_CLASS_INTERFACE:
1933         case UT_WRITE_VENDOR_INTERFACE:
1934                 /* XXX forward */
1935                 break;
1936
1937         case UT_READ_CLASS_INTERFACE:
1938         case UT_READ_VENDOR_INTERFACE:
1939                 /* XXX forward */
1940                 break;
1941
1942         case UT_WRITE_CLASS_DEVICE:
1943                 switch (req->bRequest) {
1944                 case UR_CLEAR_FEATURE:
1945                         goto tr_valid;
1946                 case UR_SET_DESCRIPTOR:
1947                 case UR_SET_FEATURE:
1948                         break;
1949                 default:
1950                         goto tr_stalled;
1951                 }
1952                 break;
1953
1954         case UT_WRITE_CLASS_OTHER:
1955                 switch (req->bRequest) {
1956                 case UR_CLEAR_FEATURE:
1957                         goto tr_handle_clear_port_feature;
1958                 case UR_SET_FEATURE:
1959                         goto tr_handle_set_port_feature;
1960                 case UR_CLEAR_TT_BUFFER:
1961                 case UR_RESET_TT:
1962                 case UR_STOP_TT:
1963                         goto tr_valid;
1964
1965                 default:
1966                         goto tr_stalled;
1967                 }
1968                 break;
1969
1970         case UT_READ_CLASS_OTHER:
1971                 switch (req->bRequest) {
1972                 case UR_GET_TT_STATE:
1973                         goto tr_handle_get_tt_state;
1974                 case UR_GET_STATUS:
1975                         goto tr_handle_get_port_status;
1976                 default:
1977                         goto tr_stalled;
1978                 }
1979                 break;
1980
1981         case UT_READ_CLASS_DEVICE:
1982                 switch (req->bRequest) {
1983                 case UR_GET_DESCRIPTOR:
1984                         goto tr_handle_get_class_descriptor;
1985                 case UR_GET_STATUS:
1986                         goto tr_handle_get_class_status;
1987
1988                 default:
1989                         goto tr_stalled;
1990                 }
1991                 break;
1992         default:
1993                 goto tr_stalled;
1994         }
1995         goto tr_valid;
1996
1997 tr_handle_get_descriptor:
1998         switch (value >> 8) {
1999         case UDESC_DEVICE:
2000                 if (value & 0xff) {
2001                         goto tr_stalled;
2002                 }
2003                 len = sizeof(uss820dci_devd);
2004                 ptr = (const void *)&uss820dci_devd;
2005                 goto tr_valid;
2006         case UDESC_CONFIG:
2007                 if (value & 0xff) {
2008                         goto tr_stalled;
2009                 }
2010                 len = sizeof(uss820dci_confd);
2011                 ptr = (const void *)&uss820dci_confd;
2012                 goto tr_valid;
2013         case UDESC_STRING:
2014                 switch (value & 0xff) {
2015                 case 0:         /* Language table */
2016                         len = sizeof(uss820dci_langtab);
2017                         ptr = (const void *)&uss820dci_langtab;
2018                         goto tr_valid;
2019
2020                 case 1:         /* Vendor */
2021                         len = sizeof(uss820dci_vendor);
2022                         ptr = (const void *)&uss820dci_vendor;
2023                         goto tr_valid;
2024
2025                 case 2:         /* Product */
2026                         len = sizeof(uss820dci_product);
2027                         ptr = (const void *)&uss820dci_product;
2028                         goto tr_valid;
2029                 default:
2030                         break;
2031                 }
2032                 break;
2033         default:
2034                 goto tr_stalled;
2035         }
2036         goto tr_stalled;
2037
2038 tr_handle_get_config:
2039         len = 1;
2040         sc->sc_hub_temp.wValue[0] = sc->sc_conf;
2041         goto tr_valid;
2042
2043 tr_handle_get_status:
2044         len = 2;
2045         USETW(sc->sc_hub_temp.wValue, UDS_SELF_POWERED);
2046         goto tr_valid;
2047
2048 tr_handle_set_address:
2049         if (value & 0xFF00) {
2050                 goto tr_stalled;
2051         }
2052         sc->sc_rt_addr = value;
2053         goto tr_valid;
2054
2055 tr_handle_set_config:
2056         if (value >= 2) {
2057                 goto tr_stalled;
2058         }
2059         sc->sc_conf = value;
2060         goto tr_valid;
2061
2062 tr_handle_get_interface:
2063         len = 1;
2064         sc->sc_hub_temp.wValue[0] = 0;
2065         goto tr_valid;
2066
2067 tr_handle_get_tt_state:
2068 tr_handle_get_class_status:
2069 tr_handle_get_iface_status:
2070 tr_handle_get_ep_status:
2071         len = 2;
2072         USETW(sc->sc_hub_temp.wValue, 0);
2073         goto tr_valid;
2074
2075 tr_handle_set_halt:
2076 tr_handle_set_interface:
2077 tr_handle_set_wakeup:
2078 tr_handle_clear_wakeup:
2079 tr_handle_clear_halt:
2080         goto tr_valid;
2081
2082 tr_handle_clear_port_feature:
2083         if (index != 1) {
2084                 goto tr_stalled;
2085         }
2086         DPRINTFN(9, "UR_CLEAR_PORT_FEATURE on port %d\n", index);
2087
2088         switch (value) {
2089         case UHF_PORT_SUSPEND:
2090                 uss820dci_wakeup_peer(sc);
2091                 break;
2092
2093         case UHF_PORT_ENABLE:
2094                 sc->sc_flags.port_enabled = 0;
2095                 break;
2096
2097         case UHF_PORT_TEST:
2098         case UHF_PORT_INDICATOR:
2099         case UHF_C_PORT_ENABLE:
2100         case UHF_C_PORT_OVER_CURRENT:
2101         case UHF_C_PORT_RESET:
2102                 /* nops */
2103                 break;
2104         case UHF_PORT_POWER:
2105                 sc->sc_flags.port_powered = 0;
2106                 uss820dci_pull_down(sc);
2107                 break;
2108         case UHF_C_PORT_CONNECTION:
2109                 sc->sc_flags.change_connect = 0;
2110                 break;
2111         case UHF_C_PORT_SUSPEND:
2112                 sc->sc_flags.change_suspend = 0;
2113                 break;
2114         default:
2115                 err = USB_ERR_IOERROR;
2116                 goto done;
2117         }
2118         goto tr_valid;
2119
2120 tr_handle_set_port_feature:
2121         if (index != 1) {
2122                 goto tr_stalled;
2123         }
2124         DPRINTFN(9, "UR_SET_PORT_FEATURE\n");
2125
2126         switch (value) {
2127         case UHF_PORT_ENABLE:
2128                 sc->sc_flags.port_enabled = 1;
2129                 break;
2130         case UHF_PORT_SUSPEND:
2131         case UHF_PORT_RESET:
2132         case UHF_PORT_TEST:
2133         case UHF_PORT_INDICATOR:
2134                 /* nops */
2135                 break;
2136         case UHF_PORT_POWER:
2137                 sc->sc_flags.port_powered = 1;
2138                 break;
2139         default:
2140                 err = USB_ERR_IOERROR;
2141                 goto done;
2142         }
2143         goto tr_valid;
2144
2145 tr_handle_get_port_status:
2146
2147         DPRINTFN(9, "UR_GET_PORT_STATUS\n");
2148
2149         if (index != 1) {
2150                 goto tr_stalled;
2151         }
2152         if (sc->sc_flags.status_vbus) {
2153                 uss820dci_pull_up(sc);
2154         } else {
2155                 uss820dci_pull_down(sc);
2156         }
2157
2158         /* Select FULL-speed and Device Side Mode */
2159
2160         value = UPS_PORT_MODE_DEVICE;
2161
2162         if (sc->sc_flags.port_powered) {
2163                 value |= UPS_PORT_POWER;
2164         }
2165         if (sc->sc_flags.port_enabled) {
2166                 value |= UPS_PORT_ENABLED;
2167         }
2168         if (sc->sc_flags.status_vbus &&
2169             sc->sc_flags.status_bus_reset) {
2170                 value |= UPS_CURRENT_CONNECT_STATUS;
2171         }
2172         if (sc->sc_flags.status_suspend) {
2173                 value |= UPS_SUSPEND;
2174         }
2175         USETW(sc->sc_hub_temp.ps.wPortStatus, value);
2176
2177         value = 0;
2178
2179         if (sc->sc_flags.change_connect) {
2180                 value |= UPS_C_CONNECT_STATUS;
2181         }
2182         if (sc->sc_flags.change_suspend) {
2183                 value |= UPS_C_SUSPEND;
2184         }
2185         USETW(sc->sc_hub_temp.ps.wPortChange, value);
2186         len = sizeof(sc->sc_hub_temp.ps);
2187         goto tr_valid;
2188
2189 tr_handle_get_class_descriptor:
2190         if (value & 0xFF) {
2191                 goto tr_stalled;
2192         }
2193         ptr = (const void *)&uss820dci_hubd;
2194         len = sizeof(uss820dci_hubd);
2195         goto tr_valid;
2196
2197 tr_stalled:
2198         err = USB_ERR_STALLED;
2199 tr_valid:
2200 done:
2201         *plength = len;
2202         *pptr = ptr;
2203         return (err);
2204 }
2205
2206 static void
2207 uss820dci_xfer_setup(struct usb_setup_params *parm)
2208 {
2209         const struct usb_hw_ep_profile *pf;
2210         struct uss820dci_softc *sc;
2211         struct usb_xfer *xfer;
2212         void *last_obj;
2213         uint32_t ntd;
2214         uint32_t n;
2215         uint8_t ep_no;
2216
2217         sc = USS820_DCI_BUS2SC(parm->udev->bus);
2218         xfer = parm->curr_xfer;
2219
2220         /*
2221          * NOTE: This driver does not use any of the parameters that
2222          * are computed from the following values. Just set some
2223          * reasonable dummies:
2224          */
2225         parm->hc_max_packet_size = 0x500;
2226         parm->hc_max_packet_count = 1;
2227         parm->hc_max_frame_size = 0x500;
2228
2229         usbd_transfer_setup_sub(parm);
2230
2231         /*
2232          * compute maximum number of TDs
2233          */
2234         if (parm->methods == &uss820dci_device_ctrl_methods) {
2235
2236                 ntd = xfer->nframes + 1 /* STATUS */ + 1 /* SYNC */ ;
2237
2238         } else if (parm->methods == &uss820dci_device_bulk_methods) {
2239
2240                 ntd = xfer->nframes + 1 /* SYNC */ ;
2241
2242         } else if (parm->methods == &uss820dci_device_intr_methods) {
2243
2244                 ntd = xfer->nframes + 1 /* SYNC */ ;
2245
2246         } else if (parm->methods == &uss820dci_device_isoc_fs_methods) {
2247
2248                 ntd = xfer->nframes + 1 /* SYNC */ ;
2249
2250         } else {
2251
2252                 ntd = 0;
2253         }
2254
2255         /*
2256          * check if "usbd_transfer_setup_sub" set an error
2257          */
2258         if (parm->err) {
2259                 return;
2260         }
2261         /*
2262          * allocate transfer descriptors
2263          */
2264         last_obj = NULL;
2265
2266         /*
2267          * get profile stuff
2268          */
2269         if (ntd) {
2270
2271                 ep_no = xfer->endpointno & UE_ADDR;
2272                 uss820dci_get_hw_ep_profile(parm->udev, &pf, ep_no);
2273
2274                 if (pf == NULL) {
2275                         /* should not happen */
2276                         parm->err = USB_ERR_INVAL;
2277                         return;
2278                 }
2279         } else {
2280                 ep_no = 0;
2281                 pf = NULL;
2282         }
2283
2284         /* align data */
2285         parm->size[0] += ((-parm->size[0]) & (USB_HOST_ALIGN - 1));
2286
2287         for (n = 0; n != ntd; n++) {
2288
2289                 struct uss820dci_td *td;
2290
2291                 if (parm->buf) {
2292
2293                         td = USB_ADD_BYTES(parm->buf, parm->size[0]);
2294
2295                         /* init TD */
2296                         td->io_tag = sc->sc_io_tag;
2297                         td->io_hdl = sc->sc_io_hdl;
2298                         td->max_packet_size = xfer->max_packet_size;
2299                         td->ep_index = ep_no;
2300                         if (pf->support_multi_buffer &&
2301                             (parm->methods != &uss820dci_device_ctrl_methods)) {
2302                                 td->support_multi_buffer = 1;
2303                         }
2304                         td->obj_next = last_obj;
2305
2306                         last_obj = td;
2307                 }
2308                 parm->size[0] += sizeof(*td);
2309         }
2310
2311         xfer->td_start[0] = last_obj;
2312 }
2313
2314 static void
2315 uss820dci_xfer_unsetup(struct usb_xfer *xfer)
2316 {
2317         return;
2318 }
2319
2320 static void
2321 uss820dci_ep_init(struct usb_device *udev, struct usb_endpoint_descriptor *edesc,
2322     struct usb_endpoint *ep)
2323 {
2324         struct uss820dci_softc *sc = USS820_DCI_BUS2SC(udev->bus);
2325
2326         DPRINTFN(2, "endpoint=%p, addr=%d, endpt=%d, mode=%d (%d)\n",
2327             ep, udev->address,
2328             edesc->bEndpointAddress, udev->flags.usb_mode,
2329             sc->sc_rt_addr);
2330
2331         if (udev->device_index != sc->sc_rt_addr) {
2332
2333                 if (udev->flags.usb_mode != USB_MODE_DEVICE) {
2334                         /* not supported */
2335                         return;
2336                 }
2337                 if (udev->speed != USB_SPEED_FULL) {
2338                         /* not supported */
2339                         return;
2340                 }
2341                 switch (edesc->bmAttributes & UE_XFERTYPE) {
2342                 case UE_CONTROL:
2343                         ep->methods = &uss820dci_device_ctrl_methods;
2344                         break;
2345                 case UE_INTERRUPT:
2346                         ep->methods = &uss820dci_device_intr_methods;
2347                         break;
2348                 case UE_ISOCHRONOUS:
2349                         ep->methods = &uss820dci_device_isoc_fs_methods;
2350                         break;
2351                 case UE_BULK:
2352                         ep->methods = &uss820dci_device_bulk_methods;
2353                         break;
2354                 default:
2355                         /* do nothing */
2356                         break;
2357                 }
2358         }
2359 }
2360
2361 static void
2362 uss820dci_set_hw_power_sleep(struct usb_bus *bus, uint32_t state)
2363 {
2364         struct uss820dci_softc *sc = USS820_DCI_BUS2SC(bus);
2365
2366         switch (state) {
2367         case USB_HW_POWER_SUSPEND:
2368                 uss820dci_suspend(sc);
2369                 break;
2370         case USB_HW_POWER_SHUTDOWN:
2371                 uss820dci_uninit(sc);
2372                 break;
2373         case USB_HW_POWER_RESUME:
2374                 uss820dci_resume(sc);
2375                 break;
2376         default:
2377                 break;
2378         }
2379 }
2380
2381 struct usb_bus_methods uss820dci_bus_methods =
2382 {
2383         .endpoint_init = &uss820dci_ep_init,
2384         .xfer_setup = &uss820dci_xfer_setup,
2385         .xfer_unsetup = &uss820dci_xfer_unsetup,
2386         .get_hw_ep_profile = &uss820dci_get_hw_ep_profile,
2387         .set_stall = &uss820dci_set_stall,
2388         .clear_stall = &uss820dci_clear_stall,
2389         .roothub_exec = &uss820dci_roothub_exec,
2390         .xfer_poll = &uss820dci_do_poll,
2391         .set_hw_power_sleep = uss820dci_set_hw_power_sleep,
2392 };