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/serial/ugensa.c

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

    1 /* $FreeBSD$ */
    2 /*      $NetBSD: ugensa.c,v 1.9.2.1 2007/03/24 14:55:50 yamt Exp $      */
    3 
    4 /*-
    5  * SPDX-License-Identifier: BSD-2-Clause-NetBSD
    6  *
    7  * Copyright (c) 2004, 2005 The NetBSD Foundation, Inc.
    8  * All rights reserved.
    9  *
   10  * This code is derived from software contributed to The NetBSD Foundation
   11  * by Roland C. Dowdeswell <elric@netbsd.org>.
   12  *
   13  * Redistribution and use in source and binary forms, with or without
   14  * modification, are permitted provided that the following conditions
   15  * are met:
   16  * 1. Redistributions of source code must retain the above copyright
   17  *    notice, this list of conditions and the following disclaimer.
   18  * 2. Redistributions in binary form must reproduce the above copyright
   19  *    notice, this list of conditions and the following disclaimer in the
   20  *    documentation and/or other materials provided with the distribution.
   21  *
   22  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
   23  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
   24  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
   25  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
   26  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
   27  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
   28  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
   29  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
   30  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
   31  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
   32  * POSSIBILITY OF SUCH DAMAGE.
   33  */
   34 
   35 /*
   36  * NOTE: all function names beginning like "ugensa_cfg_" can only
   37  * be called from within the config thread function !
   38  */
   39 
   40 #include <sys/stdint.h>
   41 #include <sys/stddef.h>
   42 #include <sys/param.h>
   43 #include <sys/queue.h>
   44 #include <sys/types.h>
   45 #include <sys/systm.h>
   46 #include <sys/kernel.h>
   47 #include <sys/bus.h>
   48 #include <sys/module.h>
   49 #include <sys/lock.h>
   50 #include <sys/mutex.h>
   51 #include <sys/condvar.h>
   52 #include <sys/sysctl.h>
   53 #include <sys/sx.h>
   54 #include <sys/unistd.h>
   55 #include <sys/callout.h>
   56 #include <sys/malloc.h>
   57 #include <sys/priv.h>
   58 
   59 #include <dev/usb/usb.h>
   60 #include <dev/usb/usbdi.h>
   61 #include "usbdevs.h"
   62 
   63 #define USB_DEBUG_VAR usb_debug
   64 #include <dev/usb/usb_debug.h>
   65 #include <dev/usb/usb_process.h>
   66 
   67 #include <dev/usb/serial/usb_serial.h>
   68 
   69 #define UGENSA_BUF_SIZE         2048    /* bytes */
   70 #define UGENSA_CONFIG_INDEX     0
   71 #define UGENSA_IFACE_INDEX      0
   72 #define UGENSA_IFACE_MAX        8       /* exclusivly */
   73 #define UGENSA_PORT_MAX         8       /* exclusivly */
   74 
   75 enum {
   76         UGENSA_BULK_DT_WR,
   77         UGENSA_BULK_DT_RD,
   78         UGENSA_N_TRANSFER,
   79 };
   80 
   81 struct ugensa_sub_softc {
   82         struct ucom_softc *sc_ucom_ptr;
   83         struct usb_xfer *sc_xfer[UGENSA_N_TRANSFER];
   84 };
   85 
   86 struct ugensa_softc {
   87         struct ucom_super_softc sc_super_ucom;
   88         struct ucom_softc sc_ucom[UGENSA_PORT_MAX];
   89         struct ugensa_sub_softc sc_sub[UGENSA_PORT_MAX];
   90 
   91         struct mtx sc_mtx;
   92         uint8_t sc_nports;
   93 };
   94 
   95 /* prototypes */
   96 
   97 static device_probe_t ugensa_probe;
   98 static device_attach_t ugensa_attach;
   99 static device_detach_t ugensa_detach;
  100 static void ugensa_free_softc(struct ugensa_softc *);
  101 
  102 static usb_callback_t ugensa_bulk_write_callback;
  103 static usb_callback_t ugensa_bulk_read_callback;
  104 
  105 static void     ugensa_free(struct ucom_softc *);
  106 static void     ugensa_start_read(struct ucom_softc *);
  107 static void     ugensa_stop_read(struct ucom_softc *);
  108 static void     ugensa_start_write(struct ucom_softc *);
  109 static void     ugensa_stop_write(struct ucom_softc *);
  110 static void     ugensa_poll(struct ucom_softc *ucom);
  111 
  112 static const struct usb_config ugensa_xfer_config[UGENSA_N_TRANSFER] = {
  113         [UGENSA_BULK_DT_WR] = {
  114                 .type = UE_BULK,
  115                 .endpoint = UE_ADDR_ANY,
  116                 .direction = UE_DIR_OUT,
  117                 .bufsize = UGENSA_BUF_SIZE,
  118                 .flags = {.pipe_bof = 1,.force_short_xfer = 1,},
  119                 .callback = &ugensa_bulk_write_callback,
  120         },
  121 
  122         [UGENSA_BULK_DT_RD] = {
  123                 .type = UE_BULK,
  124                 .endpoint = UE_ADDR_ANY,
  125                 .direction = UE_DIR_IN,
  126                 .bufsize = UGENSA_BUF_SIZE,
  127                 .flags = {.pipe_bof = 1,.short_xfer_ok = 1,},
  128                 .callback = &ugensa_bulk_read_callback,
  129         },
  130 };
  131 
  132 static const struct ucom_callback ugensa_callback = {
  133         .ucom_start_read = &ugensa_start_read,
  134         .ucom_stop_read = &ugensa_stop_read,
  135         .ucom_start_write = &ugensa_start_write,
  136         .ucom_stop_write = &ugensa_stop_write,
  137         .ucom_poll = &ugensa_poll,
  138         .ucom_free = &ugensa_free,
  139 };
  140 
  141 static device_method_t ugensa_methods[] = {
  142         /* Device methods */
  143         DEVMETHOD(device_probe, ugensa_probe),
  144         DEVMETHOD(device_attach, ugensa_attach),
  145         DEVMETHOD(device_detach, ugensa_detach),
  146         DEVMETHOD_END
  147 };
  148 
  149 static driver_t ugensa_driver = {
  150         .name = "ugensa",
  151         .methods = ugensa_methods,
  152         .size = sizeof(struct ugensa_softc),
  153 };
  154 
  155 /* Driver-info is max number of serial ports per interface */
  156 static const STRUCT_USB_HOST_ID ugensa_devs[] = {
  157         {USB_VPI(USB_VENDOR_AIRPRIME, USB_PRODUCT_AIRPRIME_PC5220, 1)},
  158         {USB_VPI(USB_VENDOR_CMOTECH, USB_PRODUCT_CMOTECH_CDMA_MODEM1, 1)},
  159         {USB_VPI(USB_VENDOR_KYOCERA2, USB_PRODUCT_KYOCERA2_CDMA_MSM_K, 1)},
  160         {USB_VPI(USB_VENDOR_HP, USB_PRODUCT_HP_49GPLUS, 1)},
  161         {USB_VPI(USB_VENDOR_NOVATEL2, USB_PRODUCT_NOVATEL2_FLEXPACKGPS, 3)},
  162         {USB_VENDOR(USB_VENDOR_GOOGLE), USB_IFACE_CLASS(UICLASS_VENDOR),
  163                 USB_IFACE_SUBCLASS(0x50), USB_IFACE_PROTOCOL(0x01), USB_DRIVER_INFO(10)},
  164 };
  165 
  166 DRIVER_MODULE(ugensa, uhub, ugensa_driver, NULL, NULL);
  167 MODULE_DEPEND(ugensa, ucom, 1, 1, 1);
  168 MODULE_DEPEND(ugensa, usb, 1, 1, 1);
  169 MODULE_VERSION(ugensa, 1);
  170 USB_PNP_HOST_INFO(ugensa_devs);
  171 
  172 static int
  173 ugensa_probe(device_t dev)
  174 {
  175         struct usb_attach_arg *uaa = device_get_ivars(dev);
  176 
  177         if (uaa->usb_mode != USB_MODE_HOST) {
  178                 return (ENXIO);
  179         }
  180         if (uaa->info.bConfigIndex != UGENSA_CONFIG_INDEX) {
  181                 return (ENXIO);
  182         }
  183         if (uaa->info.bIfaceIndex != 0) {
  184                 return (ENXIO);
  185         }
  186         return (usbd_lookup_id_by_uaa(ugensa_devs, sizeof(ugensa_devs), uaa));
  187 }
  188 
  189 static int
  190 ugensa_attach(device_t dev)
  191 {
  192         struct usb_attach_arg *uaa = device_get_ivars(dev);
  193         struct ugensa_softc *sc = device_get_softc(dev);
  194         struct ugensa_sub_softc *ssc;
  195         struct usb_interface *iface;
  196         struct usb_config xfer_config[UGENSA_N_TRANSFER];
  197         int32_t error;
  198         uint8_t iface_index;
  199         int x, maxports;
  200 
  201         maxports = USB_GET_DRIVER_INFO(uaa);
  202         device_set_usb_desc(dev);
  203         mtx_init(&sc->sc_mtx, "ugensa", NULL, MTX_DEF);
  204         ucom_ref(&sc->sc_super_ucom);
  205 
  206         for (iface_index = UGENSA_IFACE_INDEX; iface_index < UGENSA_IFACE_MAX; iface_index++) {
  207                 iface = usbd_get_iface(uaa->device, iface_index);
  208                 if (iface == NULL || iface->idesc->bInterfaceClass != UICLASS_VENDOR)
  209                         /* Not a serial port, most likely a SD reader */
  210                         continue;
  211 
  212                 /* Loop over all endpoints pairwise */
  213                 for (x = 0; x < maxports && sc->sc_nports < UGENSA_PORT_MAX; x++) {
  214                         ssc = sc->sc_sub + sc->sc_nports;
  215                         ssc->sc_ucom_ptr = sc->sc_ucom + sc->sc_nports;
  216 
  217                         memcpy(xfer_config, ugensa_xfer_config, sizeof ugensa_xfer_config);
  218                         xfer_config[UGENSA_BULK_DT_RD].ep_index = x;
  219                         xfer_config[UGENSA_BULK_DT_WR].ep_index = x;
  220 
  221                         error = usbd_transfer_setup(uaa->device,
  222                             &iface_index, ssc->sc_xfer, xfer_config,
  223                             UGENSA_N_TRANSFER, ssc, &sc->sc_mtx);
  224 
  225                         if (error) {
  226                                 if (x == 0) {
  227                                         device_printf(dev, "allocating USB "
  228                                             "transfers failed (%d)\n", error);
  229                                         goto detach;
  230                                 }
  231                                 break;
  232                         }
  233 
  234                         /* clear stall at first run */
  235                         mtx_lock(&sc->sc_mtx);
  236                         usbd_xfer_set_stall(ssc->sc_xfer[UGENSA_BULK_DT_WR]);
  237                         usbd_xfer_set_stall(ssc->sc_xfer[UGENSA_BULK_DT_RD]);
  238                         mtx_unlock(&sc->sc_mtx);
  239 
  240                         /* initialize port number */
  241                         ssc->sc_ucom_ptr->sc_portno = sc->sc_nports;
  242                         if (iface_index != uaa->info.bIfaceIndex) {
  243                                 usbd_set_parent_iface(uaa->device, iface_index,
  244                                     uaa->info.bIfaceIndex);
  245                         }
  246                         sc->sc_nports++;
  247                 }
  248         }
  249         device_printf(dev, "Found %d serial ports.\n", sc->sc_nports);
  250 
  251         error = ucom_attach(&sc->sc_super_ucom, sc->sc_ucom, sc->sc_nports, sc,
  252             &ugensa_callback, &sc->sc_mtx);
  253 
  254         if (error) {
  255                 DPRINTF("ucom attach failed\n");
  256                 goto detach;
  257         }
  258         ucom_set_pnpinfo_usb(&sc->sc_super_ucom, dev);
  259 
  260         return (0);                     /* success */
  261 
  262 detach:
  263         ugensa_detach(dev);
  264         return (ENXIO);                 /* failure */
  265 }
  266 
  267 static int
  268 ugensa_detach(device_t dev)
  269 {
  270         struct ugensa_softc *sc = device_get_softc(dev);
  271         uint8_t x;
  272 
  273         ucom_detach(&sc->sc_super_ucom, sc->sc_ucom);
  274 
  275         for (x = 0; x < sc->sc_nports; x++) {
  276                 usbd_transfer_unsetup(sc->sc_sub[x].sc_xfer, UGENSA_N_TRANSFER);
  277         }
  278 
  279         device_claim_softc(dev);
  280 
  281         ugensa_free_softc(sc);
  282 
  283         return (0);
  284 }
  285 
  286 UCOM_UNLOAD_DRAIN(ugensa);
  287 
  288 static void
  289 ugensa_free_softc(struct ugensa_softc *sc)
  290 {
  291         if (ucom_unref(&sc->sc_super_ucom)) {
  292                 mtx_destroy(&sc->sc_mtx);
  293                 device_free_softc(sc);
  294         }
  295 }
  296 
  297 static void
  298 ugensa_free(struct ucom_softc *ucom)
  299 {
  300         ugensa_free_softc(ucom->sc_parent);
  301 }
  302 
  303 static void
  304 ugensa_bulk_write_callback(struct usb_xfer *xfer, usb_error_t error)
  305 {
  306         struct ugensa_sub_softc *ssc = usbd_xfer_softc(xfer);
  307         struct usb_page_cache *pc;
  308         uint32_t actlen;
  309 
  310         switch (USB_GET_STATE(xfer)) {
  311         case USB_ST_SETUP:
  312         case USB_ST_TRANSFERRED:
  313 tr_setup:
  314                 pc = usbd_xfer_get_frame(xfer, 0);
  315                 if (ucom_get_data(ssc->sc_ucom_ptr, pc, 0,
  316                     UGENSA_BUF_SIZE, &actlen)) {
  317                         usbd_xfer_set_frame_len(xfer, 0, actlen);
  318                         usbd_transfer_submit(xfer);
  319                 }
  320                 return;
  321 
  322         default:                        /* Error */
  323                 if (error != USB_ERR_CANCELLED) {
  324                         /* try to clear stall first */
  325                         usbd_xfer_set_stall(xfer);
  326                         goto tr_setup;
  327                 }
  328                 return;
  329         }
  330 }
  331 
  332 static void
  333 ugensa_bulk_read_callback(struct usb_xfer *xfer, usb_error_t error)
  334 {
  335         struct ugensa_sub_softc *ssc = usbd_xfer_softc(xfer);
  336         struct usb_page_cache *pc;
  337         int actlen;
  338 
  339         usbd_xfer_status(xfer, &actlen, NULL, NULL, NULL);
  340 
  341         switch (USB_GET_STATE(xfer)) {
  342         case USB_ST_TRANSFERRED:
  343                 pc = usbd_xfer_get_frame(xfer, 0);
  344                 ucom_put_data(ssc->sc_ucom_ptr, pc, 0, actlen);
  345 
  346         case USB_ST_SETUP:
  347 tr_setup:
  348                 usbd_xfer_set_frame_len(xfer, 0, usbd_xfer_max_len(xfer));
  349                 usbd_transfer_submit(xfer);
  350                 return;
  351 
  352         default:                        /* Error */
  353                 if (error != USB_ERR_CANCELLED) {
  354                         /* try to clear stall first */
  355                         usbd_xfer_set_stall(xfer);
  356                         goto tr_setup;
  357                 }
  358                 return;
  359         }
  360 }
  361 
  362 static void
  363 ugensa_start_read(struct ucom_softc *ucom)
  364 {
  365         struct ugensa_softc *sc = ucom->sc_parent;
  366         struct ugensa_sub_softc *ssc = sc->sc_sub + ucom->sc_portno;
  367 
  368         usbd_transfer_start(ssc->sc_xfer[UGENSA_BULK_DT_RD]);
  369 }
  370 
  371 static void
  372 ugensa_stop_read(struct ucom_softc *ucom)
  373 {
  374         struct ugensa_softc *sc = ucom->sc_parent;
  375         struct ugensa_sub_softc *ssc = sc->sc_sub + ucom->sc_portno;
  376 
  377         usbd_transfer_stop(ssc->sc_xfer[UGENSA_BULK_DT_RD]);
  378 }
  379 
  380 static void
  381 ugensa_start_write(struct ucom_softc *ucom)
  382 {
  383         struct ugensa_softc *sc = ucom->sc_parent;
  384         struct ugensa_sub_softc *ssc = sc->sc_sub + ucom->sc_portno;
  385 
  386         usbd_transfer_start(ssc->sc_xfer[UGENSA_BULK_DT_WR]);
  387 }
  388 
  389 static void
  390 ugensa_stop_write(struct ucom_softc *ucom)
  391 {
  392         struct ugensa_softc *sc = ucom->sc_parent;
  393         struct ugensa_sub_softc *ssc = sc->sc_sub + ucom->sc_portno;
  394 
  395         usbd_transfer_stop(ssc->sc_xfer[UGENSA_BULK_DT_WR]);
  396 }
  397 
  398 static void
  399 ugensa_poll(struct ucom_softc *ucom)
  400 {
  401         struct ugensa_softc *sc = ucom->sc_parent;
  402         struct ugensa_sub_softc *ssc = sc->sc_sub + ucom->sc_portno;
  403 
  404         usbd_transfer_poll(ssc->sc_xfer, UGENSA_N_TRANSFER);
  405 }

Cache object: d25bd1c99d10823b03e361d4ce3d1dab


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