The Design and Implementation of the FreeBSD Operating System, Second Edition
Now available: The Design and Implementation of the FreeBSD Operating System (Second Edition)


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]

FreeBSD/Linux Kernel Cross Reference
sys/dev/usb/controller/uss820dci.c

Version: -  FREEBSD  -  FREEBSD-13-STABLE  -  FREEBSD-13-0  -  FREEBSD-12-STABLE  -  FREEBSD-12-0  -  FREEBSD-11-STABLE  -  FREEBSD-11-0  -  FREEBSD-10-STABLE  -  FREEBSD-10-0  -  FREEBSD-9-STABLE  -  FREEBSD-9-0  -  FREEBSD-8-STABLE  -  FREEBSD-8-0  -  FREEBSD-7-STABLE  -  FREEBSD-7-0  -  FREEBSD-6-STABLE  -  FREEBSD-6-0  -  FREEBSD-5-STABLE  -  FREEBSD-5-0  -  FREEBSD-4-STABLE  -  FREEBSD-3-STABLE  -  FREEBSD22  -  l41  -  OPENBSD  -  linux-2.6  -  MK84  -  PLAN9  -  xnu-8792 
SearchContext: -  none  -  3  -  10 

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

Cache object: 1bd6c891e629c622646f8fcf146e726c


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]


This page is part of the FreeBSD/Linux Linux Kernel Cross-Reference, and was automatically generated using a modified version of the LXR engine.