The Design and Implementation of the FreeBSD Operating System, Second Edition
Now available: The Design and Implementation of the FreeBSD Operating System (Second Edition)


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]

FreeBSD/Linux Kernel Cross Reference
sys/dev/usbmisc/uticom/uticom.c

Version: -  FREEBSD  -  FREEBSD-13-STABLE  -  FREEBSD-13-0  -  FREEBSD-12-STABLE  -  FREEBSD-12-0  -  FREEBSD-11-STABLE  -  FREEBSD-11-0  -  FREEBSD-10-STABLE  -  FREEBSD-10-0  -  FREEBSD-9-STABLE  -  FREEBSD-9-0  -  FREEBSD-8-STABLE  -  FREEBSD-8-0  -  FREEBSD-7-STABLE  -  FREEBSD-7-0  -  FREEBSD-6-STABLE  -  FREEBSD-6-0  -  FREEBSD-5-STABLE  -  FREEBSD-5-0  -  FREEBSD-4-STABLE  -  FREEBSD-3-STABLE  -  FREEBSD22  -  l41  -  OPENBSD  -  linux-2.6  -  MK84  -  PLAN9  -  xnu-8792 
SearchContext: -  none  -  3  -  10 

    1 /*
    2  * Copyright (c) 2006-2007 Dmitry Komissaroff <dxi@mail.ru>.
    3  * Copyright (c) 2007 Hasso Tepper <hasso@estpak.ee>.
    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/malloc.h>
   31 #include <sys/bus.h>
   32 #include <sys/fcntl.h>
   33 #include <sys/conf.h>
   34 #include <sys/tty.h>
   35 #include <sys/file.h>
   36 #include <sys/select.h>
   37 #include <sys/proc.h>
   38 #include <sys/poll.h>
   39 #include <sys/sysctl.h>
   40 #include <sys/taskqueue.h>
   41 
   42 #include <bus/usb/usb.h>
   43 #include <bus/usb/usbcdc.h>
   44 #include <bus/usb/usbdi.h>
   45 #include <bus/usb/usbdi_util.h>
   46 #include <bus/usb/usbdivar.h>
   47 #include <bus/usb/usb_quirks.h>
   48 
   49 #include "../ucom/ucomvar.h"
   50 
   51 #include "uticom_fw3410.h"
   52 
   53 SYSCTL_NODE(_hw_usb, OID_AUTO, uticom, CTLFLAG_RW, 0, "USB uticom");
   54 
   55 #ifdef USB_DEBUG
   56 static int      uticomdebug = 0;
   57 SYSCTL_INT(_hw_usb_uticom, OID_AUTO, debug, CTLFLAG_RW, &uticomdebug, 0,
   58            "uticom debug level");
   59 
   60 #define DPRINTFN(n, x)  do { if (uticomdebug > (n)) kprintf x; } while (0)
   61 #else
   62 #define DPRINTFN(n, x)
   63 #endif
   64 
   65 #define DPRINTF(x) DPRINTFN(0, x)
   66 
   67 #define UTICOM_CONFIG_INDEX     1
   68 #define UTICOM_ACTIVE_INDEX     2
   69 
   70 #define UTICOM_IFACE_INDEX      0
   71 
   72 /*
   73  * These are the maximum number of bytes transferred per frame.
   74  * The output buffer size cannot be increased due to the size encoding.
   75  */
   76 #define UTICOM_IBUFSZ           64
   77 #define UTICOM_OBUFSZ           64
   78 
   79 #define UTICOM_FW_BUFSZ         16284
   80 
   81 #define UTICOM_INTR_INTERVAL    100     /* ms */
   82 
   83 #define UTICOM_RQ_LINE          0
   84 /* Used to sync data0/1-toggle on reopen bulk pipe. */
   85 #define UTICOM_RQ_SOF           1
   86 #define UTICOM_RQ_SON           2
   87 
   88 #define UTICOM_RQ_BAUD          3
   89 #define UTICOM_RQ_LCR           4
   90 #define UTICOM_RQ_FCR           5
   91 #define UTICOM_RQ_RTS           6
   92 #define UTICOM_RQ_DTR           7
   93 #define UTICOM_RQ_BREAK         8
   94 #define UTICOM_RQ_CRTSCTS       9
   95 
   96 #define UTICOM_BRATE_REF        923077
   97 
   98 #define UTICOM_SET_DATA_BITS(x) (x - 5)
   99 
  100 #define UTICOM_STOP_BITS_1      0x00
  101 #define UTICOM_STOP_BITS_2      0x40
  102 
  103 #define UTICOM_PARITY_NONE      0x00
  104 #define UTICOM_PARITY_ODD       0x08
  105 #define UTICOM_PARITY_EVEN      0x18
  106 
  107 #define UTICOM_LCR_OVR          0x1
  108 #define UTICOM_LCR_PTE          0x2
  109 #define UTICOM_LCR_FRE          0x4
  110 #define UTICOM_LCR_BRK          0x8
  111 
  112 #define UTICOM_MCR_CTS          0x1
  113 #define UTICOM_MCR_DSR          0x2
  114 #define UTICOM_MCR_CD           0x4
  115 #define UTICOM_MCR_RI           0x8
  116 
  117 /* Structures */
  118 struct uticom_fw_header {
  119         uint16_t      length;
  120         uint8_t       checkSum;
  121 } __attribute__((packed));
  122 
  123 struct uticom_buf {
  124         unsigned int            buf_size;
  125         char                    *buf_buf;
  126         char                    *buf_get;
  127         char                    *buf_put;
  128 };
  129 
  130 struct  uticom_softc {
  131         struct ucom_softc       sc_ucom;
  132 
  133         int                     sc_iface_number; /* interface number */
  134 
  135         usbd_interface_handle   sc_intr_iface;  /* interrupt interface */
  136         int                     sc_intr_number; /* interrupt number */
  137         usbd_pipe_handle        sc_intr_pipe;   /* interrupt pipe */
  138         u_char                  *sc_intr_buf;   /* interrupt buffer */
  139         int                     sc_isize;
  140 
  141         u_char                  sc_dtr;         /* current DTR state */
  142         u_char                  sc_rts;         /* current RTS state */
  143         u_char                  sc_status;
  144 
  145         u_char                  sc_lsr;         /* Local status register */
  146         u_char                  sc_msr;         /* uticom status register */
  147 };
  148 
  149 static  usbd_status uticom_reset(struct uticom_softc *);
  150 static  usbd_status uticom_set_crtscts(struct uticom_softc *);
  151 static  void uticom_intr(usbd_xfer_handle, usbd_private_handle, usbd_status);
  152 
  153 static  void uticom_set(void *, int, int, int);
  154 static  void uticom_dtr(struct uticom_softc *, int);
  155 static  void uticom_rts(struct uticom_softc *, int);
  156 static  void uticom_break(struct uticom_softc *, int);
  157 static  void uticom_get_status(void *, int, u_char *, u_char *);
  158 #if 0 /* TODO */
  159 static  int  uticom_ioctl(void *, int, u_long, caddr_t, int, usb_proc_ptr);
  160 #endif
  161 static  int  uticom_param(void *, int, struct termios *);
  162 static  int  uticom_open(void *, int);
  163 static  void uticom_close(void *, int);
  164 
  165 static int uticom_download_fw(struct uticom_softc *sc, unsigned int pipeno,
  166                               usbd_device_handle dev, unsigned char *firmware,
  167                               unsigned int firmware_size);
  168 
  169 struct ucom_callback uticom_callback = {
  170         uticom_get_status,
  171         uticom_set,
  172         uticom_param,
  173         NULL, /* uticom_ioctl, TODO */
  174         uticom_open,
  175         uticom_close,
  176         NULL,
  177         NULL
  178 };
  179 
  180 static const struct usb_devno uticom_devs [] = {
  181         { USB_DEVICE(0x0451, 0x3410) }  /* TI TUSB3410 chip */
  182 };
  183 
  184 static device_probe_t uticom_match;
  185 static device_attach_t uticom_attach;
  186 static device_detach_t uticom_detach;
  187 
  188 static device_method_t uticom_methods[] = {
  189         DEVMETHOD(device_probe, uticom_match),
  190         DEVMETHOD(device_attach, uticom_attach),
  191         DEVMETHOD(device_detach, uticom_detach),
  192         DEVMETHOD_END
  193 };
  194 
  195 static driver_t uticom_driver = {
  196         "ucom",
  197         uticom_methods,
  198         sizeof (struct uticom_softc)
  199 };
  200 
  201 DRIVER_MODULE(uticom, uhub, uticom_driver, ucom_devclass, usbd_driver_load, NULL);
  202 MODULE_DEPEND(uticom, usb, 1, 1, 1);
  203 MODULE_DEPEND(uticom, ucom, UCOM_MINVER, UCOM_PREFVER, UCOM_MAXVER);
  204 MODULE_VERSION(uticom, 1);
  205 
  206 /* Sticky DSR level sysctl handling. */
  207 static int uticomstickdsr = 0;
  208 static int
  209 sysctl_hw_usb_uticom_stickdsr(SYSCTL_HANDLER_ARGS)
  210 {
  211         int err, val;
  212 
  213         val = uticomstickdsr;
  214         err = sysctl_handle_int(oidp, &val, sizeof(val), req);
  215         if (err != 0 || req->newptr == NULL)
  216                 return (err);
  217         if (val == 0 || val == 1)
  218                 uticomstickdsr = val;
  219         else
  220                 err = EINVAL;
  221 
  222         return (err);
  223 }
  224 SYSCTL_PROC(_hw_usb_uticom, OID_AUTO, stickdsr, CTLTYPE_INT | CTLFLAG_RW,
  225             0, sizeof(int), sysctl_hw_usb_uticom_stickdsr,
  226             "I", "uticom sticky dsr level");
  227 
  228 static int
  229 uticom_match(device_t self)
  230 {
  231         struct usb_attach_arg *uaa = device_get_ivars(self);
  232 
  233         if (uaa->iface != NULL)
  234                 return (UMATCH_NONE);
  235 
  236         return (usb_lookup(uticom_devs, uaa->vendor, uaa->product) != NULL ?
  237                 UMATCH_VENDOR_PRODUCT : UMATCH_NONE);
  238 }
  239 
  240 static int
  241 uticom_attach(device_t self)
  242 {
  243         struct uticom_softc *sc = device_get_softc(self);
  244         struct usb_attach_arg *uaa = device_get_ivars(self);
  245 
  246         usbd_device_handle dev = uaa->device;
  247         struct ucom_softc *ucom;
  248         usb_config_descriptor_t *cdesc;
  249         usb_interface_descriptor_t *id;
  250         usb_endpoint_descriptor_t *ed;
  251         usbd_status err;
  252         int status, i;
  253         usb_device_descriptor_t *dd;
  254 
  255         ucom = &sc->sc_ucom;
  256         bzero(sc, sizeof (struct uticom_softc));
  257         ucom->sc_dev = self;
  258         ucom->sc_udev = dev;
  259         ucom->sc_iface = uaa->iface;
  260 
  261         /* Initialize endpoints. */
  262         ucom->sc_bulkin_no = ucom->sc_bulkout_no = -1;
  263         sc->sc_intr_number = -1;
  264         sc->sc_intr_pipe = NULL;
  265 
  266         dd = usbd_get_device_descriptor(dev);
  267         DPRINTF(("%s: uticom_attach: num of configurations %d\n",
  268                  device_get_nameunit(self), dd->bNumConfigurations));
  269 
  270         /* The device without firmware has single configuration with single
  271          * bulk out interface. */
  272         if (dd->bNumConfigurations > 1)
  273                 goto fwload_done;
  274                 
  275         /* Loading firmware. */
  276         DPRINTF(("%s: uticom_attach: starting loading firmware\n",
  277                  device_get_nameunit(self)));
  278 
  279         err = usbd_set_config_index(dev, UTICOM_CONFIG_INDEX, 1);
  280         if (err) {
  281                 device_printf(self, "failed to set configuration: %s\n",
  282                               usbd_errstr(err));
  283                 ucom->sc_dying = 1;
  284                 return ENXIO;
  285         }
  286 
  287         /* Get the config descriptor. */
  288         cdesc = usbd_get_config_descriptor(ucom->sc_udev);
  289 
  290         if (cdesc == NULL) {
  291                 device_printf(self, "failed to get configuration descriptor\n");
  292                 ucom->sc_dying = 1;
  293                 return ENXIO;
  294         }
  295 
  296         err = usbd_device2interface_handle(dev, UTICOM_IFACE_INDEX,
  297                                            &ucom->sc_iface);
  298         if (err) {
  299                 device_printf(self, "failed to get interface: %s\n",
  300                               usbd_errstr(err));
  301                 ucom->sc_dying = 1;
  302                 return ENXIO;
  303         }
  304 
  305         /* Find the bulk out interface used to upload firmware. */
  306         id = usbd_get_interface_descriptor(ucom->sc_iface);
  307         sc->sc_iface_number = id->bInterfaceNumber;
  308 
  309         for (i = 0; i < id->bNumEndpoints; i++) {
  310                 ed = usbd_interface2endpoint_descriptor(ucom->sc_iface, i);
  311                 if (ed == NULL) {
  312                         device_printf(self,
  313                                       "no endpoint descriptor for %d\n", i);
  314                         ucom->sc_dying = 1;
  315                         return ENXIO;
  316                 }
  317 
  318                 if (UE_GET_DIR(ed->bEndpointAddress) == UE_DIR_OUT &&
  319                     UE_GET_XFERTYPE(ed->bmAttributes) == UE_BULK) {
  320                         ucom->sc_bulkout_no = ed->bEndpointAddress;
  321                         DPRINTF(("%s: uticom_attach: data bulk out num: %d\n",
  322                                  device_get_nameunit(self),
  323                                  ed->bEndpointAddress));
  324                 }
  325 
  326                 if (ucom->sc_bulkout_no == -1) {
  327                         device_printf(self, "could not find data bulk out\n");
  328                         ucom->sc_dying = 1;
  329                         return ENXIO;
  330                 }
  331         }
  332 
  333         status = uticom_download_fw(sc, ucom->sc_bulkout_no, dev,
  334                                     uticom_fw_3410, sizeof(uticom_fw_3410));
  335 
  336         if (status) {
  337                 device_printf(self, "firmware download failed\n");
  338                 ucom->sc_dying = 1;
  339                 return ENXIO;
  340         } else {
  341                 device_printf(self, "firmware download succeeded\n");
  342         }
  343                 
  344         status = usbd_reload_device_desc(dev);
  345         if (status) {
  346                 device_printf(self, "error reloading device descriptor\n");
  347                 ucom->sc_dying = 1;
  348                 return ENXIO;
  349         }
  350 
  351 fwload_done:
  352         dd = usbd_get_device_descriptor(dev);
  353         DPRINTF(("%s: uticom_attach: num of configurations %d\n",
  354                  device_get_nameunit(self), dd->bNumConfigurations));
  355 
  356         err = usbd_set_config_index(dev, UTICOM_ACTIVE_INDEX, 1);
  357         if (err) {
  358                 device_printf(self, "failed to set configuration: %s\n",
  359                               usbd_errstr(err));
  360                 ucom->sc_dying = 1;
  361                 return ENXIO;
  362         }
  363 
  364         /* Get the config descriptor. */
  365         cdesc = usbd_get_config_descriptor(ucom->sc_udev);
  366         if (cdesc == NULL) {
  367                 device_printf(self, "failed to get configuration descriptor\n");
  368                 ucom->sc_dying = 1;
  369                 return ENXIO;
  370         }
  371 
  372         /* Get the interface (XXX: multiport chips are not supported yet). */
  373         err = usbd_device2interface_handle(dev, UTICOM_IFACE_INDEX,
  374                                            &ucom->sc_iface);
  375         if (err) {
  376                 device_printf(self, "failed to get interface: %s\n",
  377                               usbd_errstr(err));
  378                 ucom->sc_dying = 1;
  379                 return ENXIO;
  380         }
  381 
  382         /* Find the interrupt endpoints. */
  383         id = usbd_get_interface_descriptor(ucom->sc_iface);
  384         sc->sc_iface_number = id->bInterfaceNumber;
  385 
  386         for (i = 0; i < id->bNumEndpoints; i++) {
  387                 ed = usbd_interface2endpoint_descriptor(ucom->sc_iface, i);
  388                 if (ed == NULL) {
  389                         device_printf(self,
  390                                       "no endpoint descriptor for %d\n", i);
  391                         ucom->sc_dying = 1;
  392                         return ENXIO;
  393                 }
  394 
  395                 if (UE_GET_DIR(ed->bEndpointAddress) == UE_DIR_IN &&
  396                     UE_GET_XFERTYPE(ed->bmAttributes) == UE_INTERRUPT) {
  397                         sc->sc_intr_number = ed->bEndpointAddress;
  398                         sc->sc_isize = UGETW(ed->wMaxPacketSize);
  399                 }
  400         }
  401 
  402         if (sc->sc_intr_number == -1) {
  403                 device_printf(self, "could not find interrupt in\n");
  404                 ucom->sc_dying = 1;
  405                 return ENXIO;
  406         }
  407 
  408         /* Keep interface for interrupt. */
  409         sc->sc_intr_iface = ucom->sc_iface;
  410 
  411         /* Find the bulk{in,out} endpoints. */
  412         id = usbd_get_interface_descriptor(ucom->sc_iface);
  413         sc->sc_iface_number = id->bInterfaceNumber;
  414 
  415         for (i = 0; i < id->bNumEndpoints; i++) {
  416                 ed = usbd_interface2endpoint_descriptor(ucom->sc_iface, i);
  417                 if (ed == NULL) {
  418                         device_printf(self,
  419                                       "no endpoint descriptor for %d\n", i);
  420                         ucom->sc_dying = 1;
  421                         return ENXIO;
  422                 }
  423 
  424                 if (UE_GET_DIR(ed->bEndpointAddress) == UE_DIR_IN &&
  425                     UE_GET_XFERTYPE(ed->bmAttributes) == UE_BULK) {
  426                         ucom->sc_bulkin_no = ed->bEndpointAddress;
  427                 } else if (UE_GET_DIR(ed->bEndpointAddress) == UE_DIR_OUT &&
  428                     UE_GET_XFERTYPE(ed->bmAttributes) == UE_BULK) {
  429                         ucom->sc_bulkout_no = ed->bEndpointAddress;
  430                 }
  431         }
  432 
  433         if (ucom->sc_bulkin_no == -1) {
  434                 device_printf(self, "could not find data bulk in\n");
  435                 ucom->sc_dying = 1;
  436                 return ENXIO;
  437         }
  438 
  439         if (ucom->sc_bulkout_no == -1) {
  440                 device_printf(self, "could not find data bulk out\n");
  441                 ucom->sc_dying = 1;
  442                 return ENXIO;
  443         }
  444 
  445         sc->sc_dtr = sc->sc_rts = -1;
  446         ucom->sc_parent = sc;
  447         ucom->sc_portno = UCOM_UNK_PORTNO;
  448         ucom->sc_ibufsize = UTICOM_IBUFSZ;
  449         ucom->sc_obufsize = UTICOM_OBUFSZ;
  450         ucom->sc_ibufsizepad = UTICOM_IBUFSZ;
  451         ucom->sc_opkthdrlen = 0;
  452         ucom->sc_callback = &uticom_callback;
  453 
  454         err = uticom_reset(sc);
  455         if (err) {
  456                 device_printf(self, "reset failed: %s\n", usbd_errstr(err));
  457                 ucom->sc_dying = 1;
  458                 return ENXIO;
  459         }
  460 
  461         DPRINTF(("%s: uticom_attach: in = 0x%x, out = 0x%x, intr = 0x%x\n",
  462                  device_get_nameunit(self), ucom->sc_bulkin_no,
  463                  ucom->sc_bulkout_no, sc->sc_intr_number));
  464 
  465         ucom_attach(&sc->sc_ucom);
  466         return 0;
  467 }
  468 
  469 static int
  470 uticom_detach(device_t self)
  471 {
  472         struct uticom_softc *sc = device_get_softc(self);
  473 
  474         DPRINTF(("%s: uticom_detach: sc = %p\n",
  475                  device_get_nameunit(self), sc));
  476 
  477         if (sc->sc_intr_pipe != NULL) {
  478                 usbd_abort_pipe(sc->sc_intr_pipe);
  479                 usbd_close_pipe(sc->sc_intr_pipe);
  480                 kfree(sc->sc_intr_buf, M_USBDEV);
  481                 sc->sc_intr_pipe = NULL;
  482         }
  483 
  484         sc->sc_ucom.sc_dying = 1;
  485         return (ucom_detach(&sc->sc_ucom));
  486 }
  487 
  488 static usbd_status
  489 uticom_reset(struct uticom_softc *sc)
  490 {
  491         usb_device_request_t req;
  492         usbd_status err;
  493         device_t dev = sc->sc_ucom.sc_dev;
  494 
  495         req.bmRequestType = UT_WRITE_VENDOR_DEVICE;
  496         req.bRequest = UTICOM_RQ_SON;
  497         USETW(req.wValue, 0);
  498         USETW(req.wIndex, 0);
  499         USETW(req.wLength, 0);
  500 
  501         err = usbd_do_request(sc->sc_ucom.sc_udev, &req, NULL);
  502         if (err){
  503                 device_printf(dev, "uticom_reset: %s\n", usbd_errstr(err));
  504                 return (EIO);
  505         }
  506 
  507         DPRINTF(("%s: uticom_reset: done\n", device_get_nameunit(dev)));
  508         return (0);
  509 }
  510 
  511 static void
  512 uticom_set(void *addr, int portno, int reg, int onoff)
  513 {
  514         struct uticom_softc *sc = addr;
  515 
  516         switch (reg) {
  517         case UCOM_SET_DTR:
  518                 uticom_dtr(sc, onoff);
  519                 break;
  520         case UCOM_SET_RTS:
  521                 uticom_rts(sc, onoff);
  522                 break;
  523         case UCOM_SET_BREAK:
  524                 uticom_break(sc, onoff);
  525                 break;
  526         default:
  527                 break;
  528         }
  529 }
  530 
  531 static void
  532 uticom_dtr(struct uticom_softc *sc, int onoff)
  533 {
  534         usb_device_request_t req;
  535         usbd_status err;
  536         device_t dev = sc->sc_ucom.sc_dev;
  537 
  538         DPRINTF(("%s: uticom_dtr: onoff = %d\n", device_get_nameunit(dev),
  539                  onoff));
  540 
  541         if (sc->sc_dtr == onoff)
  542                 return;
  543         sc->sc_dtr = onoff;
  544 
  545         req.bmRequestType = UT_WRITE_VENDOR_DEVICE;
  546         req.bRequest = UTICOM_RQ_DTR;
  547         USETW(req.wValue, sc->sc_dtr ? UCDC_LINE_DTR : 0);
  548         USETW(req.wIndex, 0);
  549         USETW(req.wLength, 0);
  550 
  551         err = usbd_do_request(sc->sc_ucom.sc_udev, &req, NULL);
  552         if (err)
  553                 device_printf(dev, "uticom_dtr: %s\n", usbd_errstr(err));
  554 }
  555 
  556 static void
  557 uticom_rts(struct uticom_softc *sc, int onoff)
  558 {
  559         usb_device_request_t req;
  560         usbd_status err;
  561         device_t dev = sc->sc_ucom.sc_dev;
  562 
  563         DPRINTF(("%s: uticom_rts: onoff = %d\n", device_get_nameunit(dev),
  564                  onoff));
  565 
  566         if (sc->sc_rts == onoff) 
  567                 return;
  568         sc->sc_rts = onoff;
  569         req.bmRequestType = UT_WRITE_VENDOR_DEVICE;
  570         req.bRequest = UTICOM_RQ_RTS;
  571         USETW(req.wValue, sc->sc_rts ? UCDC_LINE_RTS : 0);
  572         USETW(req.wIndex, 0);
  573         USETW(req.wLength, 0);
  574 
  575         err = usbd_do_request(sc->sc_ucom.sc_udev, &req, NULL);
  576         if (err)
  577                 device_printf(dev, "uticom_rts: %s\n", usbd_errstr(err));
  578 }
  579 
  580 static void
  581 uticom_break(struct uticom_softc *sc, int onoff)
  582 {
  583         usb_device_request_t req;
  584         usbd_status err;
  585         device_t dev = sc->sc_ucom.sc_dev;
  586 
  587         DPRINTF(("%s: uticom_break: onoff = %d\n", device_get_nameunit(dev),
  588                  onoff));
  589 
  590         req.bmRequestType = UT_WRITE_VENDOR_DEVICE;
  591         req.bRequest = UTICOM_RQ_BREAK;
  592         USETW(req.wValue, onoff ? 1 : 0);
  593         USETW(req.wIndex, 0);
  594         USETW(req.wLength, 0);
  595 
  596         err = usbd_do_request(sc->sc_ucom.sc_udev, &req, NULL);
  597         if (err)
  598                 device_printf(dev, "uticom_break: %s\n", usbd_errstr(err));
  599 }
  600 
  601 static usbd_status
  602 uticom_set_crtscts(struct uticom_softc *sc)
  603 {
  604         usb_device_request_t req;
  605         usbd_status err;
  606         device_t dev = sc->sc_ucom.sc_dev;
  607 
  608         DPRINTF(("%s: uticom_set_crtscts: on\n", device_get_nameunit(dev)));
  609 
  610         req.bmRequestType = UT_WRITE_VENDOR_DEVICE;
  611         req.bRequest = UTICOM_RQ_CRTSCTS;
  612         USETW(req.wValue, 1);
  613         USETW(req.wIndex, 0);
  614         USETW(req.wLength, 0);
  615 
  616         err = usbd_do_request(sc->sc_ucom.sc_udev, &req, NULL);
  617         if (err) {
  618                 device_printf(dev, "uticom_set_crtscts: %s\n",
  619                               usbd_errstr(err));
  620                 return (err);
  621         }
  622 
  623         return (USBD_NORMAL_COMPLETION);
  624 }
  625 
  626 static int
  627 uticom_param(void *vsc, int portno, struct termios *t)
  628 {
  629         struct uticom_softc *sc = (struct uticom_softc *)vsc;
  630         device_t dev = sc->sc_ucom.sc_dev;
  631         usb_device_request_t req;
  632         usbd_status err;
  633         uint8_t data;
  634 
  635         DPRINTF(("%s: uticom_param\n", device_get_nameunit(dev)));
  636 
  637         switch (t->c_ospeed) {
  638         case 1200:
  639         case 2400:
  640         case 4800:
  641         case 7200:
  642         case 9600:
  643         case 14400:
  644         case 19200:
  645         case 38400:
  646         case 57600:
  647         case 115200:
  648         case 230400:
  649         case 460800:
  650         case 921600:
  651                 req.bmRequestType = UT_WRITE_VENDOR_DEVICE;
  652                 req.bRequest = UTICOM_RQ_BAUD;
  653                 USETW(req.wValue, (UTICOM_BRATE_REF / t->c_ospeed));
  654                 USETW(req.wIndex, 0);
  655                 USETW(req.wLength, 0);
  656 
  657                 err = usbd_do_request(sc->sc_ucom.sc_udev, &req, 0);
  658                 if (err) {
  659                         device_printf(dev, "uticom_param: %s\n",
  660                                       usbd_errstr(err));
  661                         return (EIO);
  662                 }
  663                 break;
  664         default:
  665                 device_printf(dev, "uticom_param: unsupported baud rate %d\n",
  666                               t->c_ospeed);
  667                 return (EINVAL);
  668         }
  669 
  670         switch (ISSET(t->c_cflag, CSIZE)) {
  671         case CS5:
  672                 data = UTICOM_SET_DATA_BITS(5);
  673                 break;
  674         case CS6:
  675                 data = UTICOM_SET_DATA_BITS(6);
  676                 break;
  677         case CS7:
  678                 data = UTICOM_SET_DATA_BITS(7);
  679                 break;
  680         case CS8:
  681                 data = UTICOM_SET_DATA_BITS(8);
  682                 break;
  683         default:
  684                 return (EIO);
  685         }
  686 
  687         if (ISSET(t->c_cflag, CSTOPB))
  688                 data |= UTICOM_STOP_BITS_2;
  689         else
  690                 data |= UTICOM_STOP_BITS_1;
  691 
  692         if (ISSET(t->c_cflag, PARENB)) {
  693                 if (ISSET(t->c_cflag, PARODD))
  694                         data |= UTICOM_PARITY_ODD;
  695                 else
  696                         data |= UTICOM_PARITY_EVEN;
  697         } else
  698                 data |= UTICOM_PARITY_NONE;
  699 
  700         req.bmRequestType = UT_WRITE_VENDOR_DEVICE;
  701         req.bRequest = UTICOM_RQ_LCR;
  702         USETW(req.wIndex, 0);
  703         USETW(req.wLength, 0);
  704         USETW(req.wValue, data);
  705 
  706         err = usbd_do_request(sc->sc_ucom.sc_udev, &req, NULL);
  707         if (err) {
  708                 device_printf(dev, "uticom_param: %s\n", usbd_errstr(err));
  709                 return (err);
  710         }
  711 
  712         if (ISSET(t->c_cflag, CRTSCTS)) {
  713                 err = uticom_set_crtscts(sc);
  714                 if (err)
  715                         return (EIO);
  716         } 
  717 
  718         return (0);
  719 }
  720 
  721 static int
  722 uticom_open(void *addr, int portno)
  723 {
  724         struct uticom_softc *sc = addr;
  725         device_t dev = sc->sc_ucom.sc_dev;
  726         usbd_status err;
  727 
  728         if (sc->sc_ucom.sc_dying)
  729                 return (ENXIO);
  730 
  731         DPRINTF(("%s: uticom_open\n", device_get_nameunit(dev)));
  732 
  733         sc->sc_status = 0; /* clear status bit */
  734 
  735         if (sc->sc_intr_number != -1 && sc->sc_intr_pipe == NULL) {
  736                 sc->sc_intr_buf = kmalloc(sc->sc_isize, M_USBDEV, M_WAITOK);
  737                 err = usbd_open_pipe_intr(sc->sc_intr_iface, sc->sc_intr_number,
  738                                           USBD_SHORT_XFER_OK, &sc->sc_intr_pipe,
  739                                           sc, sc->sc_intr_buf, sc->sc_isize,
  740                                           uticom_intr, UTICOM_INTR_INTERVAL);
  741                 if (err) {
  742                         device_printf(dev, "cannot open interrupt pipe "
  743                                       "(addr %d)\n", sc->sc_intr_number);
  744                         return (EIO);
  745                 }
  746         }
  747 
  748         DPRINTF(("%s: uticom_open: port opened\n", device_get_nameunit(dev)));
  749         return (0);
  750 }
  751 
  752 static void
  753 uticom_close(void *addr, int portno)
  754 {
  755         struct uticom_softc *sc = addr;
  756         device_t dev = sc->sc_ucom.sc_dev;
  757         usb_device_request_t req;
  758         usbd_status err;
  759 
  760         if (sc->sc_ucom.sc_dying)
  761                 return;
  762 
  763         req.bmRequestType = UT_WRITE_VENDOR_DEVICE;
  764         req.bRequest = UTICOM_RQ_SON;
  765         USETW(req.wValue, 0);
  766         USETW(req.wIndex, 0);
  767         USETW(req.wLength, 0);
  768 
  769         /* Try to reset UART part of chip. */
  770         err = usbd_do_request(sc->sc_ucom.sc_udev, &req, NULL);
  771         if (err) {
  772                 device_printf(dev, "uticom_close: %s\n", usbd_errstr(err));
  773                 return;
  774         }
  775 
  776         DPRINTF(("%s: uticom_close: close\n",
  777                  device_get_nameunit(sc->sc_ucom.sc_dev)));
  778 
  779         if (sc->sc_intr_pipe != NULL) {
  780                 err = usbd_abort_pipe(sc->sc_intr_pipe);
  781                 if (err)
  782                         device_printf(dev, "abort interrupt pipe failed: %s\n",
  783                                       usbd_errstr(err));
  784                 err = usbd_close_pipe(sc->sc_intr_pipe);
  785                 if (err)
  786                         device_printf(dev, "close interrupt pipe failed: %s\n",
  787                                       usbd_errstr(err));
  788                 kfree(sc->sc_intr_buf, M_USBDEV);
  789                 sc->sc_intr_pipe = NULL;
  790         }
  791 }
  792 
  793 static void
  794 uticom_intr(usbd_xfer_handle xfer, usbd_private_handle priv, usbd_status status)
  795 {
  796         struct uticom_softc *sc = priv;
  797         u_char *buf = sc->sc_intr_buf;
  798 
  799         if (sc->sc_ucom.sc_dying)
  800                 return;
  801 
  802         if (status != USBD_NORMAL_COMPLETION) {
  803                 if (status == USBD_NOT_STARTED || status == USBD_CANCELLED) {
  804                         DPRINTF(("%s: uticom_intr: int status: %s\n",
  805                                  device_get_nameunit(sc->sc_ucom.sc_dev),
  806                                  usbd_errstr(status)));
  807                         return;
  808                 }
  809 
  810                 DPRINTF(("%s: uticom_intr: abnormal status: %s\n",
  811                         device_get_nameunit(sc->sc_ucom.sc_dev),
  812                         usbd_errstr(status)));
  813                 usbd_clear_endpoint_stall_async(sc->sc_intr_pipe);
  814                 return;
  815         }
  816 
  817         if (!xfer->actlen)
  818                 return;
  819 
  820         DPRINTF(("%s: xfer_length = %d\n",
  821                  device_get_nameunit(sc->sc_ucom.sc_dev), xfer->actlen));
  822 
  823         sc->sc_lsr = sc->sc_msr = 0;
  824 
  825         if (buf[0] == 0) {
  826                 /* msr registers */
  827                 if (buf[1] & UTICOM_MCR_CTS)
  828                         sc->sc_msr |= UMSR_CTS;
  829                 if (buf[1] & UTICOM_MCR_DSR)
  830                         sc->sc_msr |= UMSR_DSR;
  831                 if (buf[1] & UTICOM_MCR_CD)
  832                         sc->sc_msr |= UMSR_DCD;         
  833                 if (buf[1] & UTICOM_MCR_RI)
  834                         sc->sc_msr |= UMSR_RI;          
  835         } else {
  836                 /* lsr registers */
  837                 if (buf[0] & UTICOM_LCR_OVR)
  838                         sc->sc_lsr |= ULSR_OE;
  839                 if (buf[0] & UTICOM_LCR_PTE)
  840                         sc->sc_lsr |= ULSR_PE;
  841                 if (buf[0] & UTICOM_LCR_FRE)
  842                         sc->sc_lsr |= ULSR_FE;
  843                 if (buf[0] & UTICOM_LCR_BRK)
  844                         sc->sc_lsr |= ULSR_BI;  
  845         }
  846   
  847         if (uticomstickdsr)
  848                 sc->sc_msr |= UMSR_DSR;
  849 
  850         ucom_status_change(&sc->sc_ucom);
  851 }
  852 
  853 static void
  854 uticom_get_status(void *addr, int portno, u_char *lsr, u_char *msr)
  855 {
  856 #if 0 /* TODO */
  857         struct uticom_softc *sc = addr;
  858 
  859         DPRINTF(("uticom_get_status:\n"));
  860 
  861         if (lsr != NULL)
  862                 *lsr = sc->sc_lsr;
  863         if (msr != NULL)
  864                 *msr = sc->sc_msr;
  865 #endif
  866         return;
  867 }
  868 
  869 #if 0 /* TODO */
  870 static int
  871 uticom_ioctl(void *addr, int portno, u_long cmd, caddr_t data, int flag,
  872              usb_proc_ptr p)
  873 {
  874         struct uticom_softc *sc = addr;
  875         int error = 0;
  876 
  877         if (sc->sc_ucom.sc_dying)
  878                 return (EIO);
  879 
  880         DPRINTF(("uticom_ioctl: cmd = 0x%08lx\n", cmd));
  881 
  882         switch (cmd) {
  883         case TIOCNOTTY:
  884         case TIOCMGET:
  885         case TIOCMSET:
  886         case USB_GET_CM_OVER_DATA:
  887         case USB_SET_CM_OVER_DATA:
  888                 break;
  889 
  890         default:
  891                 DPRINTF(("uticom_ioctl: unknown\n"));
  892                 error = ENOTTY;
  893                 break;
  894         }
  895 
  896         return (error);
  897 }
  898 #endif
  899 
  900 static int uticom_download_fw(struct uticom_softc *sc, unsigned int pipeno,
  901                               usbd_device_handle dev, unsigned char *firmware,
  902                               unsigned int firmware_size)
  903 {
  904         int buffer_size;
  905         int pos;
  906         uint8_t cs = 0;
  907         uint8_t *buffer;
  908         usbd_status err = 0;
  909         usbd_xfer_handle oxfer = 0;
  910         u_char *obuf;
  911         usbd_pipe_handle pipe;
  912         struct uticom_fw_header *header;
  913 
  914         buffer_size = UTICOM_FW_BUFSZ + sizeof(struct uticom_fw_header);
  915         buffer = kmalloc(buffer_size, M_USBDEV, M_WAITOK);
  916 
  917         memcpy(buffer, firmware, firmware_size);
  918         memset(buffer + firmware_size, 0xff, buffer_size - firmware_size);
  919 
  920         for (pos = sizeof(struct uticom_fw_header); pos < buffer_size; pos++)
  921                 cs = (uint8_t)(cs + buffer[pos]);
  922 
  923         header = (struct uticom_fw_header*)buffer;
  924         header->length = (uint16_t)(buffer_size -
  925                                      sizeof(struct uticom_fw_header));
  926         header->checkSum = cs;
  927 
  928         DPRINTF(("%s: downloading firmware ...\n",
  929                  device_get_nameunit(sc->sc_ucom.sc_dev)));
  930 
  931         err = usbd_open_pipe(sc->sc_ucom.sc_iface, pipeno, USBD_EXCLUSIVE_USE,
  932                              &pipe);
  933         if (err) {
  934                 device_printf(sc->sc_ucom.sc_dev, "open bulk out error "
  935                               "(addr %d): %s\n", pipeno, usbd_errstr(err));
  936                 err = EIO;
  937                 goto finish;
  938         }
  939 
  940         oxfer = usbd_alloc_xfer(dev);
  941         if (oxfer == NULL) {
  942                 err = ENOMEM;
  943                 goto finish;
  944         }
  945 
  946         obuf = usbd_alloc_buffer(oxfer, buffer_size);
  947         if (obuf == NULL) {
  948                 err = ENOMEM;
  949                 goto finish;
  950         }
  951 
  952         memcpy(obuf, buffer, buffer_size);
  953 
  954         usbd_setup_xfer(oxfer, pipe, (usbd_private_handle)sc, obuf, buffer_size,
  955                         USBD_NO_COPY | USBD_SYNCHRONOUS, USBD_NO_TIMEOUT, 0);
  956         err = usbd_sync_transfer(oxfer);
  957 
  958         if (err != USBD_NORMAL_COMPLETION)
  959                 device_printf(sc->sc_ucom.sc_dev, "uticom_download_fw: "
  960                               "error: %s\n", usbd_errstr(err));
  961 
  962 finish:
  963         usbd_free_buffer(oxfer);
  964         usbd_free_xfer(oxfer);
  965         oxfer = NULL;
  966         usbd_abort_pipe(pipe);
  967         usbd_close_pipe(pipe);
  968         kfree(buffer, M_USBDEV);
  969 
  970         return err;     
  971 }

Cache object: 17988effccf54fdaa5eb4d29f864d1ce


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]


This page is part of the FreeBSD/Linux Linux Kernel Cross-Reference, and was automatically generated using a modified version of the LXR engine.