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


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

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

Cache object: 2833e60a79d4c4f1045b790430c8fd9f


[ 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.