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

Cache object: 658fc159cf3a62c5668627d413934d17


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