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