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/ufoma.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: umodem.c,v 1.45 2002/09/23 05:51:23 simonb Exp $       */
    2 
    3 #include <sys/cdefs.h>
    4 __FBSDID("$FreeBSD$");
    5 #define UFOMA_HANDSFREE
    6 /*-
    7  * SPDX-License-Identifier: BSD-2-Clause-FreeBSD AND BSD-2-Clause-NetBSD
    8  *
    9  * Copyright (c) 2005, Takanori Watanabe All rights reserved.
   10  * Copyright (c) 2003 M. Warner Losh <imp@FreeBSD.org>
   11  *
   12  * Redistribution and use in source and binary forms, with or without
   13  * modification, are permitted provided that the following conditions
   14  * are met:
   15  * 1. Redistributions of source code must retain the above copyright
   16  *    notice, this list of conditions and the following disclaimer.
   17  * 2. Redistributions in binary form must reproduce the above copyright
   18  *    notice, this list of conditions and the following disclaimer in the
   19  *    documentation and/or other materials provided with the distribution.
   20  *
   21  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
   22  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
   23  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
   24  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
   25  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
   26  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
   27  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
   28  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
   29  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
   30  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   31  * SUCH DAMAGE.
   32  */
   33 
   34 /*-
   35  * Copyright (c) 1998 The NetBSD Foundation, Inc.
   36  * All rights reserved.
   37  *
   38  * This code is derived from software contributed to The NetBSD Foundation
   39  * by Lennart Augustsson (lennart@augustsson.net) at
   40  * Carlstedt Research & Technology.
   41  *
   42  * Redistribution and use in source and binary forms, with or without
   43  * modification, are permitted provided that the following conditions
   44  * are met:
   45  * 1. Redistributions of source code must retain the above copyright
   46  *    notice, this list of conditions and the following disclaimer.
   47  * 2. Redistributions in binary form must reproduce the above copyright
   48  *    notice, this list of conditions and the following disclaimer in the
   49  *    documentation and/or other materials provided with the distribution.
   50  *
   51  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
   52  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
   53  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
   54  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
   55  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
   56  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
   57  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
   58  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
   59  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
   60  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
   61  * POSSIBILITY OF SUCH DAMAGE.
   62  */
   63 
   64 /*
   65  * Comm Class spec:  http://www.usb.org/developers/devclass_docs/usbccs10.pdf
   66  *                   http://www.usb.org/developers/devclass_docs/usbcdc11.pdf
   67  */
   68 
   69 /*
   70  * TODO:
   71  * - Implement a Call Device for modems without multiplexed commands.
   72  */
   73 
   74 /*
   75  * NOTE: all function names beginning like "ufoma_cfg_" can only
   76  * be called from within the config thread function !
   77  */
   78 
   79 #include <sys/stdint.h>
   80 #include <sys/stddef.h>
   81 #include <sys/param.h>
   82 #include <sys/queue.h>
   83 #include <sys/types.h>
   84 #include <sys/systm.h>
   85 #include <sys/kernel.h>
   86 #include <sys/bus.h>
   87 #include <sys/module.h>
   88 #include <sys/lock.h>
   89 #include <sys/mutex.h>
   90 #include <sys/condvar.h>
   91 #include <sys/sysctl.h>
   92 #include <sys/sx.h>
   93 #include <sys/unistd.h>
   94 #include <sys/callout.h>
   95 #include <sys/malloc.h>
   96 #include <sys/priv.h>
   97 #include <sys/sbuf.h>
   98 
   99 #include <dev/usb/usb.h>
  100 #include <dev/usb/usbdi.h>
  101 #include <dev/usb/usbdi_util.h>
  102 #include <dev/usb/usb_cdc.h>
  103 #include "usbdevs.h"
  104 
  105 #define USB_DEBUG_VAR usb_debug
  106 #include <dev/usb/usb_debug.h>
  107 #include <dev/usb/usb_process.h>
  108 
  109 #include <dev/usb/serial/usb_serial.h>
  110 
  111 typedef struct ufoma_mobile_acm_descriptor {
  112         uint8_t bFunctionLength;
  113         uint8_t bDescriptorType;
  114         uint8_t bDescriptorSubtype;
  115         uint8_t bType;
  116         uint8_t bMode[1];
  117 } __packed usb_mcpc_acm_descriptor;
  118 
  119 #define UISUBCLASS_MCPC 0x88
  120 
  121 #define UDESC_VS_INTERFACE 0x44
  122 #define UDESCSUB_MCPC_ACM  0x11
  123 
  124 #define UMCPC_ACM_TYPE_AB1 0x1
  125 #define UMCPC_ACM_TYPE_AB2 0x2
  126 #define UMCPC_ACM_TYPE_AB5 0x5
  127 #define UMCPC_ACM_TYPE_AB6 0x6
  128 
  129 #define UMCPC_ACM_MODE_DEACTIVATED 0x0
  130 #define UMCPC_ACM_MODE_MODEM 0x1
  131 #define UMCPC_ACM_MODE_ATCOMMAND 0x2
  132 #define UMCPC_ACM_MODE_OBEX 0x60
  133 #define UMCPC_ACM_MODE_VENDOR1 0xc0
  134 #define UMCPC_ACM_MODE_VENDOR2 0xfe
  135 #define UMCPC_ACM_MODE_UNLINKED 0xff
  136 
  137 #define UMCPC_CM_MOBILE_ACM 0x0
  138 
  139 #define UMCPC_ACTIVATE_MODE 0x60
  140 #define UMCPC_GET_MODETABLE 0x61
  141 #define UMCPC_SET_LINK 0x62
  142 #define UMCPC_CLEAR_LINK 0x63
  143 
  144 #define UMCPC_REQUEST_ACKNOWLEDGE 0x31
  145 
  146 #define UFOMA_MAX_TIMEOUT 15            /* standard says 10 seconds */
  147 #define UFOMA_CMD_BUF_SIZE 64           /* bytes */
  148 
  149 #define UFOMA_BULK_BUF_SIZE 1024        /* bytes */
  150 
  151 enum {
  152         UFOMA_CTRL_ENDPT_INTR,
  153         UFOMA_CTRL_ENDPT_READ,
  154         UFOMA_CTRL_ENDPT_WRITE,
  155         UFOMA_CTRL_ENDPT_MAX,
  156 };
  157 
  158 enum {
  159         UFOMA_BULK_ENDPT_WRITE,
  160         UFOMA_BULK_ENDPT_READ,  
  161         UFOMA_BULK_ENDPT_MAX,
  162 };
  163 
  164 struct ufoma_softc {
  165         struct ucom_super_softc sc_super_ucom;
  166         struct ucom_softc sc_ucom;
  167         struct cv sc_cv;
  168         struct mtx sc_mtx;
  169 
  170         struct usb_xfer *sc_ctrl_xfer[UFOMA_CTRL_ENDPT_MAX];
  171         struct usb_xfer *sc_bulk_xfer[UFOMA_BULK_ENDPT_MAX];
  172         uint8_t *sc_modetable;
  173         device_t sc_dev;
  174         struct usb_device *sc_udev;
  175 
  176         uint32_t sc_unit;
  177 
  178         uint16_t sc_line;
  179 
  180         uint8_t sc_num_msg;
  181         uint8_t sc_nobulk;
  182         uint8_t sc_ctrl_iface_no;
  183         uint8_t sc_ctrl_iface_index;
  184         uint8_t sc_data_iface_no;
  185         uint8_t sc_data_iface_index;
  186         uint8_t sc_cm_cap;
  187         uint8_t sc_acm_cap;
  188         uint8_t sc_lsr;
  189         uint8_t sc_msr;
  190         uint8_t sc_modetoactivate;
  191         uint8_t sc_currentmode;
  192 };
  193 
  194 /* prototypes */
  195 
  196 static device_probe_t ufoma_probe;
  197 static device_attach_t ufoma_attach;
  198 static device_detach_t ufoma_detach;
  199 static void ufoma_free_softc(struct ufoma_softc *);
  200 
  201 static usb_callback_t ufoma_ctrl_read_callback;
  202 static usb_callback_t ufoma_ctrl_write_callback;
  203 static usb_callback_t ufoma_intr_callback;
  204 static usb_callback_t ufoma_bulk_write_callback;
  205 static usb_callback_t ufoma_bulk_read_callback;
  206 
  207 static void     *ufoma_get_intconf(struct usb_config_descriptor *,
  208                     struct usb_interface_descriptor *, uint8_t, uint8_t);
  209 static void     ufoma_cfg_link_state(struct ufoma_softc *);
  210 static void     ufoma_cfg_activate_state(struct ufoma_softc *, uint16_t);
  211 static void     ufoma_free(struct ucom_softc *);
  212 static void     ufoma_cfg_open(struct ucom_softc *);
  213 static void     ufoma_cfg_close(struct ucom_softc *);
  214 static void     ufoma_cfg_set_break(struct ucom_softc *, uint8_t);
  215 static void     ufoma_cfg_get_status(struct ucom_softc *, uint8_t *,
  216                     uint8_t *);
  217 static void     ufoma_cfg_set_dtr(struct ucom_softc *, uint8_t);
  218 static void     ufoma_cfg_set_rts(struct ucom_softc *, uint8_t);
  219 static int      ufoma_pre_param(struct ucom_softc *, struct termios *);
  220 static void     ufoma_cfg_param(struct ucom_softc *, struct termios *);
  221 static int      ufoma_modem_setup(device_t, struct ufoma_softc *,
  222                     struct usb_attach_arg *);
  223 static void     ufoma_start_read(struct ucom_softc *);
  224 static void     ufoma_stop_read(struct ucom_softc *);
  225 static void     ufoma_start_write(struct ucom_softc *);
  226 static void     ufoma_stop_write(struct ucom_softc *);
  227 static void     ufoma_poll(struct ucom_softc *ucom);
  228 
  229 /*sysctl stuff*/
  230 static int ufoma_sysctl_support(SYSCTL_HANDLER_ARGS);
  231 static int ufoma_sysctl_current(SYSCTL_HANDLER_ARGS);
  232 static int ufoma_sysctl_open(SYSCTL_HANDLER_ARGS);
  233 
  234 static const struct usb_config
  235         ufoma_ctrl_config[UFOMA_CTRL_ENDPT_MAX] = {
  236         [UFOMA_CTRL_ENDPT_INTR] = {
  237                 .type = UE_INTERRUPT,
  238                 .endpoint = UE_ADDR_ANY,
  239                 .direction = UE_DIR_IN,
  240                 .flags = {.pipe_bof = 1,.short_xfer_ok = 1,},
  241                 .bufsize = sizeof(struct usb_cdc_notification),
  242                 .callback = &ufoma_intr_callback,
  243         },
  244 
  245         [UFOMA_CTRL_ENDPT_READ] = {
  246                 .type = UE_CONTROL,
  247                 .endpoint = 0x00,       /* Control pipe */
  248                 .direction = UE_DIR_ANY,
  249                 .bufsize = (sizeof(struct usb_device_request) + UFOMA_CMD_BUF_SIZE),
  250                 .flags = {.short_xfer_ok = 1,},
  251                 .callback = &ufoma_ctrl_read_callback,
  252                 .timeout = 1000,        /* 1 second */
  253         },
  254 
  255         [UFOMA_CTRL_ENDPT_WRITE] = {
  256                 .type = UE_CONTROL,
  257                 .endpoint = 0x00,       /* Control pipe */
  258                 .direction = UE_DIR_ANY,
  259                 .bufsize = (sizeof(struct usb_device_request) + 1),
  260                 .callback = &ufoma_ctrl_write_callback,
  261                 .timeout = 1000,        /* 1 second */
  262         },
  263 };
  264 
  265 static const struct usb_config
  266         ufoma_bulk_config[UFOMA_BULK_ENDPT_MAX] = {
  267         [UFOMA_BULK_ENDPT_WRITE] = {
  268                 .type = UE_BULK,
  269                 .endpoint = UE_ADDR_ANY,
  270                 .direction = UE_DIR_OUT,
  271                 .bufsize = UFOMA_BULK_BUF_SIZE,
  272                 .flags = {.pipe_bof = 1,.force_short_xfer = 1,},
  273                 .callback = &ufoma_bulk_write_callback,
  274         },
  275 
  276         [UFOMA_BULK_ENDPT_READ] = {
  277                 .type = UE_BULK,
  278                 .endpoint = UE_ADDR_ANY,
  279                 .direction = UE_DIR_IN,
  280                 .bufsize = UFOMA_BULK_BUF_SIZE,
  281                 .flags = {.pipe_bof = 1,.short_xfer_ok = 1,},
  282                 .callback = &ufoma_bulk_read_callback,
  283         },
  284 };
  285 
  286 static const struct ucom_callback ufoma_callback = {
  287         .ucom_cfg_get_status = &ufoma_cfg_get_status,
  288         .ucom_cfg_set_dtr = &ufoma_cfg_set_dtr,
  289         .ucom_cfg_set_rts = &ufoma_cfg_set_rts,
  290         .ucom_cfg_set_break = &ufoma_cfg_set_break,
  291         .ucom_cfg_param = &ufoma_cfg_param,
  292         .ucom_cfg_open = &ufoma_cfg_open,
  293         .ucom_cfg_close = &ufoma_cfg_close,
  294         .ucom_pre_param = &ufoma_pre_param,
  295         .ucom_start_read = &ufoma_start_read,
  296         .ucom_stop_read = &ufoma_stop_read,
  297         .ucom_start_write = &ufoma_start_write,
  298         .ucom_stop_write = &ufoma_stop_write,
  299         .ucom_poll = &ufoma_poll,
  300         .ucom_free = &ufoma_free,
  301 };
  302 
  303 static device_method_t ufoma_methods[] = {
  304         /* Device methods */
  305         DEVMETHOD(device_probe, ufoma_probe),
  306         DEVMETHOD(device_attach, ufoma_attach),
  307         DEVMETHOD(device_detach, ufoma_detach),
  308         DEVMETHOD_END
  309 };
  310 
  311 static driver_t ufoma_driver = {
  312         .name = "ufoma",
  313         .methods = ufoma_methods,
  314         .size = sizeof(struct ufoma_softc),
  315 };
  316 
  317 static const STRUCT_USB_HOST_ID ufoma_devs[] = {
  318         {USB_IFACE_CLASS(UICLASS_CDC),
  319          USB_IFACE_SUBCLASS(UISUBCLASS_MCPC),},
  320 };
  321 
  322 DRIVER_MODULE(ufoma, uhub, ufoma_driver, NULL, NULL);
  323 MODULE_DEPEND(ufoma, ucom, 1, 1, 1);
  324 MODULE_DEPEND(ufoma, usb, 1, 1, 1);
  325 MODULE_VERSION(ufoma, 1);
  326 USB_PNP_HOST_INFO(ufoma_devs);
  327 
  328 static int
  329 ufoma_probe(device_t dev)
  330 {
  331         struct usb_attach_arg *uaa = device_get_ivars(dev);
  332         struct usb_interface_descriptor *id;
  333         struct usb_config_descriptor *cd;
  334         usb_mcpc_acm_descriptor *mad;
  335         int error;
  336 
  337         if (uaa->usb_mode != USB_MODE_HOST)
  338                 return (ENXIO);
  339 
  340         error = usbd_lookup_id_by_uaa(ufoma_devs, sizeof(ufoma_devs), uaa);
  341         if (error)
  342                 return (error);
  343 
  344         id = usbd_get_interface_descriptor(uaa->iface);
  345         cd = usbd_get_config_descriptor(uaa->device);
  346 
  347         if (id == NULL || cd == NULL)
  348                 return (ENXIO);
  349 
  350         mad = ufoma_get_intconf(cd, id, UDESC_VS_INTERFACE, UDESCSUB_MCPC_ACM);
  351         if (mad == NULL)
  352                 return (ENXIO);
  353 
  354 #ifndef UFOMA_HANDSFREE
  355         if ((mad->bType == UMCPC_ACM_TYPE_AB5) ||
  356             (mad->bType == UMCPC_ACM_TYPE_AB6))
  357                 return (ENXIO);
  358 #endif
  359         return (BUS_PROBE_GENERIC);
  360 }
  361 
  362 static int
  363 ufoma_attach(device_t dev)
  364 {
  365         struct usb_attach_arg *uaa = device_get_ivars(dev);
  366         struct ufoma_softc *sc = device_get_softc(dev);
  367         struct usb_config_descriptor *cd;
  368         struct usb_interface_descriptor *id;
  369         struct sysctl_ctx_list *sctx;
  370         struct sysctl_oid *soid;
  371 
  372         usb_mcpc_acm_descriptor *mad;
  373         uint8_t elements;
  374         int32_t error;
  375 
  376         sc->sc_udev = uaa->device;
  377         sc->sc_dev = dev;
  378         sc->sc_unit = device_get_unit(dev);
  379 
  380         mtx_init(&sc->sc_mtx, "ufoma", NULL, MTX_DEF);
  381         ucom_ref(&sc->sc_super_ucom);
  382         cv_init(&sc->sc_cv, "CWAIT");
  383 
  384         device_set_usb_desc(dev);
  385 
  386         DPRINTF("\n");
  387 
  388         /* setup control transfers */
  389 
  390         cd = usbd_get_config_descriptor(uaa->device);
  391         id = usbd_get_interface_descriptor(uaa->iface);
  392         sc->sc_ctrl_iface_no = id->bInterfaceNumber;
  393         sc->sc_ctrl_iface_index = uaa->info.bIfaceIndex;
  394 
  395         error = usbd_transfer_setup(uaa->device,
  396             &sc->sc_ctrl_iface_index, sc->sc_ctrl_xfer,
  397             ufoma_ctrl_config, UFOMA_CTRL_ENDPT_MAX, sc, &sc->sc_mtx);
  398 
  399         if (error) {
  400                 device_printf(dev, "allocating control USB "
  401                     "transfers failed\n");
  402                 goto detach;
  403         }
  404         mad = ufoma_get_intconf(cd, id, UDESC_VS_INTERFACE, UDESCSUB_MCPC_ACM);
  405         if (mad == NULL) {
  406                 goto detach;
  407         }
  408         if (mad->bFunctionLength < sizeof(*mad)) {
  409                 device_printf(dev, "invalid MAD descriptor\n");
  410                 goto detach;
  411         }
  412         if ((mad->bType == UMCPC_ACM_TYPE_AB5) ||
  413             (mad->bType == UMCPC_ACM_TYPE_AB6)) {
  414                 sc->sc_nobulk = 1;
  415         } else {
  416                 sc->sc_nobulk = 0;
  417                 if (ufoma_modem_setup(dev, sc, uaa)) {
  418                         goto detach;
  419                 }
  420         }
  421 
  422         elements = (mad->bFunctionLength - sizeof(*mad) + 1);
  423 
  424         /* initialize mode variables */
  425 
  426         sc->sc_modetable = malloc(elements + 1, M_USBDEV, M_WAITOK);
  427 
  428         if (sc->sc_modetable == NULL) {
  429                 goto detach;
  430         }
  431         sc->sc_modetable[0] = (elements + 1);
  432         memcpy(&sc->sc_modetable[1], mad->bMode, elements);
  433 
  434         sc->sc_currentmode = UMCPC_ACM_MODE_UNLINKED;
  435         sc->sc_modetoactivate = mad->bMode[0];
  436 
  437         /* clear stall at first run, if any */
  438         mtx_lock(&sc->sc_mtx);
  439         usbd_xfer_set_stall(sc->sc_bulk_xfer[UFOMA_BULK_ENDPT_WRITE]);
  440         usbd_xfer_set_stall(sc->sc_bulk_xfer[UFOMA_BULK_ENDPT_READ]);
  441         mtx_unlock(&sc->sc_mtx);
  442 
  443         error = ucom_attach(&sc->sc_super_ucom, &sc->sc_ucom, 1, sc,
  444             &ufoma_callback, &sc->sc_mtx);
  445         if (error) {
  446                 DPRINTF("ucom_attach failed\n");
  447                 goto detach;
  448         }
  449         ucom_set_pnpinfo_usb(&sc->sc_super_ucom, dev);
  450 
  451         /*Sysctls*/
  452         sctx = device_get_sysctl_ctx(dev);
  453         soid = device_get_sysctl_tree(dev);
  454 
  455         SYSCTL_ADD_PROC(sctx, SYSCTL_CHILDREN(soid), OID_AUTO, "supportmode",
  456             CTLFLAG_RD | CTLTYPE_STRING | CTLFLAG_MPSAFE, sc, 0,
  457             ufoma_sysctl_support, "A", "Supporting port role");
  458 
  459         SYSCTL_ADD_PROC(sctx, SYSCTL_CHILDREN(soid), OID_AUTO, "currentmode",
  460         CTLFLAG_RD | CTLTYPE_STRING | CTLFLAG_MPSAFE, sc, 0,
  461         ufoma_sysctl_current, "A", "Current port role");
  462 
  463         SYSCTL_ADD_PROC(sctx, SYSCTL_CHILDREN(soid), OID_AUTO, "openmode",
  464         CTLFLAG_RW | CTLTYPE_STRING | CTLFLAG_MPSAFE, sc, 0,
  465         ufoma_sysctl_open, "A", "Mode to transit when port is opened");
  466         SYSCTL_ADD_UINT(sctx, SYSCTL_CHILDREN(soid), OID_AUTO, "comunit",
  467                         CTLFLAG_RD, &(sc->sc_super_ucom.sc_unit), 0, 
  468                         "Unit number as USB serial");
  469 
  470         return (0);                     /* success */
  471 
  472 detach:
  473         ufoma_detach(dev);
  474         return (ENXIO);                 /* failure */
  475 }
  476 
  477 static int
  478 ufoma_detach(device_t dev)
  479 {
  480         struct ufoma_softc *sc = device_get_softc(dev);
  481 
  482         ucom_detach(&sc->sc_super_ucom, &sc->sc_ucom);
  483         usbd_transfer_unsetup(sc->sc_ctrl_xfer, UFOMA_CTRL_ENDPT_MAX);
  484         usbd_transfer_unsetup(sc->sc_bulk_xfer, UFOMA_BULK_ENDPT_MAX);
  485 
  486         if (sc->sc_modetable) {
  487                 free(sc->sc_modetable, M_USBDEV);
  488         }
  489         cv_destroy(&sc->sc_cv);
  490 
  491         device_claim_softc(dev);
  492 
  493         ufoma_free_softc(sc);
  494 
  495         return (0);
  496 }
  497 
  498 UCOM_UNLOAD_DRAIN(ufoma);
  499 
  500 static void
  501 ufoma_free_softc(struct ufoma_softc *sc)
  502 {
  503         if (ucom_unref(&sc->sc_super_ucom)) {
  504                 mtx_destroy(&sc->sc_mtx);
  505                 device_free_softc(sc);
  506         }
  507 }
  508 
  509 static void
  510 ufoma_free(struct ucom_softc *ucom)
  511 {
  512         ufoma_free_softc(ucom->sc_parent);
  513 }
  514 
  515 static void *
  516 ufoma_get_intconf(struct usb_config_descriptor *cd, struct usb_interface_descriptor *id,
  517     uint8_t type, uint8_t subtype)
  518 {
  519         struct usb_descriptor *desc = (void *)id;
  520 
  521         while ((desc = usb_desc_foreach(cd, desc))) {
  522                 if (desc->bDescriptorType == UDESC_INTERFACE) {
  523                         return (NULL);
  524                 }
  525                 if ((desc->bDescriptorType == type) &&
  526                     (desc->bDescriptorSubtype == subtype)) {
  527                         break;
  528                 }
  529         }
  530         return (desc);
  531 }
  532 
  533 static void
  534 ufoma_cfg_link_state(struct ufoma_softc *sc)
  535 {
  536         struct usb_device_request req;
  537         int32_t error;
  538 
  539         req.bmRequestType = UT_WRITE_VENDOR_INTERFACE;
  540         req.bRequest = UMCPC_SET_LINK;
  541         USETW(req.wValue, UMCPC_CM_MOBILE_ACM);
  542         USETW(req.wIndex, sc->sc_ctrl_iface_no);
  543         USETW(req.wLength, sc->sc_modetable[0]);
  544 
  545         ucom_cfg_do_request(sc->sc_udev, &sc->sc_ucom, 
  546             &req, sc->sc_modetable, 0, 1000);
  547 
  548         error = cv_timedwait(&sc->sc_cv, &sc->sc_mtx, hz);
  549 
  550         if (error) {
  551                 DPRINTF("NO response\n");
  552         }
  553 }
  554 
  555 static void
  556 ufoma_cfg_activate_state(struct ufoma_softc *sc, uint16_t state)
  557 {
  558         struct usb_device_request req;
  559         int32_t error;
  560 
  561         req.bmRequestType = UT_WRITE_VENDOR_INTERFACE;
  562         req.bRequest = UMCPC_ACTIVATE_MODE;
  563         USETW(req.wValue, state);
  564         USETW(req.wIndex, sc->sc_ctrl_iface_no);
  565         USETW(req.wLength, 0);
  566 
  567         ucom_cfg_do_request(sc->sc_udev, &sc->sc_ucom, 
  568             &req, NULL, 0, 1000);
  569 
  570         error = cv_timedwait(&sc->sc_cv, &sc->sc_mtx,
  571             (UFOMA_MAX_TIMEOUT * hz));
  572         if (error) {
  573                 DPRINTF("No response\n");
  574         }
  575 }
  576 
  577 static void
  578 ufoma_ctrl_read_callback(struct usb_xfer *xfer, usb_error_t error)
  579 {
  580         struct ufoma_softc *sc = usbd_xfer_softc(xfer);
  581         struct usb_device_request req;
  582         struct usb_page_cache *pc0, *pc1;
  583         int len, aframes, nframes;
  584 
  585         usbd_xfer_status(xfer, NULL, NULL, &aframes, &nframes);
  586 
  587         switch (USB_GET_STATE(xfer)) {
  588         case USB_ST_TRANSFERRED:
  589 tr_transferred:
  590                 if (aframes != nframes)
  591                         goto tr_setup;
  592                 pc1 = usbd_xfer_get_frame(xfer, 1);
  593                 len = usbd_xfer_frame_len(xfer, 1);
  594                 if (len > 0)
  595                         ucom_put_data(&sc->sc_ucom, pc1, 0, len);
  596                 /* FALLTHROUGH */
  597         case USB_ST_SETUP:
  598 tr_setup:
  599                 if (sc->sc_num_msg) {
  600                         sc->sc_num_msg--;
  601 
  602                         req.bmRequestType = UT_READ_CLASS_INTERFACE;
  603                         req.bRequest = UCDC_GET_ENCAPSULATED_RESPONSE;
  604                         USETW(req.wIndex, sc->sc_ctrl_iface_no);
  605                         USETW(req.wValue, 0);
  606                         USETW(req.wLength, UFOMA_CMD_BUF_SIZE);
  607 
  608                         pc0 = usbd_xfer_get_frame(xfer, 0);
  609                         usbd_copy_in(pc0, 0, &req, sizeof(req));
  610 
  611                         usbd_xfer_set_frame_len(xfer, 0, sizeof(req));
  612                         usbd_xfer_set_frame_len(xfer, 1, UFOMA_CMD_BUF_SIZE);
  613                         usbd_xfer_set_frames(xfer, 2);
  614                         usbd_transfer_submit(xfer);
  615                 }
  616                 return;
  617 
  618         default:                        /* Error */
  619                 DPRINTF("error = %s\n",
  620                     usbd_errstr(error));
  621 
  622                 if (error == USB_ERR_CANCELLED) {
  623                         return;
  624                 }
  625                 goto tr_transferred;
  626         }
  627 }
  628 
  629 static void
  630 ufoma_ctrl_write_callback(struct usb_xfer *xfer, usb_error_t error)
  631 {
  632         struct ufoma_softc *sc = usbd_xfer_softc(xfer);
  633         struct usb_device_request req;
  634         struct usb_page_cache *pc;
  635         uint32_t actlen;
  636 
  637         switch (USB_GET_STATE(xfer)) {
  638         case USB_ST_TRANSFERRED:
  639 tr_transferred:
  640         case USB_ST_SETUP:
  641                 pc = usbd_xfer_get_frame(xfer, 1);
  642                 if (ucom_get_data(&sc->sc_ucom, pc, 0, 1, &actlen)) {
  643                         req.bmRequestType = UT_WRITE_CLASS_INTERFACE;
  644                         req.bRequest = UCDC_SEND_ENCAPSULATED_COMMAND;
  645                         USETW(req.wIndex, sc->sc_ctrl_iface_no);
  646                         USETW(req.wValue, 0);
  647                         USETW(req.wLength, 1);
  648 
  649                         pc = usbd_xfer_get_frame(xfer, 0);
  650                         usbd_copy_in(pc, 0, &req, sizeof(req));
  651 
  652                         usbd_xfer_set_frame_len(xfer, 0, sizeof(req));
  653                         usbd_xfer_set_frame_len(xfer, 1, 1);
  654                         usbd_xfer_set_frames(xfer, 2);
  655 
  656                         usbd_transfer_submit(xfer);
  657                 }
  658                 return;
  659 
  660         default:                        /* Error */
  661                 DPRINTF("error = %s\n", usbd_errstr(error));
  662 
  663                 if (error == USB_ERR_CANCELLED) {
  664                         return;
  665                 }
  666                 goto tr_transferred;
  667         }
  668 }
  669 
  670 static void
  671 ufoma_intr_callback(struct usb_xfer *xfer, usb_error_t error)
  672 {
  673         struct ufoma_softc *sc = usbd_xfer_softc(xfer);
  674         struct usb_cdc_notification pkt;
  675         struct usb_page_cache *pc;
  676         uint16_t wLen;
  677         uint16_t temp;
  678         uint8_t mstatus;
  679         int actlen;
  680 
  681         usbd_xfer_status(xfer, &actlen, NULL, NULL, NULL);
  682 
  683         switch (USB_GET_STATE(xfer)) {
  684         case USB_ST_TRANSFERRED:
  685                 if (actlen < 8) {
  686                         DPRINTF("too short message\n");
  687                         goto tr_setup;
  688                 }
  689                 if (actlen > (int)sizeof(pkt)) {
  690                         DPRINTF("truncating message\n");
  691                         actlen = sizeof(pkt);
  692                 }
  693                 pc = usbd_xfer_get_frame(xfer, 0);
  694                 usbd_copy_out(pc, 0, &pkt, actlen);
  695 
  696                 actlen -= 8;
  697 
  698                 wLen = UGETW(pkt.wLength);
  699                 if (actlen > wLen) {
  700                         actlen = wLen;
  701                 }
  702                 if ((pkt.bmRequestType == UT_READ_VENDOR_INTERFACE) &&
  703                     (pkt.bNotification == UMCPC_REQUEST_ACKNOWLEDGE)) {
  704                         temp = UGETW(pkt.wValue);
  705                         sc->sc_currentmode = (temp >> 8);
  706                         if (!(temp & 0xff)) {
  707                                 DPRINTF("Mode change failed!\n");
  708                         }
  709                         cv_signal(&sc->sc_cv);
  710                 }
  711                 if (pkt.bmRequestType != UCDC_NOTIFICATION) {
  712                         goto tr_setup;
  713                 }
  714                 switch (pkt.bNotification) {
  715                 case UCDC_N_RESPONSE_AVAILABLE:
  716                         if (!(sc->sc_nobulk)) {
  717                                 DPRINTF("Wrong serial state!\n");
  718                                 break;
  719                         }
  720                         if (sc->sc_num_msg != 0xFF) {
  721                                 sc->sc_num_msg++;
  722                         }
  723                         usbd_transfer_start(sc->sc_ctrl_xfer[UFOMA_CTRL_ENDPT_READ]);
  724                         break;
  725 
  726                 case UCDC_N_SERIAL_STATE:
  727                         if (sc->sc_nobulk) {
  728                                 DPRINTF("Wrong serial state!\n");
  729                                 break;
  730                         }
  731                         /*
  732                          * Set the serial state in ucom driver based on
  733                          * the bits from the notify message
  734                          */
  735                         if (actlen < 2) {
  736                                 DPRINTF("invalid notification "
  737                                     "length, %d bytes!\n", actlen);
  738                                 break;
  739                         }
  740                         DPRINTF("notify bytes = 0x%02x, 0x%02x\n",
  741                             pkt.data[0], pkt.data[1]);
  742 
  743                         /* currently, lsr is always zero. */
  744                         sc->sc_lsr = 0;
  745                         sc->sc_msr = 0;
  746 
  747                         mstatus = pkt.data[0];
  748 
  749                         if (mstatus & UCDC_N_SERIAL_RI) {
  750                                 sc->sc_msr |= SER_RI;
  751                         }
  752                         if (mstatus & UCDC_N_SERIAL_DSR) {
  753                                 sc->sc_msr |= SER_DSR;
  754                         }
  755                         if (mstatus & UCDC_N_SERIAL_DCD) {
  756                                 sc->sc_msr |= SER_DCD;
  757                         }
  758                         ucom_status_change(&sc->sc_ucom);
  759                         break;
  760 
  761                 default:
  762                         break;
  763                 }
  764 
  765         case USB_ST_SETUP:
  766 tr_setup:
  767                 usbd_xfer_set_frame_len(xfer, 0, usbd_xfer_max_len(xfer));
  768                 usbd_transfer_submit(xfer);
  769                 return;
  770 
  771         default:                        /* Error */
  772                 if (error != USB_ERR_CANCELLED) {
  773                         /* try to clear stall first */
  774                         usbd_xfer_set_stall(xfer);
  775                         goto tr_setup;
  776                 }
  777                 return;
  778         }
  779 }
  780 
  781 static void
  782 ufoma_bulk_write_callback(struct usb_xfer *xfer, usb_error_t error)
  783 {
  784         struct ufoma_softc *sc = usbd_xfer_softc(xfer);
  785         struct usb_page_cache *pc;
  786         uint32_t actlen;
  787 
  788         switch (USB_GET_STATE(xfer)) {
  789         case USB_ST_SETUP:
  790         case USB_ST_TRANSFERRED:
  791 tr_setup:
  792                 pc = usbd_xfer_get_frame(xfer, 0);
  793                 if (ucom_get_data(&sc->sc_ucom, pc, 0,
  794                     UFOMA_BULK_BUF_SIZE, &actlen)) {
  795                         usbd_xfer_set_frame_len(xfer, 0, actlen);
  796                         usbd_transfer_submit(xfer);
  797                 }
  798                 return;
  799 
  800         default:                        /* Error */
  801                 if (error != USB_ERR_CANCELLED) {
  802                         /* try to clear stall first */
  803                         usbd_xfer_set_stall(xfer);
  804                         goto tr_setup;
  805                 }
  806                 return;
  807         }
  808 }
  809 
  810 static void
  811 ufoma_bulk_read_callback(struct usb_xfer *xfer, usb_error_t error)
  812 {
  813         struct ufoma_softc *sc = usbd_xfer_softc(xfer);
  814         struct usb_page_cache *pc;
  815         int actlen;
  816 
  817         usbd_xfer_status(xfer, &actlen, NULL, NULL, NULL);
  818 
  819         switch (USB_GET_STATE(xfer)) {
  820         case USB_ST_TRANSFERRED:
  821                 pc = usbd_xfer_get_frame(xfer, 0);
  822                 ucom_put_data(&sc->sc_ucom, pc, 0, actlen);
  823 
  824         case USB_ST_SETUP:
  825 tr_setup:
  826                 usbd_xfer_set_frame_len(xfer, 0, usbd_xfer_max_len(xfer));
  827                 usbd_transfer_submit(xfer);
  828                 return;
  829 
  830         default:                        /* Error */
  831                 if (error != USB_ERR_CANCELLED) {
  832                         /* try to clear stall first */
  833                         usbd_xfer_set_stall(xfer);
  834                         goto tr_setup;
  835                 }
  836                 return;
  837         }
  838 }
  839 
  840 static void
  841 ufoma_cfg_open(struct ucom_softc *ucom)
  842 {
  843         struct ufoma_softc *sc = ucom->sc_parent;
  844 
  845         /* empty input queue */
  846 
  847         if (sc->sc_num_msg != 0xFF) {
  848                 sc->sc_num_msg++;
  849         }
  850         if (sc->sc_currentmode == UMCPC_ACM_MODE_UNLINKED) {
  851                 ufoma_cfg_link_state(sc);
  852         }
  853         if (sc->sc_currentmode == UMCPC_ACM_MODE_DEACTIVATED) {
  854                 ufoma_cfg_activate_state(sc, sc->sc_modetoactivate);
  855         }
  856 }
  857 
  858 static void
  859 ufoma_cfg_close(struct ucom_softc *ucom)
  860 {
  861         struct ufoma_softc *sc = ucom->sc_parent;
  862 
  863         ufoma_cfg_activate_state(sc, UMCPC_ACM_MODE_DEACTIVATED);
  864 }
  865 
  866 static void
  867 ufoma_cfg_set_break(struct ucom_softc *ucom, uint8_t onoff)
  868 {
  869         struct ufoma_softc *sc = ucom->sc_parent;
  870         struct usb_device_request req;
  871         uint16_t wValue;
  872 
  873         if (sc->sc_nobulk ||
  874             (sc->sc_currentmode == UMCPC_ACM_MODE_OBEX)) {
  875                 return;
  876         }
  877         if (!(sc->sc_acm_cap & USB_CDC_ACM_HAS_BREAK)) {
  878                 return;
  879         }
  880         wValue = onoff ? UCDC_BREAK_ON : UCDC_BREAK_OFF;
  881 
  882         req.bmRequestType = UT_WRITE_CLASS_INTERFACE;
  883         req.bRequest = UCDC_SEND_BREAK;
  884         USETW(req.wValue, wValue);
  885         req.wIndex[0] = sc->sc_ctrl_iface_no;
  886         req.wIndex[1] = 0;
  887         USETW(req.wLength, 0);
  888 
  889         ucom_cfg_do_request(sc->sc_udev, &sc->sc_ucom, 
  890             &req, NULL, 0, 1000);
  891 }
  892 
  893 static void
  894 ufoma_cfg_get_status(struct ucom_softc *ucom, uint8_t *lsr, uint8_t *msr)
  895 {
  896         struct ufoma_softc *sc = ucom->sc_parent;
  897 
  898         /* XXX Note: sc_lsr is always zero */
  899         *lsr = sc->sc_lsr;
  900         *msr = sc->sc_msr;
  901 }
  902 
  903 static void
  904 ufoma_cfg_set_line_state(struct ufoma_softc *sc)
  905 {
  906         struct usb_device_request req;
  907 
  908         /* Don't send line state emulation request for OBEX port */
  909         if (sc->sc_currentmode == UMCPC_ACM_MODE_OBEX) {
  910                 return;
  911         }
  912         req.bmRequestType = UT_WRITE_CLASS_INTERFACE;
  913         req.bRequest = UCDC_SET_CONTROL_LINE_STATE;
  914         USETW(req.wValue, sc->sc_line);
  915         req.wIndex[0] = sc->sc_ctrl_iface_no;
  916         req.wIndex[1] = 0;
  917         USETW(req.wLength, 0);
  918 
  919         ucom_cfg_do_request(sc->sc_udev, &sc->sc_ucom, 
  920             &req, NULL, 0, 1000);
  921 }
  922 
  923 static void
  924 ufoma_cfg_set_dtr(struct ucom_softc *ucom, uint8_t onoff)
  925 {
  926         struct ufoma_softc *sc = ucom->sc_parent;
  927 
  928         if (sc->sc_nobulk) {
  929                 return;
  930         }
  931         if (onoff)
  932                 sc->sc_line |= UCDC_LINE_DTR;
  933         else
  934                 sc->sc_line &= ~UCDC_LINE_DTR;
  935 
  936         ufoma_cfg_set_line_state(sc);
  937 }
  938 
  939 static void
  940 ufoma_cfg_set_rts(struct ucom_softc *ucom, uint8_t onoff)
  941 {
  942         struct ufoma_softc *sc = ucom->sc_parent;
  943 
  944         if (sc->sc_nobulk) {
  945                 return;
  946         }
  947         if (onoff)
  948                 sc->sc_line |= UCDC_LINE_RTS;
  949         else
  950                 sc->sc_line &= ~UCDC_LINE_RTS;
  951 
  952         ufoma_cfg_set_line_state(sc);
  953 }
  954 
  955 static int
  956 ufoma_pre_param(struct ucom_softc *ucom, struct termios *t)
  957 {
  958         return (0);                     /* we accept anything */
  959 }
  960 
  961 static void
  962 ufoma_cfg_param(struct ucom_softc *ucom, struct termios *t)
  963 {
  964         struct ufoma_softc *sc = ucom->sc_parent;
  965         struct usb_device_request req;
  966         struct usb_cdc_line_state ls;
  967 
  968         if (sc->sc_nobulk ||
  969             (sc->sc_currentmode == UMCPC_ACM_MODE_OBEX)) {
  970                 return;
  971         }
  972         DPRINTF("\n");
  973 
  974         memset(&ls, 0, sizeof(ls));
  975 
  976         USETDW(ls.dwDTERate, t->c_ospeed);
  977 
  978         if (t->c_cflag & CSTOPB) {
  979                 ls.bCharFormat = UCDC_STOP_BIT_2;
  980         } else {
  981                 ls.bCharFormat = UCDC_STOP_BIT_1;
  982         }
  983 
  984         if (t->c_cflag & PARENB) {
  985                 if (t->c_cflag & PARODD) {
  986                         ls.bParityType = UCDC_PARITY_ODD;
  987                 } else {
  988                         ls.bParityType = UCDC_PARITY_EVEN;
  989                 }
  990         } else {
  991                 ls.bParityType = UCDC_PARITY_NONE;
  992         }
  993 
  994         switch (t->c_cflag & CSIZE) {
  995         case CS5:
  996                 ls.bDataBits = 5;
  997                 break;
  998         case CS6:
  999                 ls.bDataBits = 6;
 1000                 break;
 1001         case CS7:
 1002                 ls.bDataBits = 7;
 1003                 break;
 1004         case CS8:
 1005                 ls.bDataBits = 8;
 1006                 break;
 1007         }
 1008 
 1009         req.bmRequestType = UT_WRITE_CLASS_INTERFACE;
 1010         req.bRequest = UCDC_SET_LINE_CODING;
 1011         USETW(req.wValue, 0);
 1012         req.wIndex[0] = sc->sc_ctrl_iface_no;
 1013         req.wIndex[1] = 0;
 1014         USETW(req.wLength, UCDC_LINE_STATE_LENGTH);
 1015 
 1016         ucom_cfg_do_request(sc->sc_udev, &sc->sc_ucom, 
 1017             &req, &ls, 0, 1000);
 1018 }
 1019 
 1020 static int
 1021 ufoma_modem_setup(device_t dev, struct ufoma_softc *sc,
 1022     struct usb_attach_arg *uaa)
 1023 {
 1024         struct usb_config_descriptor *cd;
 1025         struct usb_cdc_acm_descriptor *acm;
 1026         struct usb_cdc_cm_descriptor *cmd;
 1027         struct usb_interface_descriptor *id;
 1028         struct usb_interface *iface;
 1029         uint8_t i;
 1030         int32_t error;
 1031 
 1032         cd = usbd_get_config_descriptor(uaa->device);
 1033         id = usbd_get_interface_descriptor(uaa->iface);
 1034 
 1035         cmd = ufoma_get_intconf(cd, id, UDESC_CS_INTERFACE, UDESCSUB_CDC_CM);
 1036 
 1037         if ((cmd == NULL) ||
 1038             (cmd->bLength < sizeof(*cmd))) {
 1039                 return (EINVAL);
 1040         }
 1041         sc->sc_cm_cap = cmd->bmCapabilities;
 1042         sc->sc_data_iface_no = cmd->bDataInterface;
 1043 
 1044         acm = ufoma_get_intconf(cd, id, UDESC_CS_INTERFACE, UDESCSUB_CDC_ACM);
 1045 
 1046         if ((acm == NULL) ||
 1047             (acm->bLength < sizeof(*acm))) {
 1048                 return (EINVAL);
 1049         }
 1050         sc->sc_acm_cap = acm->bmCapabilities;
 1051 
 1052         device_printf(dev, "data interface %d, has %sCM over data, "
 1053             "has %sbreak\n",
 1054             sc->sc_data_iface_no,
 1055             sc->sc_cm_cap & USB_CDC_CM_OVER_DATA ? "" : "no ",
 1056             sc->sc_acm_cap & USB_CDC_ACM_HAS_BREAK ? "" : "no ");
 1057 
 1058         /* get the data interface too */
 1059 
 1060         for (i = 0;; i++) {
 1061                 iface = usbd_get_iface(uaa->device, i);
 1062 
 1063                 if (iface) {
 1064                         id = usbd_get_interface_descriptor(iface);
 1065 
 1066                         if (id && (id->bInterfaceNumber == sc->sc_data_iface_no)) {
 1067                                 sc->sc_data_iface_index = i;
 1068                                 usbd_set_parent_iface(uaa->device, i, uaa->info.bIfaceIndex);
 1069                                 break;
 1070                         }
 1071                 } else {
 1072                         device_printf(dev, "no data interface\n");
 1073                         return (EINVAL);
 1074                 }
 1075         }
 1076 
 1077         error = usbd_transfer_setup(uaa->device,
 1078             &sc->sc_data_iface_index, sc->sc_bulk_xfer,
 1079             ufoma_bulk_config, UFOMA_BULK_ENDPT_MAX, sc, &sc->sc_mtx);
 1080 
 1081         if (error) {
 1082                 device_printf(dev, "allocating BULK USB "
 1083                     "transfers failed\n");
 1084                 return (EINVAL);
 1085         }
 1086         return (0);
 1087 }
 1088 
 1089 static void
 1090 ufoma_start_read(struct ucom_softc *ucom)
 1091 {
 1092         struct ufoma_softc *sc = ucom->sc_parent;
 1093 
 1094         /* start interrupt transfer */
 1095         usbd_transfer_start(sc->sc_ctrl_xfer[UFOMA_CTRL_ENDPT_INTR]);
 1096 
 1097         /* start data transfer */
 1098         if (sc->sc_nobulk) {
 1099                 usbd_transfer_start(sc->sc_ctrl_xfer[UFOMA_CTRL_ENDPT_READ]);
 1100         } else {
 1101                 usbd_transfer_start(sc->sc_bulk_xfer[UFOMA_BULK_ENDPT_READ]);
 1102         }
 1103 }
 1104 
 1105 static void
 1106 ufoma_stop_read(struct ucom_softc *ucom)
 1107 {
 1108         struct ufoma_softc *sc = ucom->sc_parent;
 1109 
 1110         /* stop interrupt transfer */
 1111         usbd_transfer_stop(sc->sc_ctrl_xfer[UFOMA_CTRL_ENDPT_INTR]);
 1112 
 1113         /* stop data transfer */
 1114         if (sc->sc_nobulk) {
 1115                 usbd_transfer_stop(sc->sc_ctrl_xfer[UFOMA_CTRL_ENDPT_READ]);
 1116         } else {
 1117                 usbd_transfer_stop(sc->sc_bulk_xfer[UFOMA_BULK_ENDPT_READ]);
 1118         }
 1119 }
 1120 
 1121 static void
 1122 ufoma_start_write(struct ucom_softc *ucom)
 1123 {
 1124         struct ufoma_softc *sc = ucom->sc_parent;
 1125 
 1126         if (sc->sc_nobulk) {
 1127                 usbd_transfer_start(sc->sc_ctrl_xfer[UFOMA_CTRL_ENDPT_WRITE]);
 1128         } else {
 1129                 usbd_transfer_start(sc->sc_bulk_xfer[UFOMA_BULK_ENDPT_WRITE]);
 1130         }
 1131 }
 1132 
 1133 static void
 1134 ufoma_stop_write(struct ucom_softc *ucom)
 1135 {
 1136         struct ufoma_softc *sc = ucom->sc_parent;
 1137 
 1138         if (sc->sc_nobulk) {
 1139                 usbd_transfer_stop(sc->sc_ctrl_xfer[UFOMA_CTRL_ENDPT_WRITE]);
 1140         } else {
 1141                 usbd_transfer_stop(sc->sc_bulk_xfer[UFOMA_BULK_ENDPT_WRITE]);
 1142         }
 1143 }
 1144 
 1145 static struct umcpc_modetostr_tab{
 1146         int mode;
 1147         char *str;
 1148 }umcpc_modetostr_tab[]={
 1149         {UMCPC_ACM_MODE_DEACTIVATED, "deactivated"},
 1150         {UMCPC_ACM_MODE_MODEM, "modem"},
 1151         {UMCPC_ACM_MODE_ATCOMMAND, "handsfree"},
 1152         {UMCPC_ACM_MODE_OBEX, "obex"},
 1153         {UMCPC_ACM_MODE_VENDOR1, "vendor1"},
 1154         {UMCPC_ACM_MODE_VENDOR2, "vendor2"},
 1155         {UMCPC_ACM_MODE_UNLINKED, "unlinked"},
 1156         {0, NULL}
 1157 };
 1158 
 1159 static char *ufoma_mode_to_str(int mode)
 1160 {
 1161         int i;
 1162         for(i = 0 ;umcpc_modetostr_tab[i].str != NULL; i++){
 1163                 if(umcpc_modetostr_tab[i].mode == mode){
 1164                         return umcpc_modetostr_tab[i].str;
 1165                 }
 1166         }
 1167         return NULL;
 1168 }
 1169 
 1170 static int ufoma_str_to_mode(char *str)
 1171 {
 1172         int i;
 1173         for(i = 0 ;umcpc_modetostr_tab[i].str != NULL; i++){
 1174                 if(strcmp(str, umcpc_modetostr_tab[i].str)==0){
 1175                         return umcpc_modetostr_tab[i].mode;
 1176                 }
 1177         }
 1178         return -1;
 1179 }
 1180 
 1181 static int ufoma_sysctl_support(SYSCTL_HANDLER_ARGS)
 1182 {
 1183         struct ufoma_softc *sc = (struct ufoma_softc *)oidp->oid_arg1;
 1184         struct sbuf sb;
 1185         int i;
 1186         char *mode;
 1187 
 1188         sbuf_new(&sb, NULL, 1, SBUF_AUTOEXTEND);
 1189         for(i = 1; i < sc->sc_modetable[0]; i++){
 1190                 mode = ufoma_mode_to_str(sc->sc_modetable[i]);
 1191                 if(mode !=NULL){
 1192                         sbuf_cat(&sb, mode);
 1193                 }else{
 1194                         sbuf_printf(&sb, "(%02x)", sc->sc_modetable[i]);
 1195                 }
 1196                 if(i < (sc->sc_modetable[0]-1))
 1197                         sbuf_cat(&sb, ",");
 1198         }
 1199         sbuf_trim(&sb);
 1200         sbuf_finish(&sb);
 1201         sysctl_handle_string(oidp, sbuf_data(&sb), sbuf_len(&sb), req);
 1202         sbuf_delete(&sb);
 1203 
 1204         return 0;
 1205 }
 1206 static int ufoma_sysctl_current(SYSCTL_HANDLER_ARGS)
 1207 {
 1208         struct ufoma_softc *sc = (struct ufoma_softc *)oidp->oid_arg1;
 1209         char *mode;
 1210         char subbuf[]="(XXX)";
 1211         mode = ufoma_mode_to_str(sc->sc_currentmode);
 1212         if(!mode){
 1213                 mode = subbuf;
 1214                 snprintf(subbuf, sizeof(subbuf), "(%02x)", sc->sc_currentmode);
 1215         }
 1216         sysctl_handle_string(oidp, mode, strlen(mode), req);
 1217 
 1218         return 0;
 1219 
 1220 }
 1221 static int ufoma_sysctl_open(SYSCTL_HANDLER_ARGS)
 1222 {
 1223         struct ufoma_softc *sc = (struct ufoma_softc *)oidp->oid_arg1;
 1224         char *mode;
 1225         char subbuf[40];
 1226         int newmode;
 1227         int error;
 1228         int i;
 1229 
 1230         mode = ufoma_mode_to_str(sc->sc_modetoactivate);
 1231         if(mode){
 1232                 strncpy(subbuf, mode, sizeof(subbuf));
 1233         }else{
 1234                 snprintf(subbuf, sizeof(subbuf), "(%02x)", sc->sc_modetoactivate);
 1235         }
 1236         error = sysctl_handle_string(oidp, subbuf, sizeof(subbuf), req);
 1237         if(error != 0 || req->newptr == NULL){
 1238                 return error;
 1239         }
 1240 
 1241         if((newmode = ufoma_str_to_mode(subbuf)) == -1){
 1242                 return EINVAL;
 1243         }
 1244 
 1245         for(i = 1 ; i < sc->sc_modetable[0] ; i++){
 1246                 if(sc->sc_modetable[i] == newmode){
 1247                         sc->sc_modetoactivate = newmode;
 1248                         return 0;
 1249                 }
 1250         }
 1251 
 1252         return EINVAL;
 1253 }
 1254 
 1255 static void
 1256 ufoma_poll(struct ucom_softc *ucom)
 1257 {
 1258         struct ufoma_softc *sc = ucom->sc_parent;
 1259         usbd_transfer_poll(sc->sc_ctrl_xfer, UFOMA_CTRL_ENDPT_MAX);
 1260         usbd_transfer_poll(sc->sc_bulk_xfer, UFOMA_BULK_ENDPT_MAX);
 1261 }

Cache object: 3a29d691cb123462eaa36bd396041a5f


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