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