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


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

FreeBSD/Linux Kernel Cross Reference
sys/dev/ic/sl811hs.c

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

    1 /*      $NetBSD: sl811hs.c,v 1.5 2005/02/27 00:27:02 perry Exp $        */
    2 
    3 /*
    4  * Copyright (c) 2001 The NetBSD Foundation, Inc.
    5  * All rights reserved.
    6  *
    7  * This code is derived from software contributed to The NetBSD Foundation
    8  * by Tetsuya Isaki.
    9  *
   10  * Redistribution and use in source and binary forms, with or without
   11  * modification, are permitted provided that the following conditions
   12  * are met:
   13  * 1. Redistributions of source code must retain the above copyright
   14  *    notice, this list of conditions and the following disclaimer.
   15  * 2. Redistributions in binary form must reproduce the above copyright
   16  *    notice, this list of conditions and the following disclaimer in the
   17  *    documentation and/or other materials provided with the distribution.
   18  * 3. All advertising materials mentioning features or use of this software
   19  *    must display the following acknowledgement:
   20  *      This product includes software developed by the NetBSD
   21  *      Foundation, Inc. and its contributors.
   22  * 4. Neither the name of The NetBSD Foundation nor the names of its
   23  *    contributors may be used to endorse or promote products derived
   24  *    from this software without specific prior written permission.
   25  *
   26  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
   27  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
   28  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
   29  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
   30  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
   31  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
   32  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
   33  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
   34  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
   35  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
   36  * POSSIBILITY OF SUCH DAMAGE.
   37  */
   38 
   39 /*
   40  * ScanLogic SL811HS/T USB Host Controller
   41  */
   42 /*
   43  * !! HIGHLY EXPERIMENTAL CODE !!
   44  */
   45 
   46 #include <sys/cdefs.h>
   47 __KERNEL_RCSID(0, "$NetBSD: sl811hs.c,v 1.5 2005/02/27 00:27:02 perry Exp $");
   48 
   49 #include "opt_slhci.h"
   50 
   51 #include <sys/param.h>
   52 #include <sys/systm.h>
   53 #include <sys/kernel.h>
   54 #include <sys/proc.h>
   55 #include <sys/device.h>
   56 #include <sys/malloc.h>
   57 
   58 #include <machine/bus.h>
   59 #include <machine/cpu.h>
   60 
   61 #include <dev/usb/usb.h>
   62 #include <dev/usb/usbdi.h>
   63 #include <dev/usb/usbdivar.h>
   64 #include <dev/usb/usb_mem.h>
   65 #include <dev/usb/usbdevs.h>
   66 
   67 #include <dev/ic/sl811hsreg.h>
   68 #include <dev/ic/sl811hsvar.h>
   69 
   70 static inline u_int8_t sl11read(struct slhci_softc *, int);
   71 static inline void     sl11write(struct slhci_softc *, int, u_int8_t);
   72 static inline void sl11read_region(struct slhci_softc *, u_char *, int, int);
   73 static inline void sl11write_region(struct slhci_softc *, int, u_char *, int);
   74 
   75 static void             sl11_reset(struct slhci_softc *);
   76 static void             sl11_speed(struct slhci_softc *);
   77 
   78 static usbd_status      slhci_open(usbd_pipe_handle);
   79 static void             slhci_softintr(void *);
   80 static void             slhci_poll(struct usbd_bus *);
   81 static void             slhci_poll_hub(void *);
   82 static void             slhci_poll_device(void *arg);
   83 static usbd_status      slhci_allocm(struct usbd_bus *, usb_dma_t *, u_int32_t);
   84 static void             slhci_freem(struct usbd_bus *, usb_dma_t *);
   85 static usbd_xfer_handle slhci_allocx(struct usbd_bus *);
   86 static void             slhci_freex(struct usbd_bus *, usbd_xfer_handle);
   87 
   88 static int              slhci_str(usb_string_descriptor_t *, int, char *);
   89 
   90 static usbd_status      slhci_root_ctrl_transfer(usbd_xfer_handle);
   91 static usbd_status      slhci_root_ctrl_start(usbd_xfer_handle);
   92 static void             slhci_root_ctrl_abort(usbd_xfer_handle);
   93 static void             slhci_root_ctrl_close(usbd_pipe_handle);
   94 static void             slhci_root_ctrl_done(usbd_xfer_handle);
   95 
   96 static usbd_status      slhci_root_intr_transfer(usbd_xfer_handle);
   97 static usbd_status      slhci_root_intr_start(usbd_xfer_handle);
   98 static void             slhci_root_intr_abort(usbd_xfer_handle);
   99 static void             slhci_root_intr_close(usbd_pipe_handle);
  100 static void             slhci_root_intr_done(usbd_xfer_handle);
  101 
  102 static usbd_status      slhci_device_ctrl_transfer(usbd_xfer_handle);
  103 static usbd_status      slhci_device_ctrl_start(usbd_xfer_handle);
  104 static void             slhci_device_ctrl_abort(usbd_xfer_handle);
  105 static void             slhci_device_ctrl_close(usbd_pipe_handle);
  106 static void             slhci_device_ctrl_done(usbd_xfer_handle);
  107 
  108 static usbd_status      slhci_device_intr_transfer(usbd_xfer_handle);
  109 static usbd_status      slhci_device_intr_start(usbd_xfer_handle);
  110 static void             slhci_device_intr_abort(usbd_xfer_handle);
  111 static void             slhci_device_intr_close(usbd_pipe_handle);
  112 static void             slhci_device_intr_done(usbd_xfer_handle);
  113 
  114 static usbd_status      slhci_device_isoc_transfer(usbd_xfer_handle);
  115 static usbd_status      slhci_device_isoc_start(usbd_xfer_handle);
  116 static void             slhci_device_isoc_abort(usbd_xfer_handle);
  117 static void             slhci_device_isoc_close(usbd_pipe_handle);
  118 static void             slhci_device_isoc_done(usbd_xfer_handle);
  119 
  120 static usbd_status      slhci_device_bulk_transfer(usbd_xfer_handle);
  121 static usbd_status      slhci_device_bulk_start(usbd_xfer_handle);
  122 static void             slhci_device_bulk_abort(usbd_xfer_handle);
  123 static void             slhci_device_bulk_close(usbd_pipe_handle);
  124 static void             slhci_device_bulk_done(usbd_xfer_handle);
  125 
  126 static int              slhci_transaction(struct slhci_softc *,
  127         usbd_pipe_handle, u_int8_t, int, u_char *, u_int8_t);
  128 static void             slhci_noop(usbd_pipe_handle);
  129 static void             slhci_abort_xfer(usbd_xfer_handle, usbd_status);
  130 static void             slhci_device_clear_toggle(usbd_pipe_handle);
  131 
  132 extern int usbdebug;
  133 int slhci_dummy;
  134 
  135 /* For root hub */
  136 #define SLHCI_INTR_ENDPT        (1)
  137 
  138 #ifdef SLHCI_DEBUG
  139 #define D_TRACE (0x0001)        /* function trace */
  140 #define D_MSG   (0x0002)        /* debug messages */
  141 #define D_XFER  (0x0004)        /* transfer messages (noisy!) */
  142 #define D_MEM   (0x0008)        /* memory allocation */
  143 
  144 int slhci_debug = D_MSG | D_XFER;
  145 #define DPRINTF(z,x)    if((slhci_debug&(z))!=0)printf x
  146 void            print_req(usb_device_request_t *);
  147 void            print_req_hub(usb_device_request_t *);
  148 void            print_dumpreg(struct slhci_softc *);
  149 void            print_xfer(usbd_xfer_handle);
  150 #else
  151 #define DPRINTF(z,x)
  152 #endif
  153 
  154 
  155 /* XXX: sync with argument */
  156 static char *sltypestr [] = {
  157         "SL11H/T",
  158         "SL811HS/T",
  159 };
  160 
  161 
  162 struct usbd_bus_methods slhci_bus_methods = {
  163         slhci_open,
  164         slhci_softintr,
  165         slhci_poll,
  166         slhci_allocm,
  167         slhci_freem,
  168         slhci_allocx,
  169         slhci_freex,
  170 };
  171 
  172 struct usbd_pipe_methods slhci_root_ctrl_methods = {
  173         slhci_root_ctrl_transfer,
  174         slhci_root_ctrl_start,
  175         slhci_root_ctrl_abort,
  176         slhci_root_ctrl_close,
  177         slhci_noop,
  178         slhci_root_ctrl_done,
  179 };
  180 
  181 struct usbd_pipe_methods slhci_root_intr_methods = {
  182         slhci_root_intr_transfer,
  183         slhci_root_intr_start,
  184         slhci_root_intr_abort,
  185         slhci_root_intr_close,
  186         slhci_noop,
  187         slhci_root_intr_done,
  188 };
  189 
  190 struct usbd_pipe_methods slhci_device_ctrl_methods = {
  191         slhci_device_ctrl_transfer,
  192         slhci_device_ctrl_start,
  193         slhci_device_ctrl_abort,
  194         slhci_device_ctrl_close,
  195         slhci_noop,
  196         slhci_device_ctrl_done,
  197 };
  198 
  199 struct usbd_pipe_methods slhci_device_intr_methods = {
  200         slhci_device_intr_transfer,
  201         slhci_device_intr_start,
  202         slhci_device_intr_abort,
  203         slhci_device_intr_close,
  204         slhci_device_clear_toggle,
  205         slhci_device_intr_done,
  206 };
  207 
  208 struct usbd_pipe_methods slhci_device_isoc_methods = {
  209         slhci_device_isoc_transfer,
  210         slhci_device_isoc_start,
  211         slhci_device_isoc_abort,
  212         slhci_device_isoc_close,
  213         slhci_noop,
  214         slhci_device_isoc_done,
  215 };
  216 
  217 struct usbd_pipe_methods slhci_device_bulk_methods = {
  218         slhci_device_bulk_transfer,
  219         slhci_device_bulk_start,
  220         slhci_device_bulk_abort,
  221         slhci_device_bulk_close,
  222         slhci_noop,
  223         slhci_device_bulk_done,
  224 };
  225 
  226 struct slhci_pipe {
  227         struct usbd_pipe pipe;
  228 };
  229 
  230 
  231 /*
  232  * SL811HS Register read/write routine
  233  */
  234 static inline u_int8_t
  235 sl11read(struct slhci_softc *sc, int reg)
  236 {
  237         bus_space_write_1(sc->sc_iot, sc->sc_ioh, SL11_IDX_ADDR, reg);
  238         return bus_space_read_1(sc->sc_iot, sc->sc_ioh, SL11_IDX_DATA);
  239 }
  240 
  241 static inline void
  242 sl11write(struct slhci_softc *sc, int reg, u_int8_t data)
  243 {
  244         bus_space_write_1(sc->sc_iot, sc->sc_ioh, SL11_IDX_ADDR, reg);
  245         bus_space_write_1(sc->sc_iot, sc->sc_ioh, SL11_IDX_DATA, data);
  246 }
  247 
  248 static inline void
  249 sl11read_region(struct slhci_softc *sc, u_char *buf, int reg, int len)
  250 {
  251         int i;
  252         bus_space_write_1(sc->sc_iot, sc->sc_ioh, SL11_IDX_ADDR, reg);
  253         for (i = 0; i < len; i++)
  254                 buf[i] = bus_space_read_1(sc->sc_iot, sc->sc_ioh, SL11_IDX_DATA);
  255 }
  256 
  257 static inline void
  258 sl11write_region(struct slhci_softc *sc, int reg, u_char *buf, int len)
  259 {
  260         int i;
  261         bus_space_write_1(sc->sc_iot, sc->sc_ioh, SL11_IDX_ADDR, reg);
  262         for (i = 0; i < len; i++)
  263                 bus_space_write_1(sc->sc_iot, sc->sc_ioh, SL11_IDX_DATA, buf[i]);
  264 }
  265 
  266 /*
  267  * USB bus reset. From sl811hs_appnote.pdf, p22
  268  */
  269 static void
  270 sl11_reset(struct slhci_softc *sc)
  271 {
  272         u_int8_t r;
  273 
  274         DPRINTF(D_TRACE, ("%s() ", __FUNCTION__));
  275         r = sl11read(sc, SL11_CTRL);
  276         sl11write(sc, SL11_CTRL, r | SL11_CTRL_RESETENGINE);
  277         delay_ms(250);
  278         sl11write(sc, SL11_CTRL, r | SL11_CTRL_RESETENGINE | SL11_CTRL_SUSPEND);
  279         delay_ms(150);
  280         sl11write(sc, SL11_CTRL, r | SL11_CTRL_RESETENGINE);
  281         delay_ms(10);
  282         sl11write(sc, SL11_CTRL, r);
  283 }
  284 
  285 /*
  286  * Detect the speed of attached device.
  287  */
  288 static void
  289 sl11_speed(struct slhci_softc *sc)
  290 {
  291         u_int8_t r;
  292 
  293         sl11write(sc, SL11_ISR, 0xff);
  294         r = sl11read(sc, SL11_ISR);
  295         if ((r & SL11_ISR_RESET)) {
  296                 DPRINTF(D_MSG, ("NC "));
  297                 sl11write(sc, SL11_ISR, SL11_ISR_RESET);
  298                 sc->sc_connect = 0;
  299         }
  300 
  301         if ((sl11read(sc, SL11_ISR) & SL11_ISR_RESET)) {
  302                 sl11write(sc, SL11_ISR, 0xff);
  303         } else {
  304                 u_int8_t pol = 0, ctrl = 0;
  305 
  306                 sc->sc_connect = 1;
  307                 if (r & SL11_ISR_DATA) {
  308                         DPRINTF(D_MSG, ("FS "));
  309                         pol  = 0;
  310                         ctrl = SL11_CTRL_EOF2;
  311                         sc->sc_fullspeed = 1;
  312                 } else {
  313                         DPRINTF(D_MSG, ("LS "));
  314                         pol  = SL811_CSOF_POLARITY;
  315                         ctrl = SL11_CTRL_LOWSPEED;
  316                         sc->sc_fullspeed = 0;
  317                 }
  318                 sl11write(sc, SL811_CSOF, pol | SL811_CSOF_MASTER | 0x2e);
  319                 sl11write(sc, SL11_DATA, 0xe0);
  320                 sl11write(sc, SL11_CTRL, ctrl | SL11_CTRL_ENABLESOF);
  321         }
  322 
  323         sl11write(sc, SL11_E0PID,  (SL11_PID_SOF << 4) + 0);
  324         sl11write(sc, SL11_E0DEV,  0);
  325         sl11write(sc, SL11_E0CTRL, SL11_EPCTRL_ARM);
  326         delay_ms(30);
  327 }
  328 
  329 /*
  330  * If detect some known controller, return the type.
  331  * If does not, return -1.
  332  */
  333 int
  334 sl811hs_find(struct slhci_softc *sc)
  335 {
  336         int rev;
  337 
  338         sc->sc_sltype = -1;
  339         rev = sl11read(sc, SL11_REV) >> 4;
  340         if (rev >= SLTYPE_SL11H && rev <= SLTYPE_SL811HS_R14)
  341                 sc->sc_sltype = rev;
  342         return sc->sc_sltype;
  343 }
  344 
  345 /*
  346  * Attach SL11H/SL811HS. Return 0 if success.
  347  */
  348 int
  349 slhci_attach(struct slhci_softc *sc, struct device *self)
  350 {
  351         int rev;
  352 
  353         /* Detect and check the controller type */
  354         rev = sl811hs_find(sc);
  355         if (rev == -1)
  356                 return -1;
  357 
  358         printf("%s: ScanLogic %s USB Host Controller",
  359                 sc->sc_bus.bdev.dv_xname, sltypestr[(rev > 0)]);
  360         switch (rev) {
  361         case SLTYPE_SL11H:
  362                 break;
  363         case SLTYPE_SL811HS_R12:
  364                 printf(" (rev 1.2)");
  365                 break;
  366         case SLTYPE_SL811HS_R14:
  367                 printf(" (rev 1.4)");
  368                 break;
  369         default:
  370                 printf(" (unknown revision)");
  371                 break;
  372         }
  373         printf("\n");
  374 
  375         /* Initialize sc */
  376         sc->sc_bus.usbrev = USBREV_1_1;
  377         sc->sc_bus.methods = &slhci_bus_methods;
  378         sc->sc_bus.pipe_size = sizeof(struct slhci_pipe);
  379         sc->sc_bus.dmatag = sc->sc_dmat;
  380 
  381         SIMPLEQ_INIT(&sc->sc_free_xfers);
  382 
  383         usb_callout_init(sc->sc_poll_handle);
  384 
  385         /* Initialize controller */
  386         sl11write(sc, SL811_CSOF, SL811_CSOF_MASTER | 0x2e);
  387         sl11write(sc, SL11_ISR, 0xff);
  388 
  389         /* Disable interrupt, then wait 40msec */
  390         sl11write(sc, SL11_IER, 0x00);
  391         delay_ms(40);
  392 
  393         /* Reset USB engine */
  394         sl11write(sc, SL11_CTRL, SL11_CTRL_RESETENGINE | SL11_CTRL_SUSPEND);
  395         delay_ms(40);
  396         sl11write(sc, SL11_CTRL, 0x00);
  397         delay_ms(10);
  398 
  399         /* USB Bus reset for GET_PORT_STATUS */
  400         sl11_reset(sc);
  401 
  402         /* Enable interrupt */
  403         sl11write(sc, SL11_IER, SL11_IER_INSERT);
  404         /* x68k Nereid USB controller needs it */
  405         if (sc->sc_enable_intr)
  406                 sc->sc_enable_intr(sc->sc_arg, INTR_ON);
  407 
  408 #ifdef USB_DEBUG
  409         usbdebug = 0;
  410 #endif
  411 
  412         /* Attach USB devices */
  413         sc->sc_child = config_found(self, &sc->sc_bus, usbctlprint);
  414 
  415         return 0;
  416 }
  417 
  418 int
  419 slhci_intr(void *arg)
  420 {
  421         struct slhci_softc *sc = arg;
  422         u_int8_t r;
  423 #ifdef SLHCI_DEBUG
  424         char bitbuf[256];
  425 #endif
  426 
  427         r = sl11read(sc, SL11_ISR);
  428 
  429         sl11write(sc, SL11_ISR, SL11_ISR_DATA | SL11_ISR_SOFTIMER);
  430 
  431         if ((r & SL11_ISR_RESET)) {
  432                 sc->sc_flags |= SLF_RESET;
  433                 sl11write(sc, SL11_ISR, SL11_ISR_RESET);
  434         }
  435         if ((r & SL11_ISR_INSERT)) {
  436                 sc->sc_flags |= SLF_INSERT;
  437                 sl11write(sc, SL11_ISR, SL11_ISR_INSERT);
  438         }
  439 
  440 #ifdef SLHCI_DEBUG
  441         bitmask_snprintf(r,
  442                 (sl11read(sc, SL11_CTRL) & SL11_CTRL_SUSPEND)
  443                 ? "\2\x8""D+\7RESUME\6INSERT\5SOF\4res\3""BABBLE\2USBB\1USBA"
  444                 : "\2\x8""D+\7RESET\6INSERT\5SOF\4res\3""BABBLE\2USBB\1USBA",
  445                 bitbuf, sizeof(bitbuf));
  446         DPRINTF(D_XFER, ("I=%s ", bitbuf));
  447 #endif /* SLHCI_DEBUG */
  448 
  449         return 0;
  450 }
  451 
  452 usbd_status
  453 slhci_open(usbd_pipe_handle pipe)
  454 {
  455         usbd_device_handle dev = pipe->device;
  456         struct slhci_softc *sc = (struct slhci_softc *)dev->bus;
  457         usb_endpoint_descriptor_t *ed = pipe->endpoint->edesc;
  458 
  459         DPRINTF(D_TRACE, ("slhci_open(addr=%d,ep=%d,scaddr=%d)",
  460                 dev->address, ed->bEndpointAddress, sc->sc_addr));
  461 
  462         if (dev->address == sc->sc_addr) {
  463                 switch (ed->bEndpointAddress) {
  464                 case USB_CONTROL_ENDPOINT:
  465                         pipe->methods = &slhci_root_ctrl_methods;
  466                         break;
  467                 case UE_DIR_IN | SLHCI_INTR_ENDPT:
  468                         pipe->methods = &slhci_root_intr_methods;
  469                         break;
  470                 default:
  471                         printf("open:endpointErr!\n");
  472                         return USBD_INVAL;
  473                 }
  474         } else {
  475                 switch (ed->bmAttributes & UE_XFERTYPE) {
  476                 case UE_CONTROL:
  477                         DPRINTF(D_MSG, ("control "));
  478                         pipe->methods = &slhci_device_ctrl_methods;
  479                         break;
  480                 case UE_INTERRUPT:
  481                         DPRINTF(D_MSG, ("interrupt "));
  482                         pipe->methods = &slhci_device_intr_methods;
  483                         break;
  484                 case UE_ISOCHRONOUS:
  485                         DPRINTF(D_MSG, ("isochronous "));
  486                         pipe->methods = &slhci_device_isoc_methods;
  487                         break;
  488                 case UE_BULK:
  489                         DPRINTF(D_MSG, ("bluk "));
  490                         pipe->methods = &slhci_device_bulk_methods;
  491                         break;
  492                 }
  493         }
  494         return USBD_NORMAL_COMPLETION;
  495 }
  496 
  497 void
  498 slhci_softintr(void *arg)
  499 {
  500         DPRINTF(D_TRACE, ("%s()", __FUNCTION__));
  501 }
  502 
  503 void
  504 slhci_poll(struct usbd_bus *bus)
  505 {
  506         DPRINTF(D_TRACE, ("%s()", __FUNCTION__));
  507 }
  508 
  509 /*
  510  * Emulation of interrupt transfer for status change endpoint
  511  * of root hub.
  512  */
  513 void
  514 slhci_poll_hub(void *arg)
  515 {
  516         usbd_xfer_handle xfer = arg;
  517         usbd_pipe_handle pipe = xfer->pipe;
  518         struct slhci_softc *sc = (struct slhci_softc *)pipe->device->bus;
  519         int s;
  520         u_char *p;
  521 
  522         usb_callout(sc->sc_poll_handle, sc->sc_interval, slhci_poll_hub, xfer);
  523 
  524         /* USB spec 11.13.3 (p.260) */
  525         p = KERNADDR(&xfer->dmabuf, 0);
  526         p[0] = 0;
  527         if ((sc->sc_flags & (SLF_INSERT | SLF_RESET))) {
  528                 p[0] = 2;
  529                 DPRINTF(D_TRACE, ("!"));
  530         }
  531 
  532         /* no change, return NAK */
  533         if (p[0] == 0)
  534                 return;
  535 
  536         xfer->actlen = 1;
  537         xfer->status = USBD_NORMAL_COMPLETION;
  538         s = splusb();
  539         xfer->device->bus->intr_context++;
  540         usb_transfer_complete(xfer);
  541         xfer->device->bus->intr_context--;
  542         splx(s);
  543 }
  544 
  545 usbd_status
  546 slhci_allocm(struct usbd_bus *bus, usb_dma_t *dma, u_int32_t size)
  547 {
  548         struct slhci_softc *sc = (struct slhci_softc *)bus;
  549 
  550         DPRINTF(D_MEM, ("SLallocm"));
  551         return usb_allocmem(&sc->sc_bus, size, 0, dma);
  552 }
  553 
  554 void
  555 slhci_freem(struct usbd_bus *bus, usb_dma_t *dma)
  556 {
  557         struct slhci_softc *sc = (struct slhci_softc *)bus;
  558 
  559         DPRINTF(D_MEM, ("SLfreem"));
  560         usb_freemem(&sc->sc_bus, dma);
  561 }
  562 
  563 usbd_xfer_handle
  564 slhci_allocx(struct usbd_bus *bus)
  565 {
  566         struct slhci_softc *sc = (struct slhci_softc *)bus;
  567         usbd_xfer_handle xfer;
  568 
  569         DPRINTF(D_MEM, ("SLallocx"));
  570 
  571         xfer = SIMPLEQ_FIRST(&sc->sc_free_xfers);
  572         if (xfer) {
  573                 SIMPLEQ_REMOVE_HEAD(&sc->sc_free_xfers, next);
  574 #ifdef DIAGNOSTIC
  575                 if (xfer->busy_free != XFER_FREE) {
  576                         printf("slhci_allocx: xfer=%p not free, 0x%08x\n",
  577                                 xfer, xfer->busy_free);
  578                 }
  579 #endif
  580         } else {
  581                 xfer = malloc(sizeof(*xfer), M_USB, M_NOWAIT);
  582         }
  583 
  584         if (xfer) {
  585                 memset(xfer, 0, sizeof(*xfer));
  586 #ifdef DIAGNOSTIC
  587                 xfer->busy_free = XFER_BUSY;
  588 #endif
  589         }
  590 
  591         return xfer;
  592 }
  593 
  594 void
  595 slhci_freex(struct usbd_bus *bus, usbd_xfer_handle xfer)
  596 {
  597         struct slhci_softc *sc = (struct slhci_softc *)bus;
  598 
  599         DPRINTF(D_MEM, ("SLfreex"));
  600 
  601 #ifdef DIAGNOSTIC
  602         if (xfer->busy_free != XFER_BUSY) {
  603                 printf("slhci_freex: xfer=%p not busy, 0x%08x\n",
  604                         xfer, xfer->busy_free);
  605                 return;
  606         }
  607         xfer->busy_free = XFER_FREE;
  608 #endif
  609         SIMPLEQ_INSERT_HEAD(&sc->sc_free_xfers, xfer, next);
  610 }
  611 
  612 void
  613 slhci_noop(usbd_pipe_handle pipe)
  614 {
  615         DPRINTF(D_TRACE, ("%s()", __FUNCTION__));
  616 }
  617 
  618 /*
  619  * Data structures and routines to emulate the root hub.
  620  */
  621 usb_device_descriptor_t slhci_devd = {
  622         USB_DEVICE_DESCRIPTOR_SIZE,
  623         UDESC_DEVICE,           /* type */
  624         {0x01, 0x01},                   /* USB version */
  625         UDCLASS_HUB,            /* class */
  626         UDSUBCLASS_HUB,         /* subclass */
  627         0,                      /* protocol */
  628         64,                     /* max packet */
  629         {USB_VENDOR_SCANLOGIC & 0xff,   /* vendor ID (low)  */
  630          USB_VENDOR_SCANLOGIC >> 8  },  /* vendor ID (high) */
  631         {0} /* ? */,            /* product ID */
  632         {0},                    /* device */
  633         1,                      /* index to manufacturer */
  634         2,                      /* index to product */
  635         0,                      /* index to serial number */
  636         1                       /* number of configurations */
  637 };
  638 
  639 usb_config_descriptor_t slhci_confd = {
  640         USB_CONFIG_DESCRIPTOR_SIZE,
  641         UDESC_CONFIG,
  642         {USB_CONFIG_DESCRIPTOR_SIZE +
  643          USB_INTERFACE_DESCRIPTOR_SIZE +
  644          USB_ENDPOINT_DESCRIPTOR_SIZE},
  645         1,                      /* number of interfaces */
  646         1,                      /* configuration value */
  647         0,                      /* index to configuration */
  648         UC_SELF_POWERED,        /* attributes */
  649         15                      /* max current is 30mA... */
  650 };
  651 
  652 usb_interface_descriptor_t slhci_ifcd = {
  653         USB_INTERFACE_DESCRIPTOR_SIZE,
  654         UDESC_INTERFACE,
  655         0,                      /* interface number */
  656         0,                      /* alternate setting */
  657         1,                      /* number of endpoint */
  658         UICLASS_HUB,            /* class */
  659         UISUBCLASS_HUB,         /* subclass */
  660         0,                      /* protocol */
  661         0                       /* index to interface */
  662 };
  663 
  664 usb_endpoint_descriptor_t slhci_endpd = {
  665         USB_ENDPOINT_DESCRIPTOR_SIZE,
  666         UDESC_ENDPOINT,
  667         UE_DIR_IN | SLHCI_INTR_ENDPT,   /* endpoint address */
  668         UE_INTERRUPT,           /* attributes */
  669         {8},                    /* max packet size */
  670         255                     /* interval */
  671 };
  672 
  673 usb_hub_descriptor_t slhci_hubd = {
  674         USB_HUB_DESCRIPTOR_SIZE,
  675         UDESC_HUB,
  676         1,                      /* number of ports */
  677         {UHD_PWR_INDIVIDUAL | UHD_OC_NONE, 0},  /* hub characteristics */
  678         20 /* ? */,             /* 5:power on to power good */
  679         50,                     /* 6:maximum current */
  680         { 0x00 },               /* both ports are removable */
  681         { 0x00 }                /* port power control mask */
  682 };
  683 
  684 static int
  685 slhci_str(usb_string_descriptor_t *p, int l, char *s)
  686 {
  687         int i;
  688 
  689         if (l == 0)
  690                 return 0;
  691         p->bLength = 2 * strlen(s) + 2;
  692         if (l == 1)
  693                 return 1;
  694         p->bDescriptorType = UDESC_STRING;
  695         l -= 2;
  696         for (i = 0; s[i] && l > 1; i++, l -= 2)
  697                 USETW2(p->bString[i], 0, s[i]);
  698         return 2 * i + 2;
  699 }
  700 
  701 usbd_status
  702 slhci_root_ctrl_transfer(usbd_xfer_handle xfer)
  703 {
  704         usbd_status error;
  705 
  706         DPRINTF(D_TRACE, ("SLRCtrans "));
  707 
  708         /* Insert last in queue */
  709         error = usb_insert_transfer(xfer);
  710         if (error) {
  711                 DPRINTF(D_MSG, ("usb_insert_transfer returns err! "));
  712                 return error;
  713         }
  714 
  715         /*
  716          * Pipe isn't running (otherwise error would be USBD_INPROG),
  717          * so start it first.
  718          */
  719         return slhci_root_ctrl_start(SIMPLEQ_FIRST(&xfer->pipe->queue));
  720 }
  721 
  722 usbd_status
  723 slhci_root_ctrl_start(usbd_xfer_handle xfer)
  724 {
  725         struct slhci_softc *sc = (struct slhci_softc *)xfer->pipe->device->bus;
  726         usb_device_request_t *req;
  727         int len, value, index, l, s, status;
  728         int totlen = 0;
  729         void *buf = NULL;
  730         usb_port_status_t ps;
  731         usbd_status error;
  732         char slbuf[50];
  733         u_int8_t r;
  734 
  735         DPRINTF(D_TRACE, ("SLRCstart "));
  736 
  737         req = &xfer->request;
  738 
  739         len = UGETW(req->wLength);
  740         value = UGETW(req->wValue);
  741         index = UGETW(req->wIndex);
  742 
  743         if (len)
  744                 buf = KERNADDR(&xfer->dmabuf, 0);
  745 
  746 #ifdef SLHCI_DEBUG
  747         if ((slhci_debug & D_TRACE))
  748                 print_req_hub(req);
  749 #endif
  750 
  751 #define C(x,y) ((x) | ((y) << 8))
  752         switch (C(req->bRequest, req->bmRequestType)) {
  753         case C(UR_CLEAR_FEATURE, UT_WRITE_DEVICE):
  754         case C(UR_CLEAR_FEATURE, UT_WRITE_INTERFACE):
  755         case C(UR_CLEAR_FEATURE, UT_WRITE_ENDPOINT):
  756                 DPRINTF(D_MSG, ("UR_CLEAR_FEATURE "));
  757                 break;
  758         case C(UR_GET_CONFIG, UT_READ_DEVICE):
  759                 DPRINTF(D_MSG, ("UR_GET_CONFIG "));
  760                 if (len > 0) {
  761                         *(u_int8_t *)buf = sc->sc_conf;
  762                         totlen = 1;
  763                 }
  764                 break;
  765         case C(UR_GET_DESCRIPTOR, UT_READ_DEVICE):
  766                 switch (value >> 8) {
  767                 case UDESC_DEVICE:
  768                         DPRINTF(D_MSG, ("UDESC_DEVICE "));
  769                         if ((value & 0xff) != 0) {
  770                                 error = USBD_IOERROR;
  771                                 goto ret;
  772                         }
  773                         totlen = l = min(len, USB_DEVICE_DESCRIPTOR_SIZE);
  774                         memcpy(buf, &slhci_devd, l);
  775                         break;
  776                 case UDESC_CONFIG:
  777                         DPRINTF(D_MSG, ("UDESC_CONFIG "));
  778                         if ((value & 0xff) != 0) {
  779                                 error = USBD_IOERROR;
  780                                 goto ret;
  781                         }
  782                         totlen = l = min(len, USB_CONFIG_DESCRIPTOR_SIZE);
  783                         memcpy(buf, &slhci_confd, l);
  784                         buf = (char *)buf + l;
  785                         len -= l;
  786 
  787                         l = min(len, USB_INTERFACE_DESCRIPTOR_SIZE);
  788                         totlen += l;
  789                         memcpy(buf, &slhci_ifcd, l);
  790                         buf = (char *)buf + l;
  791                         len -= l;
  792 
  793                         l = min(len, USB_ENDPOINT_DESCRIPTOR_SIZE);
  794                         totlen += l;
  795                         memcpy(buf, &slhci_endpd, l);
  796                         break;
  797                 case UDESC_STRING:
  798                         DPRINTF(D_MSG, ("UDESC_STR "));
  799                         if (len == 0)
  800                                 break;
  801                         *(u_int8_t *)buf = 0;
  802                         totlen = 1;
  803                         switch (value & 0xff) {
  804                         case 0:
  805                                 break;
  806                         case 1: /* Vendor */
  807                                 totlen = slhci_str(buf, len, "ScanLogic");
  808                                 break;
  809                         case 2: /* Product */
  810                                 snprintf(slbuf, sizeof(slbuf), "%s root hub",
  811                                     sltypestr[sc->sc_sltype]);
  812                                 totlen = slhci_str(buf, len, slbuf);
  813                                 break;
  814                         default:
  815                                 printf("strerr%d ", value & 0xff);
  816                                 break;
  817                         }
  818                         break;
  819                 default:
  820                         printf("unknownGetDescriptor=%x", value);
  821                         error = USBD_IOERROR;
  822                         break;
  823                 }
  824                 break;
  825         case C(UR_GET_INTERFACE, UT_READ_INTERFACE):
  826                 /* Get Interface, 9.4.4 */
  827                 if (len > 0) {
  828                         *(u_int8_t *)buf = 0;
  829                         totlen = 1;
  830                 }
  831                 break;
  832         case C(UR_GET_STATUS, UT_READ_DEVICE):
  833                 /* Get Status from device, 9.4.5 */
  834                 if (len > 1) {
  835                         USETW(((usb_status_t *)buf)->wStatus, UDS_SELF_POWERED);
  836                         totlen = 2;
  837                 }
  838                 break;
  839         case C(UR_GET_STATUS, UT_READ_INTERFACE):
  840         case C(UR_GET_STATUS, UT_READ_ENDPOINT):
  841                 /* Get Status from interface, endpoint, 9.4.5 */
  842                 if (len > 1) {
  843                         USETW(((usb_status_t *)buf)->wStatus, 0);
  844                         totlen = 2;
  845                 }
  846                 break;
  847         case C(UR_SET_ADDRESS, UT_WRITE_DEVICE):
  848                 /* Set Address, 9.4.6 */
  849                 DPRINTF(D_MSG, ("UR_SET_ADDRESS "));
  850                 if (value >= USB_MAX_DEVICES) {
  851                         error = USBD_IOERROR;
  852                         goto ret;
  853                 }
  854                 sc->sc_addr = value;
  855                 break;
  856         case C(UR_SET_CONFIG, UT_WRITE_DEVICE):
  857                 /* Set Configuration, 9.4.7 */
  858                 DPRINTF(D_MSG, ("UR_SET_CONFIG "));
  859                 if (value != 0 && value != 1) {
  860                         error = USBD_IOERROR;
  861                         goto ret;
  862                 }
  863                 sc->sc_conf = value;
  864                 break;
  865         case C(UR_SET_DESCRIPTOR, UT_WRITE_DEVICE):
  866                 /* Set Descriptor, 9.4.8, not supported */
  867                 DPRINTF(D_MSG, ("UR_SET_DESCRIPTOR,WRITE_DEVICE not supported\n"));
  868                 break;
  869         case C(UR_SET_FEATURE, UT_WRITE_DEVICE):
  870         case C(UR_SET_FEATURE, UT_WRITE_INTERFACE):
  871         case C(UR_SET_FEATURE, UT_WRITE_ENDPOINT):
  872                 /* Set Feature, 9.4.9, not supported */
  873                 DPRINTF(D_MSG, ("UR_SET_FEATURE not supported\n"));
  874                 error = USBD_IOERROR;
  875                 break;
  876         case C(UR_SET_INTERFACE, UT_WRITE_INTERFACE):
  877                 /* Set Interface, 9.4.10, not supported */
  878                 break;
  879         case C(UR_SYNCH_FRAME, UT_WRITE_ENDPOINT):
  880                 /* Synch Frame, 9.4.11, not supported */
  881                 break;
  882 
  883         /*
  884          * Hub specific requests
  885          */
  886         case C(UR_CLEAR_FEATURE, UT_WRITE_CLASS_DEVICE):
  887                 /* Clear Hub Feature, 11.16.2.1, not supported */
  888                 DPRINTF(D_MSG, ("ClearHubFeature not supported\n"));
  889                 break;
  890         case C(UR_CLEAR_FEATURE, UT_WRITE_CLASS_OTHER):
  891                 /* Clear Port Feature, 11.16.2.2 */
  892                 if (index != 1) {
  893                         error = USBD_IOERROR;
  894                         goto ret;
  895                 }
  896                 switch (value) {
  897                 case UHF_PORT_POWER:
  898                         DPRINTF(D_MSG, ("POWER_OFF "));
  899                         sc->sc_powerstat = POWER_OFF;
  900                         /* x68k Nereid USB controller needs it */
  901                         if (sc->sc_enable_power)
  902                                 sc->sc_enable_power(sc, sc->sc_powerstat);
  903                         break;
  904                 case UHF_PORT_SUSPEND:
  905                         DPRINTF(D_MSG, ("SUSPEND "));
  906                         sl11write(sc, SL11_CTRL,
  907                                 sl11read(sc, SL11_CTRL) & ~SL11_CTRL_SUSPEND);
  908                         break;
  909                 case UHF_C_PORT_CONNECTION:
  910                         sc->sc_change &= ~UPS_C_CONNECT_STATUS;
  911                         break;
  912                 case UHF_C_PORT_RESET:
  913                         sc->sc_change &= ~UPS_C_PORT_RESET;
  914                         break;
  915                 case UHF_PORT_ENABLE:
  916                         break;
  917                 case UHF_C_PORT_SUSPEND:
  918                 case UHF_C_PORT_ENABLE:
  919                 case UHF_C_PORT_OVER_CURRENT:
  920                 default:
  921                         printf("ClrPortFeatERR:value=0x%x ", value);
  922                         error = USBD_IOERROR;
  923                         break;
  924                 }
  925                 //DPRINTF(D_XFER, ("CH=%04x ", sc->sc_change));
  926                 break;
  927         case C(UR_GET_BUS_STATE, UT_READ_CLASS_OTHER):
  928                 /* Get Bus State, 11.16.2.3, not supported */
  929                 /* shall return a STALL... */
  930                 break;
  931         case C(UR_GET_DESCRIPTOR, UT_READ_CLASS_DEVICE):
  932                 /* Get Hub Descriptor, 11.16.2.4 */
  933                 if (value != 0) {
  934                         error = USBD_IOERROR;
  935                         goto ret;
  936                 }
  937                 l = min(len, USB_HUB_DESCRIPTOR_SIZE);
  938                 totlen = l;
  939                 memcpy(buf, &slhci_hubd, l);
  940                 break;
  941         case C(UR_GET_STATUS, UT_READ_CLASS_DEVICE):
  942                 /* Get Hub Status, 11.16.2.5 */
  943                 DPRINTF(D_MSG, ("UR_GET_STATUS RCD"));
  944                 if (len != 4) {
  945                         error = USBD_IOERROR;
  946                         goto ret;
  947                 }
  948                 memset(buf, 0, len);
  949                 totlen = len;
  950                 break;
  951         case C(UR_GET_STATUS, UT_READ_CLASS_OTHER):
  952                 /* Get Port Status, 11.16.2.6 */
  953                 if (index != 1 || len != 4) {
  954                         printf("index=%d,len=%d ", index, len);
  955                         error = USBD_IOERROR;
  956                         goto ret;
  957                 }
  958                 /*
  959                  * change
  960                  * o port is always enabled.
  961                  * o cannot detect over current.
  962                  */
  963                 s = splusb();
  964                 sc->sc_change &= ~(UPS_C_CONNECT_STATUS | UPS_C_PORT_RESET);
  965                 if ((sc->sc_flags & SLF_INSERT)) {
  966                         sc->sc_flags &= ~SLF_INSERT;
  967                         sc->sc_change |= UPS_C_CONNECT_STATUS;
  968                 }
  969                 if ((sc->sc_flags & SLF_RESET)) {
  970                         sc->sc_flags &= ~SLF_RESET;
  971                         sc->sc_change |= UPS_C_PORT_RESET;
  972                 }
  973                 splx(s);
  974                 /*
  975                  * XXX It can recognize that device is detached,
  976                  * while there is sl11_speed() here.
  977                  */
  978                 if (sc->sc_change)
  979                         sl11_speed(sc);
  980                 /*
  981                  * status
  982                  * o port is always enabled.
  983                  * o cannot detect over current.
  984                  */
  985                 status = 0;
  986                 if (sc->sc_connect)
  987                         status |= UPS_CURRENT_CONNECT_STATUS | UPS_PORT_ENABLED;
  988                 r = sl11read(sc, SL11_CTRL);
  989                 if (r & SL11_CTRL_SUSPEND)
  990                         status |= UPS_SUSPEND;
  991                 if (sc->sc_powerstat)
  992                         status |= UPS_PORT_POWER;
  993                 if (!sc->sc_fullspeed)
  994                         status |= UPS_LOW_SPEED;
  995 
  996                 //DPRINTF(D_XFER, ("ST=%04x,CH=%04x ", status, sc->sc_change));
  997                 USETW(ps.wPortStatus, status);
  998                 USETW(ps.wPortChange, sc->sc_change);
  999                 l = min(len, sizeof(ps));
 1000                 memcpy(buf, &ps, l);
 1001                 totlen = l;
 1002                 break;
 1003         case C(UR_SET_DESCRIPTOR, UT_WRITE_CLASS_DEVICE):
 1004                 /* Set Hub Descriptor, 11.16.2.7, not supported */
 1005                 /* STALL ? */
 1006                 error = USBD_IOERROR;
 1007                 break;
 1008         case C(UR_SET_FEATURE, UT_WRITE_CLASS_DEVICE):
 1009                 /* Set Hub Feature, 11.16.2.8, not supported */
 1010                 break;
 1011         case C(UR_SET_FEATURE, UT_WRITE_CLASS_OTHER):
 1012                 /* Set Port Feature, 11.16.2.9 */
 1013                 if (index != 1) {
 1014                         printf("index=%d ", index);
 1015                         error = USBD_IOERROR;
 1016                         goto ret;
 1017                 }
 1018                 switch (value) {
 1019                 case UHF_PORT_RESET:
 1020                         DPRINTF(D_MSG, ("PORT_RESET "));
 1021                         sl11_reset(sc);
 1022                         sl11_speed(sc);
 1023                         sc->sc_change = 0;
 1024                         break;
 1025                 case UHF_PORT_POWER:
 1026                         DPRINTF(D_MSG, ("PORT_POWER "));
 1027                         sc->sc_powerstat = POWER_ON;
 1028                         /* x68k Nereid USB controller needs it */
 1029                         if (sc->sc_enable_power)
 1030                                 sc->sc_enable_power(sc, sc->sc_powerstat);
 1031                         delay_ms(25);
 1032                         break;
 1033                 default:
 1034                         printf("SetPortFeatERR=0x%x ", value);
 1035                         error = USBD_IOERROR;
 1036                         break;
 1037                 }
 1038                 break;
 1039         default:
 1040                 DPRINTF(D_MSG, ("ioerr(UR=%02x,UT=%02x) ",
 1041                         req->bRequest, req->bmRequestType));
 1042                 error = USBD_IOERROR;
 1043                 goto ret;
 1044         }
 1045         xfer->actlen = totlen;
 1046         error = USBD_NORMAL_COMPLETION;
 1047  ret:
 1048         xfer->status = error;
 1049         s = splusb();
 1050         usb_transfer_complete(xfer);
 1051         splx(s);
 1052         return USBD_IN_PROGRESS;
 1053 }
 1054 
 1055 void
 1056 slhci_root_ctrl_abort(usbd_xfer_handle xfer)
 1057 {
 1058         DPRINTF(D_TRACE, ("SLRCabort "));
 1059 }
 1060 
 1061 void
 1062 slhci_root_ctrl_close(usbd_pipe_handle pipe)
 1063 {
 1064         DPRINTF(D_TRACE, ("SLRCclose "));
 1065 }
 1066 
 1067 void
 1068 slhci_root_ctrl_done(usbd_xfer_handle xfer)
 1069 {
 1070         DPRINTF(D_TRACE, ("SLRCdone\n"));
 1071 }
 1072 
 1073 static usbd_status
 1074 slhci_root_intr_transfer(usbd_xfer_handle xfer)
 1075 {
 1076         usbd_status error;
 1077 
 1078         DPRINTF(D_TRACE, ("SLRItransfer "));
 1079 
 1080         /* Insert last in queue */
 1081         error = usb_insert_transfer(xfer);
 1082         if (error)
 1083                 return error;
 1084 
 1085         /*
 1086          * Pipe isn't running (otherwise error would be USBD_INPROG),
 1087          * start first.
 1088          */
 1089         return slhci_root_intr_start(SIMPLEQ_FIRST(&xfer->pipe->queue));
 1090 }
 1091 
 1092 static usbd_status
 1093 slhci_root_intr_start(usbd_xfer_handle xfer)
 1094 {
 1095         usbd_pipe_handle pipe = xfer->pipe;
 1096         struct slhci_softc *sc = (struct slhci_softc *)pipe->device->bus;
 1097 
 1098         DPRINTF(D_TRACE, ("SLRIstart "));
 1099 
 1100         sc->sc_interval = MS_TO_TICKS(xfer->pipe->endpoint->edesc->bInterval);
 1101         usb_callout(sc->sc_poll_handle, sc->sc_interval, slhci_poll_hub, xfer);
 1102         sc->sc_intr_xfer = xfer;
 1103         return USBD_IN_PROGRESS;
 1104 }
 1105 
 1106 static void
 1107 slhci_root_intr_abort(usbd_xfer_handle xfer)
 1108 {
 1109         DPRINTF(D_TRACE, ("SLRIabort "));
 1110 }
 1111 
 1112 static void
 1113 slhci_root_intr_close(usbd_pipe_handle pipe)
 1114 {
 1115         struct slhci_softc *sc = (struct slhci_softc *)pipe->device->bus;
 1116 
 1117         DPRINTF(D_TRACE, ("SLRIclose "));
 1118 
 1119         usb_uncallout(sc->sc_poll_handle, slhci_poll_hub, sc->sc_intr_xfer);
 1120         sc->sc_intr_xfer = NULL;
 1121 }
 1122 
 1123 static void
 1124 slhci_root_intr_done(usbd_xfer_handle xfer)
 1125 {
 1126         //DPRINTF(D_XFER, ("RIdn "));
 1127 }
 1128 
 1129 static usbd_status
 1130 slhci_device_ctrl_transfer(usbd_xfer_handle xfer)
 1131 {
 1132         usbd_status error;
 1133 
 1134         DPRINTF(D_TRACE, ("C"));
 1135 
 1136         error = usb_insert_transfer(xfer);
 1137         if (error)
 1138                 return error;
 1139 
 1140         return slhci_device_ctrl_start(SIMPLEQ_FIRST(&xfer->pipe->queue));
 1141 }
 1142 
 1143 static usbd_status
 1144 slhci_device_ctrl_start(usbd_xfer_handle xfer)
 1145 {
 1146         usb_device_request_t *req = &xfer->request;
 1147         usbd_pipe_handle pipe = xfer->pipe;
 1148         struct slhci_softc *sc = (struct slhci_softc *)pipe->device->bus;
 1149         usbd_status status =  USBD_NORMAL_COMPLETION;
 1150         void *buf;
 1151         int pid = SL11_PID_OUT;
 1152         int len, actlen, size;
 1153         int s;
 1154         u_int8_t toggle = 0;
 1155 
 1156         DPRINTF(D_TRACE, ("st "));
 1157 #ifdef SLHCI_DEBUG
 1158         if ((slhci_debug & D_TRACE))
 1159                 print_req_hub(req);
 1160 #endif
 1161 
 1162         /* SETUP transaction */
 1163         if (slhci_transaction(sc, pipe, SL11_PID_SETUP,
 1164                         sizeof(*req), (u_char*)req, toggle) == -1) {
 1165                 status = USBD_IOERROR;
 1166                 goto ret;
 1167         }
 1168         toggle ^= SL11_EPCTRL_DATATOGGLE;
 1169 
 1170         /* DATA transaction */
 1171         actlen = 0;
 1172         len = UGETW(req->wLength);
 1173         if (len) {
 1174                 buf = KERNADDR(&xfer->dmabuf, 0);
 1175                 if (req->bmRequestType & UT_READ)
 1176                         pid = SL11_PID_IN;
 1177                 for (; actlen < len; ) {
 1178                         size = min(len - actlen, 8/* Minimum size */);
 1179                         if (slhci_transaction(sc, pipe, pid, size, buf, toggle) == -1)
 1180                                 break;
 1181                         toggle ^= SL11_EPCTRL_DATATOGGLE;
 1182                         (u_char*)buf += size;
 1183                         actlen += size;
 1184                 }
 1185         }
 1186         xfer->actlen = actlen;
 1187 
 1188         /* ACK (status) */
 1189         if (pid == SL11_PID_IN)
 1190                 pid = SL11_PID_OUT;
 1191         else
 1192                 pid = SL11_PID_IN;
 1193         if (slhci_transaction(sc, pipe, pid, 0, NULL, toggle) == -1)
 1194                 status = USBD_IOERROR;
 1195 
 1196  ret:
 1197         xfer->status = status;
 1198 
 1199 #ifdef SLHCI_DEBUG
 1200         if((slhci_debug & D_TRACE) && UGETW(req->wLength) > 0){
 1201                 int i;
 1202                 for(i=0; i < UGETW(req->wLength); i++)
 1203                         printf("%02x", *(unsigned char*)(KERNADDR(&xfer->dmabuf, i)));
 1204                 printf(" ");
 1205         }
 1206 #endif
 1207         s = splusb();
 1208         usb_transfer_complete(xfer);
 1209         splx(s);
 1210         return USBD_IN_PROGRESS;
 1211 }
 1212 
 1213 static void
 1214 slhci_device_ctrl_abort(usbd_xfer_handle xfer)
 1215 {
 1216         DPRINTF(D_TRACE, ("Cab "));
 1217         slhci_abort_xfer(xfer, USBD_CANCELLED);
 1218 }
 1219 
 1220 static void
 1221 slhci_device_ctrl_close(usbd_pipe_handle pipe)
 1222 {
 1223         DPRINTF(D_TRACE, ("Ccl "));
 1224 }
 1225 
 1226 static void
 1227 slhci_device_ctrl_done(usbd_xfer_handle xfer)
 1228 {
 1229         DPRINTF(D_TRACE, ("Cdn "));
 1230 }
 1231 
 1232 static usbd_status
 1233 slhci_device_intr_transfer(usbd_xfer_handle xfer)
 1234 {
 1235         usbd_status error;
 1236 
 1237         DPRINTF(D_TRACE, ("INTRtrans "));
 1238 
 1239         error = usb_insert_transfer(xfer);
 1240         if (error)
 1241                 return error;
 1242 
 1243         return slhci_device_intr_start(SIMPLEQ_FIRST(&xfer->pipe->queue));
 1244 }
 1245 
 1246 static usbd_status
 1247 slhci_device_intr_start(usbd_xfer_handle xfer)
 1248 {
 1249         usbd_pipe_handle pipe = xfer->pipe;
 1250         struct slhci_xfer *sx;
 1251 
 1252         DPRINTF(D_TRACE, ("INTRstart "));
 1253 
 1254         sx = malloc(sizeof(*sx), M_USB, M_NOWAIT);
 1255         if (sx == NULL)
 1256                 goto reterr;
 1257         memset(sx, 0, sizeof(*sx));
 1258         sx->sx_xfer  = xfer;
 1259         xfer->hcpriv = sx;
 1260 
 1261         /* initialize callout */
 1262         usb_callout_init(sx->sx_callout_t);
 1263         usb_callout(sx->sx_callout_t,
 1264                 MS_TO_TICKS(pipe->endpoint->edesc->bInterval),
 1265                 slhci_poll_device, sx);
 1266 
 1267         /* ACK */
 1268         return USBD_IN_PROGRESS;
 1269 
 1270  reterr:
 1271         return USBD_IOERROR;
 1272 }
 1273 
 1274 static void
 1275 slhci_poll_device(void *arg)
 1276 {
 1277         struct slhci_xfer *sx = (struct slhci_xfer *)arg;
 1278         usbd_xfer_handle xfer = sx->sx_xfer;
 1279         usbd_pipe_handle pipe = xfer->pipe;
 1280         struct slhci_softc *sc = (struct slhci_softc *)pipe->device->bus;
 1281         void *buf;
 1282         int pid;
 1283         int r;
 1284         int s;
 1285 
 1286         DPRINTF(D_TRACE, ("pldev"));
 1287 
 1288         usb_callout(sx->sx_callout_t,
 1289                 MS_TO_TICKS(pipe->endpoint->edesc->bInterval),
 1290                 slhci_poll_device, sx);
 1291 
 1292         /* interrupt transfer */
 1293         pid = (UE_GET_DIR(pipe->endpoint->edesc->bEndpointAddress) == UE_DIR_IN)
 1294             ? SL11_PID_IN : SL11_PID_OUT;
 1295         buf = KERNADDR(&xfer->dmabuf, 0);
 1296 
 1297         r = slhci_transaction(sc, pipe, pid, xfer->length, buf, 0/*toggle*/);
 1298         if (r < 0) {
 1299                 DPRINTF(D_MSG, ("%s error", __FUNCTION__));
 1300                 return;
 1301         }
 1302         /* no change, return NAK */
 1303         if (r == 0)
 1304                 return;
 1305 
 1306         xfer->status = USBD_NORMAL_COMPLETION;
 1307         s = splusb();
 1308         xfer->device->bus->intr_context++;
 1309         usb_transfer_complete(xfer);
 1310         xfer->device->bus->intr_context--;
 1311         splx(s);
 1312 }
 1313 
 1314 static void
 1315 slhci_device_intr_abort(usbd_xfer_handle xfer)
 1316 {
 1317         struct slhci_xfer *sx;
 1318 
 1319         DPRINTF(D_TRACE, ("INTRabort "));
 1320 
 1321         sx = xfer->hcpriv;
 1322         if (sx) {
 1323                 usb_uncallout(sx->sx_callout_t, slhci_poll_device, sx);
 1324                 free(sx, M_USB);
 1325                 xfer->hcpriv = NULL;
 1326         } else {
 1327                 printf("%s: sx == NULL!\n", __FUNCTION__);
 1328         }
 1329         slhci_abort_xfer(xfer, USBD_CANCELLED);
 1330 }
 1331 
 1332 static void
 1333 slhci_device_intr_close(usbd_pipe_handle pipe)
 1334 {
 1335         DPRINTF(D_TRACE, ("INTRclose "));
 1336 }
 1337 
 1338 static void
 1339 slhci_device_intr_done(usbd_xfer_handle xfer)
 1340 {
 1341         DPRINTF(D_TRACE, ("INTRdone "));
 1342 }
 1343 
 1344 static usbd_status
 1345 slhci_device_isoc_transfer(usbd_xfer_handle xfer)
 1346 {
 1347         DPRINTF(D_TRACE, ("S"));
 1348         return USBD_NORMAL_COMPLETION;
 1349 }
 1350 
 1351 static usbd_status
 1352 slhci_device_isoc_start(usbd_xfer_handle xfer)
 1353 {
 1354         DPRINTF(D_TRACE, ("st "));
 1355         return USBD_NORMAL_COMPLETION;
 1356 }
 1357 
 1358 static void
 1359 slhci_device_isoc_abort(usbd_xfer_handle xfer)
 1360 {
 1361         DPRINTF(D_TRACE, ("Sab "));
 1362 }
 1363 
 1364 static void
 1365 slhci_device_isoc_close(usbd_pipe_handle pipe)
 1366 {
 1367         DPRINTF(D_TRACE, ("Scl "));
 1368 }
 1369 
 1370 static void
 1371 slhci_device_isoc_done(usbd_xfer_handle xfer)
 1372 {
 1373         DPRINTF(D_TRACE, ("Sdn "));
 1374 }
 1375 
 1376 static usbd_status
 1377 slhci_device_bulk_transfer(usbd_xfer_handle xfer)
 1378 {
 1379         DPRINTF(D_TRACE, ("B"));
 1380         return USBD_NORMAL_COMPLETION;
 1381 }
 1382 
 1383 static usbd_status
 1384 slhci_device_bulk_start(usbd_xfer_handle xfer)
 1385 {
 1386         DPRINTF(D_TRACE, ("st "));
 1387         return USBD_NORMAL_COMPLETION;
 1388 }
 1389 
 1390 static void
 1391 slhci_device_bulk_abort(usbd_xfer_handle xfer)
 1392 {
 1393         DPRINTF(D_TRACE, ("Bab "));
 1394 }
 1395 
 1396 static void
 1397 slhci_device_bulk_close(usbd_pipe_handle pipe)
 1398 {
 1399         DPRINTF(D_TRACE, ("Bcl "));
 1400 }
 1401 
 1402 static void
 1403 slhci_device_bulk_done(usbd_xfer_handle xfer)
 1404 {
 1405         DPRINTF(D_TRACE, ("Bdn "));
 1406 }
 1407 
 1408 #define DATA0_RD        (0x03)
 1409 #define DATA0_WR        (0x07)
 1410 #define SLHCI_TIMEOUT   (5000)
 1411 
 1412 /*
 1413  * Do a transaction.
 1414  * return 1 if ACK, 0 if NAK, -1 if error.
 1415  */
 1416 static int
 1417 slhci_transaction(struct slhci_softc *sc, usbd_pipe_handle pipe,
 1418         u_int8_t pid, int len, u_char *buf, u_int8_t toggle)
 1419 {
 1420 #ifdef SLHCI_DEBUG
 1421         char str[64];
 1422         int i;
 1423 #endif
 1424         int timeout;
 1425         int ls_via_hub = 0;
 1426         int pl;
 1427         u_int8_t isr;
 1428         u_int8_t result = 0;
 1429         u_int8_t devaddr = pipe->device->address;
 1430         u_int8_t endpointaddr = pipe->endpoint->edesc->bEndpointAddress;
 1431         u_int8_t endpoint;
 1432         u_int8_t cmd = DATA0_RD;
 1433 
 1434         endpoint = UE_GET_ADDR(endpointaddr);
 1435         DPRINTF(D_XFER, ("\n(%x,%d%s%d,%d) ",
 1436                 pid, len, (pid == SL11_PID_IN) ? "<-" : "->", devaddr, endpoint));
 1437 
 1438         /* Set registers */
 1439         sl11write(sc, SL11_E0ADDR, 0x40);
 1440         sl11write(sc, SL11_E0LEN,  len);
 1441         sl11write(sc, SL11_E0PID,  (pid << 4) + endpoint);
 1442         sl11write(sc, SL11_E0DEV,  devaddr);
 1443 
 1444         /* Set buffer unless PID_IN */
 1445         if (pid != SL11_PID_IN) {
 1446                 if (len > 0)
 1447                         sl11write_region(sc, 0x40, buf, len);
 1448                 cmd = DATA0_WR;
 1449         }
 1450 
 1451         /* timing ? */
 1452         pl = (len >> 3) + 3;
 1453 
 1454         /* Low speed device via HUB */
 1455         /* XXX does not work... */
 1456         if ((sc->sc_fullspeed) && pipe->device->speed == USB_SPEED_LOW) {
 1457                 pl = len + 16;
 1458                 cmd |= SL11_EPCTRL_PREAMBLE;
 1459 
 1460                 /*
 1461                  * SL811HS/T rev 1.2 has a bug, when it got PID_IN
 1462                  * from LowSpeed device via HUB.
 1463                  */
 1464                 if (sc->sc_sltype == SLTYPE_SL811HS_R12 && pid == SL11_PID_IN) {
 1465                         ls_via_hub = 1;
 1466                         DPRINTF(D_MSG, ("LSvH "));
 1467                 }
 1468         }
 1469 
 1470         /* timing ? */
 1471         if (sl11read(sc, SL811_CSOF) <= (u_int8_t)pl)
 1472                 cmd |= SL11_EPCTRL_SOF;
 1473 
 1474         /* Transfer */
 1475         sl11write(sc, SL11_ISR, 0xff);
 1476         sl11write(sc, SL11_E0CTRL, cmd | toggle);
 1477 
 1478         /* Polling */
 1479         for (timeout = SLHCI_TIMEOUT; timeout; timeout--) {
 1480                 isr = sl11read(sc, SL11_ISR);
 1481                 if ((isr & SL11_ISR_USBA))
 1482                         break;
 1483         }
 1484 
 1485         /* Check result status */
 1486         result = sl11read(sc, SL11_E0STAT);
 1487         if (!(result & SL11_EPSTAT_NAK) && ls_via_hub) {
 1488                 /* Resend PID_IN within 20usec */
 1489                 sl11write(sc, SL11_ISR, 0xff);
 1490                 sl11write(sc, SL11_E0CTRL, SL11_EPCTRL_ARM);
 1491         }
 1492 
 1493         sl11write(sc, SL11_ISR, 0xff);
 1494 
 1495         DPRINTF(D_XFER, ("t=%d i=%x ", SLHCI_TIMEOUT - timeout, isr));
 1496 #if SLHCI_DEBUG
 1497         bitmask_snprintf(result,
 1498                 "\2\x8STALL\7NAK\6OV\5SETUP\4DATA1\3TIMEOUT\2ERR\1ACK",
 1499                 str, sizeof(str));
 1500         DPRINTF(D_XFER, ("STAT=%s ", str));
 1501 #endif
 1502 
 1503         if ((result & SL11_EPSTAT_ERROR))
 1504                 return -1;
 1505 
 1506         if ((result & SL11_EPSTAT_NAK))
 1507                 return 0;
 1508 
 1509         /* Read buffer if PID_IN */
 1510         if (pid == SL11_PID_IN && len > 0) {
 1511                 sl11read_region(sc, buf, 0x40, len);
 1512 #if SLHCI_DEBUG
 1513                 for (i = 0; i < len; i++)
 1514                         DPRINTF(D_XFER, ("%02X ", buf[i]));
 1515 #endif
 1516         }
 1517 
 1518         return 1;
 1519 }
 1520 
 1521 void
 1522 slhci_abort_xfer(usbd_xfer_handle xfer, usbd_status status)
 1523 {
 1524         xfer->status = status;
 1525         usb_transfer_complete(xfer);
 1526 }
 1527 
 1528 void
 1529 slhci_device_clear_toggle(usbd_pipe_handle pipe)
 1530 {
 1531         DPRINTF(D_TRACE, ("SLdevice_clear_toggle "));
 1532 }
 1533 
 1534 #ifdef SLHCI_DEBUG
 1535 void
 1536 print_req(usb_device_request_t *r)
 1537 {
 1538         char *xmes[]={
 1539                 "GETSTAT",
 1540                 "CLRFEAT",
 1541                 "res",
 1542                 "SETFEAT",
 1543                 "res",
 1544                 "SETADDR",
 1545                 "GETDESC",
 1546                 "SETDESC",
 1547                 "GETCONF",
 1548                 "SETCONF",
 1549                 "GETIN/F",
 1550                 "SETIN/F",
 1551                 "SYNC_FR"
 1552         };
 1553         int req, type, value, index, len;
 1554 
 1555         req   = r->bRequest;
 1556         type  = r->bmRequestType;
 1557         value = UGETW(r->wValue);
 1558         index = UGETW(r->wIndex);
 1559         len   = UGETW(r->wLength);
 1560 
 1561         printf("%x,%s,v=%d,i=%d,l=%d ",
 1562                 type, xmes[req], value, index, len);
 1563 }
 1564 
 1565 void
 1566 print_req_hub(usb_device_request_t *r)
 1567 {
 1568         struct {
 1569                 int req;
 1570                 int type;
 1571                 char *str;
 1572         } conf[] = {
 1573                 { 1, 0x20, "ClrHubFeat"  },
 1574                 { 1, 0x23, "ClrPortFeat" },
 1575                 { 2, 0xa3, "GetBusState" },
 1576                 { 6, 0xa0, "GetHubDesc"  },
 1577                 { 0, 0xa0, "GetHubStat"  },
 1578                 { 0, 0xa3, "GetPortStat" },
 1579                 { 7, 0x20, "SetHubDesc"  },
 1580                 { 3, 0x20, "SetHubFeat"  },
 1581                 { 3, 0x23, "SetPortFeat" },
 1582                 {-1, 0, NULL},
 1583         };
 1584         int i;
 1585         int value, index, len;
 1586 
 1587         value = UGETW(r->wValue);
 1588         index = UGETW(r->wIndex);
 1589         len   = UGETW(r->wLength);
 1590         for (i = 0; ; i++) {
 1591                 if (conf[i].req == -1 )
 1592                         return print_req(r);
 1593                 if (r->bmRequestType == conf[i].type && r->bRequest == conf[i].req) {
 1594                         printf("%s", conf[i].str);
 1595                         break;
 1596                 }
 1597         }
 1598         printf(",v=%d,i=%d,l=%d ", value, index, len);
 1599 }
 1600 
 1601 void
 1602 print_dumpreg(struct slhci_softc *sc)
 1603 {
 1604         printf("00=%02x,01=%02x,02=%02x,03=%02x,04=%02x,"
 1605                "08=%02x,09=%02x,0A=%02x,0B=%02x,0C=%02x,",
 1606                 sl11read(sc, 0),  sl11read(sc, 1),
 1607                 sl11read(sc, 2),  sl11read(sc, 3),
 1608                 sl11read(sc, 4),  sl11read(sc, 8),
 1609                 sl11read(sc, 9),  sl11read(sc, 10),
 1610                 sl11read(sc, 11), sl11read(sc, 12)
 1611         );
 1612         printf("CR1=%02x,IER=%02x,0D=%02x,0E=%02x,0F=%02x ",
 1613                 sl11read(sc, 5), sl11read(sc, 6),
 1614                 sl11read(sc, 13), sl11read(sc, 14), sl11read(sc, 15)
 1615         );
 1616 }
 1617 
 1618 void
 1619 print_xfer(usbd_xfer_handle xfer)
 1620 {
 1621         printf("xfer: length=%d, actlen=%d, flags=%x, timeout=%d,",
 1622                 xfer->length, xfer->actlen, xfer->flags, xfer->timeout);
 1623         printf("request{ ");
 1624         print_req_hub(&xfer->request);
 1625         printf("} ");
 1626 }
 1627 #endif /* SLHCI_DEBUG */

Cache object: 8797d2eb6fd5a115363aff0f563dc590


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


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