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