LCOV - code coverage report
Current view: top level - dev/usb - uhci.c (source / functions) Hit Total Coverage
Test: 6.4 Lines: 0 1321 0.0 %
Date: 2018-10-19 03:25:38 Functions: 0 74 0.0 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /*      $OpenBSD: uhci.c,v 1.143 2017/05/15 10:52:08 mpi Exp $  */
       2             : /*      $NetBSD: uhci.c,v 1.172 2003/02/23 04:19:26 simonb Exp $        */
       3             : /*      $FreeBSD: src/sys/dev/usb/uhci.c,v 1.33 1999/11/17 22:33:41 n_hibma Exp $       */
       4             : 
       5             : /*
       6             :  * Copyright (c) 1998 The NetBSD Foundation, Inc.
       7             :  * All rights reserved.
       8             :  *
       9             :  * This code is derived from software contributed to The NetBSD Foundation
      10             :  * by Lennart Augustsson (lennart@augustsson.net) at
      11             :  * Carlstedt Research & Technology.
      12             :  *
      13             :  * Redistribution and use in source and binary forms, with or without
      14             :  * modification, are permitted provided that the following conditions
      15             :  * are met:
      16             :  * 1. Redistributions of source code must retain the above copyright
      17             :  *    notice, this list of conditions and the following disclaimer.
      18             :  * 2. Redistributions in binary form must reproduce the above copyright
      19             :  *    notice, this list of conditions and the following disclaimer in the
      20             :  *    documentation and/or other materials provided with the distribution.
      21             :  *
      22             :  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
      23             :  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
      24             :  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
      25             :  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
      26             :  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
      27             :  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
      28             :  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
      29             :  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
      30             :  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
      31             :  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
      32             :  * POSSIBILITY OF SUCH DAMAGE.
      33             :  */
      34             : 
      35             : #include <sys/param.h>
      36             : #include <sys/systm.h>
      37             : #include <sys/malloc.h>
      38             : #include <sys/device.h>
      39             : #include <sys/queue.h>
      40             : #include <sys/timeout.h>
      41             : #include <sys/pool.h>
      42             : #include <sys/endian.h>
      43             : 
      44             : #include <machine/bus.h>
      45             : 
      46             : #include <dev/usb/usb.h>
      47             : #include <dev/usb/usbdi.h>
      48             : #include <dev/usb/usbdivar.h>
      49             : #include <dev/usb/usb_mem.h>
      50             : 
      51             : #include <dev/usb/uhcireg.h>
      52             : #include <dev/usb/uhcivar.h>
      53             : 
      54             : /* Use bandwidth reclamation for control transfers. Some devices choke on it. */
      55             : /*#define UHCI_CTL_LOOP */
      56             : 
      57             : struct cfdriver uhci_cd = {
      58             :         NULL, "uhci", DV_DULL
      59             : };
      60             : 
      61             : #ifdef UHCI_DEBUG
      62             : struct uhci_softc *thesc;
      63             : #define DPRINTF(x)      if (uhcidebug) printf x
      64             : #define DPRINTFN(n,x)   if (uhcidebug>(n)) printf x
      65             : int uhcidebug = 0;
      66             : int uhcinoloop = 0;
      67             : #define bitmask_snprintf(q,f,b,l) snprintf((b), (l), "%b", (q), (f))
      68             : #else
      69             : #define DPRINTF(x)
      70             : #define DPRINTFN(n,x)
      71             : #endif
      72             : 
      73             : struct pool *uhcixfer;
      74             : 
      75             : struct uhci_pipe {
      76             :         struct usbd_pipe pipe;
      77             :         int nexttoggle;
      78             : 
      79             :         union {
      80             :                 /* Control pipe */
      81             :                 struct {
      82             :                         struct uhci_soft_qh *sqh;
      83             :                         struct usb_dma reqdma;
      84             :                         struct uhci_soft_td *setup, *stat;
      85             :                         u_int length;
      86             :                 } ctl;
      87             :                 /* Interrupt pipe */
      88             :                 struct {
      89             :                         int npoll;
      90             :                         int isread;
      91             :                         struct uhci_soft_qh **qhs;
      92             :                 } intr;
      93             :                 /* Bulk pipe */
      94             :                 struct {
      95             :                         struct uhci_soft_qh *sqh;
      96             :                         u_int length;
      97             :                         int isread;
      98             :                 } bulk;
      99             :                 /* Iso pipe */
     100             :                 struct iso {
     101             :                         struct uhci_soft_td **stds;
     102             :                         int next, inuse;
     103             :                 } iso;
     104             :         } u;
     105             : };
     106             : 
     107             : void            uhci_globalreset(struct uhci_softc *);
     108             : usbd_status     uhci_portreset(struct uhci_softc *, int);
     109             : void            uhci_reset(struct uhci_softc *);
     110             : usbd_status     uhci_run(struct uhci_softc *, int run);
     111             : struct uhci_soft_td *uhci_alloc_std(struct uhci_softc *);
     112             : void            uhci_free_std(struct uhci_softc *, struct uhci_soft_td *);
     113             : struct uhci_soft_qh *uhci_alloc_sqh(struct uhci_softc *);
     114             : void            uhci_free_sqh(struct uhci_softc *, struct uhci_soft_qh *);
     115             : 
     116             : void            uhci_free_std_chain(struct uhci_softc *,
     117             :                     struct uhci_soft_td *, struct uhci_soft_td *);
     118             : usbd_status     uhci_alloc_std_chain(struct uhci_softc *, u_int,
     119             :                     struct usbd_xfer *, struct uhci_soft_td **,
     120             :                     struct uhci_soft_td **);
     121             : void            uhci_poll_hub(void *);
     122             : void            uhci_check_intr(struct uhci_softc *, struct usbd_xfer *);
     123             : void            uhci_idone(struct usbd_xfer *);
     124             : 
     125             : void            uhci_abort_xfer(struct usbd_xfer *, usbd_status status);
     126             : 
     127             : void            uhci_timeout(void *);
     128             : void            uhci_timeout_task(void *);
     129             : void            uhci_add_ls_ctrl(struct uhci_softc *, struct uhci_soft_qh *);
     130             : void            uhci_add_hs_ctrl(struct uhci_softc *, struct uhci_soft_qh *);
     131             : void            uhci_add_bulk(struct uhci_softc *, struct uhci_soft_qh *);
     132             : void            uhci_remove_ls_ctrl(struct uhci_softc *, struct uhci_soft_qh *);
     133             : void            uhci_remove_hs_ctrl(struct uhci_softc *, struct uhci_soft_qh *);
     134             : void            uhci_remove_bulk(struct uhci_softc *,struct uhci_soft_qh *);
     135             : void            uhci_add_loop(struct uhci_softc *sc);
     136             : void            uhci_rem_loop(struct uhci_softc *sc);
     137             : 
     138             : usbd_status     uhci_setup_isoc(struct usbd_pipe *pipe);
     139             : void            uhci_device_isoc_enter(struct usbd_xfer *);
     140             : 
     141             : struct usbd_xfer *uhci_allocx(struct usbd_bus *);
     142             : void            uhci_freex(struct usbd_bus *, struct usbd_xfer *);
     143             : 
     144             : usbd_status     uhci_device_ctrl_transfer(struct usbd_xfer *);
     145             : usbd_status     uhci_device_ctrl_start(struct usbd_xfer *);
     146             : void            uhci_device_ctrl_abort(struct usbd_xfer *);
     147             : void            uhci_device_ctrl_close(struct usbd_pipe *);
     148             : void            uhci_device_ctrl_done(struct usbd_xfer *);
     149             : 
     150             : usbd_status     uhci_device_intr_transfer(struct usbd_xfer *);
     151             : usbd_status     uhci_device_intr_start(struct usbd_xfer *);
     152             : void            uhci_device_intr_abort(struct usbd_xfer *);
     153             : void            uhci_device_intr_close(struct usbd_pipe *);
     154             : void            uhci_device_intr_done(struct usbd_xfer *);
     155             : 
     156             : usbd_status     uhci_device_bulk_transfer(struct usbd_xfer *);
     157             : usbd_status     uhci_device_bulk_start(struct usbd_xfer *);
     158             : void            uhci_device_bulk_abort(struct usbd_xfer *);
     159             : void            uhci_device_bulk_close(struct usbd_pipe *);
     160             : void            uhci_device_bulk_done(struct usbd_xfer *);
     161             : 
     162             : usbd_status     uhci_device_isoc_transfer(struct usbd_xfer *);
     163             : usbd_status     uhci_device_isoc_start(struct usbd_xfer *);
     164             : void            uhci_device_isoc_abort(struct usbd_xfer *);
     165             : void            uhci_device_isoc_close(struct usbd_pipe *);
     166             : void            uhci_device_isoc_done(struct usbd_xfer *);
     167             : 
     168             : usbd_status     uhci_root_ctrl_transfer(struct usbd_xfer *);
     169             : usbd_status     uhci_root_ctrl_start(struct usbd_xfer *);
     170             : void            uhci_root_ctrl_abort(struct usbd_xfer *);
     171             : void            uhci_root_ctrl_close(struct usbd_pipe *);
     172             : void            uhci_root_ctrl_done(struct usbd_xfer *);
     173             : 
     174             : usbd_status     uhci_root_intr_transfer(struct usbd_xfer *);
     175             : usbd_status     uhci_root_intr_start(struct usbd_xfer *);
     176             : void            uhci_root_intr_abort(struct usbd_xfer *);
     177             : void            uhci_root_intr_close(struct usbd_pipe *);
     178             : void            uhci_root_intr_done(struct usbd_xfer *);
     179             : 
     180             : usbd_status     uhci_open(struct usbd_pipe *);
     181             : void            uhci_poll(struct usbd_bus *);
     182             : void            uhci_softintr(void *);
     183             : 
     184             : usbd_status     uhci_device_request(struct usbd_xfer *xfer);
     185             : 
     186             : void            uhci_add_intr(struct uhci_softc *, struct uhci_soft_qh *);
     187             : void            uhci_remove_intr(struct uhci_softc *, struct uhci_soft_qh *);
     188             : usbd_status     uhci_device_setintr(struct uhci_softc *sc,
     189             :                     struct uhci_pipe *pipe, int ival);
     190             : 
     191             : void            uhci_device_clear_toggle(struct usbd_pipe *pipe);
     192             : 
     193             : __inline__ struct uhci_soft_qh *uhci_find_prev_qh(struct uhci_soft_qh *,
     194             :                     struct uhci_soft_qh *);
     195             : 
     196             : #ifdef UHCI_DEBUG
     197             : void            uhci_dump_all(struct uhci_softc *);
     198             : void            uhci_dumpregs(struct uhci_softc *);
     199             : void            uhci_dump_qhs(struct uhci_soft_qh *);
     200             : void            uhci_dump_qh(struct uhci_soft_qh *);
     201             : void            uhci_dump_tds(struct uhci_soft_td *);
     202             : void            uhci_dump_td(struct uhci_soft_td *);
     203             : void            uhci_dump_xfer(struct uhci_xfer *);
     204             : void            uhci_dump(void);
     205             : #endif
     206             : 
     207             : #define UBARR(sc) bus_space_barrier((sc)->iot, (sc)->ioh, 0, (sc)->sc_size, \
     208             :                         BUS_SPACE_BARRIER_READ|BUS_SPACE_BARRIER_WRITE)
     209             : #define UWRITE1(sc, r, x) \
     210             :  do { UBARR(sc); bus_space_write_1((sc)->iot, (sc)->ioh, (r), (x)); \
     211             :  } while (/*CONSTCOND*/0)
     212             : #define UWRITE2(sc, r, x) \
     213             :  do { UBARR(sc); bus_space_write_2((sc)->iot, (sc)->ioh, (r), (x)); \
     214             :  } while (/*CONSTCOND*/0)
     215             : #define UWRITE4(sc, r, x) \
     216             :  do { UBARR(sc); bus_space_write_4((sc)->iot, (sc)->ioh, (r), (x)); \
     217             :  } while (/*CONSTCOND*/0)
     218             : 
     219             : __unused static __inline u_int8_t
     220           0 : UREAD1(struct uhci_softc *sc, bus_size_t r)
     221             : {
     222           0 :         UBARR(sc);
     223           0 :         return bus_space_read_1(sc->iot, sc->ioh, r);
     224             : }
     225             : 
     226             : __unused static __inline u_int16_t
     227           0 : UREAD2(struct uhci_softc *sc, bus_size_t r)
     228             : {
     229           0 :         UBARR(sc);
     230           0 :         return bus_space_read_2(sc->iot, sc->ioh, r);
     231             : }
     232             : 
     233             : __unused static __inline u_int32_t
     234             : UREAD4(struct uhci_softc *sc, bus_size_t r)
     235             : {
     236             :         UBARR(sc);
     237             :         return bus_space_read_4(sc->iot, sc->ioh, r);
     238             : }
     239             : 
     240             : #define UHCICMD(sc, cmd) UWRITE2(sc, UHCI_CMD, cmd)
     241             : #define UHCISTS(sc) UREAD2(sc, UHCI_STS)
     242             : 
     243             : #define UHCI_RESET_TIMEOUT 100  /* ms, reset timeout */
     244             : 
     245             : #define UHCI_CURFRAME(sc) (UREAD2(sc, UHCI_FRNUM) & UHCI_FRNUM_MASK)
     246             : 
     247             : #define UHCI_INTR_ENDPT 1
     248             : 
     249             : struct usbd_bus_methods uhci_bus_methods = {
     250             :         .open_pipe = uhci_open,
     251             :         .dev_setaddr = usbd_set_address,
     252             :         .soft_intr = uhci_softintr,
     253             :         .do_poll = uhci_poll,
     254             :         .allocx = uhci_allocx,
     255             :         .freex = uhci_freex,
     256             : };
     257             : 
     258             : struct usbd_pipe_methods uhci_root_ctrl_methods = {
     259             :         .transfer = uhci_root_ctrl_transfer,
     260             :         .start = uhci_root_ctrl_start,
     261             :         .abort = uhci_root_ctrl_abort,
     262             :         .close = uhci_root_ctrl_close,
     263             :         .done = uhci_root_ctrl_done,
     264             : };
     265             : 
     266             : struct usbd_pipe_methods uhci_root_intr_methods = {
     267             :         .transfer = uhci_root_intr_transfer,
     268             :         .start = uhci_root_intr_start,
     269             :         .abort = uhci_root_intr_abort,
     270             :         .close = uhci_root_intr_close,
     271             :         .done = uhci_root_intr_done,
     272             : };
     273             : 
     274             : struct usbd_pipe_methods uhci_device_ctrl_methods = {
     275             :         .transfer = uhci_device_ctrl_transfer,
     276             :         .start = uhci_device_ctrl_start,
     277             :         .abort = uhci_device_ctrl_abort,
     278             :         .close = uhci_device_ctrl_close,
     279             :         .done = uhci_device_ctrl_done,
     280             : };
     281             : 
     282             : struct usbd_pipe_methods uhci_device_intr_methods = {
     283             :         .transfer = uhci_device_intr_transfer,
     284             :         .start = uhci_device_intr_start,
     285             :         .abort = uhci_device_intr_abort,
     286             :         .close = uhci_device_intr_close,
     287             :         .cleartoggle = uhci_device_clear_toggle,
     288             :         .done = uhci_device_intr_done,
     289             : };
     290             : 
     291             : struct usbd_pipe_methods uhci_device_bulk_methods = {
     292             :         .transfer = uhci_device_bulk_transfer,
     293             :         .start = uhci_device_bulk_start,
     294             :         .abort = uhci_device_bulk_abort,
     295             :         .close = uhci_device_bulk_close,
     296             :         .cleartoggle = uhci_device_clear_toggle,
     297             :         .done = uhci_device_bulk_done,
     298             : };
     299             : 
     300             : struct usbd_pipe_methods uhci_device_isoc_methods = {
     301             :         .transfer = uhci_device_isoc_transfer,
     302             :         .start = uhci_device_isoc_start,
     303             :         .abort = uhci_device_isoc_abort,
     304             :         .close = uhci_device_isoc_close,
     305             :         .done = uhci_device_isoc_done,
     306             : };
     307             : 
     308             : #define uhci_add_intr_list(sc, ex) \
     309             :         LIST_INSERT_HEAD(&(sc)->sc_intrhead, (ex), inext)
     310             : #define uhci_del_intr_list(ex) \
     311             :         do { \
     312             :                 LIST_REMOVE((ex), inext); \
     313             :                 (ex)->inext.le_prev = NULL; \
     314             :         } while (0)
     315             : #define uhci_active_intr_list(ex) ((ex)->inext.le_prev != NULL)
     316             : 
     317             : __inline__ struct uhci_soft_qh *
     318           0 : uhci_find_prev_qh(struct uhci_soft_qh *pqh, struct uhci_soft_qh *sqh)
     319             : {
     320             :         DPRINTFN(15,("uhci_find_prev_qh: pqh=%p sqh=%p\n", pqh, sqh));
     321             : 
     322           0 :         for (; pqh->hlink != sqh; pqh = pqh->hlink) {
     323             : #if defined(DIAGNOSTIC) || defined(UHCI_DEBUG)
     324           0 :                 if (letoh32(pqh->qh.qh_hlink) & UHCI_PTR_T) {
     325           0 :                         printf("uhci_find_prev_qh: QH not found\n");
     326           0 :                         return (NULL);
     327             :                 }
     328             : #endif
     329             :         }
     330           0 :         return (pqh);
     331           0 : }
     332             : 
     333             : void
     334           0 : uhci_globalreset(struct uhci_softc *sc)
     335             : {
     336           0 :         UHCICMD(sc, UHCI_CMD_GRESET);   /* global reset */
     337           0 :         usb_delay_ms(&sc->sc_bus, USB_BUS_RESET_DELAY); /* wait a little */
     338           0 :         UHCICMD(sc, 0);                 /* do nothing */
     339           0 : }
     340             : 
     341             : usbd_status
     342           0 : uhci_init(struct uhci_softc *sc)
     343             : {
     344             :         usbd_status err;
     345             :         int i, j;
     346             :         struct uhci_soft_qh *clsqh, *chsqh, *bsqh, *sqh, *lsqh;
     347             :         struct uhci_soft_td *std;
     348             : 
     349             :         DPRINTFN(1,("uhci_init: start\n"));
     350             : 
     351             : #ifdef UHCI_DEBUG
     352             :         thesc = sc;
     353             : 
     354             :         if (uhcidebug > 2)
     355             :                 uhci_dumpregs(sc);
     356             : #endif
     357             : 
     358             :         /* Save SOF over HC reset. */
     359           0 :         sc->sc_saved_sof = UREAD1(sc, UHCI_SOF);
     360             : 
     361           0 :         UWRITE2(sc, UHCI_INTR, 0);              /* disable interrupts */
     362           0 :         uhci_globalreset(sc);                   /* reset the controller */
     363           0 :         uhci_reset(sc);
     364             : 
     365           0 :         if (uhcixfer == NULL) {
     366           0 :                 uhcixfer = malloc(sizeof(struct pool), M_DEVBUF, M_NOWAIT);
     367           0 :                 if (uhcixfer == NULL) {
     368           0 :                         printf("%s: unable to allocate pool descriptor\n",
     369           0 :                             sc->sc_bus.bdev.dv_xname);
     370           0 :                         return (ENOMEM);
     371             :                 }
     372           0 :                 pool_init(uhcixfer, sizeof(struct uhci_xfer), 0, IPL_SOFTUSB,
     373             :                     0, "uhcixfer", NULL);
     374           0 :         }
     375             : 
     376             :         /* Restore saved SOF. */
     377           0 :         UWRITE1(sc, UHCI_SOF, sc->sc_saved_sof);
     378             : 
     379             :         /* Allocate and initialize real frame array. */
     380           0 :         err = usb_allocmem(&sc->sc_bus,
     381             :                   UHCI_FRAMELIST_COUNT * sizeof(uhci_physaddr_t),
     382           0 :                   UHCI_FRAMELIST_ALIGN, &sc->sc_dma);
     383           0 :         if (err)
     384           0 :                 return (err);
     385           0 :         sc->sc_pframes = KERNADDR(&sc->sc_dma, 0);
     386           0 :         UWRITE2(sc, UHCI_FRNUM, 0);             /* set frame number to 0 */
     387           0 :         UWRITE4(sc, UHCI_FLBASEADDR, DMAADDR(&sc->sc_dma, 0)); /* set frame list*/
     388             : 
     389             :         /*
     390             :          * Allocate a TD, inactive, that hangs from the last QH.
     391             :          * This is to avoid a bug in the PIIX that makes it run berserk
     392             :          * otherwise.
     393             :          */
     394           0 :         std = uhci_alloc_std(sc);
     395           0 :         if (std == NULL)
     396           0 :                 return (USBD_NOMEM);
     397           0 :         std->link.std = NULL;
     398           0 :         std->td.td_link = htole32(UHCI_PTR_T);
     399           0 :         std->td.td_status = htole32(0); /* inactive */
     400           0 :         std->td.td_token = htole32(0);
     401           0 :         std->td.td_buffer = htole32(0);
     402             : 
     403             :         /* Allocate the dummy QH marking the end and used for looping the QHs.*/
     404           0 :         lsqh = uhci_alloc_sqh(sc);
     405           0 :         if (lsqh == NULL)
     406           0 :                 return (USBD_NOMEM);
     407           0 :         lsqh->hlink = NULL;
     408           0 :         lsqh->qh.qh_hlink = htole32(UHCI_PTR_T);     /* end of QH chain */
     409           0 :         lsqh->elink = std;
     410           0 :         lsqh->qh.qh_elink = htole32(std->physaddr | UHCI_PTR_TD);
     411           0 :         sc->sc_last_qh = lsqh;
     412             : 
     413             :         /* Allocate the dummy QH where bulk traffic will be queued. */
     414           0 :         bsqh = uhci_alloc_sqh(sc);
     415           0 :         if (bsqh == NULL)
     416           0 :                 return (USBD_NOMEM);
     417           0 :         bsqh->hlink = lsqh;
     418           0 :         bsqh->qh.qh_hlink = htole32(lsqh->physaddr | UHCI_PTR_QH);
     419           0 :         bsqh->elink = NULL;
     420           0 :         bsqh->qh.qh_elink = htole32(UHCI_PTR_T);
     421           0 :         sc->sc_bulk_start = sc->sc_bulk_end = bsqh;
     422             : 
     423             :         /* Allocate dummy QH where high speed control traffic will be queued. */
     424           0 :         chsqh = uhci_alloc_sqh(sc);
     425           0 :         if (chsqh == NULL)
     426           0 :                 return (USBD_NOMEM);
     427           0 :         chsqh->hlink = bsqh;
     428           0 :         chsqh->qh.qh_hlink = htole32(bsqh->physaddr | UHCI_PTR_QH);
     429           0 :         chsqh->elink = NULL;
     430           0 :         chsqh->qh.qh_elink = htole32(UHCI_PTR_T);
     431           0 :         sc->sc_hctl_start = sc->sc_hctl_end = chsqh;
     432             : 
     433             :         /* Allocate dummy QH where control traffic will be queued. */
     434           0 :         clsqh = uhci_alloc_sqh(sc);
     435           0 :         if (clsqh == NULL)
     436           0 :                 return (USBD_NOMEM);
     437           0 :         clsqh->hlink = chsqh;
     438           0 :         clsqh->qh.qh_hlink = htole32(chsqh->physaddr | UHCI_PTR_QH);
     439           0 :         clsqh->elink = NULL;
     440           0 :         clsqh->qh.qh_elink = htole32(UHCI_PTR_T);
     441           0 :         sc->sc_lctl_start = sc->sc_lctl_end = clsqh;
     442             : 
     443             :         /*
     444             :          * Make all (virtual) frame list pointers point to the interrupt
     445             :          * queue heads and the interrupt queue heads at the control
     446             :          * queue head and point the physical frame list to the virtual.
     447             :          */
     448           0 :         for(i = 0; i < UHCI_VFRAMELIST_COUNT; i++) {
     449           0 :                 std = uhci_alloc_std(sc);
     450           0 :                 sqh = uhci_alloc_sqh(sc);
     451           0 :                 if (std == NULL || sqh == NULL)
     452           0 :                         return (USBD_NOMEM);
     453           0 :                 std->link.sqh = sqh;
     454           0 :                 std->td.td_link = htole32(sqh->physaddr | UHCI_PTR_QH);
     455           0 :                 std->td.td_status = htole32(UHCI_TD_IOS); /* iso, inactive */
     456           0 :                 std->td.td_token = htole32(0);
     457           0 :                 std->td.td_buffer = htole32(0);
     458           0 :                 sqh->hlink = clsqh;
     459           0 :                 sqh->qh.qh_hlink = htole32(clsqh->physaddr | UHCI_PTR_QH);
     460           0 :                 sqh->elink = NULL;
     461           0 :                 sqh->qh.qh_elink = htole32(UHCI_PTR_T);
     462           0 :                 sc->sc_vframes[i].htd = std;
     463           0 :                 sc->sc_vframes[i].etd = std;
     464           0 :                 sc->sc_vframes[i].hqh = sqh;
     465           0 :                 sc->sc_vframes[i].eqh = sqh;
     466           0 :                 for (j = i;
     467           0 :                      j < UHCI_FRAMELIST_COUNT;
     468           0 :                      j += UHCI_VFRAMELIST_COUNT)
     469           0 :                         sc->sc_pframes[j] = htole32(std->physaddr);
     470             :         }
     471             : 
     472           0 :         LIST_INIT(&sc->sc_intrhead);
     473             : 
     474           0 :         timeout_set(&sc->sc_root_intr, uhci_poll_hub, sc);
     475             : 
     476             :         /* Set up the bus struct. */
     477           0 :         sc->sc_bus.methods = &uhci_bus_methods;
     478           0 :         sc->sc_bus.pipe_size = sizeof(struct uhci_pipe);
     479             : 
     480           0 :         sc->sc_suspend = DVACT_RESUME;
     481             : 
     482           0 :         UHCICMD(sc, UHCI_CMD_MAXP); /* Assume 64 byte packets at frame end */
     483             : 
     484             :         DPRINTFN(1,("uhci_init: enabling\n"));
     485           0 :         UWRITE2(sc, UHCI_INTR, UHCI_INTR_TOCRCIE | UHCI_INTR_RIE |
     486             :                 UHCI_INTR_IOCE | UHCI_INTR_SPIE);       /* enable interrupts */
     487             : 
     488           0 :         return (uhci_run(sc, 1));               /* and here we go... */
     489           0 : }
     490             : 
     491             : int
     492           0 : uhci_activate(struct device *self, int act)
     493             : {
     494           0 :         struct uhci_softc *sc = (struct uhci_softc *)self;
     495             :         int cmd, rv = 0;
     496             : 
     497           0 :         switch (act) {
     498             :         case DVACT_SUSPEND:
     499             : #ifdef UHCI_DEBUG
     500             :                 if (uhcidebug > 2)
     501             :                         uhci_dumpregs(sc);
     502             : #endif
     503           0 :                 rv = config_activate_children(self, act);
     504           0 :                 sc->sc_bus.use_polling++;
     505           0 :                 uhci_run(sc, 0); /* stop the controller */
     506             : 
     507             :                 /* save some state if BIOS doesn't */
     508           0 :                 sc->sc_saved_frnum = UREAD2(sc, UHCI_FRNUM);
     509             : 
     510           0 :                 UWRITE2(sc, UHCI_INTR, 0); /* disable intrs */
     511             : 
     512           0 :                 cmd = UREAD2(sc, UHCI_CMD);
     513           0 :                 UHCICMD(sc, cmd | UHCI_CMD_EGSM); /* enter global suspend */
     514           0 :                 usb_delay_ms(&sc->sc_bus, USB_RESUME_WAIT);
     515           0 :                 sc->sc_suspend = act;
     516           0 :                 sc->sc_bus.use_polling--;
     517             :                 DPRINTF(("uhci_activate: cmd=0x%x\n", UREAD2(sc, UHCI_CMD)));
     518           0 :                 break;
     519             :         case DVACT_POWERDOWN:
     520           0 :                 rv = config_activate_children(self, act);
     521           0 :                 uhci_run(sc, 0); /* stop the controller */
     522           0 :                 break;
     523             :         case DVACT_RESUME:
     524             : #ifdef DIAGNOSTIC
     525           0 :                 if (sc->sc_suspend == DVACT_RESUME)
     526           0 :                         printf("uhci_powerhook: weird, resume without suspend.\n");
     527             : #endif
     528           0 :                 sc->sc_bus.use_polling++;
     529           0 :                 sc->sc_suspend = act;
     530           0 :                 cmd = UREAD2(sc, UHCI_CMD);
     531           0 :                 if (cmd & UHCI_CMD_RS)
     532           0 :                         uhci_run(sc, 0); /* in case BIOS has started it */
     533             : 
     534             :                 /* restore saved state */
     535           0 :                 UWRITE4(sc, UHCI_FLBASEADDR, DMAADDR(&sc->sc_dma, 0));
     536           0 :                 UWRITE2(sc, UHCI_FRNUM, sc->sc_saved_frnum);
     537           0 :                 UWRITE1(sc, UHCI_SOF, sc->sc_saved_sof);
     538             : 
     539           0 :                 UHCICMD(sc, cmd | UHCI_CMD_FGR); /* force global resume */
     540           0 :                 usb_delay_ms(&sc->sc_bus, USB_RESUME_DELAY);
     541           0 :                 UHCICMD(sc, cmd & ~UHCI_CMD_EGSM); /* back to normal */
     542           0 :                 UHCICMD(sc, UHCI_CMD_MAXP);
     543           0 :                 UWRITE2(sc, UHCI_INTR, UHCI_INTR_TOCRCIE | UHCI_INTR_RIE |
     544             :                         UHCI_INTR_IOCE | UHCI_INTR_SPIE); /* re-enable intrs */
     545           0 :                 uhci_run(sc, 1); /* and start traffic again */
     546           0 :                 usb_delay_ms(&sc->sc_bus, USB_RESUME_RECOVERY);
     547           0 :                 sc->sc_bus.use_polling--;
     548             : #ifdef UHCI_DEBUG
     549             :                 if (uhcidebug > 2)
     550             :                         uhci_dumpregs(sc);
     551             : #endif
     552           0 :                 rv = config_activate_children(self, act);
     553           0 :                 break;
     554             :         default:
     555           0 :                 rv = config_activate_children(self, act);
     556           0 :                 break;
     557             :         }
     558           0 :         return (rv);
     559             : }
     560             : 
     561             : int
     562           0 : uhci_detach(struct device *self, int flags)
     563             : {
     564             : #ifdef DIAGNOSTIC
     565           0 :         struct uhci_softc *sc = (struct uhci_softc *)self;
     566             : #endif
     567             :         int rv;
     568             : 
     569           0 :         rv = config_detach_children(self, flags);
     570           0 :         if (rv != 0)
     571           0 :                 return (rv);
     572             : 
     573           0 :         KASSERT(sc->sc_intrxfer == NULL);
     574             : 
     575             :         /* XXX free other data structures XXX */
     576             : 
     577           0 :         return (rv);
     578           0 : }
     579             : 
     580             : struct usbd_xfer *
     581           0 : uhci_allocx(struct usbd_bus *bus)
     582             : {
     583             :         struct uhci_xfer *ux;
     584             : 
     585           0 :         ux = pool_get(uhcixfer, PR_NOWAIT | PR_ZERO);
     586             : #ifdef DIAGNOSTIC
     587           0 :         if (ux != NULL)
     588           0 :                 ux->isdone = 1;
     589             : #endif
     590           0 :         return ((struct usbd_xfer *)ux);
     591             : }
     592             : 
     593             : void
     594           0 : uhci_freex(struct usbd_bus *bus, struct usbd_xfer *xfer)
     595             : {
     596           0 :         struct uhci_xfer *ux = (struct uhci_xfer*)xfer;
     597             : 
     598             : #ifdef DIAGNOSTIC
     599           0 :         if (!ux->isdone) {
     600           0 :                 printf("%s: !isdone\n", __func__);
     601           0 :                 return;
     602             :         }
     603             : #endif
     604           0 :         pool_put(uhcixfer, ux);
     605           0 : }
     606             : 
     607             : #ifdef UHCI_DEBUG
     608             : void
     609             : uhci_dumpregs(struct uhci_softc *sc)
     610             : {
     611             :         DPRINTFN(-1,("%s regs: cmd=%04x, sts=%04x, intr=%04x, frnum=%04x, "
     612             :                      "flbase=%08x, sof=%04x, portsc1=%04x, portsc2=%04x\n",
     613             :                      sc->sc_bus.bdev.dv_xname,
     614             :                      UREAD2(sc, UHCI_CMD),
     615             :                      UREAD2(sc, UHCI_STS),
     616             :                      UREAD2(sc, UHCI_INTR),
     617             :                      UREAD2(sc, UHCI_FRNUM),
     618             :                      UREAD4(sc, UHCI_FLBASEADDR),
     619             :                      UREAD1(sc, UHCI_SOF),
     620             :                      UREAD2(sc, UHCI_PORTSC1),
     621             :                      UREAD2(sc, UHCI_PORTSC2)));
     622             : }
     623             : 
     624             : void
     625             : uhci_dump_td(struct uhci_soft_td *p)
     626             : {
     627             :         char sbuf[128], sbuf2[128];
     628             : 
     629             :         DPRINTFN(-1,("TD(%p) at %08lx = link=0x%08lx status=0x%08lx "
     630             :                      "token=0x%08lx buffer=0x%08lx\n",
     631             :                      p, (long)p->physaddr,
     632             :                      (long)letoh32(p->td.td_link),
     633             :                      (long)letoh32(p->td.td_status),
     634             :                      (long)letoh32(p->td.td_token),
     635             :                      (long)letoh32(p->td.td_buffer)));
     636             : 
     637             :         bitmask_snprintf((u_int32_t)letoh32(p->td.td_link), "\20\1T\2Q\3VF",
     638             :                          sbuf, sizeof(sbuf));
     639             :         bitmask_snprintf((u_int32_t)letoh32(p->td.td_status),
     640             :                          "\20\22BITSTUFF\23CRCTO\24NAK\25BABBLE\26DBUFFER\27"
     641             :                          "STALLED\30ACTIVE\31IOC\32ISO\33LS\36SPD",
     642             :                          sbuf2, sizeof(sbuf2));
     643             : 
     644             :         DPRINTFN(-1,("  %s %s,errcnt=%d,actlen=%d pid=%02x,addr=%d,endpt=%d,"
     645             :                      "D=%d,maxlen=%d\n", sbuf, sbuf2,
     646             :                      UHCI_TD_GET_ERRCNT(letoh32(p->td.td_status)),
     647             :                      UHCI_TD_GET_ACTLEN(letoh32(p->td.td_status)),
     648             :                      UHCI_TD_GET_PID(letoh32(p->td.td_token)),
     649             :                      UHCI_TD_GET_DEVADDR(letoh32(p->td.td_token)),
     650             :                      UHCI_TD_GET_ENDPT(letoh32(p->td.td_token)),
     651             :                      UHCI_TD_GET_DT(letoh32(p->td.td_token)),
     652             :                      UHCI_TD_GET_MAXLEN(letoh32(p->td.td_token))));
     653             : }
     654             : 
     655             : void
     656             : uhci_dump_qh(struct uhci_soft_qh *sqh)
     657             : {
     658             :         DPRINTFN(-1,("QH(%p) at %08x: hlink=%08x elink=%08x\n", sqh,
     659             :             (int)sqh->physaddr, letoh32(sqh->qh.qh_hlink),
     660             :             letoh32(sqh->qh.qh_elink)));
     661             : }
     662             : 
     663             : 
     664             : void
     665             : uhci_dump(void)
     666             : {
     667             :         uhci_dump_all(thesc);
     668             : }
     669             : 
     670             : void
     671             : uhci_dump_all(struct uhci_softc *sc)
     672             : {
     673             :         uhci_dumpregs(sc);
     674             :         printf("intrs=%d\n", sc->sc_bus.no_intrs);
     675             :         /*printf("framelist[i].link = %08x\n", sc->sc_framelist[0].link);*/
     676             :         uhci_dump_qh(sc->sc_lctl_start);
     677             : }
     678             : 
     679             : 
     680             : void
     681             : uhci_dump_qhs(struct uhci_soft_qh *sqh)
     682             : {
     683             :         uhci_dump_qh(sqh);
     684             : 
     685             :         /* uhci_dump_qhs displays all the QHs and TDs from the given QH onwards
     686             :          * Traverses sideways first, then down.
     687             :          *
     688             :          * QH1
     689             :          * QH2
     690             :          * No QH
     691             :          * TD2.1
     692             :          * TD2.2
     693             :          * TD1.1
     694             :          * etc.
     695             :          *
     696             :          * TD2.x being the TDs queued at QH2 and QH1 being referenced from QH1.
     697             :          */
     698             : 
     699             : 
     700             :         if (sqh->hlink != NULL && !(letoh32(sqh->qh.qh_hlink) & UHCI_PTR_T))
     701             :                 uhci_dump_qhs(sqh->hlink);
     702             :         else
     703             :                 DPRINTF(("No QH\n"));
     704             : 
     705             :         if (sqh->elink != NULL && !(letoh32(sqh->qh.qh_elink) & UHCI_PTR_T))
     706             :                 uhci_dump_tds(sqh->elink);
     707             :         else
     708             :                 DPRINTF(("No TD\n"));
     709             : }
     710             : 
     711             : void
     712             : uhci_dump_tds(struct uhci_soft_td *std)
     713             : {
     714             :         struct uhci_soft_td *td;
     715             : 
     716             :         for(td = std; td != NULL; td = td->link.std) {
     717             :                 uhci_dump_td(td);
     718             : 
     719             :                 /* Check whether the link pointer in this TD marks
     720             :                  * the link pointer as end of queue. This avoids
     721             :                  * printing the free list in case the queue/TD has
     722             :                  * already been moved there (seatbelt).
     723             :                  */
     724             :                 if (letoh32(td->td.td_link) & UHCI_PTR_T ||
     725             :                     letoh32(td->td.td_link) == 0)
     726             :                         break;
     727             :         }
     728             : }
     729             : 
     730             : void
     731             : uhci_dump_xfer(struct uhci_xfer *ex)
     732             : {
     733             :         struct usbd_pipe *pipe;
     734             :         usb_endpoint_descriptor_t *ed;
     735             :         struct usbd_device *dev;
     736             : 
     737             : #ifdef DIAGNOSTIC
     738             : #define DONE ex->isdone
     739             : #else
     740             : #define DONE 0
     741             : #endif
     742             :         if (ex == NULL) {
     743             :                 printf("ex NULL\n");
     744             :                 return;
     745             :         }
     746             :         pipe = ex->xfer.pipe;
     747             :         if (pipe == NULL) {
     748             :                 printf("ex %p: done=%d pipe=NULL\n",
     749             :                        ex, DONE);
     750             :                 return;
     751             :         }
     752             :         if (pipe->endpoint == NULL) {
     753             :                 printf("ex %p: done=%d pipe=%p pipe->endpoint=NULL\n",
     754             :                        ex, DONE, pipe);
     755             :                 return;
     756             :         }
     757             :         if (pipe->device == NULL) {
     758             :                 printf("ex %p: done=%d pipe=%p pipe->device=NULL\n",
     759             :                        ex, DONE, pipe);
     760             :                 return;
     761             :         }
     762             :         ed = pipe->endpoint->edesc;
     763             :         dev = pipe->device;
     764             :         printf("ex %p: done=%d dev=%p vid=0x%04x pid=0x%04x addr=%d pipe=%p ep=0x%02x attr=0x%02x\n",
     765             :                ex, DONE, dev,
     766             :                UGETW(dev->ddesc.idVendor),
     767             :                UGETW(dev->ddesc.idProduct),
     768             :                dev->address, pipe,
     769             :                ed->bEndpointAddress, ed->bmAttributes);
     770             : #undef DONE
     771             : }
     772             : 
     773             : void uhci_dump_xfers(struct uhci_softc *sc);
     774             : void
     775             : uhci_dump_xfers(struct uhci_softc *sc)
     776             : {
     777             :         struct uhci_xfer *ex;
     778             : 
     779             :         printf("ex list:\n");
     780             :         for (ex = LIST_FIRST(&sc->sc_intrhead); ex; ex = LIST_NEXT(ex, inext))
     781             :                 uhci_dump_xfer(ex);
     782             : }
     783             : 
     784             : void exdump(void);
     785             : void exdump(void) { uhci_dump_xfers(thesc); }
     786             : 
     787             : #endif
     788             : 
     789             : /*
     790             :  * This routine is executed periodically and simulates interrupts
     791             :  * from the root controller interrupt pipe for port status change.
     792             :  */
     793             : void
     794           0 : uhci_poll_hub(void *addr)
     795             : {
     796           0 :         struct uhci_softc *sc = addr;
     797             :         struct usbd_xfer *xfer;
     798             :         int s;
     799             :         u_char *p;
     800             : 
     801           0 :         if (sc->sc_bus.dying)
     802           0 :                 return;
     803             : 
     804           0 :         xfer = sc->sc_intrxfer;
     805           0 :         if (xfer == NULL)
     806           0 :                 return;
     807             : 
     808           0 :         p = KERNADDR(&xfer->dmabuf, 0);
     809           0 :         p[0] = 0;
     810           0 :         if (UREAD2(sc, UHCI_PORTSC1) & (UHCI_PORTSC_CSC|UHCI_PORTSC_OCIC))
     811           0 :                 p[0] |= 1<<1;
     812           0 :         if (UREAD2(sc, UHCI_PORTSC2) & (UHCI_PORTSC_CSC|UHCI_PORTSC_OCIC))
     813           0 :                 p[0] |= 1<<2;
     814           0 :         if (p[0] == 0) {
     815             :                 /* No change, try again in a while */
     816           0 :                 timeout_add_msec(&sc->sc_root_intr, 255);
     817           0 :                 return;
     818             :         }
     819             : 
     820           0 :         xfer->actlen = xfer->length;
     821           0 :         xfer->status = USBD_NORMAL_COMPLETION;
     822             : 
     823           0 :         s = splusb();
     824           0 :         xfer->device->bus->intr_context++;
     825           0 :         usb_transfer_complete(xfer);
     826           0 :         xfer->device->bus->intr_context--;
     827           0 :         splx(s);
     828           0 : }
     829             : 
     830             : void
     831           0 : uhci_root_ctrl_done(struct usbd_xfer *xfer)
     832             : {
     833           0 : }
     834             : 
     835             : /*
     836             :  * Let the last QH loop back to the high speed control transfer QH.
     837             :  * This is what intel calls "bandwidth reclamation" and improves
     838             :  * USB performance a lot for some devices.
     839             :  * If we are already looping, just count it.
     840             :  */
     841             : void
     842           0 : uhci_add_loop(struct uhci_softc *sc) {
     843             : #ifdef UHCI_DEBUG
     844             :         if (uhcinoloop)
     845             :                 return;
     846             : #endif
     847           0 :         if (++sc->sc_loops == 1) {
     848             :                 DPRINTFN(5,("uhci_add_loop\n"));
     849             :                 /* Note, we don't loop back the soft pointer. */
     850           0 :                 sc->sc_last_qh->qh.qh_hlink =
     851           0 :                     htole32(sc->sc_hctl_start->physaddr | UHCI_PTR_QH);
     852           0 :         }
     853           0 : }
     854             : 
     855             : void
     856           0 : uhci_rem_loop(struct uhci_softc *sc) {
     857             : #ifdef UHCI_DEBUG
     858             :         if (uhcinoloop)
     859             :                 return;
     860             : #endif
     861           0 :         if (--sc->sc_loops == 0) {
     862             :                 DPRINTFN(5,("uhci_rem_loop\n"));
     863           0 :                 sc->sc_last_qh->qh.qh_hlink = htole32(UHCI_PTR_T);
     864           0 :         }
     865           0 : }
     866             : 
     867             : /* Add high speed control QH, called at splusb(). */
     868             : void
     869           0 : uhci_add_hs_ctrl(struct uhci_softc *sc, struct uhci_soft_qh *sqh)
     870             : {
     871             :         struct uhci_soft_qh *eqh;
     872             : 
     873           0 :         splsoftassert(IPL_SOFTUSB);
     874             : 
     875             :         DPRINTFN(10, ("uhci_add_hs_ctrl: sqh=%p\n", sqh));
     876           0 :         eqh = sc->sc_hctl_end;
     877           0 :         sqh->hlink       = eqh->hlink;
     878           0 :         sqh->qh.qh_hlink = eqh->qh.qh_hlink;
     879           0 :         eqh->hlink       = sqh;
     880           0 :         eqh->qh.qh_hlink = htole32(sqh->physaddr | UHCI_PTR_QH);
     881           0 :         sc->sc_hctl_end = sqh;
     882             : #ifdef UHCI_CTL_LOOP
     883             :         uhci_add_loop(sc);
     884             : #endif
     885           0 : }
     886             : 
     887             : /* Remove high speed control QH, called at splusb(). */
     888             : void
     889           0 : uhci_remove_hs_ctrl(struct uhci_softc *sc, struct uhci_soft_qh *sqh)
     890             : {
     891             :         struct uhci_soft_qh *pqh;
     892             : 
     893           0 :         splsoftassert(IPL_SOFTUSB);
     894             : 
     895             :         DPRINTFN(10, ("uhci_remove_hs_ctrl: sqh=%p\n", sqh));
     896             : #ifdef UHCI_CTL_LOOP
     897             :         uhci_rem_loop(sc);
     898             : #endif
     899             :         /*
     900             :          * The T bit should be set in the elink of the QH so that the HC
     901             :          * doesn't follow the pointer.  This condition may fail if the
     902             :          * the transferred packet was short so that the QH still points
     903             :          * at the last used TD.
     904             :          * In this case we set the T bit and wait a little for the HC
     905             :          * to stop looking at the TD.
     906             :          */
     907           0 :         if (!(sqh->qh.qh_elink & htole32(UHCI_PTR_T))) {
     908           0 :                 sqh->qh.qh_elink = htole32(UHCI_PTR_T);
     909           0 :                 delay(UHCI_QH_REMOVE_DELAY);
     910           0 :         }
     911             : 
     912           0 :         pqh = uhci_find_prev_qh(sc->sc_hctl_start, sqh);
     913           0 :         pqh->hlink = sqh->hlink;
     914           0 :         pqh->qh.qh_hlink = sqh->qh.qh_hlink;
     915           0 :         delay(UHCI_QH_REMOVE_DELAY);
     916           0 :         if (sc->sc_hctl_end == sqh)
     917           0 :                 sc->sc_hctl_end = pqh;
     918           0 : }
     919             : 
     920             : /* Add low speed control QH, called at splusb(). */
     921             : void
     922           0 : uhci_add_ls_ctrl(struct uhci_softc *sc, struct uhci_soft_qh *sqh)
     923             : {
     924             :         struct uhci_soft_qh *eqh;
     925             : 
     926           0 :         splsoftassert(IPL_SOFTUSB);
     927             : 
     928             :         DPRINTFN(10, ("uhci_add_ls_ctrl: sqh=%p\n", sqh));
     929           0 :         eqh = sc->sc_lctl_end;
     930           0 :         sqh->hlink = eqh->hlink;
     931           0 :         sqh->qh.qh_hlink = eqh->qh.qh_hlink;
     932           0 :         eqh->hlink = sqh;
     933           0 :         eqh->qh.qh_hlink = htole32(sqh->physaddr | UHCI_PTR_QH);
     934           0 :         sc->sc_lctl_end = sqh;
     935           0 : }
     936             : 
     937             : /* Remove low speed control QH, called at splusb(). */
     938             : void
     939           0 : uhci_remove_ls_ctrl(struct uhci_softc *sc, struct uhci_soft_qh *sqh)
     940             : {
     941             :         struct uhci_soft_qh *pqh;
     942             : 
     943           0 :         splsoftassert(IPL_SOFTUSB);
     944             : 
     945             :         DPRINTFN(10, ("uhci_remove_ls_ctrl: sqh=%p\n", sqh));
     946             :         /* See comment in uhci_remove_hs_ctrl() */
     947           0 :         if (!(sqh->qh.qh_elink & htole32(UHCI_PTR_T))) {
     948           0 :                 sqh->qh.qh_elink = htole32(UHCI_PTR_T);
     949           0 :                 delay(UHCI_QH_REMOVE_DELAY);
     950           0 :         }
     951           0 :         pqh = uhci_find_prev_qh(sc->sc_lctl_start, sqh);
     952           0 :         pqh->hlink = sqh->hlink;
     953           0 :         pqh->qh.qh_hlink = sqh->qh.qh_hlink;
     954           0 :         delay(UHCI_QH_REMOVE_DELAY);
     955           0 :         if (sc->sc_lctl_end == sqh)
     956           0 :                 sc->sc_lctl_end = pqh;
     957           0 : }
     958             : 
     959             : /* Add bulk QH, called at splusb(). */
     960             : void
     961           0 : uhci_add_bulk(struct uhci_softc *sc, struct uhci_soft_qh *sqh)
     962             : {
     963             :         struct uhci_soft_qh *eqh;
     964             : 
     965           0 :         splsoftassert(IPL_SOFTUSB);
     966             : 
     967             :         DPRINTFN(10, ("uhci_add_bulk: sqh=%p\n", sqh));
     968           0 :         eqh = sc->sc_bulk_end;
     969           0 :         sqh->hlink = eqh->hlink;
     970           0 :         sqh->qh.qh_hlink = eqh->qh.qh_hlink;
     971           0 :         eqh->hlink = sqh;
     972           0 :         eqh->qh.qh_hlink = htole32(sqh->physaddr | UHCI_PTR_QH);
     973           0 :         sc->sc_bulk_end = sqh;
     974           0 :         uhci_add_loop(sc);
     975           0 : }
     976             : 
     977             : /* Remove bulk QH, called at splusb(). */
     978             : void
     979           0 : uhci_remove_bulk(struct uhci_softc *sc, struct uhci_soft_qh *sqh)
     980             : {
     981             :         struct uhci_soft_qh *pqh;
     982             : 
     983           0 :         splsoftassert(IPL_SOFTUSB);
     984             : 
     985             :         DPRINTFN(10, ("uhci_remove_bulk: sqh=%p\n", sqh));
     986           0 :         uhci_rem_loop(sc);
     987             :         /* See comment in uhci_remove_hs_ctrl() */
     988           0 :         if (!(sqh->qh.qh_elink & htole32(UHCI_PTR_T))) {
     989           0 :                 sqh->qh.qh_elink = htole32(UHCI_PTR_T);
     990           0 :                 delay(UHCI_QH_REMOVE_DELAY);
     991           0 :         }
     992           0 :         pqh = uhci_find_prev_qh(sc->sc_bulk_start, sqh);
     993           0 :         pqh->hlink       = sqh->hlink;
     994           0 :         pqh->qh.qh_hlink = sqh->qh.qh_hlink;
     995           0 :         delay(UHCI_QH_REMOVE_DELAY);
     996           0 :         if (sc->sc_bulk_end == sqh)
     997           0 :                 sc->sc_bulk_end = pqh;
     998           0 : }
     999             : 
    1000             : int uhci_intr1(struct uhci_softc *);
    1001             : 
    1002             : int
    1003           0 : uhci_intr(void *arg)
    1004             : {
    1005           0 :         struct uhci_softc *sc = arg;
    1006             : 
    1007           0 :         if (sc->sc_bus.dying)
    1008           0 :                 return (0);
    1009           0 :         if (sc->sc_bus.use_polling)
    1010           0 :                 return (0);
    1011           0 :         return (uhci_intr1(sc));
    1012           0 : }
    1013             : 
    1014             : int
    1015           0 : uhci_intr1(struct uhci_softc *sc)
    1016             : {
    1017             :         int status;
    1018             :         int ack;
    1019             : 
    1020           0 :         status = UREAD2(sc, UHCI_STS);
    1021           0 :         if (status == 0xffff) {
    1022           0 :                 sc->sc_bus.dying = 1;
    1023           0 :                 return (0);
    1024             :         }
    1025           0 :         status &= UHCI_STS_ALLINTRS;
    1026           0 :         if (status == 0)        /* The interrupt was not for us. */
    1027           0 :                 return (0);
    1028             : 
    1029             : #ifdef UHCI_DEBUG
    1030             :         if (uhcidebug > 15) {
    1031             :                 DPRINTF(("%s: uhci_intr1\n", sc->sc_bus.bdev.dv_xname));
    1032             :                 uhci_dumpregs(sc);
    1033             :         }
    1034             : #endif
    1035             : 
    1036           0 :         if (sc->sc_suspend != DVACT_RESUME) {
    1037           0 :                 printf("%s: interrupt while not operating ignored\n",
    1038           0 :                        sc->sc_bus.bdev.dv_xname);
    1039           0 :                 return (0);
    1040             :         }
    1041             : 
    1042             :         ack = 0;
    1043           0 :         if (status & UHCI_STS_USBINT)
    1044           0 :                 ack |= UHCI_STS_USBINT;
    1045           0 :         if (status & UHCI_STS_USBEI)
    1046           0 :                 ack |= UHCI_STS_USBEI;
    1047           0 :         if (status & UHCI_STS_RD) {
    1048           0 :                 ack |= UHCI_STS_RD;
    1049             : #ifdef UHCI_DEBUG
    1050             :                 printf("%s: resume detect\n", sc->sc_bus.bdev.dv_xname);
    1051             : #endif
    1052           0 :         }
    1053           0 :         if (status & UHCI_STS_HSE) {
    1054           0 :                 ack |= UHCI_STS_HSE;
    1055           0 :                 printf("%s: host system error\n", sc->sc_bus.bdev.dv_xname);
    1056           0 :         }
    1057           0 :         if (status & UHCI_STS_HCPE) {
    1058           0 :                 ack |= UHCI_STS_HCPE;
    1059           0 :                 printf("%s: host controller process error\n",
    1060           0 :                        sc->sc_bus.bdev.dv_xname);
    1061           0 :         }
    1062           0 :         if (status & UHCI_STS_HCH) {
    1063             :                 /* no acknowledge needed */
    1064           0 :                 if (!sc->sc_bus.dying) {
    1065           0 :                         printf("%s: host controller halted\n",
    1066           0 :                             sc->sc_bus.bdev.dv_xname);
    1067             : #ifdef UHCI_DEBUG
    1068             :                         uhci_dump_all(sc);
    1069             : #endif
    1070           0 :                 }
    1071           0 :                 sc->sc_bus.dying = 1;
    1072           0 :         }
    1073             : 
    1074           0 :         if (!ack)
    1075           0 :                 return (0);     /* nothing to acknowledge */
    1076           0 :         UWRITE2(sc, UHCI_STS, ack); /* acknowledge the ints */
    1077             : 
    1078           0 :         sc->sc_bus.no_intrs++;
    1079           0 :         usb_schedsoftintr(&sc->sc_bus);
    1080             : 
    1081             :         DPRINTFN(15, ("%s: uhci_intr1: exit\n", sc->sc_bus.bdev.dv_xname));
    1082             : 
    1083           0 :         return (1);
    1084           0 : }
    1085             : 
    1086             : void
    1087           0 : uhci_softintr(void *v)
    1088             : {
    1089           0 :         struct uhci_softc *sc = v;
    1090             :         struct uhci_xfer *ux, *nextex;
    1091             : 
    1092             :         DPRINTFN(10,("%s: uhci_softintr (%d)\n", sc->sc_bus.bdev.dv_xname,
    1093             :                      sc->sc_bus.intr_context));
    1094             : 
    1095           0 :         if (sc->sc_bus.dying)
    1096           0 :                 return;
    1097             : 
    1098           0 :         sc->sc_bus.intr_context++;
    1099             : 
    1100             :         /*
    1101             :          * Interrupts on UHCI really suck.  When the host controller
    1102             :          * interrupts because a transfer is completed there is no
    1103             :          * way of knowing which transfer it was.  You can scan down
    1104             :          * the TDs and QHs of the previous frame to limit the search,
    1105             :          * but that assumes that the interrupt was not delayed by more
    1106             :          * than 1 ms, which may not always be true (e.g. after debug
    1107             :          * output on a slow console).
    1108             :          * We scan all interrupt descriptors to see if any have
    1109             :          * completed.
    1110             :          */
    1111           0 :         for (ux = LIST_FIRST(&sc->sc_intrhead); ux; ux = nextex) {
    1112           0 :                 nextex = LIST_NEXT(ux, inext);
    1113           0 :                 uhci_check_intr(sc, &ux->xfer);
    1114             :         }
    1115             : 
    1116           0 :         if (sc->sc_softwake) {
    1117           0 :                 sc->sc_softwake = 0;
    1118           0 :                 wakeup(&sc->sc_softwake);
    1119           0 :         }
    1120             : 
    1121           0 :         sc->sc_bus.intr_context--;
    1122           0 : }
    1123             : 
    1124             : void
    1125           0 : uhci_check_intr(struct uhci_softc *sc, struct usbd_xfer *xfer)
    1126             : {
    1127           0 :         struct uhci_xfer *ux = (struct uhci_xfer *)xfer;
    1128             :         struct uhci_soft_td *std, *lstd;
    1129             :         u_int32_t status;
    1130             : 
    1131             :         DPRINTFN(15, ("%s: ux=%p\n", __func__, ux));
    1132             : #ifdef DIAGNOSTIC
    1133           0 :         if (ux == NULL) {
    1134           0 :                 printf("%s: no ux? %p\n", __func__, ux);
    1135           0 :                 return;
    1136             :         }
    1137             : #endif
    1138           0 :         if (xfer->status == USBD_CANCELLED || xfer->status == USBD_TIMEOUT) {
    1139             :                 DPRINTF(("%s: aborted xfer=%p\n", __func__, xfer));
    1140           0 :                 return;
    1141             :         }
    1142             : 
    1143           0 :         if (ux->stdstart == NULL)
    1144           0 :                 return;
    1145           0 :         lstd = ux->stdend;
    1146             : #ifdef DIAGNOSTIC
    1147           0 :         if (lstd == NULL) {
    1148           0 :                 printf("%s: std==0\n", __func__);
    1149           0 :                 return;
    1150             :         }
    1151             : #endif
    1152             :         /*
    1153             :          * If the last TD is still active we need to check whether there
    1154             :          * is an error somewhere in the middle, or whether there was a
    1155             :          * short packet (SPD and not ACTIVE).
    1156             :          */
    1157           0 :         if (letoh32(lstd->td.td_status) & UHCI_TD_ACTIVE) {
    1158             :                 DPRINTFN(12, ("%s: active ux=%p\n", __func__, ux));
    1159           0 :                 for (std = ux->stdstart; std != lstd; std = std->link.std) {
    1160           0 :                         status = letoh32(std->td.td_status);
    1161             :                         /* If there's an active TD the xfer isn't done. */
    1162           0 :                         if (status & UHCI_TD_ACTIVE)
    1163             :                                 break;
    1164             :                         /* Any kind of error makes the xfer done. */
    1165           0 :                         if (status & UHCI_TD_STALLED)
    1166             :                                 goto done;
    1167             :                         /* We want short packets, and it is short: it's done */
    1168           0 :                         if ((status & UHCI_TD_SPD) &&
    1169           0 :                               UHCI_TD_GET_ACTLEN(status) <
    1170           0 :                               UHCI_TD_GET_MAXLEN(letoh32(std->td.td_token)))
    1171             :                                 goto done;
    1172             :                 }
    1173             :                 DPRINTFN(12, ("%s: ux=%p std=%p still active\n", __func__,
    1174             :                               ux, ux->stdstart));
    1175           0 :                 return;
    1176             :         }
    1177             :  done:
    1178             :         DPRINTFN(12, ("uhci_check_intr: ux=%p done\n", ux));
    1179           0 :         timeout_del(&xfer->timeout_handle);
    1180           0 :         usb_rem_task(xfer->pipe->device, &xfer->abort_task);
    1181           0 :         uhci_idone(xfer);
    1182           0 : }
    1183             : 
    1184             : /* Called at splusb() */
    1185             : void
    1186           0 : uhci_idone(struct usbd_xfer *xfer)
    1187             : {
    1188           0 :         struct uhci_xfer *ux = (struct uhci_xfer *)xfer;
    1189           0 :         struct uhci_pipe *upipe = (struct uhci_pipe *)xfer->pipe;
    1190             :         struct uhci_soft_td *std;
    1191             :         u_int32_t status = 0, nstatus;
    1192             :         int actlen;
    1193             : 
    1194             :         DPRINTFN(12, ("uhci_idone: ux=%p\n", ux));
    1195             : #ifdef DIAGNOSTIC
    1196             :         {
    1197           0 :                 int s = splhigh();
    1198           0 :                 if (ux->isdone) {
    1199           0 :                         splx(s);
    1200             : #ifdef UHCI_DEBUG
    1201             :                         printf("uhci_idone: ux is done!\n   ");
    1202             :                         uhci_dump_xfer(ux);
    1203             : #else
    1204           0 :                         printf("uhci_idone: ux=%p is done!\n", ux);
    1205             : #endif
    1206           0 :                         return;
    1207             :                 }
    1208           0 :                 ux->isdone = 1;
    1209           0 :                 splx(s);
    1210           0 :         }
    1211             : #endif
    1212             : 
    1213           0 :         if (xfer->nframes != 0) {
    1214             :                 /* Isoc transfer, do things differently. */
    1215           0 :                 struct uhci_soft_td **stds = upipe->u.iso.stds;
    1216             :                 int i, n, nframes, len;
    1217             : 
    1218             :                 DPRINTFN(5,("uhci_idone: ux=%p isoc ready\n", ux));
    1219             : 
    1220             :                 nframes = xfer->nframes;
    1221             :                 actlen = 0;
    1222           0 :                 n = ux->curframe;
    1223           0 :                 for (i = 0; i < nframes; i++) {
    1224           0 :                         std = stds[n];
    1225             : #ifdef UHCI_DEBUG
    1226             :                         if (uhcidebug > 5) {
    1227             :                                 DPRINTFN(-1,("uhci_idone: isoc TD %d\n", i));
    1228             :                                 uhci_dump_td(std);
    1229             :                         }
    1230             : #endif
    1231           0 :                         if (++n >= UHCI_VFRAMELIST_COUNT)
    1232             :                                 n = 0;
    1233           0 :                         status = letoh32(std->td.td_status);
    1234           0 :                         len = UHCI_TD_GET_ACTLEN(status);
    1235           0 :                         xfer->frlengths[i] = len;
    1236           0 :                         actlen += len;
    1237             :                 }
    1238           0 :                 upipe->u.iso.inuse -= nframes;
    1239           0 :                 xfer->actlen = actlen;
    1240           0 :                 xfer->status = USBD_NORMAL_COMPLETION;
    1241             :                 goto end;
    1242             :         }
    1243             : 
    1244             : #ifdef UHCI_DEBUG
    1245             :         DPRINTFN(10, ("uhci_idone: ux=%p, xfer=%p, pipe=%p ready\n",
    1246             :                       ux, xfer, upipe));
    1247             :         if (uhcidebug > 10)
    1248             :                 uhci_dump_tds(ux->stdstart);
    1249             : #endif
    1250             : 
    1251             :         /* The transfer is done, compute actual length and status. */
    1252             :         actlen = 0;
    1253           0 :         for (std = ux->stdstart; std != NULL; std = std->link.std) {
    1254           0 :                 nstatus = letoh32(std->td.td_status);
    1255           0 :                 if (nstatus & UHCI_TD_ACTIVE)
    1256             :                         break;
    1257             : 
    1258             :                 status = nstatus;
    1259           0 :                 if (UHCI_TD_GET_PID(letoh32(std->td.td_token)) !=
    1260             :                     UHCI_TD_PID_SETUP)
    1261           0 :                         actlen += UHCI_TD_GET_ACTLEN(status);
    1262             :                 else {
    1263             :                         /*
    1264             :                          * UHCI will report CRCTO in addition to a STALL or NAK
    1265             :                          * for a SETUP transaction.  See section 3.2.2, "TD
    1266             :                          * CONTROL AND STATUS".
    1267             :                          */
    1268           0 :                         if (status & (UHCI_TD_STALLED | UHCI_TD_NAK))
    1269           0 :                                 status &= ~UHCI_TD_CRCTO;
    1270             :                 }
    1271             :         }
    1272             :         /* If there are left over TDs we need to update the toggle. */
    1273           0 :         if (std != NULL)
    1274           0 :                 upipe->nexttoggle = UHCI_TD_GET_DT(letoh32(std->td.td_token));
    1275             : 
    1276           0 :         status &= UHCI_TD_ERROR;
    1277             :         DPRINTFN(10, ("uhci_idone: actlen=%d, status=0x%x\n",
    1278             :                       actlen, status));
    1279           0 :         xfer->actlen = actlen;
    1280           0 :         if (status != 0) {
    1281             : #ifdef UHCI_DEBUG
    1282             :                 char sbuf[128];
    1283             : 
    1284             :                 bitmask_snprintf((u_int32_t)status,
    1285             :                                  "\20\22BITSTUFF\23CRCTO\24NAK\25"
    1286             :                                  "BABBLE\26DBUFFER\27STALLED\30ACTIVE",
    1287             :                                  sbuf, sizeof(sbuf));
    1288             : 
    1289             :                 DPRINTFN((status == UHCI_TD_STALLED)*10,
    1290             :                          ("uhci_idone: error, addr=%d, endpt=0x%02x, "
    1291             :                           "status 0x%s\n",
    1292             :                           xfer->device->address,
    1293             :                           xfer->pipe->endpoint->edesc->bEndpointAddress,
    1294             :                           sbuf));
    1295             : #endif
    1296             : 
    1297           0 :                 if (status == UHCI_TD_STALLED)
    1298           0 :                         xfer->status = USBD_STALLED;
    1299             :                 else
    1300           0 :                         xfer->status = USBD_IOERROR; /* more info XXX */
    1301             :         } else {
    1302           0 :                 xfer->status = USBD_NORMAL_COMPLETION;
    1303             :         }
    1304             : 
    1305             :  end:
    1306           0 :         usb_transfer_complete(xfer);
    1307             :         DPRINTFN(12, ("uhci_idone: ux=%p done\n", ux));
    1308           0 : }
    1309             : 
    1310             : void
    1311           0 : uhci_timeout(void *addr)
    1312             : {
    1313           0 :         struct usbd_xfer *xfer = addr;
    1314           0 :         struct uhci_softc *sc = (struct uhci_softc *)xfer->device->bus;
    1315             : 
    1316           0 :         if (sc->sc_bus.dying) {
    1317           0 :                 uhci_timeout_task(addr);
    1318           0 :                 return;
    1319             :         }
    1320             : 
    1321           0 :         usb_init_task(&xfer->abort_task, uhci_timeout_task, addr,
    1322             :             USB_TASK_TYPE_ABORT);
    1323           0 :         usb_add_task(xfer->device, &xfer->abort_task);
    1324           0 : }
    1325             : 
    1326             : void
    1327           0 : uhci_timeout_task(void *addr)
    1328             : {
    1329           0 :         struct usbd_xfer *xfer = addr;
    1330             :         int s;
    1331             : 
    1332             :         DPRINTF(("%s: xfer=%p\n", __func__, xfer));
    1333             : 
    1334           0 :         s = splusb();
    1335           0 :         uhci_abort_xfer(xfer, USBD_TIMEOUT);
    1336           0 :         splx(s);
    1337           0 : }
    1338             : 
    1339             : void
    1340           0 : uhci_poll(struct usbd_bus *bus)
    1341             : {
    1342           0 :         struct uhci_softc *sc = (struct uhci_softc *)bus;
    1343             : 
    1344           0 :         if (UREAD2(sc, UHCI_STS) & UHCI_STS_ALLINTRS)
    1345           0 :                 uhci_intr1(sc);
    1346           0 : }
    1347             : 
    1348             : void
    1349           0 : uhci_reset(struct uhci_softc *sc)
    1350             : {
    1351             :         int n;
    1352             : 
    1353           0 :         UHCICMD(sc, UHCI_CMD_HCRESET);
    1354             :         /* The reset bit goes low when the controller is done. */
    1355           0 :         for (n = 0; n < UHCI_RESET_TIMEOUT &&
    1356           0 :                     (UREAD2(sc, UHCI_CMD) & UHCI_CMD_HCRESET); n++)
    1357           0 :                 usb_delay_ms(&sc->sc_bus, 1);
    1358           0 :         if (n >= UHCI_RESET_TIMEOUT)
    1359           0 :                 printf("%s: controller did not reset\n",
    1360           0 :                        sc->sc_bus.bdev.dv_xname);
    1361           0 : }
    1362             : 
    1363             : usbd_status
    1364           0 : uhci_run(struct uhci_softc *sc, int run)
    1365             : {
    1366             :         int s, n, running;
    1367             :         u_int16_t cmd;
    1368             : 
    1369           0 :         run = run != 0;
    1370           0 :         s = splhardusb();
    1371             :         DPRINTF(("uhci_run: setting run=%d\n", run));
    1372           0 :         cmd = UREAD2(sc, UHCI_CMD);
    1373           0 :         if (run)
    1374           0 :                 cmd |= UHCI_CMD_RS;
    1375             :         else
    1376           0 :                 cmd &= ~UHCI_CMD_RS;
    1377           0 :         UHCICMD(sc, cmd);
    1378           0 :         for(n = 0; n < 10; n++) {
    1379           0 :                 running = !(UREAD2(sc, UHCI_STS) & UHCI_STS_HCH);
    1380             :                 /* return when we've entered the state we want */
    1381           0 :                 if (run == running) {
    1382           0 :                         splx(s);
    1383             :                         DPRINTF(("uhci_run: done cmd=0x%x sts=0x%x\n",
    1384             :                                  UREAD2(sc, UHCI_CMD), UREAD2(sc, UHCI_STS)));
    1385           0 :                         return (USBD_NORMAL_COMPLETION);
    1386             :                 }
    1387           0 :                 usb_delay_ms(&sc->sc_bus, 1);
    1388             :         }
    1389           0 :         splx(s);
    1390           0 :         printf("%s: cannot %s\n", sc->sc_bus.bdev.dv_xname,
    1391           0 :                run ? "start" : "stop");
    1392           0 :         return (USBD_IOERROR);
    1393           0 : }
    1394             : 
    1395             : /*
    1396             :  * Memory management routines.
    1397             :  *  uhci_alloc_std allocates TDs
    1398             :  *  uhci_alloc_sqh allocates QHs
    1399             :  * These two routines do their own free list management,
    1400             :  * partly for speed, partly because allocating DMAable memory
    1401             :  * has page size granularaity so much memory would be wasted if
    1402             :  * only one TD/QH (32 bytes) was placed in each allocated chunk.
    1403             :  */
    1404             : 
    1405             : struct uhci_soft_td *
    1406           0 : uhci_alloc_std(struct uhci_softc *sc)
    1407             : {
    1408             :         struct uhci_soft_td *std = NULL;
    1409             :         usbd_status err;
    1410             :         int i, offs;
    1411           0 :         struct usb_dma dma;
    1412             :         int s;
    1413             : 
    1414           0 :         s = splusb();
    1415           0 :         if (sc->sc_freetds == NULL) {
    1416             :                 DPRINTFN(2,("uhci_alloc_std: allocating chunk\n"));
    1417           0 :                 err = usb_allocmem(&sc->sc_bus, UHCI_STD_SIZE * UHCI_STD_CHUNK,
    1418             :                           UHCI_TD_ALIGN, &dma);
    1419           0 :                 if (err)
    1420             :                         goto out;
    1421           0 :                 for(i = 0; i < UHCI_STD_CHUNK; i++) {
    1422           0 :                         offs = i * UHCI_STD_SIZE;
    1423           0 :                         std = KERNADDR(&dma, offs);
    1424           0 :                         std->physaddr = DMAADDR(&dma, offs);
    1425           0 :                         std->link.std = sc->sc_freetds;
    1426           0 :                         sc->sc_freetds = std;
    1427             :                 }
    1428             :         }
    1429             : 
    1430           0 :         std = sc->sc_freetds;
    1431           0 :         sc->sc_freetds = std->link.std;
    1432           0 :         memset(&std->td, 0, sizeof(struct uhci_td));
    1433             : 
    1434             : out:
    1435           0 :         splx(s);
    1436           0 :         return (std);
    1437           0 : }
    1438             : 
    1439             : void
    1440           0 : uhci_free_std(struct uhci_softc *sc, struct uhci_soft_td *std)
    1441             : {
    1442             :         int s;
    1443             : 
    1444             : #ifdef DIAGNOSTIC
    1445             : #define TD_IS_FREE 0x12345678
    1446           0 :         if (letoh32(std->td.td_token) == TD_IS_FREE) {
    1447           0 :                 printf("uhci_free_std: freeing free TD %p\n", std);
    1448           0 :                 return;
    1449             :         }
    1450           0 :         std->td.td_token = htole32(TD_IS_FREE);
    1451             : #endif
    1452             : 
    1453           0 :         s = splusb();
    1454           0 :         std->link.std = sc->sc_freetds;
    1455           0 :         sc->sc_freetds = std;
    1456           0 :         splx(s);
    1457           0 : }
    1458             : 
    1459             : struct uhci_soft_qh *
    1460           0 : uhci_alloc_sqh(struct uhci_softc *sc)
    1461             : {
    1462             :         struct uhci_soft_qh *sqh = NULL;
    1463             :         usbd_status err;
    1464             :         int i, offs;
    1465           0 :         struct usb_dma dma;
    1466             :         int s;
    1467             : 
    1468           0 :         s = splusb();
    1469           0 :         if (sc->sc_freeqhs == NULL) {
    1470             :                 DPRINTFN(2, ("uhci_alloc_sqh: allocating chunk\n"));
    1471           0 :                 err = usb_allocmem(&sc->sc_bus, UHCI_SQH_SIZE * UHCI_SQH_CHUNK,
    1472             :                           UHCI_QH_ALIGN, &dma);
    1473           0 :                 if (err)
    1474             :                         goto out;
    1475           0 :                 for (i = 0; i < UHCI_SQH_CHUNK; i++) {
    1476           0 :                         offs = i * UHCI_SQH_SIZE;
    1477           0 :                         sqh = KERNADDR(&dma, offs);
    1478           0 :                         sqh->physaddr = DMAADDR(&dma, offs);
    1479           0 :                         sqh->hlink = sc->sc_freeqhs;
    1480           0 :                         sc->sc_freeqhs = sqh;
    1481             :                 }
    1482             :         }
    1483           0 :         sqh = sc->sc_freeqhs;
    1484           0 :         sc->sc_freeqhs = sqh->hlink;
    1485           0 :         memset(&sqh->qh, 0, sizeof(struct uhci_qh));
    1486             : 
    1487             : out:
    1488           0 :         splx(s);
    1489           0 :         return (sqh);
    1490           0 : }
    1491             : 
    1492             : void
    1493           0 : uhci_free_sqh(struct uhci_softc *sc, struct uhci_soft_qh *sqh)
    1494             : {
    1495           0 :         sqh->hlink = sc->sc_freeqhs;
    1496           0 :         sc->sc_freeqhs = sqh;
    1497           0 : }
    1498             : 
    1499             : void
    1500           0 : uhci_free_std_chain(struct uhci_softc *sc, struct uhci_soft_td *std,
    1501             :     struct uhci_soft_td *stdend)
    1502             : {
    1503             :         struct uhci_soft_td *p;
    1504             : 
    1505           0 :         for (; std != stdend; std = p) {
    1506           0 :                 p = std->link.std;
    1507           0 :                 uhci_free_std(sc, std);
    1508             :         }
    1509           0 : }
    1510             : 
    1511             : usbd_status
    1512           0 : uhci_alloc_std_chain(struct uhci_softc *sc, u_int len, struct usbd_xfer *xfer,
    1513             :     struct uhci_soft_td **sp, struct uhci_soft_td **ep)
    1514             : {
    1515           0 :         struct uhci_pipe *upipe = (struct uhci_pipe *)xfer->pipe;
    1516             :         struct uhci_soft_td *p, *lastp;
    1517             :         uhci_physaddr_t lastlink;
    1518             :         int i, ntd, l, tog, mps;
    1519             :         u_int32_t status;
    1520           0 :         u_int16_t flags = xfer->flags;
    1521           0 :         int rd = usbd_xfer_isread(xfer);
    1522           0 :         struct usb_dma *dma = &xfer->dmabuf;
    1523           0 :         int addr = xfer->device->address;
    1524           0 :         int endpt = xfer->pipe->endpoint->edesc->bEndpointAddress;
    1525             : 
    1526             :         DPRINTFN(8, ("%s: addr=%d endpt=%d len=%u speed=%d flags=0x%x\n",
    1527             :             __func__, addr, UE_GET_ADDR(endpt), len, xfer->device->speed,
    1528             :             flags));
    1529             : 
    1530           0 :         mps = UGETW(xfer->pipe->endpoint->edesc->wMaxPacketSize);
    1531           0 :         if (mps == 0) {
    1532           0 :                 printf("uhci_alloc_std_chain: mps=0\n");
    1533           0 :                 return (USBD_INVAL);
    1534             :         }
    1535           0 :         ntd = (len + mps - 1) / mps;
    1536           0 :         if (len == 0)
    1537           0 :                 flags |= USBD_FORCE_SHORT_XFER;
    1538           0 :         if ((flags & USBD_FORCE_SHORT_XFER) && len % mps == 0)
    1539           0 :                 ntd++;
    1540             :         DPRINTFN(10, ("%s: mps=%d ntd=%d\n", __func__, mps, ntd));
    1541           0 :         tog = upipe->nexttoggle;
    1542           0 :         if (ntd % 2 == 0)
    1543           0 :                 tog ^= 1;
    1544           0 :         upipe->nexttoggle = tog ^ 1;
    1545             :         lastp = NULL;
    1546             :         lastlink = UHCI_PTR_T;
    1547           0 :         ntd--;
    1548             :         status = UHCI_TD_ZERO_ACTLEN(UHCI_TD_SET_ERRCNT(3) | UHCI_TD_ACTIVE);
    1549           0 :         if (xfer->pipe->device->speed == USB_SPEED_LOW)
    1550           0 :                 status |= UHCI_TD_LS;
    1551           0 :         if (flags & USBD_SHORT_XFER_OK)
    1552           0 :                 status |= UHCI_TD_SPD;
    1553           0 :         for (i = ntd; i >= 0; i--) {
    1554           0 :                 p = uhci_alloc_std(sc);
    1555           0 :                 if (p == NULL) {
    1556           0 :                         uhci_free_std_chain(sc, lastp, NULL);
    1557           0 :                         return (USBD_NOMEM);
    1558             :                 }
    1559           0 :                 p->link.std = lastp;
    1560           0 :                 p->td.td_link = htole32(lastlink | UHCI_PTR_VF | UHCI_PTR_TD);
    1561             :                 lastp = p;
    1562           0 :                 lastlink = p->physaddr;
    1563           0 :                 p->td.td_status = htole32(status);
    1564           0 :                 if (i == ntd) {
    1565             :                         /* last TD */
    1566           0 :                         l = len % mps;
    1567           0 :                         if (l == 0 && !(flags & USBD_FORCE_SHORT_XFER))
    1568           0 :                                 l = mps;
    1569           0 :                         *ep = p;
    1570           0 :                 } else
    1571             :                         l = mps;
    1572           0 :                 p->td.td_token =
    1573           0 :                     htole32(rd ? UHCI_TD_IN (l, endpt, addr, tog) :
    1574             :                                  UHCI_TD_OUT(l, endpt, addr, tog));
    1575           0 :                 p->td.td_buffer = htole32(DMAADDR(dma, i * mps));
    1576           0 :                 tog ^= 1;
    1577             :         }
    1578           0 :         *sp = lastp;
    1579             :         DPRINTFN(10, ("%s: nexttog=%d\n", __func__, upipe->nexttoggle));
    1580           0 :         return (USBD_NORMAL_COMPLETION);
    1581           0 : }
    1582             : 
    1583             : void
    1584           0 : uhci_device_clear_toggle(struct usbd_pipe *pipe)
    1585             : {
    1586           0 :         struct uhci_pipe *upipe = (struct uhci_pipe *)pipe;
    1587           0 :         upipe->nexttoggle = 0;
    1588           0 : }
    1589             : 
    1590             : usbd_status
    1591           0 : uhci_device_bulk_transfer(struct usbd_xfer *xfer)
    1592             : {
    1593             :         usbd_status err;
    1594             : 
    1595             :         /* Insert last in queue. */
    1596           0 :         err = usb_insert_transfer(xfer);
    1597           0 :         if (err)
    1598           0 :                 return (err);
    1599             : 
    1600             :         /*
    1601             :          * Pipe isn't running (otherwise err would be USBD_INPROG),
    1602             :          * so start it first.
    1603             :          */
    1604           0 :         return (uhci_device_bulk_start(SIMPLEQ_FIRST(&xfer->pipe->queue)));
    1605           0 : }
    1606             : 
    1607             : usbd_status
    1608           0 : uhci_device_bulk_start(struct usbd_xfer *xfer)
    1609             : {
    1610           0 :         struct uhci_softc *sc = (struct uhci_softc *)xfer->device->bus;
    1611           0 :         struct uhci_pipe *upipe = (struct uhci_pipe *)xfer->pipe;
    1612           0 :         struct uhci_xfer *ux = (struct uhci_xfer *)xfer;
    1613           0 :         struct uhci_soft_td *data, *dataend;
    1614             :         struct uhci_soft_qh *sqh;
    1615             :         usbd_status err;
    1616             :         u_int len;
    1617             :         int s;
    1618             : 
    1619             :         DPRINTFN(3, ("uhci_device_bulk_start: xfer=%p len=%u flags=%d ux=%p\n",
    1620             :                      xfer, xfer->length, xfer->flags, ux));
    1621             : 
    1622           0 :         if (sc->sc_bus.dying)
    1623           0 :                 return (USBD_IOERROR);
    1624             : 
    1625             : #ifdef DIAGNOSTIC
    1626           0 :         if (xfer->rqflags & URQ_REQUEST)
    1627           0 :                 panic("uhci_device_bulk_start: a request");
    1628             : #endif
    1629             : 
    1630           0 :         len = xfer->length;
    1631           0 :         sqh = upipe->u.bulk.sqh;
    1632             : 
    1633           0 :         err = uhci_alloc_std_chain(sc, len, xfer, &data, &dataend);
    1634           0 :         if (err)
    1635           0 :                 return (err);
    1636           0 :         dataend->td.td_status |= htole32(UHCI_TD_IOC);
    1637             : 
    1638             : #ifdef UHCI_DEBUG
    1639             :         if (uhcidebug > 8) {
    1640             :                 DPRINTF(("uhci_device_bulk_start: data(1)\n"));
    1641             :                 uhci_dump_tds(data);
    1642             :         }
    1643             : #endif
    1644             : 
    1645             :         /* Set up interrupt info. */
    1646           0 :         ux->stdstart = data;
    1647           0 :         ux->stdend = dataend;
    1648             : #ifdef DIAGNOSTIC
    1649           0 :         if (!ux->isdone) {
    1650           0 :                 printf("uhci_device_bulk_start: not done, ux=%p\n", ux);
    1651           0 :         }
    1652           0 :         ux->isdone = 0;
    1653             : #endif
    1654             : 
    1655           0 :         sqh->elink = data;
    1656           0 :         sqh->qh.qh_elink = htole32(data->physaddr | UHCI_PTR_TD);
    1657             : 
    1658           0 :         s = splusb();
    1659           0 :         uhci_add_bulk(sc, sqh);
    1660           0 :         uhci_add_intr_list(sc, ux);
    1661             : 
    1662           0 :         if (xfer->timeout && !sc->sc_bus.use_polling) {
    1663           0 :                 timeout_del(&xfer->timeout_handle);
    1664           0 :                 timeout_set(&xfer->timeout_handle, uhci_timeout, xfer);
    1665           0 :                 timeout_add_msec(&xfer->timeout_handle, xfer->timeout);
    1666           0 :         }
    1667           0 :         xfer->status = USBD_IN_PROGRESS;
    1668           0 :         splx(s);
    1669             : 
    1670             : #ifdef UHCI_DEBUG
    1671             :         if (uhcidebug > 10) {
    1672             :                 DPRINTF(("uhci_device_bulk_start: data(2)\n"));
    1673             :                 uhci_dump_tds(data);
    1674             :         }
    1675             : #endif
    1676             : 
    1677           0 :         return (USBD_IN_PROGRESS);
    1678           0 : }
    1679             : 
    1680             : /* Abort a device bulk request. */
    1681             : void
    1682           0 : uhci_device_bulk_abort(struct usbd_xfer *xfer)
    1683             : {
    1684             :         DPRINTF(("uhci_device_bulk_abort:\n"));
    1685           0 :         uhci_abort_xfer(xfer, USBD_CANCELLED);
    1686           0 : }
    1687             : 
    1688             : /*
    1689             :  * Abort a device request.
    1690             :  * If this routine is called at splusb() it guarantees that the request
    1691             :  * will be removed from the hardware scheduling and that the callback
    1692             :  * for it will be called with USBD_CANCELLED status.
    1693             :  * It's impossible to guarantee that the requested transfer will not
    1694             :  * have happened since the hardware runs concurrently.
    1695             :  * If the transaction has already happened we rely on the ordinary
    1696             :  * interrupt processing to process it.
    1697             :  */
    1698             : void
    1699           0 : uhci_abort_xfer(struct usbd_xfer *xfer, usbd_status status)
    1700             : {
    1701           0 :         struct uhci_softc *sc = (struct uhci_softc *)xfer->device->bus;
    1702           0 :         struct uhci_xfer *ux = (struct uhci_xfer *)xfer;
    1703             :         struct uhci_soft_td *std;
    1704             :         int s;
    1705             : 
    1706             :         DPRINTFN(1,("uhci_abort_xfer: xfer=%p, status=%d\n", xfer, status));
    1707             : 
    1708           0 :         if (sc->sc_bus.dying) {
    1709             :                 /* If we're dying, just do the software part. */
    1710           0 :                 s = splusb();
    1711           0 :                 xfer->status = status;       /* make software ignore it */
    1712           0 :                 timeout_del(&xfer->timeout_handle);
    1713           0 :                 usb_rem_task(xfer->device, &xfer->abort_task);
    1714             : #ifdef DIAGNOSTIC
    1715           0 :                 ux->isdone = 1;
    1716             : #endif
    1717           0 :                 usb_transfer_complete(xfer);
    1718           0 :                 splx(s);
    1719           0 :                 return;
    1720             :         }
    1721             : 
    1722           0 :         if (xfer->device->bus->intr_context || !curproc)
    1723           0 :                 panic("uhci_abort_xfer: not in process context");
    1724             : 
    1725             :         /*
    1726             :          * Step 1: Make interrupt routine and hardware ignore xfer.
    1727             :          */
    1728           0 :         s = splusb();
    1729           0 :         xfer->status = status;       /* make software ignore it */
    1730           0 :         timeout_del(&xfer->timeout_handle);
    1731           0 :         usb_rem_task(xfer->device, &xfer->abort_task);
    1732             :         DPRINTFN(1,("uhci_abort_xfer: stop ux=%p\n", ux));
    1733           0 :         for (std = ux->stdstart; std != NULL; std = std->link.std)
    1734           0 :                 std->td.td_status &= htole32(~(UHCI_TD_ACTIVE | UHCI_TD_IOC));
    1735           0 :         splx(s);
    1736             : 
    1737             :         /*
    1738             :          * Step 2: Wait until we know hardware has finished any possible
    1739             :          * use of the xfer.  Also make sure the soft interrupt routine
    1740             :          * has run.
    1741             :          */
    1742           0 :         usb_delay_ms(&sc->sc_bus, 2); /* Hardware finishes in 1ms */
    1743           0 :         s = splusb();
    1744           0 :         sc->sc_softwake = 1;
    1745           0 :         usb_schedsoftintr(&sc->sc_bus);
    1746             :         DPRINTFN(1,("uhci_abort_xfer: tsleep\n"));
    1747           0 :         tsleep(&sc->sc_softwake, PZERO, "uhciab", 0);
    1748           0 :         splx(s);
    1749             : 
    1750             :         /*
    1751             :          * Step 3: Execute callback.
    1752             :          */
    1753             :         DPRINTFN(1,("uhci_abort_xfer: callback\n"));
    1754           0 :         s = splusb();
    1755             : #ifdef DIAGNOSTIC
    1756           0 :         ux->isdone = 1;
    1757             : #endif
    1758           0 :         usb_transfer_complete(xfer);
    1759           0 :         splx(s);
    1760           0 : }
    1761             : 
    1762             : /* Close a device bulk pipe. */
    1763             : void
    1764           0 : uhci_device_bulk_close(struct usbd_pipe *pipe)
    1765             : {
    1766           0 :         struct uhci_softc *sc = (struct uhci_softc *)pipe->device->bus;
    1767           0 :         struct uhci_pipe *upipe = (struct uhci_pipe *)pipe;
    1768             : 
    1769           0 :         uhci_free_sqh(sc, upipe->u.bulk.sqh);
    1770           0 :         pipe->endpoint->savedtoggle = upipe->nexttoggle;
    1771           0 : }
    1772             : 
    1773             : usbd_status
    1774           0 : uhci_device_ctrl_transfer(struct usbd_xfer *xfer)
    1775             : {
    1776             :         usbd_status err;
    1777             : 
    1778             :         /* Insert last in queue. */
    1779           0 :         err = usb_insert_transfer(xfer);
    1780           0 :         if (err)
    1781           0 :                 return (err);
    1782             : 
    1783             :         /*
    1784             :          * Pipe isn't running (otherwise err would be USBD_INPROG),
    1785             :          * so start it first.
    1786             :          */
    1787           0 :         return (uhci_device_ctrl_start(SIMPLEQ_FIRST(&xfer->pipe->queue)));
    1788           0 : }
    1789             : 
    1790             : usbd_status
    1791           0 : uhci_device_ctrl_start(struct usbd_xfer *xfer)
    1792             : {
    1793           0 :         struct uhci_softc *sc = (struct uhci_softc *)xfer->device->bus;
    1794             :         usbd_status err;
    1795             : 
    1796           0 :         if (sc->sc_bus.dying)
    1797           0 :                 return (USBD_IOERROR);
    1798             : 
    1799             : #ifdef DIAGNOSTIC
    1800           0 :         if (!(xfer->rqflags & URQ_REQUEST))
    1801           0 :                 panic("uhci_device_ctrl_transfer: not a request");
    1802             : #endif
    1803             : 
    1804           0 :         err = uhci_device_request(xfer);
    1805           0 :         if (err)
    1806           0 :                 return (err);
    1807             : 
    1808           0 :         return (USBD_IN_PROGRESS);
    1809           0 : }
    1810             : 
    1811             : usbd_status
    1812           0 : uhci_device_intr_transfer(struct usbd_xfer *xfer)
    1813             : {
    1814             :         usbd_status err;
    1815             : 
    1816             :         /* Insert last in queue. */
    1817           0 :         err = usb_insert_transfer(xfer);
    1818           0 :         if (err)
    1819           0 :                 return (err);
    1820             : 
    1821             :         /*
    1822             :          * Pipe isn't running (otherwise err would be USBD_INPROG),
    1823             :          * so start it first.
    1824             :          */
    1825           0 :         return (uhci_device_intr_start(SIMPLEQ_FIRST(&xfer->pipe->queue)));
    1826           0 : }
    1827             : 
    1828             : usbd_status
    1829           0 : uhci_device_intr_start(struct usbd_xfer *xfer)
    1830             : {
    1831           0 :         struct uhci_softc *sc = (struct uhci_softc *)xfer->device->bus;
    1832           0 :         struct uhci_pipe *upipe = (struct uhci_pipe *)xfer->pipe;
    1833           0 :         struct uhci_xfer *ux = (struct uhci_xfer *)xfer;
    1834           0 :         struct uhci_soft_td *data, *dataend;
    1835             :         struct uhci_soft_qh *sqh;
    1836             :         usbd_status err;
    1837             :         int i, s;
    1838             : 
    1839           0 :         if (sc->sc_bus.dying)
    1840           0 :                 return (USBD_IOERROR);
    1841             : 
    1842             :         DPRINTFN(3,("uhci_device_intr_start: xfer=%p len=%u flags=%d\n",
    1843             :                     xfer, xfer->length, xfer->flags));
    1844             : 
    1845             : #ifdef DIAGNOSTIC
    1846           0 :         if (xfer->rqflags & URQ_REQUEST)
    1847           0 :                 panic("uhci_device_intr_start: a request");
    1848             : #endif
    1849             : 
    1850           0 :         upipe->u.intr.isread = usbd_xfer_isread(xfer);
    1851             : 
    1852           0 :         err = uhci_alloc_std_chain(sc, xfer->length, xfer, &data, &dataend);
    1853             : 
    1854           0 :         if (err)
    1855           0 :                 return (err);
    1856           0 :         dataend->td.td_status |= htole32(UHCI_TD_IOC);
    1857             : 
    1858             : #ifdef UHCI_DEBUG
    1859             :         if (uhcidebug > 10) {
    1860             :                 DPRINTF(("uhci_device_intr_start: data(1)\n"));
    1861             :                 uhci_dump_tds(data);
    1862             :                 uhci_dump_qh(upipe->u.intr.qhs[0]);
    1863             :         }
    1864             : #endif
    1865             : 
    1866           0 :         s = splusb();
    1867             :         /* Set up interrupt info. */
    1868           0 :         ux->stdstart = data;
    1869           0 :         ux->stdend = dataend;
    1870             : #ifdef DIAGNOSTIC
    1871           0 :         if (!ux->isdone) {
    1872           0 :                 printf("uhci_device_intr_transfer: not done, ux=%p\n", ux);
    1873           0 :         }
    1874           0 :         ux->isdone = 0;
    1875             : #endif
    1876             : 
    1877             :         DPRINTFN(10,("uhci_device_intr_start: qhs[0]=%p\n",
    1878             :                      upipe->u.intr.qhs[0]));
    1879           0 :         for (i = 0; i < upipe->u.intr.npoll; i++) {
    1880           0 :                 sqh = upipe->u.intr.qhs[i];
    1881           0 :                 sqh->elink = data;
    1882           0 :                 sqh->qh.qh_elink = htole32(data->physaddr | UHCI_PTR_TD);
    1883             :         }
    1884           0 :         uhci_add_intr_list(sc, ux);
    1885           0 :         xfer->status = USBD_IN_PROGRESS;
    1886           0 :         splx(s);
    1887             : 
    1888             : #ifdef UHCI_DEBUG
    1889             :         if (uhcidebug > 10) {
    1890             :                 DPRINTF(("uhci_device_intr_start: data(2)\n"));
    1891             :                 uhci_dump_tds(data);
    1892             :                 uhci_dump_qh(upipe->u.intr.qhs[0]);
    1893             :         }
    1894             : #endif
    1895             : 
    1896           0 :         return (USBD_IN_PROGRESS);
    1897           0 : }
    1898             : 
    1899             : /* Abort a device control request. */
    1900             : void
    1901           0 : uhci_device_ctrl_abort(struct usbd_xfer *xfer)
    1902             : {
    1903             :         DPRINTF(("uhci_device_ctrl_abort:\n"));
    1904           0 :         uhci_abort_xfer(xfer, USBD_CANCELLED);
    1905           0 : }
    1906             : 
    1907             : /* Close a device control pipe. */
    1908             : void
    1909           0 : uhci_device_ctrl_close(struct usbd_pipe *pipe)
    1910             : {
    1911           0 : }
    1912             : 
    1913             : void
    1914           0 : uhci_device_intr_abort(struct usbd_xfer *xfer)
    1915             : {
    1916           0 :         KASSERT(!xfer->pipe->repeat || xfer->pipe->intrxfer == xfer);
    1917             : 
    1918           0 :         uhci_abort_xfer(xfer, USBD_CANCELLED);
    1919           0 : }
    1920             : 
    1921             : /* Close a device interrupt pipe. */
    1922             : void
    1923           0 : uhci_device_intr_close(struct usbd_pipe *pipe)
    1924             : {
    1925           0 :         struct uhci_pipe *upipe = (struct uhci_pipe *)pipe;
    1926           0 :         struct uhci_softc *sc = (struct uhci_softc *)pipe->device->bus;
    1927             :         int i, npoll;
    1928             :         int s;
    1929             : 
    1930             :         /* Unlink descriptors from controller data structures. */
    1931           0 :         npoll = upipe->u.intr.npoll;
    1932           0 :         s = splusb();
    1933           0 :         for (i = 0; i < npoll; i++)
    1934           0 :                 uhci_remove_intr(sc, upipe->u.intr.qhs[i]);
    1935           0 :         splx(s);
    1936             : 
    1937             :         /*
    1938             :          * We now have to wait for any activity on the physical
    1939             :          * descriptors to stop.
    1940             :          */
    1941           0 :         usb_delay_ms(&sc->sc_bus, 2);
    1942             : 
    1943           0 :         for(i = 0; i < npoll; i++)
    1944           0 :                 uhci_free_sqh(sc, upipe->u.intr.qhs[i]);
    1945           0 :         free(upipe->u.intr.qhs, M_USBHC, 0);
    1946             : 
    1947             :         /* XXX free other resources */
    1948           0 : }
    1949             : 
    1950             : usbd_status
    1951           0 : uhci_device_request(struct usbd_xfer *xfer)
    1952             : {
    1953           0 :         struct uhci_softc *sc = (struct uhci_softc *)xfer->device->bus;
    1954           0 :         struct uhci_pipe *upipe = (struct uhci_pipe *)xfer->pipe;
    1955           0 :         struct uhci_xfer *ux = (struct uhci_xfer *)xfer;
    1956           0 :         usb_device_request_t *req = &xfer->request;
    1957           0 :         int addr = xfer->device->address;
    1958           0 :         int endpt = xfer->pipe->endpoint->edesc->bEndpointAddress;
    1959           0 :         struct uhci_soft_td *setup, *data, *stat, *next, *dataend;
    1960             :         struct uhci_soft_qh *sqh;
    1961             :         u_int len;
    1962             :         u_int32_t ls;
    1963             :         usbd_status err;
    1964             :         int s;
    1965             : 
    1966             :         DPRINTFN(3,("uhci_device_request type=0x%02x, request=0x%02x, "
    1967             :                     "wValue=0x%04x, wIndex=0x%04x len=%u, addr=%d, endpt=%d\n",
    1968             :                     req->bmRequestType, req->bRequest, UGETW(req->wValue),
    1969             :                     UGETW(req->wIndex), UGETW(req->wLength),
    1970             :                     addr, endpt));
    1971             : 
    1972           0 :         ls = xfer->device->speed == USB_SPEED_LOW ? UHCI_TD_LS : 0;
    1973           0 :         len = UGETW(req->wLength);
    1974             : 
    1975           0 :         setup = upipe->u.ctl.setup;
    1976           0 :         stat = upipe->u.ctl.stat;
    1977           0 :         sqh = upipe->u.ctl.sqh;
    1978             : 
    1979             :         /* Set up data transaction */
    1980           0 :         if (len != 0) {
    1981           0 :                 upipe->nexttoggle = 1;
    1982           0 :                 err = uhci_alloc_std_chain(sc, len, xfer, &data, &dataend);
    1983           0 :                 if (err)
    1984           0 :                         return (err);
    1985           0 :                 next = data;
    1986           0 :                 dataend->link.std = stat;
    1987           0 :                 dataend->td.td_link = htole32(stat->physaddr | UHCI_PTR_VF | UHCI_PTR_TD);
    1988           0 :         } else {
    1989             :                 next = stat;
    1990             :         }
    1991           0 :         upipe->u.ctl.length = len;
    1992             : 
    1993           0 :         memcpy(KERNADDR(&upipe->u.ctl.reqdma, 0), req, sizeof *req);
    1994             : 
    1995           0 :         setup->link.std = next;
    1996           0 :         setup->td.td_link = htole32(next->physaddr | UHCI_PTR_VF | UHCI_PTR_TD);
    1997           0 :         setup->td.td_status = htole32(UHCI_TD_SET_ERRCNT(3) | ls |
    1998             :                 UHCI_TD_ACTIVE);
    1999           0 :         setup->td.td_token = htole32(UHCI_TD_SETUP(sizeof *req, endpt, addr));
    2000           0 :         setup->td.td_buffer = htole32(DMAADDR(&upipe->u.ctl.reqdma, 0));
    2001             : 
    2002           0 :         stat->link.std = NULL;
    2003           0 :         stat->td.td_link = htole32(UHCI_PTR_T);
    2004           0 :         stat->td.td_status = htole32(UHCI_TD_SET_ERRCNT(3) | ls |
    2005             :                 UHCI_TD_ACTIVE | UHCI_TD_IOC);
    2006           0 :         stat->td.td_token = htole32(usbd_xfer_isread(xfer) ?
    2007             :             UHCI_TD_OUT(0, endpt, addr, 1) : UHCI_TD_IN (0, endpt, addr, 1));
    2008           0 :         stat->td.td_buffer = htole32(0);
    2009             : 
    2010             : #ifdef UHCI_DEBUG
    2011             :         if (uhcidebug > 10) {
    2012             :                 DPRINTF(("uhci_device_request: before transfer\n"));
    2013             :                 uhci_dump_tds(setup);
    2014             :         }
    2015             : #endif
    2016             : 
    2017             :         /* Set up interrupt info. */
    2018           0 :         ux->stdstart = setup;
    2019           0 :         ux->stdend = stat;
    2020             : #ifdef DIAGNOSTIC
    2021           0 :         if (!ux->isdone) {
    2022           0 :                 printf("%s: not done, ux=%p\n", __func__, ux);
    2023           0 :         }
    2024           0 :         ux->isdone = 0;
    2025             : #endif
    2026             : 
    2027           0 :         sqh->elink = setup;
    2028           0 :         sqh->qh.qh_elink = htole32(setup->physaddr | UHCI_PTR_TD);
    2029             : 
    2030           0 :         s = splusb();
    2031           0 :         if (xfer->device->speed == USB_SPEED_LOW)
    2032           0 :                 uhci_add_ls_ctrl(sc, sqh);
    2033             :         else
    2034           0 :                 uhci_add_hs_ctrl(sc, sqh);
    2035           0 :         uhci_add_intr_list(sc, ux);
    2036             : #ifdef UHCI_DEBUG
    2037             :         if (uhcidebug > 12) {
    2038             :                 struct uhci_soft_td *std;
    2039             :                 struct uhci_soft_qh *xqh;
    2040             :                 struct uhci_soft_qh *sxqh;
    2041             :                 int maxqh = 0;
    2042             :                 uhci_physaddr_t link;
    2043             :                 DPRINTF(("uhci_device_request: follow from [0]\n"));
    2044             :                 for (std = sc->sc_vframes[0].htd, link = 0;
    2045             :                      (link & UHCI_PTR_QH) == 0;
    2046             :                      std = std->link.std) {
    2047             :                         link = letoh32(std->td.td_link);
    2048             :                         uhci_dump_td(std);
    2049             :                 }
    2050             :                 sxqh = (struct uhci_soft_qh *)std;
    2051             :                 uhci_dump_qh(sxqh);
    2052             :                 for (xqh = sxqh;
    2053             :                      xqh != NULL;
    2054             :                      xqh = (maxqh++ == 5 || xqh->hlink == sxqh ||
    2055             :                             xqh->hlink == xqh ? NULL : xqh->hlink)) {
    2056             :                         uhci_dump_qh(xqh);
    2057             :                 }
    2058             :                 DPRINTF(("Enqueued QH:\n"));
    2059             :                 uhci_dump_qh(sqh);
    2060             :                 uhci_dump_tds(sqh->elink);
    2061             :         }
    2062             : #endif
    2063           0 :         if (xfer->timeout && !sc->sc_bus.use_polling) {
    2064           0 :                 timeout_del(&xfer->timeout_handle);
    2065           0 :                 timeout_set(&xfer->timeout_handle, uhci_timeout, xfer);
    2066           0 :                 timeout_add_msec(&xfer->timeout_handle, xfer->timeout);
    2067           0 :         }
    2068           0 :         xfer->status = USBD_IN_PROGRESS;
    2069           0 :         splx(s);
    2070             : 
    2071           0 :         return (USBD_NORMAL_COMPLETION);
    2072           0 : }
    2073             : 
    2074             : usbd_status
    2075           0 : uhci_device_isoc_transfer(struct usbd_xfer *xfer)
    2076             : {
    2077             :         usbd_status err;
    2078             : 
    2079             :         DPRINTFN(5,("uhci_device_isoc_transfer: xfer=%p\n", xfer));
    2080             : 
    2081             :         /* Put it on our queue, */
    2082           0 :         err = usb_insert_transfer(xfer);
    2083             : 
    2084             :         /* bail out on error, */
    2085           0 :         if (err && err != USBD_IN_PROGRESS)
    2086           0 :                 return (err);
    2087             : 
    2088             :         /* XXX should check inuse here */
    2089             : 
    2090             :         /* insert into schedule, */
    2091           0 :         uhci_device_isoc_enter(xfer);
    2092             : 
    2093             :         /* and start if the pipe wasn't running */
    2094           0 :         if (!err)
    2095           0 :                 uhci_device_isoc_start(SIMPLEQ_FIRST(&xfer->pipe->queue));
    2096             : 
    2097           0 :         return (err);
    2098           0 : }
    2099             : 
    2100             : void
    2101           0 : uhci_device_isoc_enter(struct usbd_xfer *xfer)
    2102             : {
    2103           0 :         struct uhci_softc *sc = (struct uhci_softc *)xfer->device->bus;
    2104           0 :         struct uhci_pipe *upipe = (struct uhci_pipe *)xfer->pipe;
    2105           0 :         struct iso *iso = &upipe->u.iso;
    2106             :         struct uhci_soft_td *std;
    2107             :         u_int32_t buf, len, status;
    2108             :         int s, i, next, nframes;
    2109             : 
    2110             :         DPRINTFN(5,("uhci_device_isoc_enter: used=%d next=%d xfer=%p "
    2111             :                     "nframes=%d\n",
    2112             :                     iso->inuse, iso->next, xfer, xfer->nframes));
    2113             : 
    2114           0 :         if (sc->sc_bus.dying)
    2115           0 :                 return;
    2116             : 
    2117           0 :         if (xfer->status == USBD_IN_PROGRESS) {
    2118             :                 /* This request has already been entered into the frame list */
    2119           0 :                 printf("uhci_device_isoc_enter: xfer=%p in frame list\n", xfer);
    2120             :                 /* XXX */
    2121           0 :         }
    2122             : 
    2123             : #ifdef DIAGNOSTIC
    2124           0 :         if (iso->inuse >= UHCI_VFRAMELIST_COUNT)
    2125           0 :                 printf("uhci_device_isoc_enter: overflow!\n");
    2126             : #endif
    2127             : 
    2128           0 :         next = iso->next;
    2129           0 :         if (next == -1) {
    2130             :                 /* Not in use yet, schedule it a few frames ahead. */
    2131           0 :                 next = (UREAD2(sc, UHCI_FRNUM) + 3) % UHCI_VFRAMELIST_COUNT;
    2132             :                 DPRINTFN(2,("uhci_device_isoc_enter: start next=%d\n", next));
    2133           0 :         }
    2134             : 
    2135           0 :         xfer->status = USBD_IN_PROGRESS;
    2136           0 :         ((struct uhci_xfer *)xfer)->curframe = next;
    2137             : 
    2138           0 :         buf = DMAADDR(&xfer->dmabuf, 0);
    2139             :         status = UHCI_TD_ZERO_ACTLEN(UHCI_TD_SET_ERRCNT(0) |
    2140             :                                      UHCI_TD_ACTIVE |
    2141             :                                      UHCI_TD_IOS);
    2142           0 :         nframes = xfer->nframes;
    2143           0 :         s = splusb();
    2144           0 :         for (i = 0; i < nframes; i++) {
    2145           0 :                 std = iso->stds[next];
    2146           0 :                 if (++next >= UHCI_VFRAMELIST_COUNT)
    2147             :                         next = 0;
    2148           0 :                 len = xfer->frlengths[i];
    2149           0 :                 std->td.td_buffer = htole32(buf);
    2150           0 :                 if (i == nframes - 1)
    2151           0 :                         status |= UHCI_TD_IOC;
    2152           0 :                 std->td.td_status = htole32(status);
    2153           0 :                 std->td.td_token &= htole32(~UHCI_TD_MAXLEN_MASK);
    2154           0 :                 std->td.td_token |= htole32(UHCI_TD_SET_MAXLEN(len));
    2155             : #ifdef UHCI_DEBUG
    2156             :                 if (uhcidebug > 5) {
    2157             :                         DPRINTFN(5,("uhci_device_isoc_enter: TD %d\n", i));
    2158             :                         uhci_dump_td(std);
    2159             :                 }
    2160             : #endif
    2161           0 :                 buf += len;
    2162             :         }
    2163           0 :         iso->next = next;
    2164           0 :         iso->inuse += xfer->nframes;
    2165             : 
    2166           0 :         splx(s);
    2167           0 : }
    2168             : 
    2169             : usbd_status
    2170           0 : uhci_device_isoc_start(struct usbd_xfer *xfer)
    2171             : {
    2172           0 :         struct uhci_softc *sc = (struct uhci_softc *)xfer->device->bus;
    2173           0 :         struct uhci_pipe *upipe = (struct uhci_pipe *)xfer->pipe;
    2174           0 :         struct uhci_xfer *ux = (struct uhci_xfer *)xfer;
    2175             :         struct uhci_soft_td *end;
    2176             :         int s, i;
    2177             : 
    2178             :         DPRINTFN(5,("uhci_device_isoc_start: xfer=%p\n", xfer));
    2179             : 
    2180           0 :         if (sc->sc_bus.dying)
    2181           0 :                 return (USBD_IOERROR);
    2182             : 
    2183             : #ifdef DIAGNOSTIC
    2184           0 :         if (xfer->status != USBD_IN_PROGRESS)
    2185           0 :                 printf("uhci_device_isoc_start: not in progress %p\n", xfer);
    2186             : #endif
    2187             : 
    2188             :         /* Find the last TD */
    2189           0 :         i = ux->curframe + xfer->nframes;
    2190           0 :         if (i >= UHCI_VFRAMELIST_COUNT)
    2191           0 :                 i -= UHCI_VFRAMELIST_COUNT;
    2192           0 :         end = upipe->u.iso.stds[i];
    2193             : 
    2194             : #ifdef DIAGNOSTIC
    2195           0 :         if (end == NULL) {
    2196           0 :                 printf("uhci_device_isoc_start: end == NULL\n");
    2197           0 :                 return (USBD_INVAL);
    2198             :         }
    2199             : #endif
    2200             : 
    2201           0 :         s = splusb();
    2202             : 
    2203             :         /* Set up interrupt info. */
    2204           0 :         ux->stdstart = end;
    2205           0 :         ux->stdend = end;
    2206             : #ifdef DIAGNOSTIC
    2207           0 :         if (!ux->isdone)
    2208           0 :                 printf("%s: not done, ux=%p\n", __func__, ux);
    2209           0 :         ux->isdone = 0;
    2210             : #endif
    2211           0 :         uhci_add_intr_list(sc, ux);
    2212             : 
    2213           0 :         splx(s);
    2214             : 
    2215           0 :         return (USBD_IN_PROGRESS);
    2216           0 : }
    2217             : 
    2218             : void
    2219           0 : uhci_device_isoc_abort(struct usbd_xfer *xfer)
    2220             : {
    2221           0 :         struct uhci_xfer *ux = (struct uhci_xfer *)xfer;
    2222           0 :         struct uhci_pipe *upipe = (struct uhci_pipe *)xfer->pipe;
    2223           0 :         struct uhci_soft_td **stds = upipe->u.iso.stds;
    2224             :         struct uhci_soft_td *std;
    2225             :         int i, n, s, nframes, maxlen, len;
    2226             : 
    2227           0 :         s = splusb();
    2228             : 
    2229             :         /* Transfer is already done. */
    2230           0 :         if (xfer->status != USBD_NOT_STARTED &&
    2231           0 :             xfer->status != USBD_IN_PROGRESS) {
    2232           0 :                 splx(s);
    2233           0 :                 return;
    2234             :         }
    2235             : 
    2236             :         /* Give xfer the requested abort code. */
    2237           0 :         xfer->status = USBD_CANCELLED;
    2238             : 
    2239             :         /* make hardware ignore it, */
    2240           0 :         nframes = xfer->nframes;
    2241           0 :         n = ux->curframe;
    2242             :         maxlen = 0;
    2243           0 :         for (i = 0; i < nframes; i++) {
    2244           0 :                 std = stds[n];
    2245           0 :                 std->td.td_status &= htole32(~(UHCI_TD_ACTIVE | UHCI_TD_IOC));
    2246           0 :                 len = UHCI_TD_GET_MAXLEN(letoh32(std->td.td_token));
    2247           0 :                 if (len > maxlen)
    2248           0 :                         maxlen = len;
    2249           0 :                 if (++n >= UHCI_VFRAMELIST_COUNT)
    2250             :                         n = 0;
    2251             :         }
    2252             : 
    2253             :         /* and wait until we are sure the hardware has finished. */
    2254           0 :         delay(maxlen);
    2255             : 
    2256             : #ifdef DIAGNOSTIC
    2257           0 :         ux->isdone = 1;
    2258             : #endif
    2259             :         /* Run callback and remove from interrupt list. */
    2260           0 :         usb_transfer_complete(xfer);
    2261             : 
    2262           0 :         splx(s);
    2263           0 : }
    2264             : 
    2265             : void
    2266           0 : uhci_device_isoc_close(struct usbd_pipe *pipe)
    2267             : {
    2268           0 :         struct uhci_softc *sc = (struct uhci_softc *)pipe->device->bus;
    2269           0 :         struct uhci_pipe *upipe = (struct uhci_pipe *)pipe;
    2270             :         struct uhci_soft_td *std, *vstd;
    2271             :         struct iso *iso;
    2272             :         int i, s;
    2273             : 
    2274             :         /*
    2275             :          * Make sure all TDs are marked as inactive.
    2276             :          * Wait for completion.
    2277             :          * Unschedule.
    2278             :          * Deallocate.
    2279             :          */
    2280           0 :         iso = &upipe->u.iso;
    2281             : 
    2282           0 :         for (i = 0; i < UHCI_VFRAMELIST_COUNT; i++)
    2283           0 :                 iso->stds[i]->td.td_status &= htole32(~UHCI_TD_ACTIVE);
    2284           0 :         usb_delay_ms(&sc->sc_bus, 2); /* wait for completion */
    2285             : 
    2286           0 :         s = splusb();
    2287           0 :         for (i = 0; i < UHCI_VFRAMELIST_COUNT; i++) {
    2288           0 :                 std = iso->stds[i];
    2289           0 :                 for (vstd = sc->sc_vframes[i].htd;
    2290           0 :                      vstd != NULL && vstd->link.std != std;
    2291             :                      vstd = vstd->link.std)
    2292             :                         ;
    2293           0 :                 if (vstd == NULL) {
    2294             :                         /*panic*/
    2295           0 :                         printf("uhci_device_isoc_close: %p not found\n", std);
    2296           0 :                         splx(s);
    2297           0 :                         return;
    2298             :                 }
    2299           0 :                 vstd->link = std->link;
    2300           0 :                 vstd->td.td_link = std->td.td_link;
    2301           0 :                 uhci_free_std(sc, std);
    2302             :         }
    2303           0 :         splx(s);
    2304             : 
    2305           0 :         free(iso->stds, M_USBHC, 0);
    2306           0 : }
    2307             : 
    2308             : usbd_status
    2309           0 : uhci_setup_isoc(struct usbd_pipe *pipe)
    2310             : {
    2311           0 :         struct uhci_softc *sc = (struct uhci_softc *)pipe->device->bus;
    2312           0 :         struct uhci_pipe *upipe = (struct uhci_pipe *)pipe;
    2313           0 :         int addr = pipe->device->address;
    2314           0 :         int endpt = pipe->endpoint->edesc->bEndpointAddress;
    2315           0 :         int rd = UE_GET_DIR(endpt) == UE_DIR_IN;
    2316             :         struct uhci_soft_td *std, *vstd;
    2317             :         u_int32_t token;
    2318             :         struct iso *iso;
    2319             :         int i, s;
    2320             : 
    2321           0 :         iso = &upipe->u.iso;
    2322           0 :         iso->stds = malloc(UHCI_VFRAMELIST_COUNT *
    2323             :                            sizeof (struct uhci_soft_td *),
    2324             :                            M_USBHC, M_WAITOK);
    2325             : 
    2326           0 :         token = rd ? UHCI_TD_IN (0, endpt, addr, 0) :
    2327           0 :                      UHCI_TD_OUT(0, endpt, addr, 0);
    2328             : 
    2329             :         /* Allocate the TDs and mark as inactive; */
    2330           0 :         for (i = 0; i < UHCI_VFRAMELIST_COUNT; i++) {
    2331           0 :                 std = uhci_alloc_std(sc);
    2332           0 :                 if (std == 0)
    2333             :                         goto bad;
    2334           0 :                 std->td.td_status = htole32(UHCI_TD_IOS); /* iso, inactive */
    2335           0 :                 std->td.td_token = htole32(token);
    2336           0 :                 iso->stds[i] = std;
    2337             :         }
    2338             : 
    2339             :         /* Insert TDs into schedule. */
    2340           0 :         s = splusb();
    2341           0 :         for (i = 0; i < UHCI_VFRAMELIST_COUNT; i++) {
    2342           0 :                 std = iso->stds[i];
    2343           0 :                 vstd = sc->sc_vframes[i].htd;
    2344           0 :                 std->link = vstd->link;
    2345           0 :                 std->td.td_link = vstd->td.td_link;
    2346           0 :                 vstd->link.std = std;
    2347           0 :                 vstd->td.td_link = htole32(std->physaddr | UHCI_PTR_TD);
    2348             :         }
    2349           0 :         splx(s);
    2350             : 
    2351           0 :         iso->next = -1;
    2352           0 :         iso->inuse = 0;
    2353             : 
    2354           0 :         return (USBD_NORMAL_COMPLETION);
    2355             : 
    2356             :  bad:
    2357           0 :         while (--i >= 0)
    2358           0 :                 uhci_free_std(sc, iso->stds[i]);
    2359           0 :         free(iso->stds, M_USBHC, 0);
    2360           0 :         return (USBD_NOMEM);
    2361           0 : }
    2362             : 
    2363             : void
    2364           0 : uhci_device_isoc_done(struct usbd_xfer *xfer)
    2365             : {
    2366           0 :         struct uhci_xfer *ux = (struct uhci_xfer *)xfer;
    2367             : 
    2368             :         DPRINTFN(4, ("uhci_device_isoc_done: length=%d\n", xfer->actlen));
    2369             : 
    2370           0 :         if (!uhci_active_intr_list(ux))
    2371           0 :                 return;
    2372             : 
    2373             : #ifdef DIAGNOSTIC
    2374           0 :         if (ux->stdend == NULL) {
    2375           0 :                 printf("uhci_device_isoc_done: xfer=%p stdend==NULL\n", xfer);
    2376             : #ifdef UHCI_DEBUG
    2377             :                 uhci_dump_xfer(ux);
    2378             : #endif
    2379           0 :                 return;
    2380             :         }
    2381             : #endif
    2382             : 
    2383             :         /* Turn off the interrupt since it is active even if the TD is not. */
    2384           0 :         ux->stdend->td.td_status &= htole32(~UHCI_TD_IOC);
    2385             : 
    2386           0 :         uhci_del_intr_list(ux); /* remove from active list */
    2387           0 : }
    2388             : 
    2389             : void
    2390           0 : uhci_device_intr_done(struct usbd_xfer *xfer)
    2391             : {
    2392           0 :         struct uhci_softc *sc = (struct uhci_softc *)xfer->device->bus;
    2393           0 :         struct uhci_pipe *upipe = (struct uhci_pipe *)xfer->pipe;
    2394           0 :         struct uhci_xfer *ux = (struct uhci_xfer *)xfer;
    2395             :         struct uhci_soft_qh *sqh;
    2396             :         int i, npoll;
    2397             : 
    2398             :         DPRINTFN(5, ("uhci_device_intr_done: length=%d\n", xfer->actlen));
    2399             : 
    2400           0 :         npoll = upipe->u.intr.npoll;
    2401           0 :         for(i = 0; i < npoll; i++) {
    2402           0 :                 sqh = upipe->u.intr.qhs[i];
    2403           0 :                 sqh->elink = NULL;
    2404           0 :                 sqh->qh.qh_elink = htole32(UHCI_PTR_T);
    2405             :         }
    2406           0 :         uhci_free_std_chain(sc, ux->stdstart, NULL);
    2407             : 
    2408             :         /* XXX Wasteful. */
    2409           0 :         if (xfer->pipe->repeat) {
    2410           0 :                 struct uhci_soft_td *data, *dataend;
    2411             : 
    2412             :                 DPRINTFN(5,("uhci_device_intr_done: requeuing\n"));
    2413             : 
    2414             :                 /* This alloc cannot fail since we freed the chain above. */
    2415           0 :                 uhci_alloc_std_chain(sc, xfer->length, xfer, &data, &dataend);
    2416           0 :                 dataend->td.td_status |= htole32(UHCI_TD_IOC);
    2417             : 
    2418             : #ifdef UHCI_DEBUG
    2419             :                 if (uhcidebug > 10) {
    2420             :                         DPRINTF(("uhci_device_intr_done: data(1)\n"));
    2421             :                         uhci_dump_tds(data);
    2422             :                         uhci_dump_qh(upipe->u.intr.qhs[0]);
    2423             :                 }
    2424             : #endif
    2425             : 
    2426           0 :                 ux->stdstart = data;
    2427           0 :                 ux->stdend = dataend;
    2428             : #ifdef DIAGNOSTIC
    2429           0 :                 if (!ux->isdone) {
    2430           0 :                         printf("%s: not done, ux=%p\n", __func__, ux);
    2431           0 :                 }
    2432           0 :                 ux->isdone = 0;
    2433             : #endif
    2434           0 :                 for (i = 0; i < npoll; i++) {
    2435           0 :                         sqh = upipe->u.intr.qhs[i];
    2436           0 :                         sqh->elink = data;
    2437           0 :                         sqh->qh.qh_elink = htole32(data->physaddr | UHCI_PTR_TD);
    2438             :                 }
    2439           0 :                 xfer->status = USBD_IN_PROGRESS;
    2440             :                 /* The ux is already on the examined list, just leave it. */
    2441           0 :         } else {
    2442             :                 DPRINTFN(5,("uhci_device_intr_done: removing\n"));
    2443           0 :                 if (uhci_active_intr_list(ux))
    2444           0 :                         uhci_del_intr_list(ux);
    2445             :         }
    2446           0 : }
    2447             : 
    2448             : /* Deallocate request data structures */
    2449             : void
    2450           0 : uhci_device_ctrl_done(struct usbd_xfer *xfer)
    2451             : {
    2452           0 :         struct uhci_softc *sc = (struct uhci_softc *)xfer->device->bus;
    2453           0 :         struct uhci_pipe *upipe = (struct uhci_pipe *)xfer->pipe;
    2454           0 :         struct uhci_xfer *ux = (struct uhci_xfer *)xfer;
    2455             : 
    2456             : #ifdef DIAGNOSTIC
    2457           0 :         if (!(xfer->rqflags & URQ_REQUEST))
    2458           0 :                 panic("uhci_device_ctrl_done: not a request");
    2459             : #endif
    2460             : 
    2461           0 :         if (!uhci_active_intr_list(ux))
    2462           0 :                 return;
    2463             : 
    2464           0 :         uhci_del_intr_list(ux); /* remove from active list */
    2465             : 
    2466           0 :         if (xfer->device->speed == USB_SPEED_LOW)
    2467           0 :                 uhci_remove_ls_ctrl(sc, upipe->u.ctl.sqh);
    2468             :         else
    2469           0 :                 uhci_remove_hs_ctrl(sc, upipe->u.ctl.sqh);
    2470             : 
    2471           0 :         if (upipe->u.ctl.length != 0)
    2472           0 :                 uhci_free_std_chain(sc, ux->stdstart->link.std, ux->stdend);
    2473             : 
    2474             :         DPRINTFN(5, ("uhci_device_ctrl_done: length=%d\n", xfer->actlen));
    2475           0 : }
    2476             : 
    2477             : /* Deallocate request data structures */
    2478             : void
    2479           0 : uhci_device_bulk_done(struct usbd_xfer *xfer)
    2480             : {
    2481           0 :         struct uhci_softc *sc = (struct uhci_softc *)xfer->device->bus;
    2482           0 :         struct uhci_pipe *upipe = (struct uhci_pipe *)xfer->pipe;
    2483           0 :         struct uhci_xfer *ux = (struct uhci_xfer *)xfer;
    2484             : 
    2485             :         DPRINTFN(5,("uhci_device_bulk_done: xfer=%p ux=%p sc=%p upipe=%p\n",
    2486             :                     xfer, ux, sc, upipe));
    2487             : 
    2488           0 :         if (!uhci_active_intr_list(ux))
    2489           0 :                 return;
    2490             : 
    2491           0 :         uhci_del_intr_list(ux); /* remove from active list */
    2492             : 
    2493           0 :         uhci_remove_bulk(sc, upipe->u.bulk.sqh);
    2494             : 
    2495           0 :         uhci_free_std_chain(sc, ux->stdstart, NULL);
    2496             : 
    2497             :         DPRINTFN(5, ("uhci_device_bulk_done: length=%d\n", xfer->actlen));
    2498           0 : }
    2499             : 
    2500             : /* Add interrupt QH, called with vflock. */
    2501             : void
    2502           0 : uhci_add_intr(struct uhci_softc *sc, struct uhci_soft_qh *sqh)
    2503             : {
    2504           0 :         struct uhci_vframe *vf = &sc->sc_vframes[sqh->pos];
    2505             :         struct uhci_soft_qh *eqh;
    2506             : 
    2507             :         DPRINTFN(4, ("uhci_add_intr: n=%d sqh=%p\n", sqh->pos, sqh));
    2508             : 
    2509           0 :         eqh = vf->eqh;
    2510           0 :         sqh->hlink       = eqh->hlink;
    2511           0 :         sqh->qh.qh_hlink = eqh->qh.qh_hlink;
    2512           0 :         eqh->hlink       = sqh;
    2513           0 :         eqh->qh.qh_hlink = htole32(sqh->physaddr | UHCI_PTR_QH);
    2514           0 :         vf->eqh = sqh;
    2515           0 :         vf->bandwidth++;
    2516           0 : }
    2517             : 
    2518             : /* Remove interrupt QH. */
    2519             : void
    2520           0 : uhci_remove_intr(struct uhci_softc *sc, struct uhci_soft_qh *sqh)
    2521             : {
    2522           0 :         struct uhci_vframe *vf = &sc->sc_vframes[sqh->pos];
    2523             :         struct uhci_soft_qh *pqh;
    2524             : 
    2525             :         DPRINTFN(4, ("uhci_remove_intr: n=%d sqh=%p\n", sqh->pos, sqh));
    2526             : 
    2527             :         /* See comment in uhci_remove_ctrl() */
    2528           0 :         if (!(sqh->qh.qh_elink & htole32(UHCI_PTR_T))) {
    2529           0 :                 sqh->qh.qh_elink = htole32(UHCI_PTR_T);
    2530           0 :                 delay(UHCI_QH_REMOVE_DELAY);
    2531           0 :         }
    2532             : 
    2533           0 :         pqh = uhci_find_prev_qh(vf->hqh, sqh);
    2534           0 :         pqh->hlink       = sqh->hlink;
    2535           0 :         pqh->qh.qh_hlink = sqh->qh.qh_hlink;
    2536           0 :         delay(UHCI_QH_REMOVE_DELAY);
    2537           0 :         if (vf->eqh == sqh)
    2538           0 :                 vf->eqh = pqh;
    2539           0 :         vf->bandwidth--;
    2540           0 : }
    2541             : 
    2542             : usbd_status
    2543           0 : uhci_device_setintr(struct uhci_softc *sc, struct uhci_pipe *upipe, int ival)
    2544             : {
    2545             :         struct uhci_soft_qh *sqh, **qhs;
    2546             :         int i, npoll, s;
    2547             :         u_int bestbw, bw, bestoffs, offs;
    2548             : 
    2549             :         DPRINTFN(2, ("uhci_device_setintr: pipe=%p\n", upipe));
    2550           0 :         if (ival == 0) {
    2551           0 :                 printf("uhci_device_setintr: 0 interval\n");
    2552           0 :                 return (USBD_INVAL);
    2553             :         }
    2554             : 
    2555           0 :         if (ival > UHCI_VFRAMELIST_COUNT)
    2556           0 :                 ival = UHCI_VFRAMELIST_COUNT;
    2557           0 :         npoll = (UHCI_VFRAMELIST_COUNT + ival - 1) / ival;
    2558             :         DPRINTFN(2, ("uhci_device_setintr: ival=%d npoll=%d\n", ival, npoll));
    2559             : 
    2560           0 :         qhs = mallocarray(npoll, sizeof(struct uhci_soft_qh *), M_USBHC,
    2561             :             M_NOWAIT);
    2562           0 :         if (qhs == NULL)
    2563           0 :                 return (USBD_NOMEM);
    2564             : 
    2565             :         /*
    2566             :          * Figure out which offset in the schedule that has most
    2567             :          * bandwidth left over.
    2568             :          */
    2569             : #define MOD(i) ((i) & (UHCI_VFRAMELIST_COUNT-1))
    2570           0 :         for (bestoffs = offs = 0, bestbw = ~0; offs < ival; offs++) {
    2571           0 :                 for (bw = i = 0; i < npoll; i++)
    2572           0 :                         bw += sc->sc_vframes[MOD(i * ival + offs)].bandwidth;
    2573           0 :                 if (bw < bestbw) {
    2574             :                         bestbw = bw;
    2575             :                         bestoffs = offs;
    2576           0 :                 }
    2577             :         }
    2578             :         DPRINTFN(1, ("uhci_device_setintr: bw=%d offs=%d\n", bestbw, bestoffs));
    2579             : 
    2580           0 :         for(i = 0; i < npoll; i++) {
    2581           0 :                 sqh = uhci_alloc_sqh(sc);
    2582           0 :                 if (sqh == NULL) {
    2583           0 :                         while (i > 0)
    2584           0 :                                 uhci_free_sqh(sc, qhs[--i]);
    2585           0 :                         free(qhs, M_USBHC, 0);
    2586           0 :                         return (USBD_NOMEM);
    2587             :                 }
    2588           0 :                 sqh->elink = NULL;
    2589           0 :                 sqh->qh.qh_elink = htole32(UHCI_PTR_T);
    2590           0 :                 sqh->pos = MOD(i * ival + bestoffs);
    2591           0 :                 qhs[i] = sqh;
    2592             :         }
    2593             : #undef MOD
    2594             : 
    2595           0 :         upipe->u.intr.npoll = npoll;
    2596           0 :         upipe->u.intr.qhs = qhs;
    2597             : 
    2598           0 :         s = splusb();
    2599             :         /* Enter QHs into the controller data structures. */
    2600           0 :         for(i = 0; i < npoll; i++)
    2601           0 :                 uhci_add_intr(sc, upipe->u.intr.qhs[i]);
    2602           0 :         splx(s);
    2603             : 
    2604             :         DPRINTFN(5, ("uhci_device_setintr: returns %p\n", upipe));
    2605           0 :         return (USBD_NORMAL_COMPLETION);
    2606           0 : }
    2607             : 
    2608             : /* Open a new pipe. */
    2609             : usbd_status
    2610           0 : uhci_open(struct usbd_pipe *pipe)
    2611             : {
    2612           0 :         struct uhci_softc *sc = (struct uhci_softc *)pipe->device->bus;
    2613           0 :         struct uhci_pipe *upipe = (struct uhci_pipe *)pipe;
    2614           0 :         usb_endpoint_descriptor_t *ed = pipe->endpoint->edesc;
    2615             :         usbd_status err;
    2616             :         int ival;
    2617             : 
    2618             :         DPRINTFN(1, ("uhci_open: pipe=%p, addr=%d, endpt=%d\n",
    2619             :                      pipe, pipe->device->address, ed->bEndpointAddress));
    2620             : 
    2621           0 :         upipe->nexttoggle = pipe->endpoint->savedtoggle;
    2622             : 
    2623             :         /* Root Hub */
    2624           0 :         if (pipe->device->depth == 0) {
    2625           0 :                 switch (ed->bEndpointAddress) {
    2626             :                 case USB_CONTROL_ENDPOINT:
    2627           0 :                         pipe->methods = &uhci_root_ctrl_methods;
    2628           0 :                         break;
    2629             :                 case UE_DIR_IN | UHCI_INTR_ENDPT:
    2630           0 :                         pipe->methods = &uhci_root_intr_methods;
    2631           0 :                         break;
    2632             :                 default:
    2633           0 :                         return (USBD_INVAL);
    2634             :                 }
    2635             :         } else {
    2636           0 :                 switch (ed->bmAttributes & UE_XFERTYPE) {
    2637             :                 case UE_CONTROL:
    2638           0 :                         pipe->methods = &uhci_device_ctrl_methods;
    2639           0 :                         upipe->u.ctl.sqh = uhci_alloc_sqh(sc);
    2640           0 :                         if (upipe->u.ctl.sqh == NULL)
    2641             :                                 goto bad;
    2642           0 :                         upipe->u.ctl.setup = uhci_alloc_std(sc);
    2643           0 :                         if (upipe->u.ctl.setup == NULL) {
    2644           0 :                                 uhci_free_sqh(sc, upipe->u.ctl.sqh);
    2645           0 :                                 goto bad;
    2646             :                         }
    2647           0 :                         upipe->u.ctl.stat = uhci_alloc_std(sc);
    2648           0 :                         if (upipe->u.ctl.stat == NULL) {
    2649           0 :                                 uhci_free_sqh(sc, upipe->u.ctl.sqh);
    2650           0 :                                 uhci_free_std(sc, upipe->u.ctl.setup);
    2651           0 :                                 goto bad;
    2652             :                         }
    2653           0 :                         err = usb_allocmem(&sc->sc_bus,
    2654             :                                   sizeof(usb_device_request_t),
    2655           0 :                                   0, &upipe->u.ctl.reqdma);
    2656           0 :                         if (err) {
    2657           0 :                                 uhci_free_sqh(sc, upipe->u.ctl.sqh);
    2658           0 :                                 uhci_free_std(sc, upipe->u.ctl.setup);
    2659           0 :                                 uhci_free_std(sc, upipe->u.ctl.stat);
    2660           0 :                                 goto bad;
    2661             :                         }
    2662             :                         break;
    2663             :                 case UE_INTERRUPT:
    2664           0 :                         pipe->methods = &uhci_device_intr_methods;
    2665           0 :                         ival = pipe->interval;
    2666           0 :                         if (ival == USBD_DEFAULT_INTERVAL)
    2667           0 :                                 ival = ed->bInterval;
    2668           0 :                         return (uhci_device_setintr(sc, upipe, ival));
    2669             :                 case UE_ISOCHRONOUS:
    2670           0 :                         pipe->methods = &uhci_device_isoc_methods;
    2671           0 :                         return (uhci_setup_isoc(pipe));
    2672             :                 case UE_BULK:
    2673           0 :                         pipe->methods = &uhci_device_bulk_methods;
    2674           0 :                         upipe->u.bulk.sqh = uhci_alloc_sqh(sc);
    2675           0 :                         if (upipe->u.bulk.sqh == NULL)
    2676             :                                 goto bad;
    2677             :                         break;
    2678             :                 }
    2679             :         }
    2680           0 :         return (USBD_NORMAL_COMPLETION);
    2681             : 
    2682             :  bad:
    2683           0 :         return (USBD_NOMEM);
    2684           0 : }
    2685             : 
    2686             : /*
    2687             :  * Data structures and routines to emulate the root hub.
    2688             :  */
    2689             : usb_device_descriptor_t uhci_devd = {
    2690             :         USB_DEVICE_DESCRIPTOR_SIZE,
    2691             :         UDESC_DEVICE,           /* type */
    2692             :         {0x00, 0x01},           /* USB version */
    2693             :         UDCLASS_HUB,            /* class */
    2694             :         UDSUBCLASS_HUB,         /* subclass */
    2695             :         UDPROTO_FSHUB,          /* protocol */
    2696             :         64,                     /* max packet */
    2697             :         {0},{0},{0x00,0x01},    /* device id */
    2698             :         1,2,0,                  /* string indices */
    2699             :         1                       /* # of configurations */
    2700             : };
    2701             : 
    2702             : usb_config_descriptor_t uhci_confd = {
    2703             :         USB_CONFIG_DESCRIPTOR_SIZE,
    2704             :         UDESC_CONFIG,
    2705             :         {USB_CONFIG_DESCRIPTOR_SIZE +
    2706             :          USB_INTERFACE_DESCRIPTOR_SIZE +
    2707             :          USB_ENDPOINT_DESCRIPTOR_SIZE},
    2708             :         1,
    2709             :         1,
    2710             :         0,
    2711             :         UC_SELF_POWERED,
    2712             :         0                       /* max power */
    2713             : };
    2714             : 
    2715             : usb_interface_descriptor_t uhci_ifcd = {
    2716             :         USB_INTERFACE_DESCRIPTOR_SIZE,
    2717             :         UDESC_INTERFACE,
    2718             :         0,
    2719             :         0,
    2720             :         1,
    2721             :         UICLASS_HUB,
    2722             :         UISUBCLASS_HUB,
    2723             :         UIPROTO_FSHUB,
    2724             :         0
    2725             : };
    2726             : 
    2727             : usb_endpoint_descriptor_t uhci_endpd = {
    2728             :         USB_ENDPOINT_DESCRIPTOR_SIZE,
    2729             :         UDESC_ENDPOINT,
    2730             :         UE_DIR_IN | UHCI_INTR_ENDPT,
    2731             :         UE_INTERRUPT,
    2732             :         {8},
    2733             :         255
    2734             : };
    2735             : 
    2736             : usb_hub_descriptor_t uhci_hubd_piix = {
    2737             :         USB_HUB_DESCRIPTOR_SIZE,
    2738             :         UDESC_HUB,
    2739             :         2,
    2740             :         { UHD_PWR_NO_SWITCH | UHD_OC_INDIVIDUAL, 0 },
    2741             :         50,                     /* power on to power good */
    2742             :         0,
    2743             :         { 0x00 },               /* both ports are removable */
    2744             : };
    2745             : 
    2746             : /*
    2747             :  * The USB hub protocol requires that SET_FEATURE(PORT_RESET) also
    2748             :  * enables the port, and also states that SET_FEATURE(PORT_ENABLE)
    2749             :  * should not be used by the USB subsystem.  As we cannot issue a
    2750             :  * SET_FEATURE(PORT_ENABLE) externally, we must ensure that the port
    2751             :  * will be enabled as part of the reset.
    2752             :  *
    2753             :  * On the VT83C572, the port cannot be successfully enabled until the
    2754             :  * outstanding "port enable change" and "connection status change"
    2755             :  * events have been reset.
    2756             :  */
    2757             : usbd_status
    2758           0 : uhci_portreset(struct uhci_softc *sc, int index)
    2759             : {
    2760             :         int lim, port, x;
    2761             : 
    2762           0 :         if (index == 1)
    2763           0 :                 port = UHCI_PORTSC1;
    2764           0 :         else if (index == 2)
    2765             :                 port = UHCI_PORTSC2;
    2766             :         else
    2767           0 :                 return (USBD_IOERROR);
    2768             : 
    2769           0 :         x = URWMASK(UREAD2(sc, port));
    2770           0 :         UWRITE2(sc, port, x | UHCI_PORTSC_PR);
    2771             : 
    2772           0 :         usb_delay_ms(&sc->sc_bus, USB_PORT_ROOT_RESET_DELAY);
    2773             : 
    2774             :         DPRINTFN(3,("uhci port %d reset, status0 = 0x%04x\n",
    2775             :                     index, UREAD2(sc, port)));
    2776             : 
    2777           0 :         x = URWMASK(UREAD2(sc, port));
    2778           0 :         UWRITE2(sc, port, x & ~UHCI_PORTSC_PR);
    2779             : 
    2780           0 :         delay(100);
    2781             : 
    2782             :         DPRINTFN(3,("uhci port %d reset, status1 = 0x%04x\n",
    2783             :                     index, UREAD2(sc, port)));
    2784             : 
    2785           0 :         x = URWMASK(UREAD2(sc, port));
    2786           0 :         UWRITE2(sc, port, x  | UHCI_PORTSC_PE);
    2787             : 
    2788           0 :         for (lim = 10; --lim > 0;) {
    2789           0 :                 usb_delay_ms(&sc->sc_bus, USB_PORT_RESET_DELAY);
    2790             : 
    2791           0 :                 x = UREAD2(sc, port);
    2792             : 
    2793             :                 DPRINTFN(3,("uhci port %d iteration %u, status = 0x%04x\n",
    2794             :                             index, lim, x));
    2795             : 
    2796           0 :                 if (!(x & UHCI_PORTSC_CCS)) {
    2797             :                         /*
    2798             :                          * No device is connected (or was disconnected
    2799             :                          * during reset).  Consider the port reset.
    2800             :                          * The delay must be long enough to ensure on
    2801             :                          * the initial iteration that the device
    2802             :                          * connection will have been registered.  50ms
    2803             :                          * appears to be sufficient, but 20ms is not.
    2804             :                          */
    2805             :                         DPRINTFN(3,("uhci port %d loop %u, device detached\n",
    2806             :                                     index, lim));
    2807             :                         break;
    2808             :                 }
    2809             : 
    2810           0 :                 if (x & (UHCI_PORTSC_POEDC | UHCI_PORTSC_CSC)) {
    2811             :                         /*
    2812             :                          * Port enabled changed and/or connection
    2813             :                          * status changed were set.  Reset either or
    2814             :                          * both raised flags (by writing a 1 to that
    2815             :                          * bit), and wait again for state to settle.
    2816             :                          */
    2817           0 :                         UWRITE2(sc, port, URWMASK(x) |
    2818             :                                 (x & (UHCI_PORTSC_POEDC | UHCI_PORTSC_CSC)));
    2819           0 :                         continue;
    2820             :                 }
    2821             : 
    2822           0 :                 if (x & UHCI_PORTSC_PE)
    2823             :                         /* Port is enabled */
    2824             :                         break;
    2825             : 
    2826           0 :                 UWRITE2(sc, port, URWMASK(x) | UHCI_PORTSC_PE);
    2827             :         }
    2828             : 
    2829             :         DPRINTFN(3,("uhci port %d reset, status2 = 0x%04x\n",
    2830             :                     index, UREAD2(sc, port)));
    2831             : 
    2832           0 :         if (lim <= 0) {
    2833             :                 DPRINTFN(1,("uhci port %d reset timed out\n", index));
    2834           0 :                 return (USBD_TIMEOUT);
    2835             :         }
    2836             :         
    2837           0 :         sc->sc_isreset = 1;
    2838           0 :         return (USBD_NORMAL_COMPLETION);
    2839           0 : }
    2840             : 
    2841             : /*
    2842             :  * Simulate a hardware hub by handling all the necessary requests.
    2843             :  */
    2844             : usbd_status
    2845           0 : uhci_root_ctrl_transfer(struct usbd_xfer *xfer)
    2846             : {
    2847             :         usbd_status err;
    2848             : 
    2849             :         /* Insert last in queue. */
    2850           0 :         err = usb_insert_transfer(xfer);
    2851           0 :         if (err)
    2852           0 :                 return (err);
    2853             : 
    2854             :         /*
    2855             :          * Pipe isn't running (otherwise err would be USBD_INPROG),
    2856             :          * so start it first.
    2857             :          */
    2858           0 :         return (uhci_root_ctrl_start(SIMPLEQ_FIRST(&xfer->pipe->queue)));
    2859           0 : }
    2860             : 
    2861             : usbd_status
    2862           0 : uhci_root_ctrl_start(struct usbd_xfer *xfer)
    2863             : {
    2864           0 :         struct uhci_softc *sc = (struct uhci_softc *)xfer->device->bus;
    2865             :         usb_device_request_t *req;
    2866             :         void *buf = NULL;
    2867             :         int port, x;
    2868             :         int s, len, value, index, status, change, l, totlen = 0;
    2869           0 :         usb_port_status_t ps;
    2870             :         usbd_status err;
    2871             : 
    2872           0 :         if (sc->sc_bus.dying)
    2873           0 :                 return (USBD_IOERROR);
    2874             : 
    2875             : #ifdef DIAGNOSTIC
    2876           0 :         if (!(xfer->rqflags & URQ_REQUEST))
    2877           0 :                 panic("uhci_root_ctrl_start: not a request");
    2878             : #endif
    2879           0 :         req = &xfer->request;
    2880             : 
    2881             :         DPRINTFN(2,("uhci_root_ctrl_start type=0x%02x request=%02x\n",
    2882             :                     req->bmRequestType, req->bRequest));
    2883             : 
    2884           0 :         len = UGETW(req->wLength);
    2885           0 :         value = UGETW(req->wValue);
    2886           0 :         index = UGETW(req->wIndex);
    2887             : 
    2888           0 :         if (len != 0)
    2889           0 :                 buf = KERNADDR(&xfer->dmabuf, 0);
    2890             : 
    2891             : #define C(x,y) ((x) | ((y) << 8))
    2892           0 :         switch(C(req->bRequest, req->bmRequestType)) {
    2893             :         case C(UR_CLEAR_FEATURE, UT_WRITE_DEVICE):
    2894             :         case C(UR_CLEAR_FEATURE, UT_WRITE_INTERFACE):
    2895             :         case C(UR_CLEAR_FEATURE, UT_WRITE_ENDPOINT):
    2896             :                 /*
    2897             :                  * DEVICE_REMOTE_WAKEUP and ENDPOINT_HALT are no-ops
    2898             :                  * for the integrated root hub.
    2899             :                  */
    2900             :                 break;
    2901             :         case C(UR_GET_CONFIG, UT_READ_DEVICE):
    2902           0 :                 if (len > 0) {
    2903           0 :                         *(u_int8_t *)buf = sc->sc_conf;
    2904             :                         totlen = 1;
    2905           0 :                 }
    2906             :                 break;
    2907             :         case C(UR_GET_DESCRIPTOR, UT_READ_DEVICE):
    2908             :                 DPRINTFN(2,("uhci_root_ctrl_start wValue=0x%04x\n", value));
    2909           0 :                 switch(value >> 8) {
    2910             :                 case UDESC_DEVICE:
    2911           0 :                         if ((value & 0xff) != 0) {
    2912             :                                 err = USBD_IOERROR;
    2913           0 :                                 goto ret;
    2914             :                         }
    2915           0 :                         totlen = l = min(len, USB_DEVICE_DESCRIPTOR_SIZE);
    2916           0 :                         USETW(uhci_devd.idVendor, sc->sc_id_vendor);
    2917           0 :                         memcpy(buf, &uhci_devd, l);
    2918           0 :                         break;
    2919             :                 case UDESC_CONFIG:
    2920           0 :                         if ((value & 0xff) != 0) {
    2921             :                                 err = USBD_IOERROR;
    2922           0 :                                 goto ret;
    2923             :                         }
    2924           0 :                         totlen = l = min(len, USB_CONFIG_DESCRIPTOR_SIZE);
    2925           0 :                         memcpy(buf, &uhci_confd, l);
    2926           0 :                         buf = (char *)buf + l;
    2927           0 :                         len -= l;
    2928           0 :                         l = min(len, USB_INTERFACE_DESCRIPTOR_SIZE);
    2929           0 :                         totlen += l;
    2930           0 :                         memcpy(buf, &uhci_ifcd, l);
    2931           0 :                         buf = (char *)buf + l;
    2932           0 :                         len -= l;
    2933           0 :                         l = min(len, USB_ENDPOINT_DESCRIPTOR_SIZE);
    2934           0 :                         totlen += l;
    2935           0 :                         memcpy(buf, &uhci_endpd, l);
    2936           0 :                         break;
    2937             :                 case UDESC_STRING:
    2938           0 :                         if (len == 0)
    2939             :                                 break;
    2940           0 :                         *(u_int8_t *)buf = 0;
    2941             :                         totlen = 1;
    2942           0 :                         switch (value & 0xff) {
    2943             :                         case 0: /* Language table */
    2944           0 :                                 totlen = usbd_str(buf, len, "\001");
    2945           0 :                                 break;
    2946             :                         case 1: /* Vendor */
    2947           0 :                                 totlen = usbd_str(buf, len, sc->sc_vendor);
    2948           0 :                                 break;
    2949             :                         case 2: /* Product */
    2950           0 :                                 totlen = usbd_str(buf, len, "UHCI root hub");
    2951           0 :                                 break;
    2952             :                         }
    2953             :                         break;
    2954             :                 default:
    2955             :                         err = USBD_IOERROR;
    2956           0 :                         goto ret;
    2957             :                 }
    2958             :                 break;
    2959             :         case C(UR_GET_INTERFACE, UT_READ_INTERFACE):
    2960           0 :                 if (len > 0) {
    2961           0 :                         *(u_int8_t *)buf = 0;
    2962             :                         totlen = 1;
    2963           0 :                 }
    2964             :                 break;
    2965             :         case C(UR_GET_STATUS, UT_READ_DEVICE):
    2966           0 :                 if (len > 1) {
    2967           0 :                         USETW(((usb_status_t *)buf)->wStatus,UDS_SELF_POWERED);
    2968             :                         totlen = 2;
    2969           0 :                 }
    2970             :                 break;
    2971             :         case C(UR_GET_STATUS, UT_READ_INTERFACE):
    2972             :         case C(UR_GET_STATUS, UT_READ_ENDPOINT):
    2973           0 :                 if (len > 1) {
    2974           0 :                         USETW(((usb_status_t *)buf)->wStatus, 0);
    2975             :                         totlen = 2;
    2976           0 :                 }
    2977             :                 break;
    2978             :         case C(UR_SET_ADDRESS, UT_WRITE_DEVICE):
    2979           0 :                 if (value >= USB_MAX_DEVICES) {
    2980             :                         err = USBD_IOERROR;
    2981           0 :                         goto ret;
    2982             :                 }
    2983             :                 break;
    2984             :         case C(UR_SET_CONFIG, UT_WRITE_DEVICE):
    2985           0 :                 if (value != 0 && value != 1) {
    2986             :                         err = USBD_IOERROR;
    2987           0 :                         goto ret;
    2988             :                 }
    2989           0 :                 sc->sc_conf = value;
    2990           0 :                 break;
    2991             :         case C(UR_SET_DESCRIPTOR, UT_WRITE_DEVICE):
    2992             :                 break;
    2993             :         case C(UR_SET_FEATURE, UT_WRITE_DEVICE):
    2994             :         case C(UR_SET_FEATURE, UT_WRITE_INTERFACE):
    2995             :         case C(UR_SET_FEATURE, UT_WRITE_ENDPOINT):
    2996             :                 err = USBD_IOERROR;
    2997           0 :                 goto ret;
    2998             :         case C(UR_SET_INTERFACE, UT_WRITE_INTERFACE):
    2999             :                 break;
    3000             :         case C(UR_SYNCH_FRAME, UT_WRITE_ENDPOINT):
    3001             :                 break;
    3002             :         /* Hub requests */
    3003             :         case C(UR_CLEAR_FEATURE, UT_WRITE_CLASS_DEVICE):
    3004             :                 break;
    3005             :         case C(UR_CLEAR_FEATURE, UT_WRITE_CLASS_OTHER):
    3006             :                 DPRINTFN(3, ("uhci_root_ctrl_start: UR_CLEAR_PORT_FEATURE "
    3007             :                              "port=%d feature=%d\n",
    3008             :                              index, value));
    3009           0 :                 if (index == 1)
    3010           0 :                         port = UHCI_PORTSC1;
    3011           0 :                 else if (index == 2)
    3012             :                         port = UHCI_PORTSC2;
    3013             :                 else {
    3014             :                         err = USBD_IOERROR;
    3015           0 :                         goto ret;
    3016             :                 }
    3017           0 :                 switch(value) {
    3018             :                 case UHF_PORT_ENABLE:
    3019           0 :                         x = URWMASK(UREAD2(sc, port));
    3020           0 :                         UWRITE2(sc, port, x & ~UHCI_PORTSC_PE);
    3021           0 :                         break;
    3022             :                 case UHF_PORT_SUSPEND:
    3023           0 :                         x = URWMASK(UREAD2(sc, port));
    3024           0 :                         UWRITE2(sc, port, x & ~UHCI_PORTSC_SUSP);
    3025           0 :                         break;
    3026             :                 case UHF_PORT_RESET:
    3027           0 :                         x = URWMASK(UREAD2(sc, port));
    3028           0 :                         UWRITE2(sc, port, x & ~UHCI_PORTSC_PR);
    3029           0 :                         break;
    3030             :                 case UHF_C_PORT_CONNECTION:
    3031           0 :                         x = URWMASK(UREAD2(sc, port));
    3032           0 :                         UWRITE2(sc, port, x | UHCI_PORTSC_CSC);
    3033           0 :                         break;
    3034             :                 case UHF_C_PORT_ENABLE:
    3035           0 :                         x = URWMASK(UREAD2(sc, port));
    3036           0 :                         UWRITE2(sc, port, x | UHCI_PORTSC_POEDC);
    3037           0 :                         break;
    3038             :                 case UHF_C_PORT_OVER_CURRENT:
    3039           0 :                         x = URWMASK(UREAD2(sc, port));
    3040           0 :                         UWRITE2(sc, port, x | UHCI_PORTSC_OCIC);
    3041           0 :                         break;
    3042             :                 case UHF_C_PORT_RESET:
    3043           0 :                         sc->sc_isreset = 0;
    3044             :                         err = USBD_NORMAL_COMPLETION;
    3045           0 :                         goto ret;
    3046             :                 case UHF_PORT_CONNECTION:
    3047             :                 case UHF_PORT_OVER_CURRENT:
    3048             :                 case UHF_PORT_POWER:
    3049             :                 case UHF_PORT_LOW_SPEED:
    3050             :                 case UHF_C_PORT_SUSPEND:
    3051             :                 default:
    3052             :                         err = USBD_IOERROR;
    3053           0 :                         goto ret;
    3054             :                 }
    3055             :                 break;
    3056             :         case C(UR_GET_BUS_STATE, UT_READ_CLASS_OTHER):
    3057           0 :                 if (index == 1)
    3058           0 :                         port = UHCI_PORTSC1;
    3059           0 :                 else if (index == 2)
    3060             :                         port = UHCI_PORTSC2;
    3061             :                 else {
    3062             :                         err = USBD_IOERROR;
    3063           0 :                         goto ret;
    3064             :                 }
    3065           0 :                 if (len > 0) {
    3066           0 :                         *(u_int8_t *)buf =
    3067           0 :                                 (UREAD2(sc, port) & UHCI_PORTSC_LS) >>
    3068             :                                 UHCI_PORTSC_LS_SHIFT;
    3069             :                         totlen = 1;
    3070           0 :                 }
    3071             :                 break;
    3072             :         case C(UR_GET_DESCRIPTOR, UT_READ_CLASS_DEVICE):
    3073           0 :                 if ((value & 0xff) != 0) {
    3074             :                         err = USBD_IOERROR;
    3075           0 :                         goto ret;
    3076             :                 }
    3077           0 :                 l = min(len, USB_HUB_DESCRIPTOR_SIZE);
    3078             :                 totlen = l;
    3079           0 :                 memcpy(buf, &uhci_hubd_piix, l);
    3080           0 :                 break;
    3081             :         case C(UR_GET_STATUS, UT_READ_CLASS_DEVICE):
    3082           0 :                 if (len != 4) {
    3083             :                         err = USBD_IOERROR;
    3084           0 :                         goto ret;
    3085             :                 }
    3086           0 :                 memset(buf, 0, len);
    3087             :                 totlen = len;
    3088           0 :                 break;
    3089             :         case C(UR_GET_STATUS, UT_READ_CLASS_OTHER):
    3090           0 :                 if (index == 1)
    3091           0 :                         port = UHCI_PORTSC1;
    3092           0 :                 else if (index == 2)
    3093             :                         port = UHCI_PORTSC2;
    3094             :                 else {
    3095             :                         err = USBD_IOERROR;
    3096           0 :                         goto ret;
    3097             :                 }
    3098           0 :                 if (len != 4) {
    3099             :                         err = USBD_IOERROR;
    3100           0 :                         goto ret;
    3101             :                 }
    3102           0 :                 x = UREAD2(sc, port);
    3103             :                 status = change = 0;
    3104           0 :                 if (x & UHCI_PORTSC_CCS)
    3105           0 :                         status |= UPS_CURRENT_CONNECT_STATUS;
    3106           0 :                 if (x & UHCI_PORTSC_CSC)
    3107           0 :                         change |= UPS_C_CONNECT_STATUS;
    3108           0 :                 if (x & UHCI_PORTSC_PE)
    3109           0 :                         status |= UPS_PORT_ENABLED;
    3110           0 :                 if (x & UHCI_PORTSC_POEDC)
    3111           0 :                         change |= UPS_C_PORT_ENABLED;
    3112           0 :                 if (x & UHCI_PORTSC_OCI)
    3113           0 :                         status |= UPS_OVERCURRENT_INDICATOR;
    3114           0 :                 if (x & UHCI_PORTSC_OCIC)
    3115           0 :                         change |= UPS_C_OVERCURRENT_INDICATOR;
    3116           0 :                 if (x & UHCI_PORTSC_SUSP)
    3117           0 :                         status |= UPS_SUSPEND;
    3118           0 :                 if (x & UHCI_PORTSC_LSDA)
    3119           0 :                         status |= UPS_LOW_SPEED;
    3120           0 :                 status |= UPS_PORT_POWER;
    3121           0 :                 if (sc->sc_isreset)
    3122           0 :                         change |= UPS_C_PORT_RESET;
    3123           0 :                 USETW(ps.wPortStatus, status);
    3124           0 :                 USETW(ps.wPortChange, change);
    3125           0 :                 l = min(len, sizeof ps);
    3126           0 :                 memcpy(buf, &ps, l);
    3127             :                 totlen = l;
    3128           0 :                 break;
    3129             :         case C(UR_SET_DESCRIPTOR, UT_WRITE_CLASS_DEVICE):
    3130             :                 err = USBD_IOERROR;
    3131           0 :                 goto ret;
    3132             :         case C(UR_SET_FEATURE, UT_WRITE_CLASS_DEVICE):
    3133             :                 break;
    3134             :         case C(UR_SET_FEATURE, UT_WRITE_CLASS_OTHER):
    3135           0 :                 if (index == 1)
    3136           0 :                         port = UHCI_PORTSC1;
    3137           0 :                 else if (index == 2)
    3138             :                         port = UHCI_PORTSC2;
    3139             :                 else {
    3140             :                         err = USBD_IOERROR;
    3141           0 :                         goto ret;
    3142             :                 }
    3143           0 :                 switch(value) {
    3144             :                 case UHF_PORT_ENABLE:
    3145           0 :                         x = URWMASK(UREAD2(sc, port));
    3146           0 :                         UWRITE2(sc, port, x | UHCI_PORTSC_PE);
    3147           0 :                         break;
    3148             :                 case UHF_PORT_SUSPEND:
    3149           0 :                         x = URWMASK(UREAD2(sc, port));
    3150           0 :                         UWRITE2(sc, port, x | UHCI_PORTSC_SUSP);
    3151           0 :                         break;
    3152             :                 case UHF_PORT_RESET:
    3153           0 :                         err = uhci_portreset(sc, index);
    3154           0 :                         goto ret;
    3155             :                 case UHF_PORT_POWER:
    3156             :                         /* Pretend we turned on power */
    3157             :                         err = USBD_NORMAL_COMPLETION;
    3158           0 :                         goto ret;
    3159             :                 case UHF_PORT_DISOWN_TO_1_1:
    3160             :                         /* accept, but do nothing */
    3161             :                         err = USBD_NORMAL_COMPLETION;
    3162           0 :                         goto ret;
    3163             :                 case UHF_C_PORT_CONNECTION:
    3164             :                 case UHF_C_PORT_ENABLE:
    3165             :                 case UHF_C_PORT_OVER_CURRENT:
    3166             :                 case UHF_PORT_CONNECTION:
    3167             :                 case UHF_PORT_OVER_CURRENT:
    3168             :                 case UHF_PORT_LOW_SPEED:
    3169             :                 case UHF_C_PORT_SUSPEND:
    3170             :                 case UHF_C_PORT_RESET:
    3171             :                 default:
    3172             :                         err = USBD_IOERROR;
    3173           0 :                         goto ret;
    3174             :                 }
    3175             :                 break;
    3176             :         default:
    3177             :                 err = USBD_IOERROR;
    3178           0 :                 goto ret;
    3179             :         }
    3180           0 :         xfer->actlen = totlen;
    3181           0 :         err = USBD_NORMAL_COMPLETION;
    3182             :  ret:
    3183           0 :         xfer->status = err;
    3184           0 :         s = splusb();
    3185           0 :         usb_transfer_complete(xfer);
    3186           0 :         splx(s);
    3187           0 :         return (err);
    3188           0 : }
    3189             : 
    3190             : /* Abort a root control request. */
    3191             : void
    3192           0 : uhci_root_ctrl_abort(struct usbd_xfer *xfer)
    3193             : {
    3194             :         /* Nothing to do, all transfers are synchronous. */
    3195           0 : }
    3196             : 
    3197             : /* Close the root pipe. */
    3198             : void
    3199           0 : uhci_root_ctrl_close(struct usbd_pipe *pipe)
    3200             : {
    3201             :         DPRINTF(("uhci_root_ctrl_close\n"));
    3202           0 : }
    3203             : 
    3204             : void
    3205           0 : uhci_root_intr_abort(struct usbd_xfer *xfer)
    3206             : {
    3207           0 :         struct uhci_softc *sc = (struct uhci_softc *)xfer->device->bus;
    3208             :         int s;
    3209             : 
    3210           0 :         timeout_del(&sc->sc_root_intr);
    3211           0 :         sc->sc_intrxfer = NULL;
    3212             : 
    3213           0 :         xfer->status = USBD_CANCELLED;
    3214           0 :         s = splusb();
    3215           0 :         usb_transfer_complete(xfer);
    3216           0 :         splx(s);
    3217           0 : }
    3218             : 
    3219             : usbd_status
    3220           0 : uhci_root_intr_transfer(struct usbd_xfer *xfer)
    3221             : {
    3222             :         usbd_status err;
    3223             : 
    3224             :         /* Insert last in queue. */
    3225           0 :         err = usb_insert_transfer(xfer);
    3226           0 :         if (err)
    3227           0 :                 return (err);
    3228             : 
    3229             :         /* Pipe isn't running (otherwise err would be USBD_INPROG),
    3230             :          * start first
    3231             :          */
    3232           0 :         return (uhci_root_intr_start(SIMPLEQ_FIRST(&xfer->pipe->queue)));
    3233           0 : }
    3234             : 
    3235             : /* Start a transfer on the root interrupt pipe */
    3236             : usbd_status
    3237           0 : uhci_root_intr_start(struct usbd_xfer *xfer)
    3238             : {
    3239           0 :         struct uhci_softc *sc = (struct uhci_softc *)xfer->device->bus;
    3240             : 
    3241           0 :         if (sc->sc_bus.dying)
    3242           0 :                 return (USBD_IOERROR);
    3243             : 
    3244           0 :         sc->sc_intrxfer = xfer;
    3245           0 :         timeout_add_msec(&sc->sc_root_intr, 255);
    3246             : 
    3247           0 :         return (USBD_IN_PROGRESS);
    3248           0 : }
    3249             : 
    3250             : void
    3251           0 : uhci_root_intr_close(struct usbd_pipe *pipe)
    3252             : {
    3253           0 : }
    3254             : 
    3255             : void
    3256           0 : uhci_root_intr_done(struct usbd_xfer *xfer)
    3257             : {
    3258           0 :         struct uhci_softc *sc = (struct uhci_softc *)xfer->device->bus;
    3259             : 
    3260           0 :         if (xfer->pipe->repeat)
    3261           0 :                 timeout_add_msec(&sc->sc_root_intr, 255);
    3262           0 : }

Generated by: LCOV version 1.13