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/uplcom.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: uplcom.c,v 1.21 2001/11/13 06:24:56 lukem Exp $        */
    2 
    3 #include <sys/cdefs.h>
    4 __FBSDID("$FreeBSD$");
    5 
    6 /*-
    7  * SPDX-License-Identifier: BSD-2-Clause-FreeBSD AND BSD-2-Clause-NetBSD
    8  *
    9  * Copyright (c) 2001-2003, 2005 Shunsuke Akiyama <akiyama@jp.FreeBSD.org>.
   10  * All rights reserved.
   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) 2001 The NetBSD Foundation, Inc.
   36  * All rights reserved.
   37  *
   38  * This code is derived from software contributed to The NetBSD Foundation
   39  * by Ichiro FUKUHARA (ichiro@ichiro.org).
   40  *
   41  * Redistribution and use in source and binary forms, with or without
   42  * modification, are permitted provided that the following conditions
   43  * are met:
   44  * 1. Redistributions of source code must retain the above copyright
   45  *    notice, this list of conditions and the following disclaimer.
   46  * 2. Redistributions in binary form must reproduce the above copyright
   47  *    notice, this list of conditions and the following disclaimer in the
   48  *    documentation and/or other materials provided with the distribution.
   49  *
   50  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
   51  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
   52  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
   53  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
   54  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
   55  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
   56  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
   57  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
   58  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
   59  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
   60  * POSSIBILITY OF SUCH DAMAGE.
   61  */
   62 
   63 /*
   64  * This driver supports several USB-to-RS232 serial adapters driven by
   65  * Prolific PL-2303, PL-2303X and probably PL-2303HX USB-to-RS232
   66  * bridge chip.  The adapters are sold under many different brand
   67  * names.
   68  *
   69  * Datasheets are available at Prolific www site at
   70  * http://www.prolific.com.tw.  The datasheets don't contain full
   71  * programming information for the chip.
   72  *
   73  * PL-2303HX is probably programmed the same as PL-2303X.
   74  *
   75  * There are several differences between PL-2303 and PL-2303(H)X.
   76  * PL-2303(H)X can do higher bitrate in bulk mode, has _probably_
   77  * different command for controlling CRTSCTS and needs special
   78  * sequence of commands for initialization which aren't also
   79  * documented in the datasheet.
   80  */
   81 
   82 #include <sys/stdint.h>
   83 #include <sys/stddef.h>
   84 #include <sys/param.h>
   85 #include <sys/queue.h>
   86 #include <sys/types.h>
   87 #include <sys/systm.h>
   88 #include <sys/kernel.h>
   89 #include <sys/bus.h>
   90 #include <sys/module.h>
   91 #include <sys/lock.h>
   92 #include <sys/mutex.h>
   93 #include <sys/condvar.h>
   94 #include <sys/sysctl.h>
   95 #include <sys/sx.h>
   96 #include <sys/unistd.h>
   97 #include <sys/callout.h>
   98 #include <sys/malloc.h>
   99 #include <sys/priv.h>
  100 
  101 #include <dev/usb/usb.h>
  102 #include <dev/usb/usbdi.h>
  103 #include <dev/usb/usbdi_util.h>
  104 #include <dev/usb/usb_cdc.h>
  105 #include "usbdevs.h"
  106 
  107 #define USB_DEBUG_VAR uplcom_debug
  108 #include <dev/usb/usb_debug.h>
  109 #include <dev/usb/usb_process.h>
  110 
  111 #include <dev/usb/serial/usb_serial.h>
  112 
  113 #ifdef USB_DEBUG
  114 static int uplcom_debug = 0;
  115 
  116 static SYSCTL_NODE(_hw_usb, OID_AUTO, uplcom, CTLFLAG_RW | CTLFLAG_MPSAFE, 0,
  117     "USB uplcom");
  118 SYSCTL_INT(_hw_usb_uplcom, OID_AUTO, debug, CTLFLAG_RWTUN,
  119     &uplcom_debug, 0, "Debug level");
  120 #endif
  121 
  122 #define UPLCOM_MODVER                   1       /* module version */
  123 
  124 #define UPLCOM_CONFIG_INDEX             0
  125 #define UPLCOM_IFACE_INDEX              0
  126 #define UPLCOM_SECOND_IFACE_INDEX       1
  127 
  128 #ifndef UPLCOM_INTR_INTERVAL
  129 #define UPLCOM_INTR_INTERVAL            0       /* default */
  130 #endif
  131 
  132 #define UPLCOM_BULK_BUF_SIZE 1024       /* bytes */
  133 
  134 #define UPLCOM_SET_REQUEST              0x01
  135 #define UPLCOM_SET_REQUEST_PL2303HXN    0x80
  136 #define UPLCOM_SET_CRTSCTS              0x41
  137 #define UPLCOM_SET_CRTSCTS_PL2303X      0x61
  138 #define UPLCOM_SET_CRTSCTS_PL2303HXN    0xFA
  139 #define UPLCOM_CLEAR_CRTSCTS_PL2303HXN  0xFF
  140 #define UPLCOM_CRTSCTS_REG_PL2303HXN    0x0A
  141 #define UPLCOM_STATUS_REG_PL2303HX      0x8080
  142 #define RSAQ_STATUS_CTS                 0x80
  143 #define RSAQ_STATUS_OVERRUN_ERROR       0x40
  144 #define RSAQ_STATUS_PARITY_ERROR        0x20 
  145 #define RSAQ_STATUS_FRAME_ERROR 0x10
  146 #define RSAQ_STATUS_RING                0x08
  147 #define RSAQ_STATUS_BREAK_ERROR 0x04
  148 #define RSAQ_STATUS_DSR                 0x02
  149 #define RSAQ_STATUS_DCD                 0x01
  150 
  151 #define TYPE_PL2303                     0
  152 #define TYPE_PL2303HX                   1
  153 #define TYPE_PL2303HXD                  2
  154 #define TYPE_PL2303HXN                  3
  155 
  156 #define UPLCOM_STATE_INDEX              8
  157 
  158 enum {
  159         UPLCOM_BULK_DT_WR,
  160         UPLCOM_BULK_DT_RD,
  161         UPLCOM_INTR_DT_RD,
  162         UPLCOM_N_TRANSFER,
  163 };
  164 
  165 struct uplcom_softc {
  166         struct ucom_super_softc sc_super_ucom;
  167         struct ucom_softc sc_ucom;
  168 
  169         struct usb_xfer *sc_xfer[UPLCOM_N_TRANSFER];
  170         struct usb_device *sc_udev;
  171         struct mtx sc_mtx;
  172 
  173         uint16_t sc_line;
  174 
  175         uint8_t sc_lsr;                 /* local status register */
  176         uint8_t sc_msr;                 /* uplcom status register */
  177         uint8_t sc_chiptype;            /* type of chip */
  178         uint8_t sc_ctrl_iface_no;
  179         uint8_t sc_data_iface_no;
  180         uint8_t sc_iface_index[2];
  181 };
  182 
  183 /* prototypes */
  184 
  185 static usb_error_t uplcom_reset(struct uplcom_softc *, struct usb_device *);
  186 static usb_error_t uplcom_pl2303_do(struct usb_device *, uint8_t, uint8_t,
  187                         uint16_t, uint16_t, uint16_t);
  188 static int      uplcom_pl2303_init(struct usb_device *, uint8_t);
  189 static void     uplcom_free(struct ucom_softc *);
  190 static void     uplcom_cfg_set_dtr(struct ucom_softc *, uint8_t);
  191 static void     uplcom_cfg_set_rts(struct ucom_softc *, uint8_t);
  192 static void     uplcom_cfg_set_break(struct ucom_softc *, uint8_t);
  193 static int      uplcom_pre_param(struct ucom_softc *, struct termios *);
  194 static void     uplcom_cfg_param(struct ucom_softc *, struct termios *);
  195 static void     uplcom_start_read(struct ucom_softc *);
  196 static void     uplcom_stop_read(struct ucom_softc *);
  197 static void     uplcom_start_write(struct ucom_softc *);
  198 static void     uplcom_stop_write(struct ucom_softc *);
  199 static void     uplcom_cfg_get_status(struct ucom_softc *, uint8_t *,
  200                     uint8_t *);
  201 static void     uplcom_poll(struct ucom_softc *ucom);
  202 
  203 static device_probe_t uplcom_probe;
  204 static device_attach_t uplcom_attach;
  205 static device_detach_t uplcom_detach;
  206 static void uplcom_free_softc(struct uplcom_softc *);
  207 
  208 static usb_callback_t uplcom_intr_callback;
  209 static usb_callback_t uplcom_write_callback;
  210 static usb_callback_t uplcom_read_callback;
  211 
  212 static const struct usb_config uplcom_config_data[UPLCOM_N_TRANSFER] = {
  213         [UPLCOM_BULK_DT_WR] = {
  214                 .type = UE_BULK,
  215                 .endpoint = UE_ADDR_ANY,
  216                 .direction = UE_DIR_OUT,
  217                 .bufsize = UPLCOM_BULK_BUF_SIZE,
  218                 .flags = {.pipe_bof = 1,.force_short_xfer = 1,},
  219                 .callback = &uplcom_write_callback,
  220                 .if_index = 0,
  221         },
  222 
  223         [UPLCOM_BULK_DT_RD] = {
  224                 .type = UE_BULK,
  225                 .endpoint = UE_ADDR_ANY,
  226                 .direction = UE_DIR_IN,
  227                 .bufsize = UPLCOM_BULK_BUF_SIZE,
  228                 .flags = {.pipe_bof = 1,.short_xfer_ok = 1,},
  229                 .callback = &uplcom_read_callback,
  230                 .if_index = 0,
  231         },
  232 
  233         [UPLCOM_INTR_DT_RD] = {
  234                 .type = UE_INTERRUPT,
  235                 .endpoint = UE_ADDR_ANY,
  236                 .direction = UE_DIR_IN,
  237                 .flags = {.pipe_bof = 1,.short_xfer_ok = 1,},
  238                 .bufsize = 0,   /* use wMaxPacketSize */
  239                 .callback = &uplcom_intr_callback,
  240                 .if_index = 1,
  241         },
  242 };
  243 
  244 static struct ucom_callback uplcom_callback = {
  245         .ucom_cfg_get_status = &uplcom_cfg_get_status,
  246         .ucom_cfg_set_dtr = &uplcom_cfg_set_dtr,
  247         .ucom_cfg_set_rts = &uplcom_cfg_set_rts,
  248         .ucom_cfg_set_break = &uplcom_cfg_set_break,
  249         .ucom_cfg_param = &uplcom_cfg_param,
  250         .ucom_pre_param = &uplcom_pre_param,
  251         .ucom_start_read = &uplcom_start_read,
  252         .ucom_stop_read = &uplcom_stop_read,
  253         .ucom_start_write = &uplcom_start_write,
  254         .ucom_stop_write = &uplcom_stop_write,
  255         .ucom_poll = &uplcom_poll,
  256         .ucom_free = &uplcom_free,
  257 };
  258 
  259 #define UPLCOM_DEV(v,p)                         \
  260   { USB_VENDOR(USB_VENDOR_##v), USB_PRODUCT(USB_PRODUCT_##v##_##p) }
  261 
  262 static const STRUCT_USB_HOST_ID uplcom_devs[] = {
  263         UPLCOM_DEV(ACERP, S81),                 /* BenQ S81 phone */
  264         UPLCOM_DEV(ADLINK, ND6530),             /* ADLINK ND-6530 USB-Serial */
  265         UPLCOM_DEV(ALCATEL, OT535),             /* Alcatel One Touch 535/735 */
  266         UPLCOM_DEV(ALCOR, AU9720),              /* Alcor AU9720 USB 2.0-RS232 */
  267         UPLCOM_DEV(ANCHOR, SERIAL),             /* Anchor Serial adapter */
  268         UPLCOM_DEV(ATEN, UC232A),               /* PLANEX USB-RS232 URS-03 */
  269         UPLCOM_DEV(ATEN, UC232B),               /* Prolific USB-RS232 Controller D */
  270         UPLCOM_DEV(BELKIN, F5U257),             /* Belkin F5U257 USB to Serial */
  271         UPLCOM_DEV(COREGA, CGUSBRS232R),        /* Corega CG-USBRS232R */
  272         UPLCOM_DEV(EPSON, CRESSI_EDY),          /* Cressi Edy diving computer */
  273         UPLCOM_DEV(EPSON, N2ITION3),            /* Zeagle N2iTion3 diving computer */
  274         UPLCOM_DEV(ELECOM, UCSGT),              /* ELECOM UC-SGT Serial Adapter */
  275         UPLCOM_DEV(ELECOM, UCSGT0),             /* ELECOM UC-SGT Serial Adapter */
  276         UPLCOM_DEV(HAL, IMR001),                /* HAL Corporation Crossam2+USB */
  277         UPLCOM_DEV(HP, LD220),                  /* HP LD220 POS Display */
  278         UPLCOM_DEV(IODATA, USBRSAQ),            /* I/O DATA USB-RSAQ */
  279         UPLCOM_DEV(IODATA, USBRSAQ5),           /* I/O DATA USB-RSAQ5 */
  280         UPLCOM_DEV(ITEGNO, WM1080A),            /* iTegno WM1080A GSM/GFPRS modem */
  281         UPLCOM_DEV(ITEGNO, WM2080A),            /* iTegno WM2080A CDMA modem */
  282         UPLCOM_DEV(LEADTEK, 9531),              /* Leadtek 9531 GPS */
  283         UPLCOM_DEV(MICROSOFT, 700WX),           /* Microsoft Palm 700WX */
  284         UPLCOM_DEV(MOBILEACTION, MA620),        /* Mobile Action MA-620 Infrared Adapter */
  285         UPLCOM_DEV(NETINDEX, WS002IN),          /* Willcom W-S002IN */
  286         UPLCOM_DEV(NOKIA2, CA42),               /* Nokia CA-42 cable */
  287         UPLCOM_DEV(OTI, DKU5),                  /* OTI DKU-5 cable */
  288         UPLCOM_DEV(PANASONIC, TYTP50P6S),       /* Panasonic TY-TP50P6-S flat screen */
  289         UPLCOM_DEV(PLX, CA42),                  /* PLX CA-42 clone cable */
  290         UPLCOM_DEV(PROLIFIC, ALLTRONIX_GPRS),   /* Alltronix ACM003U00 modem */
  291         UPLCOM_DEV(PROLIFIC, ALDIGA_AL11U),     /* AlDiga AL-11U modem */
  292         UPLCOM_DEV(PROLIFIC, DCU11),            /* DCU-11 Phone Cable */
  293         UPLCOM_DEV(PROLIFIC, HCR331),           /* HCR331 Card Reader */
  294         UPLCOM_DEV(PROLIFIC, MICROMAX_610U),    /* Micromax 610U modem */
  295         UPLCOM_DEV(PROLIFIC, MOTOROLA),         /* Motorola cable */
  296         UPLCOM_DEV(PROLIFIC, PHAROS),           /* Prolific Pharos */
  297         UPLCOM_DEV(PROLIFIC, PL2303),           /* Generic adapter */
  298         UPLCOM_DEV(PROLIFIC, PL2303GC),         /* Generic adapter (PL2303HXN, type GC) */
  299         UPLCOM_DEV(PROLIFIC, PL2303GB),         /* Generic adapter (PL2303HXN, type GB) */
  300         UPLCOM_DEV(PROLIFIC, PL2303GT),         /* Generic adapter (PL2303HXN, type GT) */
  301         UPLCOM_DEV(PROLIFIC, PL2303GL),         /* Generic adapter (PL2303HXN, type GL) */
  302         UPLCOM_DEV(PROLIFIC, PL2303GE),         /* Generic adapter (PL2303HXN, type GE) */
  303         UPLCOM_DEV(PROLIFIC, PL2303GS),         /* Generic adapter (PL2303HXN, type GS) */
  304         UPLCOM_DEV(PROLIFIC, RSAQ2),            /* I/O DATA USB-RSAQ2 */
  305         UPLCOM_DEV(PROLIFIC, RSAQ3),            /* I/O DATA USB-RSAQ3 */
  306         UPLCOM_DEV(PROLIFIC, UIC_MSR206),       /* UIC MSR206 Card Reader */
  307         UPLCOM_DEV(PROLIFIC2, PL2303),          /* Prolific adapter */
  308         UPLCOM_DEV(RADIOSHACK, USBCABLE),       /* Radio Shack USB Adapter */
  309         UPLCOM_DEV(RATOC, REXUSB60),            /* RATOC REX-USB60 */
  310         UPLCOM_DEV(SAGEM, USBSERIAL),           /* Sagem USB-Serial Controller */
  311         UPLCOM_DEV(SAMSUNG, I330),              /* Samsung I330 phone cradle */
  312         UPLCOM_DEV(SANWA, KB_USB2),             /* Sanwa KB-USB2 Multimeter cable */
  313         UPLCOM_DEV(SIEMENS3, EF81),             /* Siemens EF81 */
  314         UPLCOM_DEV(SIEMENS3, SX1),              /* Siemens SX1 */
  315         UPLCOM_DEV(SIEMENS3, X65),              /* Siemens X65 */
  316         UPLCOM_DEV(SIEMENS3, X75),              /* Siemens X75 */
  317         UPLCOM_DEV(SITECOM, SERIAL),            /* Sitecom USB to Serial */
  318         UPLCOM_DEV(SMART, PL2303),              /* SMART Technologies USB to Serial */
  319         UPLCOM_DEV(SONY, QN3),                  /* Sony QN3 phone cable */
  320         UPLCOM_DEV(SONYERICSSON, DATAPILOT),    /* Sony Ericsson Datapilot */
  321         UPLCOM_DEV(SONYERICSSON, DCU10),        /* Sony Ericsson DCU-10 Cable */
  322         UPLCOM_DEV(SOURCENEXT, KEIKAI8),        /* SOURCENEXT KeikaiDenwa 8 */
  323         UPLCOM_DEV(SOURCENEXT, KEIKAI8_CHG),    /* SOURCENEXT KeikaiDenwa 8 with charger */
  324         UPLCOM_DEV(SPEEDDRAGON, MS3303H),       /* Speed Dragon USB-Serial */
  325         UPLCOM_DEV(SYNTECH, CPT8001C),          /* Syntech CPT-8001C Barcode scanner */
  326         UPLCOM_DEV(TDK, UHA6400),               /* TDK USB-PHS Adapter UHA6400 */
  327         UPLCOM_DEV(TDK, UPA9664),               /* TDK USB-PHS Adapter UPA9664 */
  328         UPLCOM_DEV(TRIPPLITE, U209),            /* Tripp-Lite U209-000-R USB to Serial */
  329         UPLCOM_DEV(YCCABLE, PL2303),            /* YC Cable USB-Serial */
  330 };
  331 #undef UPLCOM_DEV
  332 
  333 static device_method_t uplcom_methods[] = {
  334         DEVMETHOD(device_probe, uplcom_probe),
  335         DEVMETHOD(device_attach, uplcom_attach),
  336         DEVMETHOD(device_detach, uplcom_detach),
  337         DEVMETHOD_END
  338 };
  339 
  340 static driver_t uplcom_driver = {
  341         .name = "uplcom",
  342         .methods = uplcom_methods,
  343         .size = sizeof(struct uplcom_softc),
  344 };
  345 
  346 DRIVER_MODULE(uplcom, uhub, uplcom_driver, NULL, NULL);
  347 MODULE_DEPEND(uplcom, ucom, 1, 1, 1);
  348 MODULE_DEPEND(uplcom, usb, 1, 1, 1);
  349 MODULE_VERSION(uplcom, UPLCOM_MODVER);
  350 USB_PNP_HOST_INFO(uplcom_devs);
  351 
  352 static int
  353 uplcom_probe(device_t dev)
  354 {
  355         struct usb_attach_arg *uaa = device_get_ivars(dev);
  356 
  357         DPRINTFN(11, "\n");
  358 
  359         if (uaa->usb_mode != USB_MODE_HOST) {
  360                 return (ENXIO);
  361         }
  362         if (uaa->info.bConfigIndex != UPLCOM_CONFIG_INDEX) {
  363                 return (ENXIO);
  364         }
  365         if (uaa->info.bIfaceIndex != UPLCOM_IFACE_INDEX) {
  366                 return (ENXIO);
  367         }
  368         return (usbd_lookup_id_by_uaa(uplcom_devs, sizeof(uplcom_devs), uaa));
  369 }
  370 
  371 static int
  372 uplcom_attach(device_t dev)
  373 {
  374         struct usb_attach_arg *uaa = device_get_ivars(dev);
  375         struct uplcom_softc *sc = device_get_softc(dev);
  376         struct usb_interface *iface;
  377         struct usb_interface_descriptor *id;
  378         struct usb_device_descriptor *dd;
  379         int error;
  380 
  381         struct usb_device_request req;
  382         usb_error_t err;
  383         uint8_t buf[4];
  384 
  385         DPRINTFN(11, "\n");
  386 
  387         device_set_usb_desc(dev);
  388         mtx_init(&sc->sc_mtx, "uplcom", NULL, MTX_DEF);
  389         ucom_ref(&sc->sc_super_ucom);
  390 
  391         DPRINTF("sc = %p\n", sc);
  392 
  393         sc->sc_udev = uaa->device;
  394 
  395         dd = usbd_get_device_descriptor(sc->sc_udev);
  396 
  397         switch (UGETW(dd->bcdDevice)) {
  398         case 0x0300:
  399                 sc->sc_chiptype = TYPE_PL2303HX;
  400                 /* or TA, that is HX with external crystal */
  401                 break;
  402         case 0x0400:
  403                 sc->sc_chiptype = TYPE_PL2303HXD;
  404                 /* or EA, that is HXD with ESD protection */
  405                 /* or RA, that has internal voltage level converter that works only up to 1Mbaud (!) */
  406                 break;
  407         case 0x0500:
  408                 sc->sc_chiptype = TYPE_PL2303HXD;
  409                 /* in fact it's TB, that is HXD with external crystal */
  410                 break;
  411         default:
  412                 /* NOTE: I have no info about the bcdDevice for the base PL2303 (up to 1.2Mbaud,
  413                    only fixed rates) and for PL2303SA (8-pin chip, up to 115200 baud */
  414                 /* Determine the chip type.  This algorithm is taken from Linux. */
  415                 if (dd->bDeviceClass == 0x02)
  416                         sc->sc_chiptype = TYPE_PL2303;
  417                 else if (dd->bMaxPacketSize == 0x40)
  418                         sc->sc_chiptype = TYPE_PL2303HX;
  419                 else
  420                         sc->sc_chiptype = TYPE_PL2303;
  421                 break;
  422         }
  423 
  424         /*
  425          * The new chip revision PL2303HXN is only compatible with the new
  426          * UPLCOM_SET_REQUEST_PL2303HXN command. Issuing the old command
  427          * UPLCOM_SET_REQUEST to the new chip raises an error. Thus, PL2303HX
  428          * and PL2303HXN can be distinguished by issuing an old-style request
  429          * (on a status register) to the new chip and checking the error.
  430          */
  431         if (sc->sc_chiptype == TYPE_PL2303HX) {
  432                 req.bmRequestType = UT_READ_VENDOR_DEVICE;
  433                 req.bRequest = UPLCOM_SET_REQUEST;
  434                 USETW(req.wValue, UPLCOM_STATUS_REG_PL2303HX);
  435                 req.wIndex[0] = sc->sc_data_iface_no;
  436                 req.wIndex[1] = 0;
  437                 USETW(req.wLength, 1);
  438                 err = usbd_do_request(sc->sc_udev, NULL, &req, buf);
  439                 if (err)
  440                         sc->sc_chiptype = TYPE_PL2303HXN;
  441         }
  442 
  443         switch (sc->sc_chiptype) {
  444         case TYPE_PL2303:
  445                 DPRINTF("chiptype: 2303\n");
  446                 break;
  447         case TYPE_PL2303HX:
  448                 DPRINTF("chiptype: 2303HX/TA\n");
  449                 break;
  450         case TYPE_PL2303HXN:
  451                 DPRINTF("chiptype: 2303HXN\n");
  452                 break;
  453         case TYPE_PL2303HXD:
  454                 DPRINTF("chiptype: 2303HXD/TB/RA/EA\n");
  455                 break;
  456         default:
  457                 DPRINTF("chiptype: unknown %d\n", sc->sc_chiptype);
  458                 break;
  459         }
  460 
  461         /*
  462          * USB-RSAQ1 has two interface
  463          *
  464          *  USB-RSAQ1       | USB-RSAQ2
  465          * -----------------+-----------------
  466          * Interface 0      |Interface 0
  467          *  Interrupt(0x81) | Interrupt(0x81)
  468          * -----------------+ BulkIN(0x02)
  469          * Interface 1      | BulkOUT(0x83)
  470          *   BulkIN(0x02)   |
  471          *   BulkOUT(0x83)  |
  472          */
  473 
  474         sc->sc_ctrl_iface_no = uaa->info.bIfaceNum;
  475         sc->sc_iface_index[1] = UPLCOM_IFACE_INDEX;
  476 
  477         iface = usbd_get_iface(uaa->device, UPLCOM_SECOND_IFACE_INDEX);
  478         if (iface) {
  479                 id = usbd_get_interface_descriptor(iface);
  480                 if (id == NULL) {
  481                         device_printf(dev, "no interface descriptor (2)\n");
  482                         goto detach;
  483                 }
  484                 sc->sc_data_iface_no = id->bInterfaceNumber;
  485                 sc->sc_iface_index[0] = UPLCOM_SECOND_IFACE_INDEX;
  486                 usbd_set_parent_iface(uaa->device,
  487                     UPLCOM_SECOND_IFACE_INDEX, uaa->info.bIfaceIndex);
  488         } else {
  489                 sc->sc_data_iface_no = sc->sc_ctrl_iface_no;
  490                 sc->sc_iface_index[0] = UPLCOM_IFACE_INDEX;
  491         }
  492 
  493         error = usbd_transfer_setup(uaa->device,
  494             sc->sc_iface_index, sc->sc_xfer, uplcom_config_data,
  495             UPLCOM_N_TRANSFER, sc, &sc->sc_mtx);
  496         if (error) {
  497                 DPRINTF("one or more missing USB endpoints, "
  498                     "error=%s\n", usbd_errstr(error));
  499                 goto detach;
  500         }
  501         error = uplcom_reset(sc, uaa->device);
  502         if (error) {
  503                 device_printf(dev, "reset failed, error=%s\n",
  504                     usbd_errstr(error));
  505                 goto detach;
  506         }
  507 
  508         if (sc->sc_chiptype == TYPE_PL2303) {
  509                 /* HX variants seem to lock up after a clear stall request. */
  510                 mtx_lock(&sc->sc_mtx);
  511                 usbd_xfer_set_stall(sc->sc_xfer[UPLCOM_BULK_DT_WR]);
  512                 usbd_xfer_set_stall(sc->sc_xfer[UPLCOM_BULK_DT_RD]);
  513                 mtx_unlock(&sc->sc_mtx);
  514         } else if (sc->sc_chiptype == TYPE_PL2303HX ||
  515                    sc->sc_chiptype == TYPE_PL2303HXD) {
  516                 /* reset upstream data pipes */
  517                 if (uplcom_pl2303_do(sc->sc_udev, UT_WRITE_VENDOR_DEVICE,
  518                     UPLCOM_SET_REQUEST, 8, 0, 0) ||
  519                     uplcom_pl2303_do(sc->sc_udev, UT_WRITE_VENDOR_DEVICE,
  520                     UPLCOM_SET_REQUEST, 9, 0, 0)) {
  521                         goto detach;
  522                 }
  523         } else if (sc->sc_chiptype == TYPE_PL2303HXN) {
  524                 /* reset upstream data pipes */
  525                 if (uplcom_pl2303_do(sc->sc_udev, UT_WRITE_VENDOR_DEVICE,
  526                     UPLCOM_SET_REQUEST_PL2303HXN, 0x07, 0x03, 0)) {
  527                         goto detach;
  528                 }
  529         }
  530 
  531         error = ucom_attach(&sc->sc_super_ucom, &sc->sc_ucom, 1, sc,
  532             &uplcom_callback, &sc->sc_mtx);
  533         if (error) {
  534                 goto detach;
  535         }
  536         /*
  537          * do the initialization during attach so that the system does not
  538          * sleep during open:
  539          */
  540         if (uplcom_pl2303_init(uaa->device, sc->sc_chiptype)) {
  541                 device_printf(dev, "init failed\n");
  542                 goto detach;
  543         }
  544         ucom_set_pnpinfo_usb(&sc->sc_super_ucom, dev);
  545 
  546         return (0);
  547 
  548 detach:
  549         uplcom_detach(dev);
  550         return (ENXIO);
  551 }
  552 
  553 static int
  554 uplcom_detach(device_t dev)
  555 {
  556         struct uplcom_softc *sc = device_get_softc(dev);
  557 
  558         DPRINTF("sc=%p\n", sc);
  559 
  560         ucom_detach(&sc->sc_super_ucom, &sc->sc_ucom);
  561         usbd_transfer_unsetup(sc->sc_xfer, UPLCOM_N_TRANSFER);
  562 
  563         device_claim_softc(dev);
  564 
  565         uplcom_free_softc(sc);
  566 
  567         return (0);
  568 }
  569 
  570 UCOM_UNLOAD_DRAIN(uplcom);
  571 
  572 static void
  573 uplcom_free_softc(struct uplcom_softc *sc)
  574 {
  575         if (ucom_unref(&sc->sc_super_ucom)) {
  576                 mtx_destroy(&sc->sc_mtx);
  577                 device_free_softc(sc);
  578         }
  579 }
  580 
  581 static void
  582 uplcom_free(struct ucom_softc *ucom)
  583 {
  584         uplcom_free_softc(ucom->sc_parent);
  585 }
  586 
  587 static usb_error_t
  588 uplcom_reset(struct uplcom_softc *sc, struct usb_device *udev)
  589 {
  590         struct usb_device_request req;
  591 
  592         if (sc->sc_chiptype == TYPE_PL2303HXN) {
  593                 /* PL2303HXN doesn't need this reset sequence */
  594                 return (0);
  595         }
  596 
  597         req.bmRequestType = UT_WRITE_VENDOR_DEVICE;
  598         req.bRequest = UPLCOM_SET_REQUEST;
  599         USETW(req.wValue, 0);
  600         req.wIndex[0] = sc->sc_data_iface_no;
  601         req.wIndex[1] = 0;
  602         USETW(req.wLength, 0);
  603 
  604         return (usbd_do_request(udev, NULL, &req, NULL));
  605 }
  606 
  607 static usb_error_t
  608 uplcom_pl2303_do(struct usb_device *udev, uint8_t req_type, uint8_t request,
  609     uint16_t value, uint16_t index, uint16_t length)
  610 {
  611         struct usb_device_request req;
  612         usb_error_t err;
  613         uint8_t buf[4];
  614 
  615         req.bmRequestType = req_type;
  616         req.bRequest = request;
  617         USETW(req.wValue, value);
  618         USETW(req.wIndex, index);
  619         USETW(req.wLength, length);
  620 
  621         err = usbd_do_request(udev, NULL, &req, buf);
  622         if (err) {
  623                 DPRINTF("error=%s\n", usbd_errstr(err));
  624                 return (1);
  625         }
  626         return (0);
  627 }
  628 
  629 static int
  630 uplcom_pl2303_init(struct usb_device *udev, uint8_t chiptype)
  631 {
  632         int err;
  633 
  634         if (chiptype == TYPE_PL2303HXN) {
  635                 /* PL2303HXN doesn't need this initialization sequence */
  636                 return (0);
  637         }
  638 
  639         if (uplcom_pl2303_do(udev, UT_READ_VENDOR_DEVICE, UPLCOM_SET_REQUEST, 0x8484, 0, 1)
  640             || uplcom_pl2303_do(udev, UT_WRITE_VENDOR_DEVICE, UPLCOM_SET_REQUEST, 0x0404, 0, 0)
  641             || uplcom_pl2303_do(udev, UT_READ_VENDOR_DEVICE, UPLCOM_SET_REQUEST, 0x8484, 0, 1)
  642             || uplcom_pl2303_do(udev, UT_READ_VENDOR_DEVICE, UPLCOM_SET_REQUEST, 0x8383, 0, 1)
  643             || uplcom_pl2303_do(udev, UT_READ_VENDOR_DEVICE, UPLCOM_SET_REQUEST, 0x8484, 0, 1)
  644             || uplcom_pl2303_do(udev, UT_WRITE_VENDOR_DEVICE, UPLCOM_SET_REQUEST, 0x0404, 1, 0)
  645             || uplcom_pl2303_do(udev, UT_READ_VENDOR_DEVICE, UPLCOM_SET_REQUEST, 0x8484, 0, 1)
  646             || uplcom_pl2303_do(udev, UT_READ_VENDOR_DEVICE, UPLCOM_SET_REQUEST, 0x8383, 0, 1)
  647             || uplcom_pl2303_do(udev, UT_WRITE_VENDOR_DEVICE, UPLCOM_SET_REQUEST, 0, 1, 0)
  648             || uplcom_pl2303_do(udev, UT_WRITE_VENDOR_DEVICE, UPLCOM_SET_REQUEST, 1, 0, 0))
  649                 return (EIO);
  650 
  651         if (chiptype != TYPE_PL2303)
  652                 err = uplcom_pl2303_do(udev, UT_WRITE_VENDOR_DEVICE, UPLCOM_SET_REQUEST, 2, 0x44, 0);
  653         else
  654                 err = uplcom_pl2303_do(udev, UT_WRITE_VENDOR_DEVICE, UPLCOM_SET_REQUEST, 2, 0x24, 0);
  655         if (err)
  656                 return (EIO);
  657 
  658         return (0);
  659 }
  660 
  661 static void
  662 uplcom_cfg_set_dtr(struct ucom_softc *ucom, uint8_t onoff)
  663 {
  664         struct uplcom_softc *sc = ucom->sc_parent;
  665         struct usb_device_request req;
  666 
  667         DPRINTF("onoff = %d\n", onoff);
  668 
  669         if (onoff)
  670                 sc->sc_line |= UCDC_LINE_DTR;
  671         else
  672                 sc->sc_line &= ~UCDC_LINE_DTR;
  673 
  674         req.bmRequestType = UT_WRITE_CLASS_INTERFACE;
  675         req.bRequest = UCDC_SET_CONTROL_LINE_STATE;
  676         USETW(req.wValue, sc->sc_line);
  677         req.wIndex[0] = sc->sc_data_iface_no;
  678         req.wIndex[1] = 0;
  679         USETW(req.wLength, 0);
  680 
  681         ucom_cfg_do_request(sc->sc_udev, &sc->sc_ucom, 
  682             &req, NULL, 0, 1000);
  683 }
  684 
  685 static void
  686 uplcom_cfg_set_rts(struct ucom_softc *ucom, uint8_t onoff)
  687 {
  688         struct uplcom_softc *sc = ucom->sc_parent;
  689         struct usb_device_request req;
  690 
  691         DPRINTF("onoff = %d\n", onoff);
  692 
  693         if (onoff)
  694                 sc->sc_line |= UCDC_LINE_RTS;
  695         else
  696                 sc->sc_line &= ~UCDC_LINE_RTS;
  697 
  698         req.bmRequestType = UT_WRITE_CLASS_INTERFACE;
  699         req.bRequest = UCDC_SET_CONTROL_LINE_STATE;
  700         USETW(req.wValue, sc->sc_line);
  701         req.wIndex[0] = sc->sc_data_iface_no;
  702         req.wIndex[1] = 0;
  703         USETW(req.wLength, 0);
  704 
  705         ucom_cfg_do_request(sc->sc_udev, &sc->sc_ucom, 
  706             &req, NULL, 0, 1000);
  707 }
  708 
  709 static void
  710 uplcom_cfg_set_break(struct ucom_softc *ucom, uint8_t onoff)
  711 {
  712         struct uplcom_softc *sc = ucom->sc_parent;
  713         struct usb_device_request req;
  714         uint16_t temp;
  715 
  716         DPRINTF("onoff = %d\n", onoff);
  717 
  718         temp = (onoff ? UCDC_BREAK_ON : UCDC_BREAK_OFF);
  719 
  720         req.bmRequestType = UT_WRITE_CLASS_INTERFACE;
  721         req.bRequest = UCDC_SEND_BREAK;
  722         USETW(req.wValue, temp);
  723         req.wIndex[0] = sc->sc_data_iface_no;
  724         req.wIndex[1] = 0;
  725         USETW(req.wLength, 0);
  726 
  727         ucom_cfg_do_request(sc->sc_udev, &sc->sc_ucom, 
  728             &req, NULL, 0, 1000);
  729 }
  730 
  731 /*
  732  * NOTE: These baud rates are officially supported, they can be written
  733  * directly into dwDTERate register.
  734  *
  735  * Free baudrate setting is not supported by the base PL2303, and on
  736  * other models it requires writing a divisor value to dwDTERate instead
  737  * of the raw baudrate. The formula for divisor calculation is not published
  738  * by the vendor, so it is speculative, though the official product homepage
  739  * refers to the Linux module source as a reference implementation.
  740  */
  741 static const uint32_t uplcom_rates[] = {
  742         /*
  743          * Basic 'standard' speed rates, supported by all models
  744          * NOTE: 900 and 56000 actually works as well
  745          */
  746         75, 150, 300, 600, 900, 1200, 1800, 2400, 3600, 4800, 7200, 9600, 14400,
  747         19200, 28800, 38400, 56000, 57600, 115200,
  748         /*
  749          * Advanced speed rates up to 6Mbs, supported by HX/TA and HXD/TB/EA/RA
  750      * NOTE: regardless of the spec, 256000 does not work
  751          */
  752         128000, 134400, 161280, 201600, 230400, 268800, 403200, 460800, 614400,
  753         806400, 921600, 1228800, 2457600, 3000000, 6000000,
  754         /*
  755          * Advanced speed rates up to 12, supported by HXD/TB/EA/RA
  756          */
  757         12000000
  758 };
  759 
  760 #define N_UPLCOM_RATES  nitems(uplcom_rates)
  761 
  762 static int
  763 uplcom_baud_supported(unsigned speed)
  764 {
  765         int i;
  766         for (i = 0; i < N_UPLCOM_RATES; i++) {
  767                 if (uplcom_rates[i] == speed)
  768                         return 1;
  769         }
  770         return 0;
  771 }
  772 
  773 static int
  774 uplcom_pre_param(struct ucom_softc *ucom, struct termios *t)
  775 {
  776         struct uplcom_softc *sc = ucom->sc_parent;
  777 
  778         DPRINTF("\n");
  779 
  780         /**
  781          * Check requested baud rate.
  782          *
  783          * The PL2303 can only set specific baud rates, up to 1228800 baud.
  784          * The PL2303HX can set any baud rate up to 6Mb.
  785          * The PL2303HX rev. D and PL2303HXN can set any baud rate up to 12Mb.
  786          *
  787          */
  788 
  789         /* accept raw divisor data, if someone wants to do the math in user domain */
  790         if (t->c_ospeed & 0x80000000)
  791                 return 0;
  792         switch (sc->sc_chiptype) {
  793                 case TYPE_PL2303HXN:
  794                         if (t->c_ospeed <= 12000000)
  795                                 return (0);
  796                         break;
  797                 case TYPE_PL2303HXD:
  798                         if (t->c_ospeed <= 12000000)
  799                                 return (0);
  800                         break;
  801                 case TYPE_PL2303HX:
  802                         if (t->c_ospeed <= 6000000)
  803                                 return (0);
  804                         break;
  805                 default:
  806                         if (uplcom_baud_supported(t->c_ospeed))
  807                                 return (0);
  808                         break;
  809         }
  810 
  811         DPRINTF("uplcom_param: bad baud rate (%d)\n", t->c_ospeed);
  812         return (EIO);
  813 }
  814 
  815 static unsigned
  816 uplcom_encode_baud_rate_divisor(uint8_t *buf, unsigned baud)
  817 {
  818         unsigned baseline, mantissa, exponent;
  819 
  820         /* Determine the baud rate divisor. This algorithm is taken from Linux. */
  821         /*
  822          * Apparently the formula is:
  823          *   baudrate = baseline / (mantissa * 4^exponent)
  824          * where
  825          *   mantissa = buf[8:0]
  826          *   exponent = buf[11:9]
  827          */
  828         if (baud == 0)
  829                 baud = 1;
  830         baseline = 383385600;
  831         mantissa = baseline / baud;
  832         if (mantissa == 0)
  833                 mantissa = 1;
  834         exponent = 0;
  835         while (mantissa >= 512) {
  836                 if (exponent < 7) {
  837                         mantissa >>= 2; /* divide by 4 */
  838                         exponent++;
  839                 } else {
  840                         /* Exponent is maxed. Trim mantissa and leave. This gives approx. 45.8 baud */
  841                         mantissa = 511;
  842                         break;
  843                 }
  844         }
  845 
  846         buf[3] = 0x80;
  847         buf[2] = 0;
  848         buf[1] = exponent << 1 | mantissa >> 8;
  849         buf[0] = mantissa & 0xff;
  850 
  851         /* Calculate and return the exact baud rate. */
  852         baud = (baseline / mantissa) >> (exponent << 1);
  853         DPRINTF("real baud rate will be %u\n", baud);
  854 
  855         return baud;
  856 }
  857 static void
  858 uplcom_cfg_param(struct ucom_softc *ucom, struct termios *t)
  859 {
  860         struct uplcom_softc *sc = ucom->sc_parent;
  861         struct usb_cdc_line_state ls;
  862         struct usb_device_request req;
  863 
  864         DPRINTF("sc = %p\n", sc);
  865 
  866         memset(&ls, 0, sizeof(ls));
  867 
  868         /*
  869          * NOTE: If unsupported baud rates are set directly, the PL2303* uses 9600 baud.
  870          */
  871         if ((t->c_ospeed & 0x80000000) || uplcom_baud_supported(t->c_ospeed))
  872                 USETDW(ls.dwDTERate, t->c_ospeed);
  873         else
  874                 t->c_ospeed = uplcom_encode_baud_rate_divisor((uint8_t*)&ls.dwDTERate, t->c_ospeed);
  875 
  876         if (t->c_cflag & CSTOPB) {
  877                 if ((t->c_cflag & CSIZE) == CS5) {
  878                         /*
  879                          * NOTE: Comply with "real" UARTs / RS232:
  880                          *       use 1.5 instead of 2 stop bits with 5 data bits
  881                          */
  882                         ls.bCharFormat = UCDC_STOP_BIT_1_5;
  883                 } else {
  884                         ls.bCharFormat = UCDC_STOP_BIT_2;
  885                 }
  886         } else {
  887                 ls.bCharFormat = UCDC_STOP_BIT_1;
  888         }
  889 
  890         if (t->c_cflag & PARENB) {
  891                 if (t->c_cflag & PARODD) {
  892                         ls.bParityType = UCDC_PARITY_ODD;
  893                 } else {
  894                         ls.bParityType = UCDC_PARITY_EVEN;
  895                 }
  896         } else {
  897                 ls.bParityType = UCDC_PARITY_NONE;
  898         }
  899 
  900         switch (t->c_cflag & CSIZE) {
  901         case CS5:
  902                 ls.bDataBits = 5;
  903                 break;
  904         case CS6:
  905                 ls.bDataBits = 6;
  906                 break;
  907         case CS7:
  908                 ls.bDataBits = 7;
  909                 break;
  910         case CS8:
  911                 ls.bDataBits = 8;
  912                 break;
  913         }
  914 
  915         DPRINTF("rate=0x%08x fmt=%d parity=%d bits=%d\n",
  916             UGETDW(ls.dwDTERate), ls.bCharFormat,
  917             ls.bParityType, ls.bDataBits);
  918 
  919         req.bmRequestType = UT_WRITE_CLASS_INTERFACE;
  920         req.bRequest = UCDC_SET_LINE_CODING;
  921         USETW(req.wValue, 0);
  922         req.wIndex[0] = sc->sc_data_iface_no;
  923         req.wIndex[1] = 0;
  924         USETW(req.wLength, UCDC_LINE_STATE_LENGTH);
  925 
  926         ucom_cfg_do_request(sc->sc_udev, &sc->sc_ucom, 
  927             &req, &ls, 0, 1000);
  928 
  929         if (t->c_cflag & CRTSCTS) {
  930                 DPRINTF("crtscts = on\n");
  931 
  932                 req.bmRequestType = UT_WRITE_VENDOR_DEVICE;
  933                 if (sc->sc_chiptype == TYPE_PL2303HXN) {
  934                         req.bRequest = UPLCOM_SET_REQUEST_PL2303HXN;
  935                         USETW(req.wValue, UPLCOM_CRTSCTS_REG_PL2303HXN);
  936                         USETW(req.wIndex, UPLCOM_SET_CRTSCTS_PL2303HXN);
  937                 } else {
  938                         req.bRequest = UPLCOM_SET_REQUEST;
  939                         USETW(req.wValue, 0);
  940                         if (sc->sc_chiptype != TYPE_PL2303)
  941                                 USETW(req.wIndex, UPLCOM_SET_CRTSCTS_PL2303X);
  942                         else
  943                                 USETW(req.wIndex, UPLCOM_SET_CRTSCTS);
  944                 }
  945                 USETW(req.wLength, 0);
  946 
  947                 ucom_cfg_do_request(sc->sc_udev, &sc->sc_ucom, 
  948                     &req, NULL, 0, 1000);
  949         } else {
  950                 req.bmRequestType = UT_WRITE_VENDOR_DEVICE;
  951                 if (sc->sc_chiptype == TYPE_PL2303HXN) {
  952                         req.bRequest = UPLCOM_SET_REQUEST_PL2303HXN;
  953                         USETW(req.wValue, UPLCOM_CRTSCTS_REG_PL2303HXN);
  954                         USETW(req.wIndex, UPLCOM_CLEAR_CRTSCTS_PL2303HXN);
  955                 }
  956                 else {
  957                         req.bRequest = UPLCOM_SET_REQUEST;
  958                         USETW(req.wValue, 0);
  959                         USETW(req.wIndex, 0);
  960                 }
  961                 USETW(req.wLength, 0);
  962                 ucom_cfg_do_request(sc->sc_udev, &sc->sc_ucom, 
  963                     &req, NULL, 0, 1000);
  964         }
  965 }
  966 
  967 static void
  968 uplcom_start_read(struct ucom_softc *ucom)
  969 {
  970         struct uplcom_softc *sc = ucom->sc_parent;
  971 
  972         /* start interrupt endpoint */
  973         usbd_transfer_start(sc->sc_xfer[UPLCOM_INTR_DT_RD]);
  974 
  975         /* start read endpoint */
  976         usbd_transfer_start(sc->sc_xfer[UPLCOM_BULK_DT_RD]);
  977 }
  978 
  979 static void
  980 uplcom_stop_read(struct ucom_softc *ucom)
  981 {
  982         struct uplcom_softc *sc = ucom->sc_parent;
  983 
  984         /* stop interrupt endpoint */
  985         usbd_transfer_stop(sc->sc_xfer[UPLCOM_INTR_DT_RD]);
  986 
  987         /* stop read endpoint */
  988         usbd_transfer_stop(sc->sc_xfer[UPLCOM_BULK_DT_RD]);
  989 }
  990 
  991 static void
  992 uplcom_start_write(struct ucom_softc *ucom)
  993 {
  994         struct uplcom_softc *sc = ucom->sc_parent;
  995 
  996         usbd_transfer_start(sc->sc_xfer[UPLCOM_BULK_DT_WR]);
  997 }
  998 
  999 static void
 1000 uplcom_stop_write(struct ucom_softc *ucom)
 1001 {
 1002         struct uplcom_softc *sc = ucom->sc_parent;
 1003 
 1004         usbd_transfer_stop(sc->sc_xfer[UPLCOM_BULK_DT_WR]);
 1005 }
 1006 
 1007 static void
 1008 uplcom_cfg_get_status(struct ucom_softc *ucom, uint8_t *lsr, uint8_t *msr)
 1009 {
 1010         struct uplcom_softc *sc = ucom->sc_parent;
 1011 
 1012         DPRINTF("\n");
 1013 
 1014         *lsr = sc->sc_lsr;
 1015         *msr = sc->sc_msr;
 1016 }
 1017 
 1018 static void
 1019 uplcom_intr_callback(struct usb_xfer *xfer, usb_error_t error)
 1020 {
 1021         struct uplcom_softc *sc = usbd_xfer_softc(xfer);
 1022         struct usb_page_cache *pc;
 1023         uint8_t buf[9];
 1024         int actlen;
 1025 
 1026         usbd_xfer_status(xfer, &actlen, NULL, NULL, NULL);
 1027 
 1028         switch (USB_GET_STATE(xfer)) {
 1029         case USB_ST_TRANSFERRED:
 1030 
 1031                 DPRINTF("actlen = %u\n", actlen);
 1032 
 1033                 if (actlen >= 9) {
 1034                         pc = usbd_xfer_get_frame(xfer, 0);
 1035                         usbd_copy_out(pc, 0, buf, sizeof(buf));
 1036 
 1037                         DPRINTF("status = 0x%02x\n", buf[UPLCOM_STATE_INDEX]);
 1038 
 1039                         sc->sc_lsr = 0;
 1040                         sc->sc_msr = 0;
 1041 
 1042                         if (buf[UPLCOM_STATE_INDEX] & RSAQ_STATUS_CTS) {
 1043                                 sc->sc_msr |= SER_CTS;
 1044                         }
 1045                         if (buf[UPLCOM_STATE_INDEX] & RSAQ_STATUS_OVERRUN_ERROR) {
 1046                                 sc->sc_lsr |= ULSR_OE;
 1047                         }
 1048                         if (buf[UPLCOM_STATE_INDEX] & RSAQ_STATUS_PARITY_ERROR) {
 1049                                 sc->sc_lsr |= ULSR_PE;
 1050                         }
 1051                         if (buf[UPLCOM_STATE_INDEX] & RSAQ_STATUS_FRAME_ERROR) {
 1052                                 sc->sc_lsr |= ULSR_FE;
 1053                         }
 1054                         if (buf[UPLCOM_STATE_INDEX] & RSAQ_STATUS_RING) {
 1055                                 sc->sc_msr |= SER_RI;
 1056                         }
 1057                         if (buf[UPLCOM_STATE_INDEX] & RSAQ_STATUS_BREAK_ERROR) {
 1058                                 sc->sc_lsr |= ULSR_BI;
 1059                         }
 1060                         if (buf[UPLCOM_STATE_INDEX] & RSAQ_STATUS_DSR) {
 1061                                 sc->sc_msr |= SER_DSR;
 1062                         }
 1063                         if (buf[UPLCOM_STATE_INDEX] & RSAQ_STATUS_DCD) {
 1064                                 sc->sc_msr |= SER_DCD;
 1065                         }
 1066                         ucom_status_change(&sc->sc_ucom);
 1067                 }
 1068         case USB_ST_SETUP:
 1069 tr_setup:
 1070                 usbd_xfer_set_frame_len(xfer, 0, usbd_xfer_max_len(xfer));
 1071                 usbd_transfer_submit(xfer);
 1072                 return;
 1073 
 1074         default:                        /* Error */
 1075                 if (error != USB_ERR_CANCELLED) {
 1076                         /* try to clear stall first */
 1077                         usbd_xfer_set_stall(xfer);
 1078                         goto tr_setup;
 1079                 }
 1080                 return;
 1081         }
 1082 }
 1083 
 1084 static void
 1085 uplcom_write_callback(struct usb_xfer *xfer, usb_error_t error)
 1086 {
 1087         struct uplcom_softc *sc = usbd_xfer_softc(xfer);
 1088         struct usb_page_cache *pc;
 1089         uint32_t actlen;
 1090 
 1091         switch (USB_GET_STATE(xfer)) {
 1092         case USB_ST_SETUP:
 1093         case USB_ST_TRANSFERRED:
 1094 tr_setup:
 1095                 pc = usbd_xfer_get_frame(xfer, 0);
 1096                 if (ucom_get_data(&sc->sc_ucom, pc, 0,
 1097                     UPLCOM_BULK_BUF_SIZE, &actlen)) {
 1098                         DPRINTF("actlen = %d\n", actlen);
 1099 
 1100                         usbd_xfer_set_frame_len(xfer, 0, actlen);
 1101                         usbd_transfer_submit(xfer);
 1102                 }
 1103                 return;
 1104 
 1105         default:                        /* Error */
 1106                 if (error != USB_ERR_CANCELLED) {
 1107                         /* try to clear stall first */
 1108                         usbd_xfer_set_stall(xfer);
 1109                         goto tr_setup;
 1110                 }
 1111                 return;
 1112         }
 1113 }
 1114 
 1115 static void
 1116 uplcom_read_callback(struct usb_xfer *xfer, usb_error_t error)
 1117 {
 1118         struct uplcom_softc *sc = usbd_xfer_softc(xfer);
 1119         struct usb_page_cache *pc;
 1120         int actlen;
 1121 
 1122         usbd_xfer_status(xfer, &actlen, NULL, NULL, NULL);
 1123 
 1124         switch (USB_GET_STATE(xfer)) {
 1125         case USB_ST_TRANSFERRED:
 1126                 pc = usbd_xfer_get_frame(xfer, 0);
 1127                 ucom_put_data(&sc->sc_ucom, pc, 0, actlen);
 1128 
 1129         case USB_ST_SETUP:
 1130 tr_setup:
 1131                 usbd_xfer_set_frame_len(xfer, 0, usbd_xfer_max_len(xfer));
 1132                 usbd_transfer_submit(xfer);
 1133                 return;
 1134 
 1135         default:                        /* Error */
 1136                 if (error != USB_ERR_CANCELLED) {
 1137                         /* try to clear stall first */
 1138                         usbd_xfer_set_stall(xfer);
 1139                         goto tr_setup;
 1140                 }
 1141                 return;
 1142         }
 1143 }
 1144 
 1145 static void
 1146 uplcom_poll(struct ucom_softc *ucom)
 1147 {
 1148         struct uplcom_softc *sc = ucom->sc_parent;
 1149         usbd_transfer_poll(sc->sc_xfer, UPLCOM_N_TRANSFER);
 1150 }

Cache object: eb9cda1340e0f880bececf4bd5a697ed


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