LCOV - code coverage report
Current view: top level - dev/usb - uplcom.c (source / functions) Hit Total Coverage
Test: 6.4 Lines: 0 315 0.0 %
Date: 2018-10-19 03:25:38 Functions: 0 16 0.0 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /*      $OpenBSD: uplcom.c,v 1.72 2018/06/18 19:05:24 mikeb Exp $       */
       2             : /*      $NetBSD: uplcom.c,v 1.29 2002/09/23 05:51:23 simonb Exp $       */
       3             : /*
       4             :  * Copyright (c) 2001 The NetBSD Foundation, Inc.
       5             :  * All rights reserved.
       6             :  *
       7             :  * This code is derived from software contributed to The NetBSD Foundation
       8             :  * by Ichiro FUKUHARA (ichiro@ichiro.org).
       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 NETBSD FOUNDATION, INC. AND CONTRIBUTORS
      20             :  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
      21             :  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
      22             :  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
      23             :  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
      24             :  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
      25             :  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
      26             :  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
      27             :  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
      28             :  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
      29             :  * POSSIBILITY OF SUCH DAMAGE.
      30             :  */
      31             : 
      32             : /*
      33             :  * Simple datasheet
      34             :  * http://www.prolific.com.tw/PDF/PL-2303%20Market%20Spec.pdf
      35             :  * http://www.hitachi-hitec.com/jyouhou/prolific/2303.pdf
      36             :  *      (english)
      37             :  *
      38             :  */
      39             : 
      40             : #include <sys/param.h>
      41             : #include <sys/systm.h>
      42             : #include <sys/kernel.h>
      43             : #include <sys/malloc.h>
      44             : #include <sys/ioctl.h>
      45             : #include <sys/conf.h>
      46             : #include <sys/tty.h>
      47             : #include <sys/selinfo.h>
      48             : #include <sys/device.h>
      49             : #include <sys/poll.h>
      50             : 
      51             : #include <dev/usb/usb.h>
      52             : #include <dev/usb/usbcdc.h>
      53             : 
      54             : #include <dev/usb/usbdi.h>
      55             : #include <dev/usb/usbdi_util.h>
      56             : #include <dev/usb/usbdevs.h>
      57             : 
      58             : #include <dev/usb/ucomvar.h>
      59             : 
      60             : #ifdef UPLCOM_DEBUG
      61             : #define DPRINTFN(n, x)  do { if (uplcomdebug > (n)) printf x; } while (0)
      62             : int     uplcomdebug = 0;
      63             : #else
      64             : #define DPRINTFN(n, x)
      65             : #endif
      66             : #define DPRINTF(x) DPRINTFN(0, x)
      67             : 
      68             : #define UPLCOM_IFACE_INDEX      0
      69             : #define UPLCOM_SECOND_IFACE_INDEX       1
      70             : 
      71             : #define UPLCOM_SET_REQUEST      0x01
      72             : #define UPLCOM_SET_CRTSCTS      0x41
      73             : #define UPLCOM_HX_SET_CRTSCTS   0x61
      74             : #define RSAQ_STATUS_CTS         0x80
      75             : #define RSAQ_STATUS_DSR         0x02
      76             : #define RSAQ_STATUS_DCD         0x01
      77             : 
      78             : struct  uplcom_softc {
      79             :         struct device            sc_dev;        /* base device */
      80             :         struct usbd_device      *sc_udev;       /* USB device */
      81             :         struct usbd_interface   *sc_iface;      /* interface */
      82             :         int                      sc_iface_number;       /* interface number */
      83             : 
      84             :         struct usbd_interface   *sc_intr_iface; /* interrupt interface */
      85             :         int                      sc_intr_number;        /* interrupt number */
      86             :         struct usbd_pipe        *sc_intr_pipe;  /* interrupt pipe */
      87             :         u_char                  *sc_intr_buf;   /* interrupt buffer */
      88             :         int                      sc_isize;
      89             : 
      90             :         struct usb_cdc_line_state sc_line_state;/* current line state */
      91             :         int                      sc_dtr;        /* current DTR state */
      92             :         int                      sc_rts;        /* current RTS state */
      93             : 
      94             :         struct device           *sc_subdev;     /* ucom device */
      95             : 
      96             :         u_char                   sc_lsr;        /* Local status register */
      97             :         u_char                   sc_msr;        /* uplcom status register */
      98             :         int                      sc_type_hx;    /* HX variant */
      99             : };
     100             : 
     101             : /*
     102             :  * These are the maximum number of bytes transferred per frame.
     103             :  * The output buffer size cannot be increased due to the size encoding.
     104             :  */
     105             : #define UPLCOMIBUFSIZE 256
     106             : #define UPLCOMOBUFSIZE 256
     107             : 
     108             : usbd_status uplcom_reset(struct uplcom_softc *);
     109             : usbd_status uplcom_set_line_coding(struct uplcom_softc *sc,
     110             :     struct usb_cdc_line_state *state);
     111             : usbd_status uplcom_set_crtscts(struct uplcom_softc *);
     112             : void uplcom_intr(struct usbd_xfer *, void *, usbd_status);
     113             : 
     114             : void uplcom_set(void *, int, int, int);
     115             : void uplcom_dtr(struct uplcom_softc *, int);
     116             : void uplcom_rts(struct uplcom_softc *, int);
     117             : void uplcom_break(struct uplcom_softc *, int);
     118             : void uplcom_set_line_state(struct uplcom_softc *);
     119             : void uplcom_get_status(void *, int portno, u_char *lsr, u_char *msr);
     120             : int  uplcom_param(void *, int, struct termios *);
     121             : int  uplcom_open(void *, int);
     122             : void uplcom_close(void *, int);
     123             : 
     124             : struct  ucom_methods uplcom_methods = {
     125             :         uplcom_get_status,
     126             :         uplcom_set,
     127             :         uplcom_param,
     128             :         NULL,
     129             :         uplcom_open,
     130             :         uplcom_close,
     131             :         NULL,
     132             :         NULL,
     133             : };
     134             : 
     135             : static const struct usb_devno uplcom_devs[] = {
     136             :         { USB_VENDOR_ALCATEL, USB_PRODUCT_ALCATEL_OT535 },
     137             :         { USB_VENDOR_ANCHOR, USB_PRODUCT_ANCHOR_SERIAL },
     138             :         { USB_VENDOR_ATEN, USB_PRODUCT_ATEN_UC232A },
     139             :         { USB_VENDOR_BELKIN, USB_PRODUCT_BELKIN_F5U257 },
     140             :         { USB_VENDOR_ELECOM, USB_PRODUCT_ELECOM_UCSGT },
     141             :         { USB_VENDOR_ELECOM, USB_PRODUCT_ELECOM_UCSGT0 },
     142             :         { USB_VENDOR_HAL, USB_PRODUCT_HAL_IMR001 },
     143             :         { USB_VENDOR_HP, USB_PRODUCT_HP_LD220 },
     144             :         { USB_VENDOR_IODATA, USB_PRODUCT_IODATA_USBRSAQ },
     145             :         { USB_VENDOR_IODATA, USB_PRODUCT_IODATA_USBRSAQ5 },
     146             :         { USB_VENDOR_LEADTEK, USB_PRODUCT_LEADTEK_9531 },
     147             :         { USB_VENDOR_MICROSOFT, USB_PRODUCT_MICROSOFT_700WX },
     148             :         { USB_VENDOR_MOBILEACTION, USB_PRODUCT_MOBILEACTION_MA620 },
     149             :         { USB_VENDOR_NOKIA, USB_PRODUCT_NOKIA_CA42 },
     150             :         { USB_VENDOR_OTI, USB_PRODUCT_OTI_DKU5 },
     151             :         { USB_VENDOR_PLX, USB_PRODUCT_PLX_CA42 },
     152             :         { USB_VENDOR_PANASONIC, USB_PRODUCT_PANASONIC_TYTP50P6S },
     153             :         { USB_VENDOR_PROLIFIC, USB_PRODUCT_PROLIFIC_PL2303 },
     154             :         { USB_VENDOR_PROLIFIC, USB_PRODUCT_PROLIFIC_PL2303X },
     155             :         { USB_VENDOR_PROLIFIC, USB_PRODUCT_PROLIFIC_PL2303X2 },
     156             :         { USB_VENDOR_PROLIFIC, USB_PRODUCT_PROLIFIC_RSAQ2 },
     157             :         { USB_VENDOR_PROLIFIC, USB_PRODUCT_PROLIFIC_PL2303BENQ },
     158             :         { USB_VENDOR_PROLIFIC2, USB_PRODUCT_PROLIFIC2_PL2303 },
     159             :         { USB_VENDOR_RADIOSHACK, USB_PRODUCT_RADIOSHACK_PL2303 },
     160             :         { USB_VENDOR_RATOC, USB_PRODUCT_RATOC_REXUSB60 },
     161             :         { USB_VENDOR_SAGEM, USB_PRODUCT_SAGEM_SERIAL },
     162             :         { USB_VENDOR_SIEMENS3, USB_PRODUCT_SIEMENS3_SX1 },
     163             :         { USB_VENDOR_SIEMENS3, USB_PRODUCT_SIEMENS3_X65 },
     164             :         { USB_VENDOR_SIEMENS3, USB_PRODUCT_SIEMENS3_X75 },
     165             :         { USB_VENDOR_SITECOM, USB_PRODUCT_SITECOM_CN104 },
     166             :         { USB_VENDOR_SOURCENEXT, USB_PRODUCT_SOURCENEXT_KEIKAI8 },
     167             :         { USB_VENDOR_SOURCENEXT, USB_PRODUCT_SOURCENEXT_KEIKAI8_CHG },
     168             :         { USB_VENDOR_SPEEDDRAGON, USB_PRODUCT_SPEEDDRAGON_MS3303H },
     169             :         { USB_VENDOR_SUSTEEN, USB_PRODUCT_SUSTEEN_DCU11 },
     170             :         { USB_VENDOR_SYNTECH, USB_PRODUCT_SYNTECH_SERIAL },
     171             :         { USB_VENDOR_TDK, USB_PRODUCT_TDK_UHA6400 },
     172             :         { USB_VENDOR_TDK, USB_PRODUCT_TDK_UPA9664 },
     173             :         { USB_VENDOR_TRIPPLITE, USB_PRODUCT_TRIPPLITE_U209 },
     174             :         { USB_VENDOR_SMART, USB_PRODUCT_SMART_PL2303 },
     175             :         { USB_VENDOR_YCCABLE, USB_PRODUCT_YCCABLE_PL2303 }
     176             : };
     177             : #define uplcom_lookup(v, p) usb_lookup(uplcom_devs, v, p)
     178             : 
     179             : int uplcom_match(struct device *, void *, void *);
     180             : void uplcom_attach(struct device *, struct device *, void *);
     181             : int uplcom_detach(struct device *, int);
     182             : 
     183             : struct cfdriver uplcom_cd = {
     184             :         NULL, "uplcom", DV_DULL
     185             : };
     186             : 
     187             : const struct cfattach uplcom_ca = {
     188             :         sizeof(struct uplcom_softc), uplcom_match, uplcom_attach, uplcom_detach
     189             : };
     190             : 
     191             : int
     192           0 : uplcom_match(struct device *parent, void *match, void *aux)
     193             : {
     194           0 :         struct usb_attach_arg *uaa = aux;
     195             : 
     196           0 :         if (uaa->iface == NULL)
     197           0 :                 return (UMATCH_NONE);
     198             : 
     199           0 :         return (uplcom_lookup(uaa->vendor, uaa->product) != NULL ?
     200             :                 UMATCH_VENDOR_PRODUCT : UMATCH_NONE);
     201           0 : }
     202             : 
     203             : void
     204           0 : uplcom_attach(struct device *parent, struct device *self, void *aux)
     205             : {
     206           0 :         struct uplcom_softc *sc = (struct uplcom_softc *)self;
     207           0 :         struct usb_attach_arg *uaa = aux;
     208           0 :         struct usbd_device *dev = uaa->device;
     209             :         usb_config_descriptor_t *cdesc;
     210             :         usb_device_descriptor_t *ddesc;
     211             :         usb_interface_descriptor_t *id;
     212             :         usb_endpoint_descriptor_t *ed;
     213           0 :         char *devname = sc->sc_dev.dv_xname;
     214             :         usbd_status err;
     215             :         int i;
     216           0 :         struct ucom_attach_args uca;
     217             : 
     218           0 :         sc->sc_udev = dev;
     219             : 
     220             :         DPRINTF(("\n\nuplcom attach: sc=%p\n", sc));
     221             : 
     222             :         /* initialize endpoints */
     223           0 :         uca.bulkin = uca.bulkout = -1;
     224           0 :         sc->sc_intr_number = -1;
     225           0 :         sc->sc_intr_pipe = NULL;
     226             : 
     227             :         /* get the config descriptor */
     228           0 :         cdesc = usbd_get_config_descriptor(sc->sc_udev);
     229             : 
     230           0 :         if (cdesc == NULL) {
     231           0 :                 printf("%s: failed to get configuration descriptor\n",
     232             :                         sc->sc_dev.dv_xname);
     233           0 :                 usbd_deactivate(sc->sc_udev);
     234           0 :                 return;
     235             :         }
     236             : 
     237             :         /* get the device descriptor */
     238           0 :         ddesc = usbd_get_device_descriptor(sc->sc_udev);
     239           0 :         if (ddesc == NULL) {
     240           0 :                 printf("%s: failed to get device descriptor\n",
     241             :                     sc->sc_dev.dv_xname);
     242           0 :                 usbd_deactivate(sc->sc_udev);
     243           0 :                 return;
     244             :         }
     245             : 
     246             :         /*
     247             :          * The Linux driver suggest this will only be true for the HX
     248             :          * variants. The datasheets disagree.
     249             :          */
     250           0 :         if (ddesc->bDeviceClass == 0x02)
     251           0 :                 sc->sc_type_hx = 0;
     252           0 :         else if (ddesc->bMaxPacketSize == 0x40)
     253           0 :                 sc->sc_type_hx = 1;
     254             :         else
     255           0 :                 sc->sc_type_hx = 0;
     256             : 
     257             : #ifdef USB_DEBUG
     258             :         /* print the chip type */
     259             :         if (sc->sc_type_hx) {
     260             :                 DPRINTF(("uplcom_attach: chiptype 2303X\n"));
     261             :         } else {
     262             :                 DPRINTF(("uplcom_attach: chiptype 2303\n"));
     263             :         }
     264             : #endif
     265             :         /* get the (first/common) interface */
     266           0 :         err = usbd_device2interface_handle(dev, UPLCOM_IFACE_INDEX,
     267           0 :                                                         &sc->sc_iface);
     268           0 :         if (err) {
     269           0 :                 printf("\n%s: failed to get interface, err=%s\n",
     270           0 :                         devname, usbd_errstr(err));
     271           0 :                 usbd_deactivate(sc->sc_udev);
     272           0 :                 return;
     273             :         }
     274             : 
     275             :         /* Find the interrupt endpoints */
     276             : 
     277           0 :         id = usbd_get_interface_descriptor(sc->sc_iface);
     278           0 :         sc->sc_iface_number = id->bInterfaceNumber;
     279             : 
     280           0 :         for (i = 0; i < id->bNumEndpoints; i++) {
     281           0 :                 ed = usbd_interface2endpoint_descriptor(sc->sc_iface, i);
     282           0 :                 if (ed == NULL) {
     283           0 :                         printf("%s: no endpoint descriptor for %d\n",
     284             :                                 sc->sc_dev.dv_xname, i);
     285           0 :                         usbd_deactivate(sc->sc_udev);
     286           0 :                         return;
     287             :                 }
     288             : 
     289           0 :                 if (UE_GET_DIR(ed->bEndpointAddress) == UE_DIR_IN &&
     290           0 :                     UE_GET_XFERTYPE(ed->bmAttributes) == UE_INTERRUPT) {
     291           0 :                         sc->sc_intr_number = ed->bEndpointAddress;
     292           0 :                         sc->sc_isize = UGETW(ed->wMaxPacketSize);
     293           0 :                 }
     294             :         }
     295             : 
     296           0 :         if (sc->sc_intr_number== -1) {
     297           0 :                 printf("%s: Could not find interrupt in\n",
     298             :                         sc->sc_dev.dv_xname);
     299           0 :                 usbd_deactivate(sc->sc_udev);
     300           0 :                 return;
     301             :         }
     302             : 
     303             :         /* keep interface for interrupt */
     304           0 :         sc->sc_intr_iface = sc->sc_iface;
     305             : 
     306             :         /*
     307             :          * USB-RSAQ1 has two interface
     308             :          *
     309             :          *  USB-RSAQ1       | USB-RSAQ2
     310             :          * -----------------+-----------------
     311             :          * Interface 0      |Interface 0
     312             :          *  Interrupt(0x81) | Interrupt(0x81)
     313             :          * -----------------+ BulkIN(0x02)
     314             :          * Interface 1      | BulkOUT(0x83)
     315             :          *   BulkIN(0x02)   |
     316             :          *   BulkOUT(0x83)  |
     317             :          */
     318           0 :         if (cdesc->bNumInterface == 2) {
     319           0 :                 err = usbd_device2interface_handle(dev,
     320             :                                 UPLCOM_SECOND_IFACE_INDEX, &sc->sc_iface);
     321           0 :                 if (err) {
     322           0 :                         printf("\n%s: failed to get second interface, err=%s\n",
     323           0 :                             devname, usbd_errstr(err));
     324           0 :                         usbd_deactivate(sc->sc_udev);
     325           0 :                         return;
     326             :                 }
     327             :         }
     328             : 
     329             :         /* Find the bulk{in,out} endpoints */
     330             : 
     331           0 :         id = usbd_get_interface_descriptor(sc->sc_iface);
     332           0 :         sc->sc_iface_number = id->bInterfaceNumber;
     333             : 
     334           0 :         for (i = 0; i < id->bNumEndpoints; i++) {
     335           0 :                 ed = usbd_interface2endpoint_descriptor(sc->sc_iface, i);
     336           0 :                 if (ed == NULL) {
     337           0 :                         printf("%s: no endpoint descriptor for %d\n",
     338             :                                 sc->sc_dev.dv_xname, i);
     339           0 :                         usbd_deactivate(sc->sc_udev);
     340           0 :                         return;
     341             :                 }
     342             : 
     343           0 :                 if (UE_GET_DIR(ed->bEndpointAddress) == UE_DIR_IN &&
     344           0 :                     UE_GET_XFERTYPE(ed->bmAttributes) == UE_BULK) {
     345           0 :                         uca.bulkin = ed->bEndpointAddress;
     346           0 :                 } else if (UE_GET_DIR(ed->bEndpointAddress) == UE_DIR_OUT &&
     347           0 :                     UE_GET_XFERTYPE(ed->bmAttributes) == UE_BULK) {
     348           0 :                         uca.bulkout = ed->bEndpointAddress;
     349           0 :                 }
     350             :         }
     351             : 
     352           0 :         if (uca.bulkin == -1) {
     353           0 :                 printf("%s: Could not find data bulk in\n",
     354             :                         sc->sc_dev.dv_xname);
     355           0 :                 usbd_deactivate(sc->sc_udev);
     356           0 :                 return;
     357             :         }
     358             : 
     359           0 :         if (uca.bulkout == -1) {
     360           0 :                 printf("%s: Could not find data bulk out\n",
     361             :                         sc->sc_dev.dv_xname);
     362           0 :                 usbd_deactivate(sc->sc_udev);
     363           0 :                 return;
     364             :         }
     365             : 
     366           0 :         sc->sc_dtr = sc->sc_rts = -1;
     367           0 :         uca.portno = UCOM_UNK_PORTNO;
     368             :         /* bulkin, bulkout set above */
     369           0 :         uca.ibufsize = UPLCOMIBUFSIZE;
     370           0 :         uca.obufsize = UPLCOMOBUFSIZE;
     371           0 :         uca.ibufsizepad = UPLCOMIBUFSIZE;
     372           0 :         uca.opkthdrlen = 0;
     373           0 :         uca.device = dev;
     374           0 :         uca.iface = sc->sc_iface;
     375           0 :         uca.methods = &uplcom_methods;
     376           0 :         uca.arg = sc;
     377           0 :         uca.info = NULL;
     378             : 
     379           0 :         err = uplcom_reset(sc);
     380             : 
     381           0 :         if (err) {
     382           0 :                 printf("%s: reset failed, %s\n", sc->sc_dev.dv_xname,
     383           0 :                         usbd_errstr(err));
     384           0 :                 usbd_deactivate(sc->sc_udev);
     385           0 :                 return;
     386             :         }
     387             : 
     388             :         DPRINTF(("uplcom: in=0x%x out=0x%x intr=0x%x\n",
     389             :                         uca.bulkin, uca.bulkout, sc->sc_intr_number ));
     390           0 :         sc->sc_subdev = config_found_sm(self, &uca, ucomprint, ucomsubmatch);
     391           0 : }
     392             : 
     393             : int
     394           0 : uplcom_detach(struct device *self, int flags)
     395             : {
     396           0 :         struct uplcom_softc *sc = (struct uplcom_softc *)self;
     397             :         int rv = 0;
     398             : 
     399             :         DPRINTF(("uplcom_detach: sc=%p flags=%d\n", sc, flags));
     400             : 
     401           0 :         if (sc->sc_intr_pipe != NULL) {
     402           0 :                 usbd_abort_pipe(sc->sc_intr_pipe);
     403           0 :                 usbd_close_pipe(sc->sc_intr_pipe);
     404           0 :                 free(sc->sc_intr_buf, M_USBDEV, sc->sc_isize);
     405           0 :                 sc->sc_intr_pipe = NULL;
     406           0 :         }
     407             : 
     408           0 :         if (sc->sc_subdev != NULL) {
     409           0 :                 rv = config_detach(sc->sc_subdev, flags);
     410           0 :                 sc->sc_subdev = NULL;
     411           0 :         }
     412             : 
     413           0 :         return (rv);
     414             : }
     415             : 
     416             : usbd_status
     417           0 : uplcom_reset(struct uplcom_softc *sc)
     418             : {
     419           0 :         usb_device_request_t req;
     420             :         usbd_status err;
     421             : 
     422           0 :         req.bmRequestType = UT_WRITE_VENDOR_DEVICE;
     423           0 :         req.bRequest = UPLCOM_SET_REQUEST;
     424           0 :         USETW(req.wValue, 0);
     425           0 :         USETW(req.wIndex, sc->sc_iface_number);
     426           0 :         USETW(req.wLength, 0);
     427             : 
     428           0 :         err = usbd_do_request(sc->sc_udev, &req, 0);
     429           0 :         if (err)
     430           0 :                 return (EIO);
     431             : 
     432           0 :         return (0);
     433           0 : }
     434             : 
     435             : void
     436           0 : uplcom_set_line_state(struct uplcom_softc *sc)
     437             : {
     438           0 :         usb_device_request_t req;
     439             :         int ls;
     440             : 
     441             :         /* Make sure we have initialized state for sc_dtr and sc_rts */
     442           0 :         if (sc->sc_dtr == -1)
     443           0 :                 sc->sc_dtr = 0;
     444           0 :         if (sc->sc_rts == -1)
     445           0 :                 sc->sc_rts = 0;
     446             : 
     447           0 :         ls = (sc->sc_dtr ? UCDC_LINE_DTR : 0) |
     448           0 :             (sc->sc_rts ? UCDC_LINE_RTS : 0);
     449             : 
     450           0 :         req.bmRequestType = UT_WRITE_CLASS_INTERFACE;
     451           0 :         req.bRequest = UCDC_SET_CONTROL_LINE_STATE;
     452           0 :         USETW(req.wValue, ls);
     453           0 :         USETW(req.wIndex, sc->sc_iface_number);
     454           0 :         USETW(req.wLength, 0);
     455             : 
     456           0 :         (void)usbd_do_request(sc->sc_udev, &req, 0);
     457             : 
     458           0 : }
     459             : 
     460             : void
     461           0 : uplcom_set(void *addr, int portno, int reg, int onoff)
     462             : {
     463           0 :         struct uplcom_softc *sc = addr;
     464             : 
     465           0 :         switch (reg) {
     466             :         case UCOM_SET_DTR:
     467           0 :                 uplcom_dtr(sc, onoff);
     468           0 :                 break;
     469             :         case UCOM_SET_RTS:
     470           0 :                 uplcom_rts(sc, onoff);
     471           0 :                 break;
     472             :         case UCOM_SET_BREAK:
     473           0 :                 uplcom_break(sc, onoff);
     474           0 :                 break;
     475             :         default:
     476             :                 break;
     477             :         }
     478           0 : }
     479             : 
     480             : void
     481           0 : uplcom_dtr(struct uplcom_softc *sc, int onoff)
     482             : {
     483             : 
     484             :         DPRINTF(("uplcom_dtr: onoff=%d\n", onoff));
     485             : 
     486           0 :         if (sc->sc_dtr != -1 && !sc->sc_dtr == !onoff)
     487             :                 return;
     488             : 
     489           0 :         sc->sc_dtr = !!onoff;
     490             : 
     491           0 :         uplcom_set_line_state(sc);
     492           0 : }
     493             : 
     494             : void
     495           0 : uplcom_rts(struct uplcom_softc *sc, int onoff)
     496             : {
     497             :         DPRINTF(("uplcom_rts: onoff=%d\n", onoff));
     498             : 
     499           0 :         if (sc->sc_rts == -1 && !sc->sc_rts == !onoff)
     500             :                 return;
     501             : 
     502           0 :         sc->sc_rts = !!onoff;
     503             : 
     504           0 :         uplcom_set_line_state(sc);
     505           0 : }
     506             : 
     507             : void
     508           0 : uplcom_break(struct uplcom_softc *sc, int onoff)
     509             : {
     510           0 :         usb_device_request_t req;
     511             : 
     512             :         DPRINTF(("uplcom_break: onoff=%d\n", onoff));
     513             : 
     514           0 :         req.bmRequestType = UT_WRITE_CLASS_INTERFACE;
     515           0 :         req.bRequest = UCDC_SEND_BREAK;
     516           0 :         USETW(req.wValue, onoff ? UCDC_BREAK_ON : UCDC_BREAK_OFF);
     517           0 :         USETW(req.wIndex, sc->sc_iface_number);
     518           0 :         USETW(req.wLength, 0);
     519             : 
     520           0 :         (void)usbd_do_request(sc->sc_udev, &req, 0);
     521           0 : }
     522             : 
     523             : usbd_status
     524           0 : uplcom_set_crtscts(struct uplcom_softc *sc)
     525             : {
     526           0 :         usb_device_request_t req;
     527             :         usbd_status err;
     528             : 
     529             :         DPRINTF(("uplcom_set_crtscts: on\n"));
     530             : 
     531           0 :         req.bmRequestType = UT_WRITE_VENDOR_DEVICE;
     532           0 :         req.bRequest = UPLCOM_SET_REQUEST;
     533           0 :         USETW(req.wValue, 0);
     534           0 :         USETW(req.wIndex,
     535             :             (sc->sc_type_hx ? UPLCOM_HX_SET_CRTSCTS : UPLCOM_SET_CRTSCTS));
     536           0 :         USETW(req.wLength, 0);
     537             : 
     538           0 :         err = usbd_do_request(sc->sc_udev, &req, 0);
     539           0 :         if (err) {
     540             :                 DPRINTF(("uplcom_set_crtscts: failed, err=%s\n",
     541             :                         usbd_errstr(err)));
     542           0 :                 return (err);
     543             :         }
     544             : 
     545           0 :         return (USBD_NORMAL_COMPLETION);
     546           0 : }
     547             : 
     548             : usbd_status
     549           0 : uplcom_set_line_coding(struct uplcom_softc *sc,
     550             :     struct usb_cdc_line_state *state)
     551             : {
     552           0 :         usb_device_request_t req;
     553             :         usbd_status err;
     554             : 
     555             :         DPRINTF(("uplcom_set_line_coding: rate=%d fmt=%d parity=%d bits=%d\n",
     556             :                 UGETDW(state->dwDTERate), state->bCharFormat,
     557             :                 state->bParityType, state->bDataBits));
     558             : 
     559           0 :         if (memcmp(state, &sc->sc_line_state, UCDC_LINE_STATE_LENGTH) == 0) {
     560             :                 DPRINTF(("uplcom_set_line_coding: already set\n"));
     561           0 :                 return (USBD_NORMAL_COMPLETION);
     562             :         }
     563             : 
     564           0 :         req.bmRequestType = UT_WRITE_CLASS_INTERFACE;
     565           0 :         req.bRequest = UCDC_SET_LINE_CODING;
     566           0 :         USETW(req.wValue, 0);
     567           0 :         USETW(req.wIndex, sc->sc_iface_number);
     568           0 :         USETW(req.wLength, UCDC_LINE_STATE_LENGTH);
     569             : 
     570           0 :         err = usbd_do_request(sc->sc_udev, &req, state);
     571           0 :         if (err) {
     572             :                 DPRINTF(("uplcom_set_line_coding: failed, err=%s\n",
     573             :                         usbd_errstr(err)));
     574           0 :                 return (err);
     575             :         }
     576             : 
     577           0 :         sc->sc_line_state = *state;
     578             : 
     579           0 :         return (USBD_NORMAL_COMPLETION);
     580           0 : }
     581             : 
     582             : int
     583           0 : uplcom_param(void *addr, int portno, struct termios *t)
     584             : {
     585           0 :         struct uplcom_softc *sc = addr;
     586             :         usbd_status err;
     587           0 :         struct usb_cdc_line_state ls;
     588             : 
     589             :         DPRINTF(("uplcom_param: sc=%p\n", sc));
     590             : 
     591           0 :         USETDW(ls.dwDTERate, t->c_ospeed);
     592           0 :         if (ISSET(t->c_cflag, CSTOPB))
     593           0 :                 ls.bCharFormat = UCDC_STOP_BIT_2;
     594             :         else
     595           0 :                 ls.bCharFormat = UCDC_STOP_BIT_1;
     596           0 :         if (ISSET(t->c_cflag, PARENB)) {
     597           0 :                 if (ISSET(t->c_cflag, PARODD))
     598           0 :                         ls.bParityType = UCDC_PARITY_ODD;
     599             :                 else
     600           0 :                         ls.bParityType = UCDC_PARITY_EVEN;
     601             :         } else
     602           0 :                 ls.bParityType = UCDC_PARITY_NONE;
     603           0 :         switch (ISSET(t->c_cflag, CSIZE)) {
     604             :         case CS5:
     605           0 :                 ls.bDataBits = 5;
     606           0 :                 break;
     607             :         case CS6:
     608           0 :                 ls.bDataBits = 6;
     609           0 :                 break;
     610             :         case CS7:
     611           0 :                 ls.bDataBits = 7;
     612           0 :                 break;
     613             :         case CS8:
     614           0 :                 ls.bDataBits = 8;
     615           0 :                 break;
     616             :         }
     617             : 
     618           0 :         err = uplcom_set_line_coding(sc, &ls);
     619           0 :         if (err) {
     620             :                 DPRINTF(("uplcom_param: err=%s\n", usbd_errstr(err)));
     621           0 :                 return (EIO);
     622             :         }
     623             : 
     624           0 :         if (ISSET(t->c_cflag, CRTSCTS))
     625           0 :                 uplcom_set_crtscts(sc);
     626             : 
     627           0 :         if (sc->sc_rts == -1 || sc->sc_dtr == -1)
     628           0 :                 uplcom_set_line_state(sc);
     629             : 
     630           0 :         if (err) {
     631             :                 DPRINTF(("uplcom_param: err=%s\n", usbd_errstr(err)));
     632           0 :                 return (EIO);
     633             :         }
     634             : 
     635           0 :         return (0);
     636           0 : }
     637             : 
     638             : int
     639           0 : uplcom_open(void *addr, int portno)
     640             : {
     641           0 :         struct uplcom_softc *sc = addr;
     642           0 :         usb_device_request_t req;
     643             :         usbd_status uerr;
     644             :         int err;
     645             : 
     646           0 :         if (usbd_is_dying(sc->sc_udev))
     647           0 :                 return (EIO);
     648             : 
     649             :         DPRINTF(("uplcom_open: sc=%p\n", sc));
     650             : 
     651           0 :         if (sc->sc_intr_number != -1 && sc->sc_intr_pipe == NULL) {
     652           0 :                 sc->sc_intr_buf = malloc(sc->sc_isize, M_USBDEV, M_WAITOK);
     653           0 :                 err = usbd_open_pipe_intr(sc->sc_intr_iface, sc->sc_intr_number,
     654             :                         USBD_SHORT_XFER_OK, &sc->sc_intr_pipe, sc,
     655           0 :                         sc->sc_intr_buf, sc->sc_isize,
     656             :                         uplcom_intr, USBD_DEFAULT_INTERVAL);
     657           0 :                 if (err) {
     658             :                         DPRINTF(("%s: cannot open interrupt pipe (addr %d)\n",
     659             :                                 sc->sc_dev.dv_xname, sc->sc_intr_number));
     660           0 :                                         return (EIO);
     661             :                 }
     662             :         }
     663             : 
     664           0 :         if (sc->sc_type_hx == 1) {
     665             :                 /*
     666             :                  * Undocumented (vendor unresponsive) - possibly changes
     667             :                  * flow control semantics. It is needed for HX variant devices.
     668             :                  */
     669           0 :                 req.bmRequestType = UT_WRITE_VENDOR_DEVICE;
     670           0 :                 req.bRequest = UPLCOM_SET_REQUEST;
     671           0 :                 USETW(req.wValue, 2);
     672           0 :                 USETW(req.wIndex, 0x44);
     673           0 :                 USETW(req.wLength, 0);
     674             : 
     675           0 :                 uerr = usbd_do_request(sc->sc_udev, &req, 0);
     676           0 :                 if (uerr)
     677           0 :                         return (EIO);
     678             : 
     679             :                 /* Reset upstream data pipes */
     680           0 :                 req.bmRequestType = UT_WRITE_VENDOR_DEVICE;
     681           0 :                 req.bRequest = UPLCOM_SET_REQUEST;
     682           0 :                 USETW(req.wValue, 8);
     683           0 :                 USETW(req.wIndex, 0);
     684           0 :                 USETW(req.wLength, 0);
     685             : 
     686           0 :                 uerr = usbd_do_request(sc->sc_udev, &req, 0);
     687           0 :                 if (uerr)
     688           0 :                         return (EIO);
     689             : 
     690           0 :                 req.bmRequestType = UT_WRITE_VENDOR_DEVICE;
     691           0 :                 req.bRequest = UPLCOM_SET_REQUEST;
     692           0 :                 USETW(req.wValue, 9);
     693           0 :                 USETW(req.wIndex, 0);
     694           0 :                 USETW(req.wLength, 0);
     695             : 
     696           0 :                 uerr = usbd_do_request(sc->sc_udev, &req, 0);
     697           0 :                 if (uerr)
     698           0 :                         return (EIO);
     699             :         }
     700             : 
     701           0 :         return (0);
     702           0 : }
     703             : 
     704             : void
     705           0 : uplcom_close(void *addr, int portno)
     706             : {
     707           0 :         struct uplcom_softc *sc = addr;
     708             :         int err;
     709             : 
     710           0 :         if (usbd_is_dying(sc->sc_udev))
     711           0 :                 return;
     712             : 
     713             :         DPRINTF(("uplcom_close: close\n"));
     714             : 
     715           0 :         if (sc->sc_intr_pipe != NULL) {
     716           0 :                 usbd_abort_pipe(sc->sc_intr_pipe);
     717           0 :                 err = usbd_close_pipe(sc->sc_intr_pipe);
     718           0 :                 if (err)
     719           0 :                         printf("%s: close interrupt pipe failed: %s\n",
     720           0 :                                 sc->sc_dev.dv_xname, usbd_errstr(err));
     721           0 :                 free(sc->sc_intr_buf, M_USBDEV, sc->sc_isize);
     722           0 :                 sc->sc_intr_pipe = NULL;
     723           0 :         }
     724           0 : }
     725             : 
     726             : void
     727           0 : uplcom_intr(struct usbd_xfer *xfer, void *priv, usbd_status status)
     728             : {
     729           0 :         struct uplcom_softc *sc = priv;
     730           0 :         u_char *buf = sc->sc_intr_buf;
     731             :         u_char pstatus;
     732             : 
     733           0 :         if (usbd_is_dying(sc->sc_udev))
     734           0 :                 return;
     735             : 
     736           0 :         if (status != USBD_NORMAL_COMPLETION) {
     737           0 :                 if (status == USBD_NOT_STARTED || status == USBD_CANCELLED)
     738           0 :                         return;
     739             : 
     740             :                 DPRINTF(("%s: abnormal status: %s\n", sc->sc_dev.dv_xname,
     741             :                         usbd_errstr(status)));
     742           0 :                 usbd_clear_endpoint_stall_async(sc->sc_intr_pipe);
     743           0 :                 return;
     744             :         }
     745             : 
     746             :         DPRINTF(("%s: uplcom status = %02x\n", sc->sc_dev.dv_xname, buf[8]));
     747             : 
     748           0 :         sc->sc_lsr = sc->sc_msr = 0;
     749           0 :         pstatus = buf[8];
     750           0 :         if (ISSET(pstatus, RSAQ_STATUS_CTS))
     751           0 :                 sc->sc_msr |= UMSR_CTS;
     752             :         else
     753           0 :                 sc->sc_msr &= ~UMSR_CTS;
     754           0 :         if (ISSET(pstatus, RSAQ_STATUS_DSR))
     755           0 :                 sc->sc_msr |= UMSR_DSR;
     756             :         else
     757           0 :                 sc->sc_msr &= ~UMSR_DSR;
     758           0 :         if (ISSET(pstatus, RSAQ_STATUS_DCD))
     759           0 :                 sc->sc_msr |= UMSR_DCD;
     760             :         else
     761           0 :                 sc->sc_msr &= ~UMSR_DCD;
     762           0 :         ucom_status_change((struct ucom_softc *) sc->sc_subdev);
     763           0 : }
     764             : 
     765             : void
     766           0 : uplcom_get_status(void *addr, int portno, u_char *lsr, u_char *msr)
     767             : {
     768           0 :         struct uplcom_softc *sc = addr;
     769             : 
     770             :         DPRINTF(("uplcom_get_status:\n"));
     771             : 
     772           0 :         if (lsr != NULL)
     773           0 :                 *lsr = sc->sc_lsr;
     774           0 :         if (msr != NULL)
     775           0 :                 *msr = sc->sc_msr;
     776           0 : }

Generated by: LCOV version 1.13