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