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