LCOV - code coverage report
Current view: top level - dev/usb - uticom.c (source / functions) Hit Total Coverage
Test: 6.4 Lines: 0 410 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: uticom.c,v 1.33 2018/03/15 00:42:41 kevlo Exp $       */
       2             : /*
       3             :  * Copyright (c) 2005 Dmitry Komissaroff <dxi@mail.ru>.
       4             :  *
       5             :  * Redistribution and use in source and binary forms, with or without
       6             :  * modification, are permitted provided that the following conditions
       7             :  * are met:
       8             :  * 1. Redistributions of source code must retain the above copyright
       9             :  *    notice, this list of conditions and the following disclaimer.
      10             :  * 2. Redistributions in binary form must reproduce the above copyright
      11             :  *    notice, this list of conditions and the following disclaimer in the
      12             :  *    documentation and/or other materials provided with the distribution.
      13             :  *
      14             :  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
      15             :  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
      16             :  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
      17             :  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
      18             :  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
      19             :  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
      20             :  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
      21             :  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
      22             :  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
      23             :  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
      24             :  * SUCH DAMAGE.
      25             :  */
      26             : 
      27             : #include <sys/param.h>
      28             : #include <sys/systm.h>
      29             : #include <sys/kernel.h>
      30             : #include <sys/device.h>
      31             : #include <sys/malloc.h>
      32             : #include <sys/conf.h>
      33             : #include <sys/tty.h>
      34             : 
      35             : #include <machine/bus.h>
      36             : 
      37             : #include <dev/usb/usb.h>
      38             : #include <dev/usb/usbdi.h>
      39             : #include <dev/usb/usbdivar.h>
      40             : #include <dev/usb/usbdi_util.h>
      41             : #include <dev/usb/usbdevs.h>
      42             : #include <dev/usb/usbcdc.h>
      43             : 
      44             : #include <dev/usb/ucomvar.h>
      45             : 
      46             : #ifdef UTICOM_DEBUG
      47             : static int uticomdebug = 0;
      48             : #define DPRINTFN(n, x)  do { if (uticomdebug > (n)) printf x; } while (0)
      49             : #else
      50             : #define DPRINTFN(n, x)
      51             : #endif
      52             : 
      53             : #define DPRINTF(x) DPRINTFN(0, x)
      54             : 
      55             : #define UTICOM_CONFIG_INDEX     1
      56             : #define UTICOM_ACTIVE_INDEX     2
      57             : 
      58             : #define UTICOM_IFACE_INDEX      0
      59             : 
      60             : /*
      61             :  * These are the maximum number of bytes transferred per frame.
      62             :  * The output buffer size cannot be increased due to the size encoding.
      63             :  */
      64             : #define UTICOM_IBUFSZ           64
      65             : #define UTICOM_OBUFSZ           64
      66             : 
      67             : #define UTICOM_FW_BUFSZ         16284
      68             : 
      69             : #define UTICOM_INTR_INTERVAL    100     /* ms */
      70             : 
      71             : #define UTICOM_RQ_LINE          0
      72             : /* Used to sync data0/1-toggle on reopen bulk pipe. */
      73             : #define UTICOM_RQ_SOF           1
      74             : #define UTICOM_RQ_SON           2
      75             : 
      76             : #define UTICOM_RQ_BAUD          3
      77             : #define UTICOM_RQ_LCR           4
      78             : #define UTICOM_RQ_FCR           5
      79             : #define UTICOM_RQ_RTS           6
      80             : #define UTICOM_RQ_DTR           7
      81             : #define UTICOM_RQ_BREAK         8
      82             : #define UTICOM_RQ_CRTSCTS       9
      83             : 
      84             : #define UTICOM_BRATE_REF        923077
      85             : 
      86             : #define UTICOM_SET_DATA_BITS(x) (x - 5)
      87             : 
      88             : #define UTICOM_STOP_BITS_1      0x00
      89             : #define UTICOM_STOP_BITS_2      0x40
      90             : 
      91             : #define UTICOM_PARITY_NONE      0x00
      92             : #define UTICOM_PARITY_ODD       0x08
      93             : #define UTICOM_PARITY_EVEN      0x18
      94             : 
      95             : #define UTICOM_LCR_OVR          0x1
      96             : #define UTICOM_LCR_PTE          0x2
      97             : #define UTICOM_LCR_FRE          0x4
      98             : #define UTICOM_LCR_BRK          0x8
      99             : 
     100             : #define UTICOM_MCR_CTS          0x1
     101             : #define UTICOM_MCR_DSR          0x2
     102             : #define UTICOM_MCR_CD           0x4
     103             : #define UTICOM_MCR_RI           0x8
     104             : 
     105             : /* Structures */
     106             : struct uticom_fw_header {
     107             :         uint16_t        length;
     108             :         uint8_t         checkSum;
     109             : } __packed;
     110             : 
     111             : struct uticom_buf {
     112             :         unsigned int            buf_size;
     113             :         char                    *buf_buf;
     114             :         char                    *buf_get;
     115             :         char                    *buf_put;
     116             : };
     117             : 
     118             : struct  uticom_softc {
     119             :         struct device            sc_dev;        /* base device */
     120             :         struct usbd_device      *sc_udev;       /* device */
     121             :         struct usbd_interface   *sc_iface;      /* interface */
     122             : 
     123             :         struct usbd_interface   *sc_intr_iface; /* interrupt interface */
     124             :         int                     sc_intr_number; /* interrupt number */
     125             :         struct usbd_pipe        *sc_intr_pipe;  /* interrupt pipe */
     126             :         u_char                  *sc_intr_buf;   /* interrupt buffer */
     127             :         int                     sc_isize;
     128             : 
     129             :         u_char                  sc_dtr;         /* current DTR state */
     130             :         u_char                  sc_rts;         /* current RTS state */
     131             :         u_char                  sc_status;
     132             : 
     133             :         u_char                  sc_lsr;         /* Local status register */
     134             :         u_char                  sc_msr;         /* uticom status register */
     135             : 
     136             :         struct device           *sc_subdev;
     137             : };
     138             : 
     139             : static  usbd_status uticom_reset(struct uticom_softc *);
     140             : static  usbd_status uticom_set_crtscts(struct uticom_softc *);
     141             : static  void uticom_intr(struct usbd_xfer *, void *, usbd_status);
     142             : 
     143             : static  void uticom_set(void *, int, int, int);
     144             : static  void uticom_dtr(struct uticom_softc *, int);
     145             : static  void uticom_rts(struct uticom_softc *, int);
     146             : static  void uticom_break(struct uticom_softc *, int);
     147             : static  void uticom_get_status(void *, int, u_char *, u_char *);
     148             : static  int  uticom_param(void *, int, struct termios *);
     149             : static  int  uticom_open(void *, int);
     150             : static  void uticom_close(void *, int);
     151             : 
     152             : void uticom_attach_hook(struct device *);
     153             : 
     154             : static int uticom_download_fw(struct uticom_softc *sc, int pipeno,
     155             :     struct usbd_device *dev);
     156             : 
     157             : struct ucom_methods uticom_methods = {
     158             :         uticom_get_status,
     159             :         uticom_set,
     160             :         uticom_param,
     161             :         NULL,
     162             :         uticom_open,
     163             :         uticom_close,
     164             :         NULL,
     165             :         NULL
     166             : };
     167             : 
     168             : int     uticom_match(struct device *, void *, void *);
     169             : void    uticom_attach(struct device *, struct device *, void *);
     170             : int     uticom_detach(struct device *, int);
     171             : 
     172             : struct cfdriver uticom_cd = {
     173             :         NULL, "uticom", DV_DULL
     174             : };
     175             : 
     176             : const struct cfattach uticom_ca = {
     177             :         sizeof(struct uticom_softc), uticom_match, uticom_attach, uticom_detach
     178             : };
     179             : 
     180             : static const struct usb_devno uticom_devs[] = {
     181             :         { USB_VENDOR_TI, USB_PRODUCT_TI_TUSB3410 },
     182             :         { USB_VENDOR_TI, USB_PRODUCT_TI_MSP430_JTAG },
     183             :         { USB_VENDOR_STARTECH, USB_PRODUCT_STARTECH_ICUSB232X },
     184             :         { USB_VENDOR_MOXA, USB_PRODUCT_MOXA_UPORT1110 },
     185             :         { USB_VENDOR_ABBOTT, USB_PRODUCT_ABBOTT_STEREO_PLUG }
     186             : };
     187             : 
     188             : int
     189           0 : uticom_match(struct device *parent, void *match, void *aux)
     190             : {
     191           0 :         struct usb_attach_arg *uaa = aux;
     192             : 
     193           0 :         if (uaa->iface != NULL)
     194           0 :                 return (UMATCH_NONE);
     195             : 
     196           0 :         return (usb_lookup(uticom_devs, uaa->vendor, uaa->product) != NULL ?
     197             :             UMATCH_VENDOR_PRODUCT : UMATCH_NONE);
     198           0 : }
     199             : 
     200             : void
     201           0 : uticom_attach(struct device *parent, struct device *self, void *aux)
     202             : {
     203           0 :         struct uticom_softc     *sc = (struct uticom_softc *)self;
     204           0 :         struct usb_attach_arg   *uaa = aux;
     205           0 :         struct usbd_device      *dev = uaa->device;
     206             : 
     207           0 :         sc->sc_udev = dev;
     208           0 :         sc->sc_iface = uaa->iface;
     209             : 
     210           0 :         config_mountroot(self, uticom_attach_hook);
     211           0 : }
     212             : 
     213             : void
     214           0 : uticom_attach_hook(struct device *self)
     215             : {
     216           0 :         struct uticom_softc             *sc = (struct uticom_softc *)self;
     217             :         usb_config_descriptor_t         *cdesc;
     218             :         usb_interface_descriptor_t      *id;
     219             :         usb_endpoint_descriptor_t       *ed;
     220             :         usbd_status                      err;
     221             :         int                              status, i;
     222             :         usb_device_descriptor_t         *dd;
     223           0 :         struct ucom_attach_args          uca;
     224             : 
     225             :         /* Initialize endpoints. */
     226           0 :         uca.bulkin = uca.bulkout = -1;
     227           0 :         sc->sc_intr_number = -1;
     228           0 :         sc->sc_intr_pipe = NULL;
     229             : 
     230           0 :         dd = usbd_get_device_descriptor(sc->sc_udev);
     231             :         DPRINTF(("%s: uticom_attach: num of configurations %d\n",
     232             :             sc->sc_dev.dv_xname, dd->bNumConfigurations));
     233             : 
     234             :         /* The device without firmware has single configuration with single
     235             :          * bulk out interface. */
     236           0 :         if (dd->bNumConfigurations > 1)
     237             :                 goto fwload_done;
     238             : 
     239             :         /* Loading firmware. */
     240             :         DPRINTF(("%s: uticom_attach: starting loading firmware\n",
     241             :             sc->sc_dev.dv_xname));
     242             : 
     243           0 :         err = usbd_set_config_index(sc->sc_udev, UTICOM_CONFIG_INDEX, 1);
     244           0 :         if (err) {
     245           0 :                 printf("%s: failed to set configuration: %s\n",
     246           0 :                     sc->sc_dev.dv_xname, usbd_errstr(err));
     247           0 :                 usbd_deactivate(sc->sc_udev);
     248           0 :                 return;
     249             :         }
     250             : 
     251             :         /* Get the config descriptor. */
     252           0 :         cdesc = usbd_get_config_descriptor(sc->sc_udev);
     253             : 
     254           0 :         if (cdesc == NULL) {
     255           0 :                 printf("%s: failed to get configuration descriptor\n",
     256           0 :                     sc->sc_dev.dv_xname);
     257           0 :                 usbd_deactivate(sc->sc_udev);
     258           0 :                 return;
     259             :         }
     260             : 
     261           0 :         err = usbd_device2interface_handle(sc->sc_udev, UTICOM_IFACE_INDEX,
     262           0 :             &sc->sc_iface);
     263           0 :         if (err) {
     264           0 :                 printf("%s: failed to get interface: %s\n",
     265           0 :                     sc->sc_dev.dv_xname, usbd_errstr(err));
     266           0 :                 usbd_deactivate(sc->sc_udev);
     267           0 :                 return;
     268             :         }
     269             : 
     270             :         /* Find the bulk out interface used to upload firmware. */
     271           0 :         id = usbd_get_interface_descriptor(sc->sc_iface);
     272             : 
     273           0 :         for (i = 0; i < id->bNumEndpoints; i++) {
     274           0 :                 ed = usbd_interface2endpoint_descriptor(sc->sc_iface, i);
     275           0 :                 if (ed == NULL) {
     276           0 :                         printf("%s: no endpoint descriptor for %d\n",
     277           0 :                             sc->sc_dev.dv_xname, i);
     278           0 :                         usbd_deactivate(sc->sc_udev);
     279           0 :                         return;
     280             :                 }
     281             : 
     282           0 :                 if (UE_GET_DIR(ed->bEndpointAddress) == UE_DIR_OUT &&
     283           0 :                     UE_GET_XFERTYPE(ed->bmAttributes) == UE_BULK) {
     284           0 :                         uca.bulkout = ed->bEndpointAddress;
     285             :                         DPRINTF(("%s: uticom_attach: data bulk out num: %d\n",
     286             :                             sc->sc_dev.dv_xname, ed->bEndpointAddress));
     287           0 :                 }
     288             : 
     289           0 :                 if (uca.bulkout == -1) {
     290           0 :                         printf("%s: could not find data bulk out\n",
     291           0 :                             sc->sc_dev.dv_xname);
     292           0 :                         usbd_deactivate(sc->sc_udev);
     293           0 :                         return;
     294             :                 }
     295             :         }
     296             : 
     297           0 :         status = uticom_download_fw(sc, uca.bulkout, sc->sc_udev);
     298             : 
     299           0 :         if (status) {
     300           0 :                 printf("%s: firmware download failed\n",
     301           0 :                     sc->sc_dev.dv_xname);
     302           0 :                 usbd_deactivate(sc->sc_udev);
     303           0 :                 return;
     304             :         } else {
     305             :                 DPRINTF(("%s: firmware download succeeded\n",
     306             :                     sc->sc_dev.dv_xname));
     307             :         }
     308             : 
     309           0 :         status = usbd_reload_device_desc(sc->sc_udev);
     310           0 :         if (status) {
     311           0 :                 printf("%s: error reloading device descriptor\n",
     312           0 :                     sc->sc_dev.dv_xname);
     313           0 :                 usbd_deactivate(sc->sc_udev);
     314           0 :                 return;
     315             :         }
     316             : 
     317             : fwload_done:
     318           0 :         dd = usbd_get_device_descriptor(sc->sc_udev);
     319             :         DPRINTF(("%s: uticom_attach: num of configurations %d\n",
     320             :             sc->sc_dev.dv_xname, dd->bNumConfigurations));
     321             : 
     322           0 :         err = usbd_set_config_index(sc->sc_udev, UTICOM_ACTIVE_INDEX, 1);
     323           0 :         if (err) {
     324           0 :                 printf("%s: failed to set configuration: %s\n",
     325           0 :                     sc->sc_dev.dv_xname, usbd_errstr(err));
     326           0 :                 usbd_deactivate(sc->sc_udev);
     327           0 :                 return;
     328             :         }
     329             : 
     330             :         /* Get the config descriptor. */
     331           0 :         cdesc = usbd_get_config_descriptor(sc->sc_udev);
     332           0 :         if (cdesc == NULL) {
     333           0 :                 printf("%s: failed to get configuration descriptor\n",
     334           0 :                     sc->sc_dev.dv_xname);
     335           0 :                 usbd_deactivate(sc->sc_udev);
     336           0 :                 return;
     337             :         }
     338             : 
     339             :         /* Get the interface (XXX: multiport chips are not supported yet). */
     340           0 :         err = usbd_device2interface_handle(sc->sc_udev, UTICOM_IFACE_INDEX,
     341           0 :             &sc->sc_iface);
     342           0 :         if (err) {
     343           0 :                 printf("%s: failed to get interface: %s\n",
     344           0 :                     sc->sc_dev.dv_xname, usbd_errstr(err));
     345           0 :                 usbd_deactivate(sc->sc_udev);
     346           0 :                 return;
     347             :         }
     348             : 
     349             :         /* Find the interrupt endpoints. */
     350           0 :         id = usbd_get_interface_descriptor(sc->sc_iface);
     351             : 
     352           0 :         for (i = 0; i < id->bNumEndpoints; i++) {
     353           0 :                 ed = usbd_interface2endpoint_descriptor(sc->sc_iface, i);
     354           0 :                 if (ed == NULL) {
     355           0 :                         printf("%s: no endpoint descriptor for %d\n",
     356           0 :                             sc->sc_dev.dv_xname, i);
     357           0 :                         usbd_deactivate(sc->sc_udev);
     358           0 :                         return;
     359             :                 }
     360             : 
     361           0 :                 if (UE_GET_DIR(ed->bEndpointAddress) == UE_DIR_IN &&
     362           0 :                     UE_GET_XFERTYPE(ed->bmAttributes) == UE_INTERRUPT) {
     363           0 :                         sc->sc_intr_number = ed->bEndpointAddress;
     364           0 :                         sc->sc_isize = UGETW(ed->wMaxPacketSize);
     365             : 
     366           0 :                 }
     367             :         }
     368             : 
     369           0 :         if (sc->sc_intr_number == -1) {
     370           0 :                 printf("%s: could not find interrupt in\n",
     371           0 :                     sc->sc_dev.dv_xname);
     372           0 :                 usbd_deactivate(sc->sc_udev);
     373           0 :                 return;
     374             :         }
     375             : 
     376             :         /* Keep interface for interrupt. */
     377           0 :         sc->sc_intr_iface = sc->sc_iface;
     378             : 
     379             :         /* Find the bulk{in,out} endpoints. */
     380           0 :         id = usbd_get_interface_descriptor(sc->sc_iface);
     381             : 
     382           0 :         for (i = 0; i < id->bNumEndpoints; i++) {
     383           0 :                 ed = usbd_interface2endpoint_descriptor(sc->sc_iface, i);
     384           0 :                 if (ed == NULL) {
     385           0 :                         printf("%s: no endpoint descriptor for %d\n",
     386           0 :                             sc->sc_dev.dv_xname, i);
     387           0 :                         usbd_deactivate(sc->sc_udev);
     388           0 :                         return;
     389             :                 }
     390             : 
     391           0 :                 if (UE_GET_DIR(ed->bEndpointAddress) == UE_DIR_IN &&
     392           0 :                     UE_GET_XFERTYPE(ed->bmAttributes) == UE_BULK) {
     393           0 :                         uca.bulkin = ed->bEndpointAddress;
     394           0 :                 } else if (UE_GET_DIR(ed->bEndpointAddress) == UE_DIR_OUT &&
     395           0 :                     UE_GET_XFERTYPE(ed->bmAttributes) == UE_BULK) {
     396           0 :                         uca.bulkout = ed->bEndpointAddress;
     397           0 :                 }
     398             :         }
     399             : 
     400           0 :         if (uca.bulkin == -1) {
     401           0 :                 printf("%s: could not find data bulk in\n",
     402           0 :                     sc->sc_dev.dv_xname);
     403           0 :                 usbd_deactivate(sc->sc_udev);
     404           0 :                 return;
     405             :         }
     406             : 
     407           0 :         if (uca.bulkout == -1) {
     408           0 :                 printf("%s: could not find data bulk out\n",
     409           0 :                     sc->sc_dev.dv_xname);
     410           0 :                 usbd_deactivate(sc->sc_udev);
     411           0 :                 return;
     412             :         }
     413             : 
     414           0 :         sc->sc_dtr = sc->sc_rts = -1;
     415             : 
     416           0 :         uca.portno = UCOM_UNK_PORTNO;
     417           0 :         uca.ibufsize = UTICOM_IBUFSZ;
     418           0 :         uca.obufsize = UTICOM_OBUFSZ;
     419           0 :         uca.ibufsizepad = UTICOM_IBUFSZ;
     420           0 :         uca.device = sc->sc_udev;
     421           0 :         uca.iface = sc->sc_iface;
     422           0 :         uca.opkthdrlen = 0;
     423           0 :         uca.methods = &uticom_methods;
     424           0 :         uca.arg = sc;
     425           0 :         uca.info = NULL;
     426             : 
     427           0 :         err = uticom_reset(sc);
     428           0 :         if (err) {
     429           0 :                 printf("%s: reset failed: %s\n",
     430           0 :                     sc->sc_dev.dv_xname, usbd_errstr(err));
     431           0 :                 usbd_deactivate(sc->sc_udev);
     432           0 :                 return;
     433             :         }
     434             : 
     435             :         DPRINTF(("%s: uticom_attach: in = 0x%x, out = 0x%x, intr = 0x%x\n",
     436             :             sc->sc_dev.dv_xname, uca.bulkin,
     437             :             uca.bulkout, sc->sc_intr_number));
     438             : 
     439           0 :         sc->sc_subdev = config_found_sm((struct device *)sc, &uca, ucomprint, ucomsubmatch);
     440           0 : }
     441             : 
     442             : int
     443           0 : uticom_detach(struct device *self, int flags)
     444             : {
     445           0 :         struct uticom_softc *sc = (struct uticom_softc *)self;
     446             : 
     447             :         DPRINTF(("%s: uticom_detach: sc = %p\n",
     448             :             sc->sc_dev.dv_xname, sc));
     449             : 
     450           0 :         if (sc->sc_subdev != NULL) {
     451           0 :                 config_detach(sc->sc_subdev, flags);
     452           0 :                 sc->sc_subdev = NULL;
     453           0 :         }
     454             : 
     455           0 :         if (sc->sc_intr_pipe != NULL) {
     456           0 :                 usbd_abort_pipe(sc->sc_intr_pipe);
     457           0 :                 usbd_close_pipe(sc->sc_intr_pipe);
     458           0 :                 free(sc->sc_intr_buf, M_USBDEV, sc->sc_isize);
     459           0 :                 sc->sc_intr_pipe = NULL;
     460           0 :         }
     461             : 
     462           0 :         return (0);
     463             : }
     464             : 
     465             : static usbd_status
     466           0 : uticom_reset(struct uticom_softc *sc)
     467             : {
     468           0 :         usb_device_request_t req;
     469             :         usbd_status err;
     470             : 
     471           0 :         req.bmRequestType = UT_WRITE_VENDOR_DEVICE;
     472           0 :         req.bRequest = UTICOM_RQ_SON;
     473           0 :         USETW(req.wValue, 0);
     474           0 :         USETW(req.wIndex, 0);
     475           0 :         USETW(req.wLength, 0);
     476             : 
     477           0 :         err = usbd_do_request(sc->sc_udev, &req, NULL);
     478           0 :         if (err){
     479           0 :                 printf("%s: uticom_reset: %s\n",
     480           0 :                     sc->sc_dev.dv_xname, usbd_errstr(err));
     481           0 :                 return (EIO);
     482             :         }
     483             : 
     484             :         DPRINTF(("%s: uticom_reset: done\n", sc->sc_dev.dv_xname));
     485           0 :         return (0);
     486           0 : }
     487             : 
     488             : static void
     489           0 : uticom_set(void *addr, int portno, int reg, int onoff)
     490             : {
     491           0 :         struct uticom_softc *sc = addr;
     492             : 
     493           0 :         switch (reg) {
     494             :         case UCOM_SET_DTR:
     495           0 :                 uticom_dtr(sc, onoff);
     496           0 :                 break;
     497             :         case UCOM_SET_RTS:
     498           0 :                 uticom_rts(sc, onoff);
     499           0 :                 break;
     500             :         case UCOM_SET_BREAK:
     501           0 :                 uticom_break(sc, onoff);
     502           0 :                 break;
     503             :         default:
     504             :                 break;
     505             :         }
     506           0 : }
     507             : 
     508             : static void
     509           0 : uticom_dtr(struct uticom_softc *sc, int onoff)
     510             : {
     511           0 :         usb_device_request_t req;
     512             :         usbd_status err;
     513             : 
     514             :         DPRINTF(("%s: uticom_dtr: onoff = %d\n", sc->sc_dev.dv_xname,
     515             :             onoff));
     516             : 
     517           0 :         if (sc->sc_dtr == onoff)
     518           0 :                 return;
     519           0 :         sc->sc_dtr = onoff;
     520             : 
     521           0 :         req.bmRequestType = UT_WRITE_VENDOR_DEVICE;
     522           0 :         req.bRequest = UTICOM_RQ_DTR;
     523           0 :         USETW(req.wValue, sc->sc_dtr ? UCDC_LINE_DTR : 0);
     524           0 :         USETW(req.wIndex, 0);
     525           0 :         USETW(req.wLength, 0);
     526             : 
     527           0 :         err = usbd_do_request(sc->sc_udev, &req, NULL);
     528           0 :         if (err)
     529           0 :                 printf("%s: uticom_dtr: %s\n",
     530           0 :                     sc->sc_dev.dv_xname, usbd_errstr(err));
     531           0 : }
     532             : 
     533             : static void
     534           0 : uticom_rts(struct uticom_softc *sc, int onoff)
     535             : {
     536           0 :         usb_device_request_t req;
     537             :         usbd_status err;
     538             : 
     539             :         DPRINTF(("%s: uticom_rts: onoff = %d\n", sc->sc_dev.dv_xname,
     540             :             onoff));
     541             : 
     542           0 :         if (sc->sc_rts == onoff)
     543           0 :                 return;
     544           0 :         sc->sc_rts = onoff;
     545           0 :         req.bmRequestType = UT_WRITE_VENDOR_DEVICE;
     546           0 :         req.bRequest = UTICOM_RQ_RTS;
     547           0 :         USETW(req.wValue, sc->sc_rts ? UCDC_LINE_RTS : 0);
     548           0 :         USETW(req.wIndex, 0);
     549           0 :         USETW(req.wLength, 0);
     550             : 
     551           0 :         err = usbd_do_request(sc->sc_udev, &req, NULL);
     552           0 :         if (err)
     553           0 :                 printf("%s: uticom_rts: %s\n",
     554           0 :                     sc->sc_dev.dv_xname, usbd_errstr(err));
     555           0 : }
     556             : 
     557             : static void
     558           0 : uticom_break(struct uticom_softc *sc, int onoff)
     559             : {
     560           0 :         usb_device_request_t req;
     561             :         usbd_status err;
     562             : 
     563             :         DPRINTF(("%s: uticom_break: onoff = %d\n", sc->sc_dev.dv_xname,
     564             :             onoff));
     565             : 
     566           0 :         req.bmRequestType = UT_WRITE_VENDOR_DEVICE;
     567           0 :         req.bRequest = UTICOM_RQ_BREAK;
     568           0 :         USETW(req.wValue, onoff ? 1 : 0);
     569           0 :         USETW(req.wIndex, 0);
     570           0 :         USETW(req.wLength, 0);
     571             : 
     572           0 :         err = usbd_do_request(sc->sc_udev, &req, NULL);
     573           0 :         if (err)
     574           0 :                 printf("%s: uticom_break: %s\n",
     575           0 :                     sc->sc_dev.dv_xname, usbd_errstr(err));
     576           0 : }
     577             : 
     578             : static usbd_status
     579           0 : uticom_set_crtscts(struct uticom_softc *sc)
     580             : {
     581           0 :         usb_device_request_t req;
     582             :         usbd_status err;
     583             : 
     584             :         DPRINTF(("%s: uticom_set_crtscts: on\n", sc->sc_dev.dv_xname));
     585             : 
     586           0 :         req.bmRequestType = UT_WRITE_VENDOR_DEVICE;
     587           0 :         req.bRequest = UTICOM_RQ_CRTSCTS;
     588           0 :         USETW(req.wValue, 1);
     589           0 :         USETW(req.wIndex, 0);
     590           0 :         USETW(req.wLength, 0);
     591             : 
     592           0 :         err = usbd_do_request(sc->sc_udev, &req, NULL);
     593           0 :         if (err) {
     594           0 :                 printf("%s: uticom_set_crtscts: %s\n",
     595           0 :                     sc->sc_dev.dv_xname, usbd_errstr(err));
     596           0 :                 return (err);
     597             :         }
     598             : 
     599           0 :         return (USBD_NORMAL_COMPLETION);
     600           0 : }
     601             : 
     602             : static int
     603           0 : uticom_param(void *vsc, int portno, struct termios *t)
     604             : {
     605           0 :         struct uticom_softc *sc = (struct uticom_softc *)vsc;
     606           0 :         usb_device_request_t req;
     607             :         usbd_status err;
     608             :         uint8_t data;
     609             : 
     610             :         DPRINTF(("%s: uticom_param\n", sc->sc_dev.dv_xname));
     611             : 
     612           0 :         switch (t->c_ospeed) {
     613             :         case 1200:
     614             :         case 2400:
     615             :         case 4800:
     616             :         case 7200:
     617             :         case 9600:
     618             :         case 14400:
     619             :         case 19200:
     620             :         case 38400:
     621             :         case 57600:
     622             :         case 115200:
     623             :         case 230400:
     624             :         case 460800:
     625             :         case 921600:
     626           0 :                 req.bmRequestType = UT_WRITE_VENDOR_DEVICE;
     627           0 :                 req.bRequest = UTICOM_RQ_BAUD;
     628           0 :                 USETW(req.wValue, (UTICOM_BRATE_REF / t->c_ospeed));
     629           0 :                 USETW(req.wIndex, 0);
     630           0 :                 USETW(req.wLength, 0);
     631             : 
     632           0 :                 err = usbd_do_request(sc->sc_udev, &req, 0);
     633           0 :                 if (err) {
     634           0 :                         printf("%s: uticom_param: %s\n",
     635           0 :                             sc->sc_dev.dv_xname, usbd_errstr(err));
     636           0 :                         return (EIO);
     637             :                 }
     638             :                 break;
     639             :         default:
     640           0 :                 printf("%s: uticom_param: unsupported baud rate %d\n",
     641           0 :                     sc->sc_dev.dv_xname, t->c_ospeed);
     642           0 :                 return (EINVAL);
     643             :         }
     644             : 
     645           0 :         switch (ISSET(t->c_cflag, CSIZE)) {
     646             :         case CS5:
     647             :                 data = UTICOM_SET_DATA_BITS(5);
     648           0 :                 break;
     649             :         case CS6:
     650             :                 data = UTICOM_SET_DATA_BITS(6);
     651           0 :                 break;
     652             :         case CS7:
     653             :                 data = UTICOM_SET_DATA_BITS(7);
     654           0 :                 break;
     655             :         case CS8:
     656             :                 data = UTICOM_SET_DATA_BITS(8);
     657           0 :                 break;
     658             :         default:
     659             :                 return (EIO);
     660             :         }
     661             : 
     662           0 :         if (ISSET(t->c_cflag, CSTOPB))
     663           0 :                 data |= UTICOM_STOP_BITS_2;
     664             :         else
     665             :                 data |= UTICOM_STOP_BITS_1;
     666             : 
     667           0 :         if (ISSET(t->c_cflag, PARENB)) {
     668           0 :                 if (ISSET(t->c_cflag, PARODD))
     669           0 :                         data |= UTICOM_PARITY_ODD;
     670             :                 else
     671           0 :                         data |= UTICOM_PARITY_EVEN;
     672             :         } else
     673           0 :                 data |= UTICOM_PARITY_NONE;
     674             : 
     675           0 :         req.bmRequestType = UT_WRITE_VENDOR_DEVICE;
     676           0 :         req.bRequest = UTICOM_RQ_LCR;
     677           0 :         USETW(req.wIndex, 0);
     678           0 :         USETW(req.wLength, 0);
     679           0 :         USETW(req.wValue, data);
     680             : 
     681           0 :         err = usbd_do_request(sc->sc_udev, &req, NULL);
     682           0 :         if (err) {
     683           0 :                 printf("%s: uticom_param: %s\n",
     684           0 :                     sc->sc_dev.dv_xname, usbd_errstr(err));
     685           0 :                 return (err);
     686             :         }
     687             : 
     688           0 :         if (ISSET(t->c_cflag, CRTSCTS)) {
     689           0 :                 err = uticom_set_crtscts(sc);
     690           0 :                 if (err)
     691           0 :                         return (EIO);
     692             :         }
     693             : 
     694           0 :         return (0);
     695           0 : }
     696             : 
     697             : static int
     698           0 : uticom_open(void *addr, int portno)
     699             : {
     700           0 :         struct uticom_softc *sc = addr;
     701             :         usbd_status err;
     702             : 
     703           0 :         if (usbd_is_dying(sc->sc_udev))
     704           0 :                 return (ENXIO);
     705             : 
     706             :         DPRINTF(("%s: uticom_open\n", sc->sc_dev.dv_xname));
     707             : 
     708           0 :         sc->sc_status = 0; /* clear status bit */
     709             : 
     710           0 :         if (sc->sc_intr_number != -1 && sc->sc_intr_pipe == NULL) {
     711           0 :                 sc->sc_intr_buf = malloc(sc->sc_isize, M_USBDEV, M_WAITOK);
     712           0 :                 err = usbd_open_pipe_intr(sc->sc_intr_iface, sc->sc_intr_number,
     713             :                     USBD_SHORT_XFER_OK, &sc->sc_intr_pipe, sc, sc->sc_intr_buf,
     714           0 :                     sc->sc_isize, uticom_intr, UTICOM_INTR_INTERVAL);
     715           0 :                 if (err) {
     716           0 :                         printf("%s: cannot open interrupt pipe (addr %d)\n",
     717           0 :                             sc->sc_dev.dv_xname, sc->sc_intr_number);
     718           0 :                         return (EIO);
     719             :                 }
     720             :         }
     721             : 
     722             :         DPRINTF(("%s: uticom_open: port opened\n", sc->sc_dev.dv_xname));
     723           0 :         return (0);
     724           0 : }
     725             : 
     726             : static void
     727           0 : uticom_close(void *addr, int portno)
     728             : {
     729           0 :         struct uticom_softc *sc = addr;
     730           0 :         usb_device_request_t req;
     731             :         usbd_status err;
     732             : 
     733           0 :         if (usbd_is_dying(sc->sc_udev))
     734           0 :                 return;
     735             : 
     736           0 :         req.bmRequestType = UT_WRITE_VENDOR_DEVICE;
     737           0 :         req.bRequest = UTICOM_RQ_SON;
     738           0 :         USETW(req.wValue, 0);
     739           0 :         USETW(req.wIndex, 0);
     740           0 :         USETW(req.wLength, 0);
     741             : 
     742             :         /* Try to reset UART part of chip. */
     743           0 :         err = usbd_do_request(sc->sc_udev, &req, NULL);
     744           0 :         if (err) {
     745           0 :                 printf("%s: uticom_close: %s\n",
     746           0 :                     sc->sc_dev.dv_xname, usbd_errstr(err));
     747           0 :                 return;
     748             :         }
     749             : 
     750             :         DPRINTF(("%s: uticom_close: close\n", sc->sc_dev.dv_xname));
     751             : 
     752           0 :         if (sc->sc_intr_pipe != NULL) {
     753           0 :                 usbd_abort_pipe(sc->sc_intr_pipe);
     754           0 :                 err = usbd_close_pipe(sc->sc_intr_pipe);
     755           0 :                 if (err)
     756           0 :                         printf("%s: close interrupt pipe failed: %s\n",
     757           0 :                             sc->sc_dev.dv_xname, usbd_errstr(err));
     758           0 :                 free(sc->sc_intr_buf, M_USBDEV, sc->sc_isize);
     759           0 :                 sc->sc_intr_pipe = NULL;
     760           0 :         }
     761           0 : }
     762             : 
     763             : static void
     764           0 : uticom_intr(struct usbd_xfer *xfer, void *priv, usbd_status status)
     765             : {
     766           0 :         struct uticom_softc *sc = priv;
     767           0 :         u_char *buf = sc->sc_intr_buf;
     768             : 
     769           0 :         if (usbd_is_dying(sc->sc_udev))
     770           0 :                 return;
     771             : 
     772           0 :         if (status != USBD_NORMAL_COMPLETION) {
     773           0 :                 if (status == USBD_NOT_STARTED || status == USBD_CANCELLED) {
     774             :                         DPRINTF(("%s: uticom_intr: int status: %s\n",
     775             :                             sc->sc_dev.dv_xname, usbd_errstr(status)));
     776           0 :                         return;
     777             :                 }
     778             : 
     779             :                 DPRINTF(("%s: uticom_intr: abnormal status: %s\n",
     780             :                     sc->sc_dev.dv_xname, usbd_errstr(status)));
     781           0 :                 usbd_clear_endpoint_stall_async(sc->sc_intr_pipe);
     782           0 :                 return;
     783             :         }
     784             : 
     785           0 :         if (!xfer->actlen)
     786           0 :                 return;
     787             : 
     788             :         DPRINTF(("%s: xfer_length = %d\n", sc->sc_dev.dv_xname,
     789             :             xfer->actlen));
     790             : 
     791           0 :         sc->sc_lsr = sc->sc_msr = 0;
     792             : 
     793           0 :         if (buf[0] == 0) {
     794             :                 /* msr registers */
     795           0 :                 if (buf[1] & UTICOM_MCR_CTS)
     796           0 :                         sc->sc_msr |= UMSR_CTS;
     797           0 :                 if (buf[1] & UTICOM_MCR_DSR)
     798           0 :                         sc->sc_msr |= UMSR_DSR;
     799           0 :                 if (buf[1] & UTICOM_MCR_CD)
     800           0 :                         sc->sc_msr |= UMSR_DCD;
     801           0 :                 if (buf[1] & UTICOM_MCR_RI)
     802           0 :                         sc->sc_msr |= UMSR_RI;
     803             :         } else {
     804             :                 /* lsr registers */
     805           0 :                 if (buf[0] & UTICOM_LCR_OVR)
     806           0 :                         sc->sc_lsr |= ULSR_OE;
     807           0 :                 if (buf[0] & UTICOM_LCR_PTE)
     808           0 :                         sc->sc_lsr |= ULSR_PE;
     809           0 :                 if (buf[0] & UTICOM_LCR_FRE)
     810           0 :                         sc->sc_lsr |= ULSR_FE;
     811           0 :                 if (buf[0] & UTICOM_LCR_BRK)
     812           0 :                         sc->sc_lsr |= ULSR_BI;
     813             :         }
     814             : 
     815             : //      if (uticomstickdsr)
     816             : //              sc->sc_msr |= UMSR_DSR;
     817             : 
     818           0 :         ucom_status_change((struct ucom_softc *)sc->sc_subdev);
     819           0 : }
     820             : 
     821             : static void
     822           0 : uticom_get_status(void *addr, int portno, u_char *lsr, u_char *msr)
     823             : {
     824             : #if 0 /* TODO */
     825             :         struct uticom_softc *sc = addr;
     826             : 
     827             :         DPRINTF(("uticom_get_status:\n"));
     828             : 
     829             :         if (lsr != NULL)
     830             :                 *lsr = sc->sc_lsr;
     831             :         if (msr != NULL)
     832             :                 *msr = sc->sc_msr;
     833             : #endif
     834           0 :         return;
     835             : }
     836             : 
     837             : static int
     838           0 : uticom_download_fw(struct uticom_softc *sc, int pipeno,
     839             :     struct usbd_device *dev)
     840             : {
     841           0 :         u_char *obuf, *firmware;
     842           0 :         size_t firmware_size;
     843             :         int buffer_size, pos;
     844             :         uint8_t cs = 0, *buffer;
     845             :         usbd_status err;
     846             :         struct uticom_fw_header *header;
     847             :         struct usbd_xfer *oxfer = 0;
     848             :         usbd_status error = 0;
     849           0 :         struct usbd_pipe *pipe;
     850             : 
     851           0 :         error = loadfirmware("tusb3410", &firmware, &firmware_size);
     852           0 :         if (error)
     853           0 :                 return (error);
     854             : 
     855             :         buffer_size = UTICOM_FW_BUFSZ + sizeof(struct uticom_fw_header);
     856           0 :         buffer = malloc(buffer_size, M_USBDEV, M_WAITOK | M_CANFAIL);
     857             : 
     858           0 :         if (!buffer) {
     859           0 :                 printf("%s: uticom_download_fw: out of memory\n",
     860           0 :                     sc->sc_dev.dv_xname);
     861           0 :                 free(firmware, M_DEVBUF, firmware_size);
     862           0 :                 return ENOMEM;
     863             :         }
     864             : 
     865           0 :         memcpy(buffer, firmware, firmware_size);
     866           0 :         memset(buffer + firmware_size, 0xff, buffer_size - firmware_size);
     867             : 
     868           0 :         for (pos = sizeof(struct uticom_fw_header); pos < buffer_size; pos++)
     869           0 :                 cs = (uint8_t)(cs + buffer[pos]);
     870             : 
     871           0 :         header = (struct uticom_fw_header*)buffer;
     872           0 :         header->length = (uint16_t)(buffer_size -
     873             :             sizeof(struct uticom_fw_header));
     874           0 :         header->checkSum = cs;
     875             : 
     876             :         DPRINTF(("%s: downloading firmware ...\n",
     877             :             sc->sc_dev.dv_xname));
     878             : 
     879           0 :         err = usbd_open_pipe(sc->sc_iface, pipeno, USBD_EXCLUSIVE_USE,
     880             :             &pipe);
     881           0 :         if (err) {
     882           0 :                 printf("%s: open bulk out error (addr %d): %s\n",
     883           0 :                     sc->sc_dev.dv_xname, pipeno, usbd_errstr(err));
     884             :                 error = EIO;
     885           0 :                 goto finish;
     886             :         }
     887             : 
     888           0 :         oxfer = usbd_alloc_xfer(dev);
     889           0 :         if (oxfer == NULL) {
     890             :                 error = ENOMEM;
     891           0 :                 goto finish;
     892             :         }
     893             : 
     894           0 :         obuf = usbd_alloc_buffer(oxfer, buffer_size);
     895           0 :         if (obuf == NULL) {
     896             :                 error = ENOMEM;
     897           0 :                 goto finish;
     898             :         }
     899             : 
     900           0 :         memcpy(obuf, buffer, buffer_size);
     901             : 
     902           0 :         usbd_setup_xfer(oxfer, pipe, (void *)sc, obuf, buffer_size,
     903             :             USBD_NO_COPY | USBD_SYNCHRONOUS, USBD_NO_TIMEOUT, 0);
     904           0 :         err = usbd_transfer(oxfer);
     905             : 
     906           0 :         if (err != USBD_NORMAL_COMPLETION)
     907           0 :                 printf("%s: uticom_download_fw: error: %s\n",
     908           0 :                     sc->sc_dev.dv_xname, usbd_errstr(err));
     909             : 
     910             : finish:
     911           0 :         free(firmware, M_DEVBUF, firmware_size);
     912           0 :         usbd_free_buffer(oxfer);
     913           0 :         usbd_free_xfer(oxfer);
     914             :         oxfer = NULL;
     915           0 :         usbd_abort_pipe(pipe);
     916           0 :         usbd_close_pipe(pipe);
     917           0 :         free(buffer, M_USBDEV, buffer_size);
     918           0 :         return err;
     919           0 : }

Generated by: LCOV version 1.13