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


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

FreeBSD/Linux Kernel Cross Reference
sys/dev/usb/uvscom.c

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

    1 /*      $NetBSD: usb/uvscom.c,v 1.1 2002/03/19 15:08:42 augustss Exp $  */
    2 /*-
    3  * Copyright (c) 2001-2003, 2005 Shunsuke Akiyama <akiyama@jp.FreeBSD.org>.
    4  * All rights reserved.
    5  *
    6  * Redistribution and use in source and binary forms, with or without
    7  * modification, are permitted provided that the following conditions
    8  * are met:
    9  * 1. Redistributions of source code must retain the above copyright
   10  *    notice, this list of conditions and the following disclaimer.
   11  * 2. Redistributions in binary form must reproduce the above copyright
   12  *    notice, this list of conditions and the following disclaimer in the
   13  *    documentation and/or other materials provided with the distribution.
   14  *
   15  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
   16  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
   17  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
   18  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
   19  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
   20  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
   21  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
   22  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
   23  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
   24  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   25  * SUCH DAMAGE.
   26  *
   27  */
   28 
   29 #include <sys/cdefs.h>
   30 __FBSDID("$FreeBSD: releng/7.3/sys/dev/usb/uvscom.c 171233 2007-07-05 06:28:46Z imp $");
   31 
   32 /*
   33  * uvscom: SUNTAC Slipper U VS-10U driver.
   34  * Slipper U is a PC Card to USB converter for data communication card
   35  * adapter.  It supports DDI Pocket's Air H" C@rd, C@rd H" 64, NTT's P-in,
   36  * P-in m@ater and various data communication card adapters.
   37  */
   38 
   39 #include "opt_uvscom.h"
   40 
   41 #include <sys/param.h>
   42 #include <sys/systm.h>
   43 #include <sys/kernel.h>
   44 #include <sys/malloc.h>
   45 #include <sys/module.h>
   46 #include <sys/fcntl.h>
   47 #include <sys/conf.h>
   48 #include <sys/serial.h>
   49 #include <sys/tty.h>
   50 #include <sys/file.h>
   51 #include <sys/bus.h>
   52 #include <sys/ioccom.h>
   53 #include <sys/selinfo.h>
   54 #include <sys/proc.h>
   55 #include <sys/poll.h>
   56 #include <sys/sysctl.h>
   57 #include <sys/taskqueue.h>
   58 
   59 #include <dev/usb/usb.h>
   60 #include <dev/usb/usbcdc.h>
   61 
   62 #include <dev/usb/usbdi.h>
   63 #include <dev/usb/usbdi_util.h>
   64 #include "usbdevs.h"
   65 #include <dev/usb/usb_quirks.h>
   66 
   67 #include <dev/usb/ucomvar.h>
   68 
   69 SYSCTL_NODE(_hw_usb, OID_AUTO, uvscom, CTLFLAG_RW, 0, "USB uvscom");
   70 #ifdef USB_DEBUG
   71 static int      uvscomdebug = 0;
   72 SYSCTL_INT(_hw_usb_uvscom, OID_AUTO, debug, CTLFLAG_RW,
   73            &uvscomdebug, 0, "uvscom debug level");
   74 
   75 #define DPRINTFN(n, x) do { \
   76                                 if (uvscomdebug > (n)) \
   77                                         printf x; \
   78                         } while (0)
   79 #else
   80 #define DPRINTFN(n, x)
   81 #endif
   82 #define DPRINTF(x) DPRINTFN(0, x)
   83 
   84 #define UVSCOM_MODVER           1       /* module version */
   85 
   86 #define UVSCOM_CONFIG_INDEX     0
   87 #define UVSCOM_IFACE_INDEX      0
   88 
   89 #ifndef UVSCOM_INTR_INTERVAL
   90 #define UVSCOM_INTR_INTERVAL    100     /* mS */
   91 #endif
   92 
   93 #define UVSCOM_UNIT_WAIT        5
   94 
   95 /* Request */
   96 #define UVSCOM_SET_SPEED        0x10
   97 #define UVSCOM_LINE_CTL         0x11
   98 #define UVSCOM_SET_PARAM        0x12
   99 #define UVSCOM_READ_STATUS      0xd0
  100 #define UVSCOM_SHUTDOWN         0xe0
  101 
  102 /* UVSCOM_SET_SPEED parameters */
  103 #define UVSCOM_SPEED_150BPS     0x00
  104 #define UVSCOM_SPEED_300BPS     0x01
  105 #define UVSCOM_SPEED_600BPS     0x02
  106 #define UVSCOM_SPEED_1200BPS    0x03
  107 #define UVSCOM_SPEED_2400BPS    0x04
  108 #define UVSCOM_SPEED_4800BPS    0x05
  109 #define UVSCOM_SPEED_9600BPS    0x06
  110 #define UVSCOM_SPEED_19200BPS   0x07
  111 #define UVSCOM_SPEED_38400BPS   0x08
  112 #define UVSCOM_SPEED_57600BPS   0x09
  113 #define UVSCOM_SPEED_115200BPS  0x0a
  114 
  115 /* UVSCOM_LINE_CTL parameters */
  116 #define UVSCOM_BREAK            0x40
  117 #define UVSCOM_RTS              0x02
  118 #define UVSCOM_DTR              0x01
  119 #define UVSCOM_LINE_INIT        0x08
  120 
  121 /* UVSCOM_SET_PARAM parameters */
  122 #define UVSCOM_DATA_MASK        0x03
  123 #define UVSCOM_DATA_BIT_8       0x03
  124 #define UVSCOM_DATA_BIT_7       0x02
  125 #define UVSCOM_DATA_BIT_6       0x01
  126 #define UVSCOM_DATA_BIT_5       0x00
  127 
  128 #define UVSCOM_STOP_MASK        0x04
  129 #define UVSCOM_STOP_BIT_2       0x04
  130 #define UVSCOM_STOP_BIT_1       0x00
  131 
  132 #define UVSCOM_PARITY_MASK      0x18
  133 #define UVSCOM_PARITY_EVEN      0x18
  134 #if 0
  135 #define UVSCOM_PARITY_UNK       0x10
  136 #endif
  137 #define UVSCOM_PARITY_ODD       0x08
  138 #define UVSCOM_PARITY_NONE      0x00
  139 
  140 /* Status bits */
  141 #define UVSCOM_TXRDY            0x04
  142 #define UVSCOM_RXRDY            0x01
  143 
  144 #define UVSCOM_DCD              0x08
  145 #define UVSCOM_NOCARD           0x04
  146 #define UVSCOM_DSR              0x02
  147 #define UVSCOM_CTS              0x01
  148 #define UVSCOM_USTAT_MASK       (UVSCOM_NOCARD | UVSCOM_DSR | UVSCOM_CTS)
  149 
  150 struct  uvscom_softc {
  151         struct ucom_softc       sc_ucom;
  152 
  153         int                     sc_iface_number;/* interface number */
  154 
  155         usbd_interface_handle   sc_intr_iface;  /* interrupt interface */
  156         int                     sc_intr_number; /* interrupt number */
  157         usbd_pipe_handle        sc_intr_pipe;   /* interrupt pipe */
  158         u_char                  *sc_intr_buf;   /* interrupt buffer */
  159         int                     sc_isize;
  160 
  161         u_char                  sc_dtr;         /* current DTR state */
  162         u_char                  sc_rts;         /* current RTS state */
  163 
  164         u_char                  sc_lsr;         /* Local status register */
  165         u_char                  sc_msr;         /* uvscom status register */
  166 
  167         uint16_t                sc_lcr;         /* Line control */
  168         u_char                  sc_usr;         /* unit status */
  169 
  170         struct task             sc_task;
  171 };
  172 
  173 /*
  174  * These are the maximum number of bytes transferred per frame.
  175  * The output buffer size cannot be increased due to the size encoding.
  176  */
  177 #define UVSCOMIBUFSIZE          512
  178 #define UVSCOMOBUFSIZE          64
  179 
  180 #ifndef UVSCOM_DEFAULT_OPKTSIZE
  181 #define UVSCOM_DEFAULT_OPKTSIZE 8
  182 #endif
  183 
  184 static  usbd_status uvscom_shutdown(struct uvscom_softc *);
  185 static  usbd_status uvscom_reset(struct uvscom_softc *);
  186 static  usbd_status uvscom_set_line_coding(struct uvscom_softc *,
  187                                            uint16_t, uint16_t);
  188 static  usbd_status uvscom_set_line(struct uvscom_softc *, uint16_t);
  189 static  usbd_status uvscom_set_crtscts(struct uvscom_softc *);
  190 static  void uvscom_get_status(void *, int, u_char *, u_char *);
  191 static  void uvscom_dtr(struct uvscom_softc *, int);
  192 static  void uvscom_rts(struct uvscom_softc *, int);
  193 static  void uvscom_break(struct uvscom_softc *, int);
  194 
  195 static  void uvscom_set(void *, int, int, int);
  196 static  void uvscom_intr(usbd_xfer_handle, usbd_private_handle, usbd_status);
  197 #if 0 /* TODO */
  198 static  int  uvscom_ioctl(void *, int, u_long, caddr_t, int, usb_proc_ptr);
  199 #endif
  200 static  int  uvscom_param(void *, int, struct termios *);
  201 static  int  uvscom_open(void *, int);
  202 static  void uvscom_close(void *, int);
  203 static  void uvscom_notify(void *, int);
  204 
  205 struct ucom_callback uvscom_callback = {
  206         uvscom_get_status,
  207         uvscom_set,
  208         uvscom_param,
  209         NULL, /* uvscom_ioctl, TODO */
  210         uvscom_open,
  211         uvscom_close,
  212         NULL,
  213         NULL
  214 };
  215 
  216 static const struct usb_devno uvscom_devs [] = {
  217         /* SUNTAC U-Cable type A4 */
  218         { USB_VENDOR_SUNTAC, USB_PRODUCT_SUNTAC_AS144L4 },
  219         /* SUNTAC U-Cable type D2 */
  220         { USB_VENDOR_SUNTAC, USB_PRODUCT_SUNTAC_DS96L },
  221         /* SUNTAC Ir-Trinity */
  222         { USB_VENDOR_SUNTAC, USB_PRODUCT_SUNTAC_IS96U },
  223         /* SUNTAC U-Cable type P1 */
  224         { USB_VENDOR_SUNTAC, USB_PRODUCT_SUNTAC_PS64P1 },
  225         /* SUNTAC Slipper U */
  226         { USB_VENDOR_SUNTAC, USB_PRODUCT_SUNTAC_VS10U },
  227 };
  228 #define uvscom_lookup(v, p) usb_lookup(uvscom_devs, v, p)
  229 
  230 static device_probe_t uvscom_match;
  231 static device_attach_t uvscom_attach;
  232 static device_detach_t uvscom_detach;
  233 
  234 static device_method_t uvscom_methods[] = {
  235         /* Device interface */
  236         DEVMETHOD(device_probe, uvscom_match),
  237         DEVMETHOD(device_attach, uvscom_attach),
  238         DEVMETHOD(device_detach, uvscom_detach),
  239         { 0, 0 }
  240 };
  241 
  242 static driver_t uvscom_driver = {
  243         "ucom",
  244         uvscom_methods,
  245         sizeof (struct uvscom_softc)
  246 };
  247 
  248 DRIVER_MODULE(uvscom, uhub, uvscom_driver, ucom_devclass, usbd_driver_load, 0);
  249 MODULE_DEPEND(uvscom, usb, 1, 1, 1);
  250 MODULE_DEPEND(uvscom, ucom, UCOM_MINVER, UCOM_PREFVER, UCOM_MAXVER);
  251 MODULE_VERSION(uvscom, UVSCOM_MODVER);
  252 
  253 static int      uvscomobufsiz = UVSCOM_DEFAULT_OPKTSIZE;
  254 static int      uvscominterval = UVSCOM_INTR_INTERVAL;
  255 
  256 static int
  257 sysctl_hw_usb_uvscom_opktsize(SYSCTL_HANDLER_ARGS)
  258 {
  259         int err, val;
  260 
  261         val = uvscomobufsiz;
  262         err = sysctl_handle_int(oidp, &val, 0, req);
  263         if (err != 0 || req->newptr == NULL)
  264                 return (err);
  265         if (0 < val && val <= UVSCOMOBUFSIZE)
  266                 uvscomobufsiz = val;
  267         else
  268                 err = EINVAL;
  269 
  270         return (err);
  271 }
  272 
  273 static int
  274 sysctl_hw_usb_uvscom_interval(SYSCTL_HANDLER_ARGS)
  275 {
  276         int err, val;
  277 
  278         val = uvscominterval;
  279         err = sysctl_handle_int(oidp, &val, 0, req);
  280         if (err != 0 || req->newptr == NULL)
  281                 return (err);
  282         if (0 < val && val <= 1000)
  283                 uvscominterval = val;
  284         else
  285                 err = EINVAL;
  286 
  287         return (err);
  288 }
  289 
  290 SYSCTL_PROC(_hw_usb_uvscom, OID_AUTO, opktsize, CTLTYPE_INT | CTLFLAG_RW,
  291             0, sizeof(int), sysctl_hw_usb_uvscom_opktsize,
  292             "I", "uvscom output packet size");
  293 SYSCTL_PROC(_hw_usb_uvscom, OID_AUTO, interval, CTLTYPE_INT | CTLFLAG_RW,
  294             0, sizeof(int), sysctl_hw_usb_uvscom_interval,
  295             "I", "uvscom interrpt pipe interval");
  296 
  297 static int
  298 uvscom_match(device_t self)
  299 {
  300         struct usb_attach_arg *uaa = device_get_ivars(self);
  301 
  302         if (uaa->iface != NULL)
  303                 return (UMATCH_NONE);
  304 
  305         return (uvscom_lookup(uaa->vendor, uaa->product) != NULL ?
  306                 UMATCH_VENDOR_PRODUCT : UMATCH_NONE);
  307 }
  308 
  309 static int
  310 uvscom_attach(device_t self)
  311 {
  312         struct uvscom_softc *sc = device_get_softc(self);
  313         struct usb_attach_arg *uaa = device_get_ivars(self);
  314         usbd_device_handle dev = uaa->device;
  315         struct ucom_softc *ucom;
  316         usb_config_descriptor_t *cdesc;
  317         usb_interface_descriptor_t *id;
  318         usb_endpoint_descriptor_t *ed;
  319         usbd_status err;
  320         int i;
  321 
  322         ucom = &sc->sc_ucom;
  323         ucom->sc_dev = self;
  324         ucom->sc_udev = dev;
  325         ucom->sc_iface = uaa->iface;
  326 
  327         DPRINTF(("uvscom attach: sc = %p\n", sc));
  328 
  329         /* initialize endpoints */
  330         ucom->sc_bulkin_no = ucom->sc_bulkout_no = -1;
  331         sc->sc_intr_number = -1;
  332         sc->sc_intr_pipe = NULL;
  333 
  334         /* Move the device into the configured state. */
  335         err = usbd_set_config_index(dev, UVSCOM_CONFIG_INDEX, 1);
  336         if (err) {
  337                 device_printf(self, "failed to set configuration, err=%s\n",
  338                     usbd_errstr(err));
  339                 goto error;
  340         }
  341 
  342         /* get the config descriptor */
  343         cdesc = usbd_get_config_descriptor(ucom->sc_udev);
  344 
  345         if (cdesc == NULL) {
  346                 device_printf(self, "failed to get configuration descriptor\n");
  347                 goto error;
  348         }
  349 
  350         /* get the common interface */
  351         err = usbd_device2interface_handle(dev, UVSCOM_IFACE_INDEX,
  352                                            &ucom->sc_iface);
  353         if (err) {
  354                 device_printf(self, "failed to get interface, err=%s\n",
  355                     usbd_errstr(err));
  356                 goto error;
  357         }
  358 
  359         id = usbd_get_interface_descriptor(ucom->sc_iface);
  360         sc->sc_iface_number = id->bInterfaceNumber;
  361 
  362         /* Find endpoints */
  363         for (i = 0; i < id->bNumEndpoints; i++) {
  364                 ed = usbd_interface2endpoint_descriptor(ucom->sc_iface, i);
  365                 if (ed == NULL) {
  366                         device_printf(self, "no endpoint descriptor for %d\n",
  367                             i);
  368                         goto error;
  369                 }
  370 
  371                 if (UE_GET_DIR(ed->bEndpointAddress) == UE_DIR_IN &&
  372                     UE_GET_XFERTYPE(ed->bmAttributes) == UE_BULK) {
  373                         ucom->sc_bulkin_no = ed->bEndpointAddress;
  374                 } else if (UE_GET_DIR(ed->bEndpointAddress) == UE_DIR_OUT &&
  375                            UE_GET_XFERTYPE(ed->bmAttributes) == UE_BULK) {
  376                         ucom->sc_bulkout_no = ed->bEndpointAddress;
  377                 } else if (UE_GET_DIR(ed->bEndpointAddress) == UE_DIR_IN &&
  378                            UE_GET_XFERTYPE(ed->bmAttributes) == UE_INTERRUPT) {
  379                         sc->sc_intr_number = ed->bEndpointAddress;
  380                         sc->sc_isize = UGETW(ed->wMaxPacketSize);
  381                 }
  382         }
  383 
  384         if (ucom->sc_bulkin_no == -1) {
  385                 device_printf(self, "Could not find data bulk in\n");
  386                 goto error;
  387         }
  388         if (ucom->sc_bulkout_no == -1) {
  389                 device_printf(self, "Could not find data bulk out\n");
  390                 goto error;
  391         }
  392         if (sc->sc_intr_number == -1) {
  393                 device_printf(self, "Could not find interrupt in\n");
  394                 goto error;
  395         }
  396 
  397         sc->sc_dtr = sc->sc_rts = 0;
  398         sc->sc_lcr = UVSCOM_LINE_INIT;
  399 
  400         ucom->sc_parent = sc;
  401         ucom->sc_portno = UCOM_UNK_PORTNO;
  402         /* bulkin, bulkout set above */
  403         ucom->sc_ibufsize = UVSCOMIBUFSIZE;
  404         ucom->sc_obufsize = uvscomobufsiz;
  405         ucom->sc_ibufsizepad = UVSCOMIBUFSIZE;
  406         ucom->sc_opkthdrlen = 0;
  407         ucom->sc_callback = &uvscom_callback;
  408 
  409         err = uvscom_reset(sc);
  410 
  411         if (err) {
  412                 device_printf(self, "reset failed, %s\n", usbd_errstr(err));
  413                 goto error;
  414         }
  415 
  416         DPRINTF(("uvscom: in = 0x%x out = 0x%x intr = 0x%x\n",
  417                  ucom->sc_bulkin_no, ucom->sc_bulkout_no, sc->sc_intr_number));
  418 
  419         TASK_INIT(&sc->sc_task, 0, uvscom_notify, sc);
  420         ucom_attach(&sc->sc_ucom);
  421         return 0;
  422 
  423 error:
  424         ucom->sc_dying = 1;
  425         return ENXIO;
  426 }
  427 
  428 static int
  429 uvscom_detach(device_t self)
  430 {
  431         struct uvscom_softc *sc = device_get_softc(self);
  432         int rv = 0;
  433 
  434         DPRINTF(("uvscom_detach: sc = %p\n", sc));
  435 
  436         sc->sc_ucom.sc_dying = 1;
  437 
  438         if (sc->sc_intr_pipe != NULL) {
  439                 usbd_abort_pipe(sc->sc_intr_pipe);
  440                 usbd_close_pipe(sc->sc_intr_pipe);
  441                 free(sc->sc_intr_buf, M_USBDEV);
  442                 sc->sc_intr_pipe = NULL;
  443         }
  444 
  445         rv = ucom_detach(&sc->sc_ucom);
  446 
  447         return (rv);
  448 }
  449 
  450 static usbd_status
  451 uvscom_readstat(struct uvscom_softc *sc)
  452 {
  453         usb_device_request_t req;
  454         usbd_status err;
  455         uint16_t r;
  456 
  457         DPRINTF(("%s: send readstat\n", device_get_nameunit(sc->sc_ucom.sc_dev)));
  458 
  459         req.bmRequestType = UT_READ_VENDOR_DEVICE;
  460         req.bRequest = UVSCOM_READ_STATUS;
  461         USETW(req.wValue, 0);
  462         USETW(req.wIndex, 0);
  463         USETW(req.wLength, 2);
  464 
  465         err = usbd_do_request(sc->sc_ucom.sc_udev, &req, &r);
  466         if (err) {
  467                 device_printf(sc->sc_ucom.sc_dev, "uvscom_readstat: %s\n",
  468                     usbd_errstr(err));
  469                 return (err);
  470         }
  471 
  472         DPRINTF(("%s: uvscom_readstat: r = %d\n",
  473                  device_get_nameunit(sc->sc_ucom.sc_dev), r));
  474 
  475         return (USBD_NORMAL_COMPLETION);
  476 }
  477 
  478 static usbd_status
  479 uvscom_shutdown(struct uvscom_softc *sc)
  480 {
  481         usb_device_request_t req;
  482         usbd_status err;
  483 
  484         DPRINTF(("%s: send shutdown\n", device_get_nameunit(sc->sc_ucom.sc_dev)));
  485 
  486         req.bmRequestType = UT_WRITE_VENDOR_DEVICE;
  487         req.bRequest = UVSCOM_SHUTDOWN;
  488         USETW(req.wValue, 0);
  489         USETW(req.wIndex, 0);
  490         USETW(req.wLength, 0);
  491 
  492         err = usbd_do_request(sc->sc_ucom.sc_udev, &req, NULL);
  493         if (err) {
  494                 device_printf(sc->sc_ucom.sc_dev, "uvscom_shutdown: %s\n",
  495                     usbd_errstr(err));
  496                 return (err);
  497         }
  498 
  499         return (USBD_NORMAL_COMPLETION);
  500 }
  501 
  502 static usbd_status
  503 uvscom_reset(struct uvscom_softc *sc)
  504 {
  505         DPRINTF(("%s: uvscom_reset\n", device_get_nameunit(sc->sc_ucom.sc_dev)));
  506 
  507         return (USBD_NORMAL_COMPLETION);
  508 }
  509 
  510 static usbd_status
  511 uvscom_set_crtscts(struct uvscom_softc *sc)
  512 {
  513         DPRINTF(("%s: uvscom_set_crtscts\n", device_get_nameunit(sc->sc_ucom.sc_dev)));
  514 
  515         return (USBD_NORMAL_COMPLETION);
  516 }
  517 
  518 static usbd_status
  519 uvscom_set_line(struct uvscom_softc *sc, uint16_t line)
  520 {
  521         usb_device_request_t req;
  522         usbd_status err;
  523 
  524         DPRINTF(("%s: uvscom_set_line: %04x\n",
  525                  device_get_nameunit(sc->sc_ucom.sc_dev), line));
  526 
  527         req.bmRequestType = UT_WRITE_VENDOR_DEVICE;
  528         req.bRequest = UVSCOM_LINE_CTL;
  529         USETW(req.wValue, line);
  530         USETW(req.wIndex, 0);
  531         USETW(req.wLength, 0);
  532 
  533         err = usbd_do_request(sc->sc_ucom.sc_udev, &req, NULL);
  534         if (err) {
  535                 device_printf(sc->sc_ucom.sc_dev, "uvscom_set_line: %s\n",
  536                     usbd_errstr(err));
  537                 return (err);
  538         }
  539 
  540         return (USBD_NORMAL_COMPLETION);
  541 }
  542 
  543 static usbd_status
  544 uvscom_set_line_coding(struct uvscom_softc *sc, uint16_t lsp, uint16_t ls)
  545 {
  546         usb_device_request_t req;
  547         usbd_status err;
  548 
  549         DPRINTF(("%s: uvscom_set_line_coding: %02x %02x\n",
  550                  device_get_nameunit(sc->sc_ucom.sc_dev), lsp, ls));
  551 
  552         req.bmRequestType = UT_WRITE_VENDOR_DEVICE;
  553         req.bRequest = UVSCOM_SET_SPEED;
  554         USETW(req.wValue, lsp);
  555         USETW(req.wIndex, 0);
  556         USETW(req.wLength, 0);
  557 
  558         err = usbd_do_request(sc->sc_ucom.sc_udev, &req, NULL);
  559         if (err) {
  560                 device_printf(sc->sc_ucom.sc_dev, "uvscom_set_line_coding: %s\n",
  561                     usbd_errstr(err));
  562                 return (err);
  563         }
  564 
  565         req.bmRequestType = UT_WRITE_VENDOR_DEVICE;
  566         req.bRequest = UVSCOM_SET_PARAM;
  567         USETW(req.wValue, ls);
  568         USETW(req.wIndex, 0);
  569         USETW(req.wLength, 0);
  570 
  571         err = usbd_do_request(sc->sc_ucom.sc_udev, &req, NULL);
  572         if (err) {
  573                 device_printf(sc->sc_ucom.sc_dev, "uvscom_set_line_coding: %s\n",
  574                     usbd_errstr(err));
  575                 return (err);
  576         }
  577 
  578         return (USBD_NORMAL_COMPLETION);
  579 }
  580 
  581 static void
  582 uvscom_dtr(struct uvscom_softc *sc, int onoff)
  583 {
  584         DPRINTF(("%s: uvscom_dtr: onoff = %d\n",
  585                  device_get_nameunit(sc->sc_ucom.sc_dev), onoff));
  586 
  587         if (sc->sc_dtr == onoff)
  588                 return;                 /* no change */
  589 
  590         sc->sc_dtr = onoff;
  591 
  592         if (onoff)
  593                 SET(sc->sc_lcr, UVSCOM_DTR);
  594         else
  595                 CLR(sc->sc_lcr, UVSCOM_DTR);
  596 
  597         uvscom_set_line(sc, sc->sc_lcr);
  598 }
  599 
  600 static void
  601 uvscom_rts(struct uvscom_softc *sc, int onoff)
  602 {
  603         DPRINTF(("%s: uvscom_rts: onoff = %d\n",
  604                  device_get_nameunit(sc->sc_ucom.sc_dev), onoff));
  605 
  606         if (sc->sc_rts == onoff)
  607                 return;                 /* no change */
  608 
  609         sc->sc_rts = onoff;
  610 
  611         if (onoff)
  612                 SET(sc->sc_lcr, UVSCOM_RTS);
  613         else
  614                 CLR(sc->sc_lcr, UVSCOM_RTS);
  615 
  616         uvscom_set_line(sc, sc->sc_lcr);
  617 }
  618 
  619 static void
  620 uvscom_break(struct uvscom_softc *sc, int onoff)
  621 {
  622         DPRINTF(("%s: uvscom_break: onoff = %d\n",
  623                  device_get_nameunit(sc->sc_ucom.sc_dev), onoff));
  624 
  625         if (onoff)
  626                 uvscom_set_line(sc, SET(sc->sc_lcr, UVSCOM_BREAK));
  627 }
  628 
  629 static void
  630 uvscom_set(void *addr, int portno, int reg, int onoff)
  631 {
  632         struct uvscom_softc *sc = addr;
  633 
  634         switch (reg) {
  635         case UCOM_SET_DTR:
  636                 uvscom_dtr(sc, onoff);
  637                 break;
  638         case UCOM_SET_RTS:
  639                 uvscom_rts(sc, onoff);
  640                 break;
  641         case UCOM_SET_BREAK:
  642                 uvscom_break(sc, onoff);
  643                 break;
  644         default:
  645                 break;
  646         }
  647 }
  648 
  649 static int
  650 uvscom_param(void *addr, int portno, struct termios *t)
  651 {
  652         struct uvscom_softc *sc = addr;
  653         usbd_status err;
  654         uint16_t lsp;
  655         uint16_t ls;
  656 
  657         DPRINTF(("%s: uvscom_param: sc = %p\n",
  658                  device_get_nameunit(sc->sc_ucom.sc_dev), sc));
  659 
  660         ls = 0;
  661 
  662         switch (t->c_ospeed) {
  663         case B150:
  664                 lsp = UVSCOM_SPEED_150BPS;
  665                 break;
  666         case B300:
  667                 lsp = UVSCOM_SPEED_300BPS;
  668                 break;
  669         case B600:
  670                 lsp = UVSCOM_SPEED_600BPS;
  671                 break;
  672         case B1200:
  673                 lsp = UVSCOM_SPEED_1200BPS;
  674                 break;
  675         case B2400:
  676                 lsp = UVSCOM_SPEED_2400BPS;
  677                 break;
  678         case B4800:
  679                 lsp = UVSCOM_SPEED_4800BPS;
  680                 break;
  681         case B9600:
  682                 lsp = UVSCOM_SPEED_9600BPS;
  683                 break;
  684         case B19200:
  685                 lsp = UVSCOM_SPEED_19200BPS;
  686                 break;
  687         case B38400:
  688                 lsp = UVSCOM_SPEED_38400BPS;
  689                 break;
  690         case B57600:
  691                 lsp = UVSCOM_SPEED_57600BPS;
  692                 break;
  693         case B115200:
  694                 lsp = UVSCOM_SPEED_115200BPS;
  695                 break;
  696         default:
  697                 return (EIO);
  698         }
  699 
  700         if (ISSET(t->c_cflag, CSTOPB))
  701                 SET(ls, UVSCOM_STOP_BIT_2);
  702         else
  703                 SET(ls, UVSCOM_STOP_BIT_1);
  704 
  705         if (ISSET(t->c_cflag, PARENB)) {
  706                 if (ISSET(t->c_cflag, PARODD))
  707                         SET(ls, UVSCOM_PARITY_ODD);
  708                 else
  709                         SET(ls, UVSCOM_PARITY_EVEN);
  710         } else
  711                 SET(ls, UVSCOM_PARITY_NONE);
  712 
  713         switch (ISSET(t->c_cflag, CSIZE)) {
  714         case CS5:
  715                 SET(ls, UVSCOM_DATA_BIT_5);
  716                 break;
  717         case CS6:
  718                 SET(ls, UVSCOM_DATA_BIT_6);
  719                 break;
  720         case CS7:
  721                 SET(ls, UVSCOM_DATA_BIT_7);
  722                 break;
  723         case CS8:
  724                 SET(ls, UVSCOM_DATA_BIT_8);
  725                 break;
  726         default:
  727                 return (EIO);
  728         }
  729 
  730         err = uvscom_set_line_coding(sc, lsp, ls);
  731         if (err)
  732                 return (EIO);
  733 
  734         if (ISSET(t->c_cflag, CRTSCTS)) {
  735                 err = uvscom_set_crtscts(sc);
  736                 if (err)
  737                         return (EIO);
  738         }
  739 
  740         return (0);
  741 }
  742 
  743 static int
  744 uvscom_open(void *addr, int portno)
  745 {
  746         struct uvscom_softc *sc = addr;
  747         int err;
  748         int i;
  749 
  750         if (sc->sc_ucom.sc_dying)
  751                 return (ENXIO);
  752 
  753         DPRINTF(("uvscom_open: sc = %p\n", sc));
  754 
  755         /* change output packet size */
  756         sc->sc_ucom.sc_obufsize = uvscomobufsiz;
  757 
  758         if (sc->sc_intr_number != -1 && sc->sc_intr_pipe == NULL) {
  759                 DPRINTF(("uvscom_open: open interrupt pipe.\n"));
  760 
  761                 sc->sc_usr = 0;         /* clear unit status */
  762 
  763                 err = uvscom_readstat(sc);
  764                 if (err) {
  765                         DPRINTF(("%s: uvscom_open: readstat faild\n",
  766                                  device_get_nameunit(sc->sc_ucom.sc_dev)));
  767                         return (ENXIO);
  768                 }
  769 
  770                 sc->sc_intr_buf = malloc(sc->sc_isize, M_USBDEV, M_WAITOK);
  771                 err = usbd_open_pipe_intr(sc->sc_ucom.sc_iface,
  772                                           sc->sc_intr_number,
  773                                           USBD_SHORT_XFER_OK,
  774                                           &sc->sc_intr_pipe,
  775                                           sc,
  776                                           sc->sc_intr_buf,
  777                                           sc->sc_isize,
  778                                           uvscom_intr,
  779                                           uvscominterval);
  780                 if (err) {
  781                         device_printf(sc->sc_ucom.sc_dev,
  782                             "cannot open interrupt pipe (addr %d)\n",
  783                             sc->sc_intr_number);
  784                         return (ENXIO);
  785                 }
  786         } else {
  787                 DPRINTF(("uvscom_open: did not open interrupt pipe.\n"));
  788         }
  789 
  790         if ((sc->sc_usr & UVSCOM_USTAT_MASK) == 0) {
  791                 /* unit is not ready */
  792 
  793                 for (i = UVSCOM_UNIT_WAIT; i > 0; --i) {
  794                         pause("uvsop", hz);     /* XXX */
  795                         if (ISSET(sc->sc_usr, UVSCOM_USTAT_MASK))
  796                                 break;
  797                 }
  798                 if (i == 0) {
  799                         DPRINTF(("%s: unit is not ready\n",
  800                                  device_get_nameunit(sc->sc_ucom.sc_dev)));
  801                         return (ENXIO);
  802                 }
  803 
  804                 /* check PC Card was inserted */
  805                 if (ISSET(sc->sc_usr, UVSCOM_NOCARD)) {
  806                         DPRINTF(("%s: no card\n",
  807                                  device_get_nameunit(sc->sc_ucom.sc_dev)));
  808                         return (ENXIO);
  809                 }
  810         }
  811 
  812         return (0);
  813 }
  814 
  815 static void
  816 uvscom_close(void *addr, int portno)
  817 {
  818         struct uvscom_softc *sc = addr;
  819         int err;
  820 
  821         if (sc->sc_ucom.sc_dying)
  822                 return;
  823 
  824         DPRINTF(("uvscom_close: close\n"));
  825 
  826         uvscom_shutdown(sc);
  827 
  828         if (sc->sc_intr_pipe != NULL) {
  829                 err = usbd_abort_pipe(sc->sc_intr_pipe);
  830                 if (err)
  831                         device_printf(sc->sc_ucom.sc_dev,
  832                             "abort interrupt pipe failed: %s\n",
  833                             usbd_errstr(err));
  834                 err = usbd_close_pipe(sc->sc_intr_pipe);
  835                 if (err)
  836                         device_printf(sc->sc_ucom.sc_dev,
  837                             "close interrupt pipe failed: %s\n",
  838                             usbd_errstr(err));
  839                 free(sc->sc_intr_buf, M_USBDEV);
  840                 sc->sc_intr_pipe = NULL;
  841         }
  842 }
  843 
  844 static void
  845 uvscom_intr(usbd_xfer_handle xfer, usbd_private_handle priv, usbd_status status)
  846 {
  847         struct uvscom_softc *sc = priv;
  848         u_char *buf = sc->sc_intr_buf;
  849         u_char pstatus;
  850 
  851         if (sc->sc_ucom.sc_dying)
  852                 return;
  853 
  854         if (status != USBD_NORMAL_COMPLETION) {
  855                 if (status == USBD_NOT_STARTED || status == USBD_CANCELLED)
  856                         return;
  857 
  858                 device_printf(sc->sc_ucom.sc_dev,       
  859                     "uvscom_intr: abnormal status: %s\n",
  860                     usbd_errstr(status));
  861                 usbd_clear_endpoint_stall_async(sc->sc_intr_pipe);
  862                 return;
  863         }
  864 
  865         DPRINTFN(2, ("%s: uvscom status = %02x %02x\n",
  866                  device_get_nameunit(sc->sc_ucom.sc_dev), buf[0], buf[1]));
  867 
  868         sc->sc_lsr = sc->sc_msr = 0;
  869         sc->sc_usr = buf[1];
  870 
  871         pstatus = buf[0];
  872         if (ISSET(pstatus, UVSCOM_TXRDY))
  873                 SET(sc->sc_lsr, ULSR_TXRDY);
  874         if (ISSET(pstatus, UVSCOM_RXRDY))
  875                 SET(sc->sc_lsr, ULSR_RXRDY);
  876 
  877         pstatus = buf[1];
  878         if (ISSET(pstatus, UVSCOM_CTS))
  879                 SET(sc->sc_msr, SER_CTS);
  880         if (ISSET(pstatus, UVSCOM_DSR))
  881                 SET(sc->sc_msr, SER_DSR);
  882         if (ISSET(pstatus, UVSCOM_DCD))
  883                 SET(sc->sc_msr, SER_DCD);
  884 
  885         /* Deferred notifying to the ucom layer */
  886         taskqueue_enqueue(taskqueue_swi_giant, &sc->sc_task);
  887 }
  888 
  889 static void
  890 uvscom_notify(void *arg, int count)
  891 {
  892         struct uvscom_softc *sc;
  893 
  894         sc = (struct uvscom_softc *)arg;
  895         if (sc->sc_ucom.sc_dying)
  896                 return;
  897         ucom_status_change(&sc->sc_ucom);
  898 }
  899 
  900 static void
  901 uvscom_get_status(void *addr, int portno, u_char *lsr, u_char *msr)
  902 {
  903         struct uvscom_softc *sc = addr;
  904 
  905         if (lsr != NULL)
  906                 *lsr = sc->sc_lsr;
  907         if (msr != NULL)
  908                 *msr = sc->sc_msr;
  909 }
  910 
  911 #if 0 /* TODO */
  912 static int
  913 uvscom_ioctl(void *addr, int portno, u_long cmd, caddr_t data, int flag,
  914              struct thread *p)
  915 {
  916         struct uvscom_softc *sc = addr;
  917         int error = 0;
  918 
  919         if (sc->sc_ucom.sc_dying)
  920                 return (EIO);
  921 
  922         DPRINTF(("uvscom_ioctl: cmd = 0x%08lx\n", cmd));
  923 
  924         switch (cmd) {
  925         case TIOCNOTTY:
  926         case TIOCMGET:
  927         case TIOCMSET:
  928                 break;
  929 
  930         default:
  931                 DPRINTF(("uvscom_ioctl: unknown\n"));
  932                 error = ENOTTY;
  933                 break;
  934         }
  935 
  936         return (error);
  937 }
  938 #endif

Cache object: f25f9fdf6dd689afeaf5dea7a7a88c67


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