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/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 /*-
    4  * Copyright (c) 2001-2003, 2005 Shunsuke Akiyama <akiyama@jp.FreeBSD.org>.
    5  * All rights reserved.
    6  *
    7  * Redistribution and use in source and binary forms, with or without
    8  * modification, are permitted provided that the following conditions
    9  * are met:
   10  * 1. Redistributions of source code must retain the above copyright
   11  *    notice, this list of conditions and the following disclaimer.
   12  * 2. Redistributions in binary form must reproduce the above copyright
   13  *    notice, this list of conditions and the following disclaimer in the
   14  *    documentation and/or other materials provided with the distribution.
   15  *
   16  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
   17  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
   18  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
   19  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
   20  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
   21  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
   22  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
   23  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
   24  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
   25  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   26  * SUCH DAMAGE.
   27  */
   28 
   29 #include <sys/cdefs.h>
   30 __FBSDID("$FreeBSD: releng/7.3/sys/dev/usb/uplcom.c 189659 2009-03-11 01:03:32Z thompsa $");
   31 
   32 /*-
   33  * Copyright (c) 2001 The NetBSD Foundation, Inc.
   34  * All rights reserved.
   35  *
   36  * This code is derived from software contributed to The NetBSD Foundation
   37  * by Ichiro FUKUHARA (ichiro@ichiro.org).
   38  *
   39  * Redistribution and use in source and binary forms, with or without
   40  * modification, are permitted provided that the following conditions
   41  * are met:
   42  * 1. Redistributions of source code must retain the above copyright
   43  *    notice, this list of conditions and the following disclaimer.
   44  * 2. Redistributions in binary form must reproduce the above copyright
   45  *    notice, this list of conditions and the following disclaimer in the
   46  *    documentation and/or other materials provided with the distribution.
   47  * 3. All advertising materials mentioning features or use of this software
   48  *    must display the following acknowledgement:
   49  *        This product includes software developed by the NetBSD
   50  *        Foundation, Inc. and its contributors.
   51  * 4. Neither the name of The NetBSD Foundation nor the names of its
   52  *    contributors may be used to endorse or promote products derived
   53  *    from this software without specific prior written permission.
   54  *
   55  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
   56  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
   57  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
   58  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
   59  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
   60  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
   61  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
   62  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
   63  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
   64  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
   65  * POSSIBILITY OF SUCH DAMAGE.
   66  */
   67 
   68 /*
   69  * This driver supports several USB-to-RS232 serial adapters driven by
   70  * Prolific PL-2303, PL-2303X and probably PL-2303HX USB-to-RS232
   71  * bridge chip.  The adapters are sold under many different brand
   72  * names.
   73  *
   74  * Datasheets are available at Prolific www site at
   75  * http://www.prolific.com.tw.  The datasheets don't contain full
   76  * programming information for the chip.
   77  *
   78  * PL-2303HX is probably programmed the same as PL-2303X.
   79  *
   80  * There are several differences between PL-2303 and PL-2303(H)X.
   81  * PL-2303(H)X can do higher bitrate in bulk mode, has _probably_
   82  * different command for controlling CRTSCTS and needs special
   83  * sequence of commands for initialization which aren't also
   84  * documented in the datasheet.
   85  */
   86 
   87 #include "opt_uplcom.h"
   88 
   89 #include <sys/param.h>
   90 #include <sys/systm.h>
   91 #include <sys/kernel.h>
   92 #include <sys/module.h>
   93 #include <sys/malloc.h>
   94 #include <sys/bus.h>
   95 #include <sys/ioccom.h>
   96 #include <sys/fcntl.h>
   97 #include <sys/conf.h>
   98 #include <sys/serial.h>
   99 #include <sys/tty.h>
  100 #include <sys/file.h>
  101 #include <sys/selinfo.h>
  102 #include <sys/proc.h>
  103 #include <sys/poll.h>
  104 #include <sys/sysctl.h>
  105 #include <sys/uio.h>
  106 #include <sys/taskqueue.h>
  107 
  108 #include <machine/bus.h>
  109 
  110 #include <dev/usb/usb.h>
  111 #include <dev/usb/usbcdc.h>
  112 
  113 #include <dev/usb/usbdi.h>
  114 #include <dev/usb/usbdivar.h>
  115 #include <dev/usb/usbdi_util.h>
  116 #include "usbdevs.h"
  117 #include <dev/usb/usb_quirks.h>
  118 
  119 #include <dev/usb/ucomvar.h>
  120 
  121 SYSCTL_NODE(_hw_usb, OID_AUTO, uplcom, CTLFLAG_RW, 0, "USB uplcom");
  122 #ifdef USB_DEBUG
  123 static int      uplcomdebug = 0;
  124 SYSCTL_INT(_hw_usb_uplcom, OID_AUTO, debug, CTLFLAG_RW,
  125            &uplcomdebug, 0, "uplcom debug level");
  126 
  127 #define DPRINTFN(n, x)  do { \
  128                                 if (uplcomdebug > (n)) \
  129                                         printf x; \
  130                         } while (0)
  131 #else
  132 #define DPRINTFN(n, x)
  133 #endif
  134 #define DPRINTF(x) DPRINTFN(0, x)
  135 
  136 #define UPLCOM_MODVER                   1       /* module version */
  137 
  138 #define UPLCOM_CONFIG_INDEX             0
  139 #define UPLCOM_IFACE_INDEX              0
  140 #define UPLCOM_SECOND_IFACE_INDEX       1
  141 
  142 #ifndef UPLCOM_INTR_INTERVAL
  143 #define UPLCOM_INTR_INTERVAL            100     /* ms */
  144 #endif
  145 
  146 #define UPLCOM_SET_REQUEST              0x01
  147 #define UPLCOM_SET_CRTSCTS              0x41
  148 #define UPLCOM_SET_CRTSCTS_PL2303X      0x61
  149 #define RSAQ_STATUS_CTS                 0x80
  150 #define RSAQ_STATUS_DSR                 0x02
  151 #define RSAQ_STATUS_DCD                 0x01
  152 
  153 #define TYPE_PL2303                     0
  154 #define TYPE_PL2303X                    1
  155 
  156 struct  uplcom_softc {
  157         struct ucom_softc       sc_ucom;
  158 
  159         int                     sc_iface_number;        /* interface number */
  160 
  161         usbd_interface_handle   sc_intr_iface;  /* interrupt interface */
  162         int                     sc_intr_number; /* interrupt number */
  163         usbd_pipe_handle        sc_intr_pipe;   /* interrupt pipe */
  164         u_char                  *sc_intr_buf;   /* interrupt buffer */
  165         int                     sc_isize;
  166 
  167         usb_cdc_line_state_t    sc_line_state;  /* current line state */
  168         u_char                  sc_dtr;         /* current DTR state */
  169         u_char                  sc_rts;         /* current RTS state */
  170         u_char                  sc_status;
  171 
  172         u_char                  sc_lsr;         /* Local status register */
  173         u_char                  sc_msr;         /* uplcom status register */
  174 
  175         int                     sc_chiptype;    /* Type of chip */
  176 
  177         struct task             sc_task;
  178 };
  179 
  180 /*
  181  * These are the maximum number of bytes transferred per frame.
  182  * The output buffer size cannot be increased due to the size encoding.
  183  */
  184 #define UPLCOMIBUFSIZE 256
  185 #define UPLCOMOBUFSIZE 256
  186 
  187 static  usbd_status uplcom_reset(struct uplcom_softc *);
  188 static  usbd_status uplcom_set_line_coding(struct uplcom_softc *,
  189                                            usb_cdc_line_state_t *);
  190 static  usbd_status uplcom_set_crtscts(struct uplcom_softc *);
  191 static  void uplcom_intr(usbd_xfer_handle, usbd_private_handle, usbd_status);
  192 
  193 static  void uplcom_set(void *, int, int, int);
  194 static  void uplcom_dtr(struct uplcom_softc *, int);
  195 static  void uplcom_rts(struct uplcom_softc *, int);
  196 static  void uplcom_break(struct uplcom_softc *, int);
  197 static  void uplcom_set_line_state(struct uplcom_softc *);
  198 static  void uplcom_get_status(void *, int, u_char *, u_char *);
  199 #if 0 /* TODO */
  200 static  int  uplcom_ioctl(void *, int, u_long, caddr_t, int, usb_proc_ptr);
  201 #endif
  202 static  int  uplcom_param(void *, int, struct termios *);
  203 static  int  uplcom_open(void *, int);
  204 static  void uplcom_close(void *, int);
  205 static  void uplcom_notify(void *, int);
  206 
  207 struct ucom_callback uplcom_callback = {
  208         uplcom_get_status,
  209         uplcom_set,
  210         uplcom_param,
  211         NULL, /* uplcom_ioctl, TODO */
  212         uplcom_open,
  213         uplcom_close,
  214         NULL,
  215         NULL
  216 };
  217 
  218 static const struct uplcom_product {
  219         uint16_t        vendor;
  220         uint16_t        product;
  221         int32_t         release;         /* release is a 16bit entity,
  222                                           * if -1 is specified we "don't care"
  223                                           * This is a floor value.  The table
  224                                           * must have newer revs before older
  225                                           * revs (and -1 last).
  226                                           */
  227         char            chiptype;
  228 } uplcom_products [] = {
  229         { USB_VENDOR_RADIOSHACK, USB_PRODUCT_RADIOSHACK_USBCABLE, -1, TYPE_PL2303 },
  230 
  231         /* I/O DATA USB-RSAQ */
  232         { USB_VENDOR_IODATA, USB_PRODUCT_IODATA_USBRSAQ, -1, TYPE_PL2303 },
  233         /* Prolific Pharos */
  234         { USB_VENDOR_PROLIFIC, USB_PRODUCT_PROLIFIC_PHAROS, -1, TYPE_PL2303 },
  235         /* I/O DATA USB-RSAQ2 */
  236         { USB_VENDOR_PROLIFIC, USB_PRODUCT_PROLIFIC_RSAQ2, -1, TYPE_PL2303 },
  237         /* I/O DATA USB-RSAQ3 */
  238         { USB_VENDOR_PROLIFIC, USB_PRODUCT_PROLIFIC_RSAQ3, -1, TYPE_PL2303X },
  239         /* Willcom W-SIM*/
  240         { USB_VENDOR_PROLIFIC2, USB_PRODUCT_PROLIFIC2_WSIM, -1, TYPE_PL2303X},
  241         /* PLANEX USB-RS232 URS-03 */
  242         { USB_VENDOR_ATEN, USB_PRODUCT_ATEN_UC232A, -1, TYPE_PL2303 },
  243         /* TrendNet TU-S9 */
  244         { USB_VENDOR_PROLIFIC, USB_PRODUCT_PROLIFIC_PL2303,
  245           0x400, TYPE_PL2303X },
  246         /* ST Lab USB-SERIAL-4 */
  247         { USB_VENDOR_PROLIFIC, USB_PRODUCT_PROLIFIC_PL2303,
  248           0x300, TYPE_PL2303X },
  249         /* IOGEAR/ATEN UC-232A (also ST Lab USB-SERIAL-1) */
  250         { USB_VENDOR_PROLIFIC, USB_PRODUCT_PROLIFIC_PL2303, -1, TYPE_PL2303 },
  251         /* TDK USB-PHS Adapter UHA6400 */
  252         { USB_VENDOR_TDK, USB_PRODUCT_TDK_UHA6400, -1, TYPE_PL2303 },
  253         /* RATOC REX-USB60 */
  254         { USB_VENDOR_RATOC, USB_PRODUCT_RATOC_REXUSB60, -1, TYPE_PL2303 },
  255         /* ELECOM UC-SGT */
  256         { USB_VENDOR_ELECOM, USB_PRODUCT_ELECOM_UCSGT, -1, TYPE_PL2303 },
  257         { USB_VENDOR_ELECOM, USB_PRODUCT_ELECOM_UCSGT0, -1, TYPE_PL2303 },
  258         /* Sagem USB-Serial Controller */
  259         { USB_VENDOR_SAGEM, USB_PRODUCT_SAGEM_USBSERIAL, -1, TYPE_PL2303X },
  260         /* Sony Ericsson USB Cable */
  261         { USB_VENDOR_SONYERICSSON, USB_PRODUCT_SONYERICSSON_DCU10,
  262           -1,TYPE_PL2303 },
  263         /* SOURCENEXT KeikaiDenwa 8 */
  264         { USB_VENDOR_SOURCENEXT, USB_PRODUCT_SOURCENEXT_KEIKAI8,
  265           -1, TYPE_PL2303 },
  266         /* SOURCENEXT KeikaiDenwa 8 with charger */
  267         { USB_VENDOR_SOURCENEXT, USB_PRODUCT_SOURCENEXT_KEIKAI8_CHG,
  268           -1, TYPE_PL2303 },
  269         /* HAL Corporation Crossam2+USB */
  270         { USB_VENDOR_HAL, USB_PRODUCT_HAL_IMR001, -1, TYPE_PL2303 },
  271         /* Sitecom USB to Serial */
  272         { USB_VENDOR_SITECOM, USB_PRODUCT_SITECOM_SERIAL, -1, TYPE_PL2303 },
  273         /* Tripp-Lite U209-000-R */
  274         { USB_VENDOR_TRIPPLITE, USB_PRODUCT_TRIPPLITE_U209, -1, TYPE_PL2303X },
  275         /* Mobile Action MA-620 Infrared Adapter */
  276         { USB_VENDOR_MOBILEACTION, USB_PRODUCT_MOBILEACTION_MA620, -1,
  277           TYPE_PL2303X },
  278         { 0, 0 }
  279 };
  280 
  281 static device_probe_t uplcom_match;
  282 static device_attach_t uplcom_attach;
  283 static device_detach_t uplcom_detach;
  284 
  285 static device_method_t uplcom_methods[] = {
  286         /* Device interface */
  287         DEVMETHOD(device_probe, uplcom_match),
  288         DEVMETHOD(device_attach, uplcom_attach),
  289         DEVMETHOD(device_detach, uplcom_detach),
  290         { 0, 0 }
  291 };
  292 
  293 static driver_t uplcom_driver = {
  294         "ucom",
  295         uplcom_methods,
  296         sizeof (struct uplcom_softc)
  297 };
  298 
  299 DRIVER_MODULE(uplcom, uhub, uplcom_driver, ucom_devclass, usbd_driver_load, 0);
  300 MODULE_DEPEND(uplcom, usb, 1, 1, 1);
  301 MODULE_DEPEND(uplcom, ucom, UCOM_MINVER, UCOM_PREFVER, UCOM_MAXVER);
  302 MODULE_VERSION(uplcom, UPLCOM_MODVER);
  303 
  304 static int      uplcominterval = UPLCOM_INTR_INTERVAL;
  305 
  306 static int
  307 sysctl_hw_usb_uplcom_interval(SYSCTL_HANDLER_ARGS)
  308 {
  309         int err, val;
  310 
  311         val = uplcominterval;
  312         err = sysctl_handle_int(oidp, &val, 0, req);
  313         if (err != 0 || req->newptr == NULL)
  314                 return (err);
  315         if (0 < val && val <= 1000)
  316                 uplcominterval = val;
  317         else
  318                 err = EINVAL;
  319 
  320         return (err);
  321 }
  322 
  323 SYSCTL_PROC(_hw_usb_uplcom, OID_AUTO, interval, CTLTYPE_INT | CTLFLAG_RW,
  324             0, sizeof(int), sysctl_hw_usb_uplcom_interval,
  325             "I", "uplcom interrupt pipe interval");
  326 
  327 static int
  328 uplcom_match(device_t self)
  329 {
  330         struct usb_attach_arg *uaa = device_get_ivars(self);
  331         int i;
  332 
  333         if (uaa->iface != NULL)
  334                 return (UMATCH_NONE);
  335 
  336         for (i = 0; uplcom_products[i].vendor != 0; i++) {
  337                 if (uplcom_products[i].vendor == uaa->vendor &&
  338                     uplcom_products[i].product == uaa->product &&
  339                     (uplcom_products[i].release <= uaa->release ||
  340                      uplcom_products[i].release == -1)) {
  341                         return (UMATCH_VENDOR_PRODUCT);
  342                 }
  343         }
  344         return (UMATCH_NONE);
  345 }
  346 
  347 static int
  348 uplcom_attach(device_t self)
  349 {
  350         struct uplcom_softc *sc = device_get_softc(self);
  351         struct usb_attach_arg *uaa = device_get_ivars(self);
  352         usbd_device_handle dev = uaa->device;
  353         struct ucom_softc *ucom;
  354         usb_config_descriptor_t *cdesc;
  355         usb_interface_descriptor_t *id;
  356         usb_endpoint_descriptor_t *ed;
  357         const char *devname;
  358         usbd_status err;
  359         int i;
  360 
  361         ucom = &sc->sc_ucom;
  362         ucom->sc_dev = self;
  363         ucom->sc_udev = dev;
  364         ucom->sc_iface = uaa->iface;
  365 
  366         devname = device_get_nameunit(ucom->sc_dev);
  367 
  368         DPRINTF(("uplcom attach: sc = %p\n", sc));
  369 
  370         /* determine chip type */
  371         for (i = 0; uplcom_products[i].vendor != 0; i++) {
  372                 if (uplcom_products[i].vendor == uaa->vendor &&
  373                     uplcom_products[i].product == uaa->product &&
  374                     (uplcom_products[i].release == uaa->release ||
  375                      uplcom_products[i].release == -1)) {
  376                         sc->sc_chiptype = uplcom_products[i].chiptype;
  377                         break;
  378                 }
  379         }
  380 
  381         /*
  382          * check we found the device - attach should have ensured we
  383          * don't get here without matching device
  384          */
  385         if (uplcom_products[i].vendor == 0) {
  386                 printf("%s: didn't match\n", devname);
  387                 ucom->sc_dying = 1;
  388                 goto error;
  389         }
  390 
  391 #ifdef USB_DEBUG
  392         /* print the chip type */
  393         if (sc->sc_chiptype == TYPE_PL2303X) {
  394                 DPRINTF(("uplcom_attach: chiptype 2303X\n"));
  395         } else {
  396                 DPRINTF(("uplcom_attach: chiptype 2303\n"));
  397         }
  398 #endif
  399 
  400         /* initialize endpoints */
  401         ucom->sc_bulkin_no = ucom->sc_bulkout_no = -1;
  402         sc->sc_intr_number = -1;
  403         sc->sc_intr_pipe = NULL;
  404 
  405         /* Move the device into the configured state. */
  406         err = usbd_set_config_index(dev, UPLCOM_CONFIG_INDEX, 1);
  407         if (err) {
  408                 printf("%s: failed to set configuration: %s\n",
  409                         devname, usbd_errstr(err));
  410                 ucom->sc_dying = 1;
  411                 goto error;
  412         }
  413 
  414         /* get the config descriptor */
  415         cdesc = usbd_get_config_descriptor(ucom->sc_udev);
  416 
  417         if (cdesc == NULL) {
  418                 printf("%s: failed to get configuration descriptor\n",
  419                         device_get_nameunit(ucom->sc_dev));
  420                 ucom->sc_dying = 1;
  421                 goto error;
  422         }
  423 
  424         /* get the (first/common) interface */
  425         err = usbd_device2interface_handle(dev, UPLCOM_IFACE_INDEX,
  426                                            &ucom->sc_iface);
  427         if (err) {
  428                 printf("%s: failed to get interface: %s\n",
  429                         devname, usbd_errstr(err));
  430                 ucom->sc_dying = 1;
  431                 goto error;
  432         }
  433 
  434         /* Find the interrupt endpoints */
  435 
  436         id = usbd_get_interface_descriptor(ucom->sc_iface);
  437         sc->sc_iface_number = id->bInterfaceNumber;
  438 
  439         for (i = 0; i < id->bNumEndpoints; i++) {
  440                 ed = usbd_interface2endpoint_descriptor(ucom->sc_iface, i);
  441                 if (ed == NULL) {
  442                         printf("%s: no endpoint descriptor for %d\n",
  443                                 device_get_nameunit(ucom->sc_dev), i);
  444                         ucom->sc_dying = 1;
  445                         goto error;
  446                 }
  447 
  448                 if (UE_GET_DIR(ed->bEndpointAddress) == UE_DIR_IN &&
  449                     UE_GET_XFERTYPE(ed->bmAttributes) == UE_INTERRUPT) {
  450                         sc->sc_intr_number = ed->bEndpointAddress;
  451                         sc->sc_isize = UGETW(ed->wMaxPacketSize);
  452                 }
  453         }
  454 
  455         if (sc->sc_intr_number == -1) {
  456                 printf("%s: Could not find interrupt in\n",
  457                         device_get_nameunit(ucom->sc_dev));
  458                 ucom->sc_dying = 1;
  459                 goto error;
  460         }
  461 
  462         /* keep interface for interrupt */
  463         sc->sc_intr_iface = ucom->sc_iface;
  464 
  465         /*
  466          * USB-RSAQ1 has two interface
  467          *
  468          *  USB-RSAQ1       | USB-RSAQ2
  469          * -----------------+-----------------
  470          * Interface 0      |Interface 0
  471          *  Interrupt(0x81) | Interrupt(0x81)
  472          * -----------------+ BulkIN(0x02)
  473          * Interface 1      | BulkOUT(0x83)
  474          *   BulkIN(0x02)   |
  475          *   BulkOUT(0x83)  |
  476          */
  477         if (cdesc->bNumInterface == 2) {
  478                 err = usbd_device2interface_handle(dev,
  479                                                    UPLCOM_SECOND_IFACE_INDEX,
  480                                                    &ucom->sc_iface);
  481                 if (err) {
  482                         printf("%s: failed to get second interface: %s\n",
  483                                 devname, usbd_errstr(err));
  484                         ucom->sc_dying = 1;
  485                         goto error;
  486                 }
  487         }
  488 
  489         /* Find the bulk{in,out} endpoints */
  490 
  491         id = usbd_get_interface_descriptor(ucom->sc_iface);
  492         sc->sc_iface_number = id->bInterfaceNumber;
  493 
  494         for (i = 0; i < id->bNumEndpoints; i++) {
  495                 ed = usbd_interface2endpoint_descriptor(ucom->sc_iface, i);
  496                 if (ed == NULL) {
  497                         printf("%s: no endpoint descriptor for %d\n",
  498                                 device_get_nameunit(ucom->sc_dev), i);
  499                         ucom->sc_dying = 1;
  500                         goto error;
  501                 }
  502 
  503                 if (UE_GET_DIR(ed->bEndpointAddress) == UE_DIR_IN &&
  504                     UE_GET_XFERTYPE(ed->bmAttributes) == UE_BULK) {
  505                         ucom->sc_bulkin_no = ed->bEndpointAddress;
  506                 } else if (UE_GET_DIR(ed->bEndpointAddress) == UE_DIR_OUT &&
  507                     UE_GET_XFERTYPE(ed->bmAttributes) == UE_BULK) {
  508                         ucom->sc_bulkout_no = ed->bEndpointAddress;
  509                 }
  510         }
  511 
  512         if (ucom->sc_bulkin_no == -1) {
  513                 printf("%s: Could not find data bulk in\n",
  514                         device_get_nameunit(ucom->sc_dev));
  515                 ucom->sc_dying = 1;
  516                 goto error;
  517         }
  518 
  519         if (ucom->sc_bulkout_no == -1) {
  520                 printf("%s: Could not find data bulk out\n",
  521                         device_get_nameunit(ucom->sc_dev));
  522                 ucom->sc_dying = 1;
  523                 goto error;
  524         }
  525 
  526         sc->sc_dtr = sc->sc_rts = -1;
  527         ucom->sc_parent = sc;
  528         ucom->sc_portno = UCOM_UNK_PORTNO;
  529         /* bulkin, bulkout set above */
  530         ucom->sc_ibufsize = UPLCOMIBUFSIZE;
  531         ucom->sc_obufsize = UPLCOMOBUFSIZE;
  532         ucom->sc_ibufsizepad = UPLCOMIBUFSIZE;
  533         ucom->sc_opkthdrlen = 0;
  534         ucom->sc_callback = &uplcom_callback;
  535 
  536         err = uplcom_reset(sc);
  537 
  538         if (err) {
  539                 printf("%s: reset failed: %s\n",
  540                        device_get_nameunit(ucom->sc_dev), usbd_errstr(err));
  541                 ucom->sc_dying = 1;
  542                 goto error;
  543         }
  544 
  545         DPRINTF(("uplcom: in = 0x%x, out = 0x%x, intr = 0x%x\n",
  546                  ucom->sc_bulkin_no, ucom->sc_bulkout_no, sc->sc_intr_number));
  547 
  548         TASK_INIT(&sc->sc_task, 0, uplcom_notify, sc);
  549         ucom_attach(&sc->sc_ucom);
  550         return 0;
  551 
  552 error:
  553         return ENXIO;
  554 }
  555 
  556 static int
  557 uplcom_detach(device_t self)
  558 {
  559         struct uplcom_softc *sc = device_get_softc(self);
  560         int rv = 0;
  561 
  562         DPRINTF(("uplcom_detach: sc = %p\n", sc));
  563 
  564         if (sc->sc_intr_pipe != NULL) {
  565                 usbd_abort_pipe(sc->sc_intr_pipe);
  566                 usbd_close_pipe(sc->sc_intr_pipe);
  567                 free(sc->sc_intr_buf, M_USBDEV);
  568                 sc->sc_intr_pipe = NULL;
  569         }
  570 
  571         sc->sc_ucom.sc_dying = 1;
  572 
  573         rv = ucom_detach(&sc->sc_ucom);
  574 
  575         return (rv);
  576 }
  577 
  578 static usbd_status
  579 uplcom_reset(struct uplcom_softc *sc)
  580 {
  581         usb_device_request_t req;
  582         usbd_status err;
  583 
  584         req.bmRequestType = UT_WRITE_VENDOR_DEVICE;
  585         req.bRequest = UPLCOM_SET_REQUEST;
  586         USETW(req.wValue, 0);
  587         USETW(req.wIndex, sc->sc_iface_number);
  588         USETW(req.wLength, 0);
  589 
  590         err = usbd_do_request(sc->sc_ucom.sc_udev, &req, 0);
  591         if (err) {
  592                 printf("%s: uplcom_reset: %s\n",
  593                        device_get_nameunit(sc->sc_ucom.sc_dev), usbd_errstr(err));
  594                 return (EIO);
  595         }
  596 
  597         return (0);
  598 }
  599 
  600 struct pl2303x_init {
  601         uint8_t         req_type;
  602         uint8_t         request;
  603         uint16_t        value;
  604         uint16_t        index;
  605         uint16_t        length;
  606 };
  607 
  608 static const struct pl2303x_init pl2303x[] = {
  609         { UT_READ_VENDOR_DEVICE,  UPLCOM_SET_REQUEST, 0x8484,    0, 0 },
  610         { UT_WRITE_VENDOR_DEVICE, UPLCOM_SET_REQUEST, 0x0404,    0, 0 },
  611         { UT_READ_VENDOR_DEVICE,  UPLCOM_SET_REQUEST, 0x8484,    0, 0 },
  612         { UT_READ_VENDOR_DEVICE,  UPLCOM_SET_REQUEST, 0x8383,    0, 0 },
  613         { UT_READ_VENDOR_DEVICE,  UPLCOM_SET_REQUEST, 0x8484,    0, 0 },
  614         { UT_WRITE_VENDOR_DEVICE, UPLCOM_SET_REQUEST, 0x0404,    1, 0 },
  615         { UT_READ_VENDOR_DEVICE,  UPLCOM_SET_REQUEST, 0x8484,    0, 0 },
  616         { UT_READ_VENDOR_DEVICE,  UPLCOM_SET_REQUEST, 0x8383,    0, 0 },
  617         { UT_WRITE_VENDOR_DEVICE, UPLCOM_SET_REQUEST,      0,    1, 0 },
  618         { UT_WRITE_VENDOR_DEVICE, UPLCOM_SET_REQUEST,      1,    0, 0 },
  619         { UT_WRITE_VENDOR_DEVICE, UPLCOM_SET_REQUEST,      2, 0x44, 0 }
  620 };
  621 #define N_PL2302X_INIT  (sizeof(pl2303x)/sizeof(pl2303x[0]))
  622 
  623 static usbd_status
  624 uplcom_pl2303x_init(struct uplcom_softc *sc)
  625 {
  626         usb_device_request_t req;
  627         usbd_status err;
  628         int i;
  629 
  630         for (i = 0; i < N_PL2302X_INIT; i++) {
  631                 req.bmRequestType = pl2303x[i].req_type;
  632                 req.bRequest = pl2303x[i].request;
  633                 USETW(req.wValue, pl2303x[i].value);
  634                 USETW(req.wIndex, pl2303x[i].index);
  635                 USETW(req.wLength, pl2303x[i].length);
  636 
  637                 err = usbd_do_request(sc->sc_ucom.sc_udev, &req, 0);
  638                 if (err) {
  639                         printf("%s: uplcom_pl2303x_init: %d: %s\n",
  640                                 device_get_nameunit(sc->sc_ucom.sc_dev), i,
  641                                 usbd_errstr(err));
  642                         return (EIO);
  643                 }
  644         }
  645 
  646         return (0);
  647 }
  648 
  649 static void
  650 uplcom_set_line_state(struct uplcom_softc *sc)
  651 {
  652         usb_device_request_t req;
  653         int ls;
  654         usbd_status err;
  655 
  656         ls = (sc->sc_dtr ? UCDC_LINE_DTR : 0) |
  657                 (sc->sc_rts ? UCDC_LINE_RTS : 0);
  658         req.bmRequestType = UT_WRITE_CLASS_INTERFACE;
  659         req.bRequest = UCDC_SET_CONTROL_LINE_STATE;
  660         USETW(req.wValue, ls);
  661         USETW(req.wIndex, sc->sc_iface_number);
  662         USETW(req.wLength, 0);
  663 
  664         err = usbd_do_request(sc->sc_ucom.sc_udev, &req, 0);
  665         if (err)
  666                 printf("%s: uplcom_set_line_status: %s\n",
  667                        device_get_nameunit(sc->sc_ucom.sc_dev), usbd_errstr(err));
  668 }
  669 
  670 static void
  671 uplcom_set(void *addr, int portno, int reg, int onoff)
  672 {
  673         struct uplcom_softc *sc = addr;
  674 
  675         switch (reg) {
  676         case UCOM_SET_DTR:
  677                 uplcom_dtr(sc, onoff);
  678                 break;
  679         case UCOM_SET_RTS:
  680                 uplcom_rts(sc, onoff);
  681                 break;
  682         case UCOM_SET_BREAK:
  683                 uplcom_break(sc, onoff);
  684                 break;
  685         default:
  686                 break;
  687         }
  688 }
  689 
  690 static void
  691 uplcom_dtr(struct uplcom_softc *sc, int onoff)
  692 {
  693         DPRINTF(("uplcom_dtr: onoff = %d\n", onoff));
  694 
  695         if (sc->sc_dtr == onoff)
  696                 return;
  697         sc->sc_dtr = onoff;
  698 
  699         uplcom_set_line_state(sc);
  700 }
  701 
  702 static void
  703 uplcom_rts(struct uplcom_softc *sc, int onoff)
  704 {
  705         DPRINTF(("uplcom_rts: onoff = %d\n", onoff));
  706 
  707         if (sc->sc_rts == onoff)
  708                 return;
  709         sc->sc_rts = onoff;
  710 
  711         uplcom_set_line_state(sc);
  712 }
  713 
  714 static void
  715 uplcom_break(struct uplcom_softc *sc, int onoff)
  716 {
  717         usb_device_request_t req;
  718         usbd_status err;
  719 
  720         DPRINTF(("uplcom_break: onoff = %d\n", onoff));
  721 
  722         req.bmRequestType = UT_WRITE_CLASS_INTERFACE;
  723         req.bRequest = UCDC_SEND_BREAK;
  724         USETW(req.wValue, onoff ? UCDC_BREAK_ON : UCDC_BREAK_OFF);
  725         USETW(req.wIndex, sc->sc_iface_number);
  726         USETW(req.wLength, 0);
  727 
  728         err = usbd_do_request(sc->sc_ucom.sc_udev, &req, 0);
  729         if (err)
  730                 printf("%s: uplcom_break: %s\n",
  731                        device_get_nameunit(sc->sc_ucom.sc_dev), usbd_errstr(err));
  732 }
  733 
  734 static usbd_status
  735 uplcom_set_crtscts(struct uplcom_softc *sc)
  736 {
  737         usb_device_request_t req;
  738         usbd_status err;
  739 
  740         DPRINTF(("uplcom_set_crtscts: on\n"));
  741 
  742         req.bmRequestType = UT_WRITE_VENDOR_DEVICE;
  743         req.bRequest = UPLCOM_SET_REQUEST;
  744         USETW(req.wValue, 0);
  745         if (sc->sc_chiptype == TYPE_PL2303X)
  746                 USETW(req.wIndex, UPLCOM_SET_CRTSCTS_PL2303X);
  747         else
  748                 USETW(req.wIndex, UPLCOM_SET_CRTSCTS);
  749         USETW(req.wLength, 0);
  750 
  751         err = usbd_do_request(sc->sc_ucom.sc_udev, &req, 0);
  752         if (err) {
  753                 printf("%s: uplcom_set_crtscts: %s\n",
  754                        device_get_nameunit(sc->sc_ucom.sc_dev), usbd_errstr(err));
  755                 return (err);
  756         }
  757 
  758         return (USBD_NORMAL_COMPLETION);
  759 }
  760 
  761 static usbd_status
  762 uplcom_set_line_coding(struct uplcom_softc *sc, usb_cdc_line_state_t *state)
  763 {
  764         usb_device_request_t req;
  765         usbd_status err;
  766 
  767         DPRINTF((
  768 "uplcom_set_line_coding: rate = %d, fmt = %d, parity = %d bits = %d\n",
  769                  UGETDW(state->dwDTERate), state->bCharFormat,
  770                  state->bParityType, state->bDataBits));
  771 
  772         if (memcmp(state, &sc->sc_line_state, UCDC_LINE_STATE_LENGTH) == 0) {
  773                 DPRINTF(("uplcom_set_line_coding: already set\n"));
  774                 return (USBD_NORMAL_COMPLETION);
  775         }
  776 
  777         req.bmRequestType = UT_WRITE_CLASS_INTERFACE;
  778         req.bRequest = UCDC_SET_LINE_CODING;
  779         USETW(req.wValue, 0);
  780         USETW(req.wIndex, sc->sc_iface_number);
  781         USETW(req.wLength, UCDC_LINE_STATE_LENGTH);
  782 
  783         err = usbd_do_request(sc->sc_ucom.sc_udev, &req, state);
  784         if (err) {
  785                 printf("%s: uplcom_set_line_coding: %s\n",
  786                        device_get_nameunit(sc->sc_ucom.sc_dev), usbd_errstr(err));
  787                 return (err);
  788         }
  789 
  790         sc->sc_line_state = *state;
  791 
  792         return (USBD_NORMAL_COMPLETION);
  793 }
  794 
  795 static const int uplcom_rates[] = {
  796         75, 150, 300, 600, 1200, 1800, 2400, 3600, 4800, 7200, 9600, 14400,
  797         19200, 28800, 38400, 57600, 115200,
  798         /*
  799          * Higher speeds are probably possible. PL2303X supports up to
  800          * 6Mb and can set any rate
  801          */
  802         230400, 460800, 614400, 921600, 1228800
  803 };
  804 #define N_UPLCOM_RATES  (sizeof(uplcom_rates)/sizeof(uplcom_rates[0]))
  805 
  806 static int
  807 uplcom_param(void *addr, int portno, struct termios *t)
  808 {
  809         struct uplcom_softc *sc = addr;
  810         usbd_status err;
  811         usb_cdc_line_state_t ls;
  812         int i;
  813 
  814         DPRINTF(("uplcom_param: sc = %p\n", sc));
  815 
  816         /* Check requested baud rate */
  817         for (i = 0; i < N_UPLCOM_RATES; i++)
  818                 if (uplcom_rates[i] == t->c_ospeed)
  819                         break;
  820         if (i == N_UPLCOM_RATES) {
  821                 DPRINTF(("uplcom_param: bad baud rate (%d)\n", t->c_ospeed));
  822                 return (EIO);
  823         }
  824 
  825         USETDW(ls.dwDTERate, t->c_ospeed);
  826         if (ISSET(t->c_cflag, CSTOPB))
  827                 ls.bCharFormat = UCDC_STOP_BIT_2;
  828         else
  829                 ls.bCharFormat = UCDC_STOP_BIT_1;
  830         if (ISSET(t->c_cflag, PARENB)) {
  831                 if (ISSET(t->c_cflag, PARODD))
  832                         ls.bParityType = UCDC_PARITY_ODD;
  833                 else
  834                         ls.bParityType = UCDC_PARITY_EVEN;
  835         } else
  836                 ls.bParityType = UCDC_PARITY_NONE;
  837         switch (ISSET(t->c_cflag, CSIZE)) {
  838         case CS5:
  839                 ls.bDataBits = 5;
  840                 break;
  841         case CS6:
  842                 ls.bDataBits = 6;
  843                 break;
  844         case CS7:
  845                 ls.bDataBits = 7;
  846                 break;
  847         case CS8:
  848                 ls.bDataBits = 8;
  849                 break;
  850         }
  851 
  852         err = uplcom_set_line_coding(sc, &ls);
  853         if (err)
  854                 return (EIO);
  855 
  856         if (ISSET(t->c_cflag, CRTSCTS)) {
  857                 err = uplcom_set_crtscts(sc);
  858                 if (err)
  859                         return (EIO);
  860         }
  861 
  862         return (0);
  863 }
  864 
  865 static int
  866 uplcom_open(void *addr, int portno)
  867 {
  868         struct uplcom_softc *sc = addr;
  869         int err;
  870 
  871         if (sc->sc_ucom.sc_dying)
  872                 return (ENXIO);
  873 
  874         DPRINTF(("uplcom_open: sc = %p\n", sc));
  875 
  876         if (sc->sc_intr_number != -1 && sc->sc_intr_pipe == NULL) {
  877                 sc->sc_status = 0; /* clear status bit */
  878                 sc->sc_intr_buf = malloc(sc->sc_isize, M_USBDEV, M_WAITOK);
  879                 err = usbd_open_pipe_intr(sc->sc_intr_iface,
  880                                           sc->sc_intr_number,
  881                                           USBD_SHORT_XFER_OK,
  882                                           &sc->sc_intr_pipe,
  883                                           sc,
  884                                           sc->sc_intr_buf,
  885                                           sc->sc_isize,
  886                                           uplcom_intr,
  887                                           uplcominterval);
  888                 if (err) {
  889                         printf("%s: cannot open interrupt pipe (addr %d)\n",
  890                                device_get_nameunit(sc->sc_ucom.sc_dev),
  891                                sc->sc_intr_number);
  892                         return (EIO);
  893                 }
  894         }
  895 
  896         if (sc->sc_chiptype == TYPE_PL2303X)
  897                 return (uplcom_pl2303x_init(sc));
  898 
  899         return (0);
  900 }
  901 
  902 static void
  903 uplcom_close(void *addr, int portno)
  904 {
  905         struct uplcom_softc *sc = addr;
  906         int err;
  907 
  908         if (sc->sc_ucom.sc_dying)
  909                 return;
  910 
  911         DPRINTF(("uplcom_close: close\n"));
  912 
  913         if (sc->sc_intr_pipe != NULL) {
  914                 err = usbd_abort_pipe(sc->sc_intr_pipe);
  915                 if (err)
  916                         printf("%s: abort interrupt pipe failed: %s\n",
  917                                device_get_nameunit(sc->sc_ucom.sc_dev),
  918                                usbd_errstr(err));
  919                 err = usbd_close_pipe(sc->sc_intr_pipe);
  920                 if (err)
  921                         printf("%s: close interrupt pipe failed: %s\n",
  922                                device_get_nameunit(sc->sc_ucom.sc_dev),
  923                                usbd_errstr(err));
  924                 free(sc->sc_intr_buf, M_USBDEV);
  925                 sc->sc_intr_pipe = NULL;
  926         }
  927 }
  928 
  929 static void
  930 uplcom_intr(usbd_xfer_handle xfer, usbd_private_handle priv, usbd_status status)
  931 {
  932         struct uplcom_softc *sc = priv;
  933         u_char *buf = sc->sc_intr_buf;
  934         u_char pstatus;
  935 
  936         if (sc->sc_ucom.sc_dying)
  937                 return;
  938 
  939         if (status != USBD_NORMAL_COMPLETION) {
  940                 if (status == USBD_NOT_STARTED || status == USBD_CANCELLED)
  941                         return;
  942 
  943                 DPRINTF(("%s: uplcom_intr: abnormal status: %s\n",
  944                         device_get_nameunit(sc->sc_ucom.sc_dev),
  945                         usbd_errstr(status)));
  946                 usbd_clear_endpoint_stall_async(sc->sc_intr_pipe);
  947                 return;
  948         }
  949 
  950         DPRINTF(("%s: uplcom status = %02x\n",
  951                  device_get_nameunit(sc->sc_ucom.sc_dev), buf[8]));
  952 
  953         sc->sc_lsr = sc->sc_msr = 0;
  954         pstatus = buf[8];
  955         if (ISSET(pstatus, RSAQ_STATUS_CTS))
  956                 sc->sc_msr |= SER_CTS;
  957         else
  958                 sc->sc_msr &= ~SER_CTS;
  959         if (ISSET(pstatus, RSAQ_STATUS_DSR))
  960                 sc->sc_msr |= SER_DSR;
  961         else
  962                 sc->sc_msr &= ~SER_DSR;
  963         if (ISSET(pstatus, RSAQ_STATUS_DCD))
  964                 sc->sc_msr |= SER_DCD;
  965         else
  966                 sc->sc_msr &= ~SER_DCD;
  967 
  968         /* Deferred notifying to the ucom layer */
  969         taskqueue_enqueue(taskqueue_swi_giant, &sc->sc_task);
  970 }
  971 
  972 static void
  973 uplcom_notify(void *arg, int count)
  974 {
  975         struct uplcom_softc *sc;
  976 
  977         sc = (struct uplcom_softc *)arg;
  978         if (sc->sc_ucom.sc_dying)
  979                 return;
  980         ucom_status_change(&sc->sc_ucom);
  981 }
  982 
  983 static void
  984 uplcom_get_status(void *addr, int portno, u_char *lsr, u_char *msr)
  985 {
  986         struct uplcom_softc *sc = addr;
  987 
  988         DPRINTF(("uplcom_get_status:\n"));
  989 
  990         if (lsr != NULL)
  991                 *lsr = sc->sc_lsr;
  992         if (msr != NULL)
  993                 *msr = sc->sc_msr;
  994 }
  995 
  996 #if 0 /* TODO */
  997 static int
  998 uplcom_ioctl(void *addr, int portno, u_long cmd, caddr_t data, int flag,
  999              struct thread *p)
 1000 {
 1001         struct uplcom_softc *sc = addr;
 1002         int error = 0;
 1003 
 1004         if (sc->sc_ucom.sc_dying)
 1005                 return (EIO);
 1006 
 1007         DPRINTF(("uplcom_ioctl: cmd = 0x%08lx\n", cmd));
 1008 
 1009         switch (cmd) {
 1010         case TIOCNOTTY:
 1011         case TIOCMGET:
 1012         case TIOCMSET:
 1013         case USB_GET_CM_OVER_DATA:
 1014         case USB_SET_CM_OVER_DATA:
 1015                 break;
 1016 
 1017         default:
 1018                 DPRINTF(("uplcom_ioctl: unknown\n"));
 1019                 error = ENOTTY;
 1020                 break;
 1021         }
 1022 
 1023         return (error);
 1024 }
 1025 #endif

Cache object: b3e0c122e0e3ba86ed30eeab8238eabf


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