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/ubser.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) 2004 Bernd Walter <ticso@freebsd.org>
    3  *
    4  * $URL: https://devel.bwct.de/svn/projects/ubser/ubser.c $
    5  * $Date: 2004-02-29 01:53:10 +0100 (Sun, 29 Feb 2004) $
    6  * $Author: ticso $
    7  * $Rev: 1127 $
    8  */
    9 
   10 /*-
   11  * Copyright (c) 2001-2002, Shunsuke Akiyama <akiyama@jp.FreeBSD.org>.
   12  * All rights reserved.
   13  *
   14  * Redistribution and use in source and binary forms, with or without
   15  * modification, are permitted provided that the following conditions
   16  * are met:
   17  * 1. Redistributions of source code must retain the above copyright
   18  *    notice, this list of conditions and the following disclaimer.
   19  * 2. Redistributions in binary form must reproduce the above copyright
   20  *    notice, this list of conditions and the following disclaimer in the
   21  *    documentation and/or other materials provided with the distribution.
   22  *
   23  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
   24  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
   25  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
   26  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
   27  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
   28  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
   29  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
   30  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
   31  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
   32  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   33  * SUCH DAMAGE.
   34  */
   35 
   36 /*-
   37  * Copyright (c) 2000 The NetBSD Foundation, Inc.
   38  * All rights reserved.
   39  *
   40  * This code is derived from software contributed to The NetBSD Foundation
   41  * by Lennart Augustsson (lennart@augustsson.net).
   42  *
   43  * Redistribution and use in source and binary forms, with or without
   44  * modification, are permitted provided that the following conditions
   45  * are met:
   46  * 1. Redistributions of source code must retain the above copyright
   47  *    notice, this list of conditions and the following disclaimer.
   48  * 2. Redistributions in binary form must reproduce the above copyright
   49  *    notice, this list of conditions and the following disclaimer in the
   50  *    documentation and/or other materials provided with the distribution.
   51  * 3. All advertising materials mentioning features or use of this software
   52  *    must display the following acknowledgement:
   53  *        This product includes software developed by the NetBSD
   54  *        Foundation, Inc. and its contributors.
   55  * 4. Neither the name of The NetBSD Foundation nor the names of its
   56  *    contributors may be used to endorse or promote products derived
   57  *    from this software without specific prior written permission.
   58  *
   59  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
   60  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
   61  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
   62  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
   63  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
   64  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
   65  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
   66  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
   67  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
   68  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
   69  * POSSIBILITY OF SUCH DAMAGE.
   70  */
   71 
   72 #include <sys/cdefs.h>
   73 __FBSDID("$FreeBSD: releng/7.3/sys/dev/usb/ubser.c 171234 2007-07-05 06:42:14Z imp $");
   74 
   75 /*
   76  * BWCT serial adapter driver
   77  */
   78 
   79 #include <sys/cdefs.h>
   80 
   81 #include <sys/param.h>
   82 #include <sys/systm.h>
   83 #include <sys/kernel.h>
   84 #include <sys/module.h>
   85 #include <sys/malloc.h>
   86 #include <sys/bus.h>
   87 #include <sys/ioccom.h>
   88 #include <sys/fcntl.h>
   89 #include <sys/conf.h>
   90 #include <sys/serial.h>
   91 #include <sys/tty.h>
   92 #include <sys/clist.h>
   93 #include <sys/file.h>
   94 
   95 #include <sys/selinfo.h>
   96 
   97 #include <sys/sysctl.h>
   98 
   99 #include <dev/usb/usb.h>
  100 #include <dev/usb/usbhid.h>
  101 
  102 #include <dev/usb/usbdi.h>
  103 #include <dev/usb/usbdi_util.h>
  104 #include "usbdevs.h"
  105 
  106 #include <dev/usb/ubser.h>
  107 
  108 #ifdef USB_DEBUG
  109 static int ubserdebug = 0;
  110 SYSCTL_NODE(_hw_usb, OID_AUTO, ubser, CTLFLAG_RW, 0, "USB ubser");
  111 SYSCTL_INT(_hw_usb_ubser, OID_AUTO, debug, CTLFLAG_RW,
  112            &ubserdebug, 0, "ubser debug level");
  113 #define DPRINTF(x)      do { \
  114                                 if (ubserdebug) \
  115                                         printf x; \
  116                         } while (0)
  117 
  118 #define DPRINTFN(n, x)  do { \
  119                                 if (ubserdebug > (n)) \
  120                                         printf x; \
  121                         } while (0)
  122 #else
  123 #define DPRINTF(x)
  124 #define DPRINTFN(n,x)
  125 #endif
  126 
  127 #define ISSET(t, f)     ((t) & (f))
  128 #define SET(t, f)       (t) |= (f)
  129 #define CLR(t, f)       (t) &= ~((unsigned)(f))
  130 
  131 struct ubser_port {
  132         int                      p_port;
  133         struct ubser_softc      *p_sc;
  134         usbd_xfer_handle         p_oxfer;       /* write request */
  135         u_char                  *p_obuf;        /* write buffer */
  136         struct tty              *p_tty;
  137 };
  138 
  139 struct ubser_softc {
  140         device_t                sc_dev;
  141         usbd_device_handle      sc_udev;
  142         usbd_interface_handle   sc_iface;       /* data interface */
  143         int                     sc_ifaceno;
  144 
  145         int                     sc_refcnt;
  146         u_char                  sc_dying;
  147         u_char                  sc_opening;
  148         int                     sc_state;
  149         uint8_t                 sc_numser;
  150 
  151         int                     sc_bulkin_no;   /* bulk in endpoint address */
  152         usbd_pipe_handle        sc_bulkin_pipe; /* bulk in pipe */
  153         usbd_xfer_handle        sc_ixfer;       /* read request */
  154         u_char                  *sc_ibuf;       /* read buffer */
  155         u_int                   sc_ibufsize;    /* read buffer size */
  156         u_int                   sc_ibufsizepad; /* read buffer size padded */
  157 
  158         int                     sc_bulkout_no;  /* bulk out endpoint address */
  159         usbd_pipe_handle        sc_bulkout_pipe;/* bulk out pipe */
  160         u_int                   sc_obufsize;    /* write buffer size */
  161         u_int                   sc_opkthdrlen;  /* header length of
  162                                                    output packet */
  163 
  164         struct ubser_port       *sc_port;
  165 };
  166 
  167 static int ubserparam(struct tty *, struct termios *);
  168 static void ubserstart(struct tty *);
  169 static void ubserstop(struct tty *, int);
  170 static usbd_status ubserstartread(struct ubser_softc *);
  171 static void ubserreadcb(usbd_xfer_handle, usbd_private_handle, usbd_status);
  172 static void ubserwritecb(usbd_xfer_handle, usbd_private_handle, usbd_status);
  173 static void ubser_cleanup(struct ubser_softc *sc);
  174 
  175 static t_break_t        ubserbreak;
  176 static t_open_t         ubseropen;
  177 static t_close_t        ubserclose;
  178 static t_modem_t        ubsermodem;
  179 
  180 static device_probe_t ubser_match;
  181 static device_attach_t ubser_attach;
  182 static device_detach_t ubser_detach;
  183 
  184 static device_method_t ubser_methods[] = {
  185         /* Device interface */
  186         DEVMETHOD(device_probe,         ubser_match),
  187         DEVMETHOD(device_attach,        ubser_attach),
  188         DEVMETHOD(device_detach,        ubser_detach),
  189 
  190         { 0, 0 }
  191 };
  192 
  193 static driver_t ubser_driver = {
  194         "ubser",
  195         ubser_methods,
  196         sizeof(struct ubser_softc)
  197 };
  198 
  199 static devclass_t ubser_devclass;
  200 
  201 static int
  202 ubser_match(device_t self)
  203 {
  204         struct usb_attach_arg *uaa = device_get_ivars(self);
  205         usb_string_descriptor_t us;
  206         usb_interface_descriptor_t *id;
  207         usb_device_descriptor_t *dd;
  208         int err, size;
  209 
  210         if (uaa->iface == NULL)
  211                 return (UMATCH_NONE);
  212 
  213         DPRINTFN(20,("ubser: vendor=0x%x, product=0x%x\n",
  214                      uaa->vendor, uaa->product));
  215 
  216         dd = usbd_get_device_descriptor(uaa->device);
  217         if (dd == NULL) {
  218                 printf("ubser: failed to get device descriptor\n");
  219                 return (UMATCH_NONE);
  220         }
  221 
  222         id = usbd_get_interface_descriptor(uaa->iface);
  223         if (id == NULL) {
  224                 printf("ubser: failed to get interface descriptor\n");
  225                 return (UMATCH_NONE);
  226         }
  227 
  228         err = usbd_get_string_desc(uaa->device, dd->iManufacturer, 0, &us,
  229             &size);
  230         if (err != 0)
  231                 return (UMATCH_NONE);
  232 
  233         /* check if this is a BWCT vendor specific ubser interface */
  234         if (strcmp((char*)us.bString, "B\0W\0C\0T\0") == 0 &&
  235             id->bInterfaceClass == 0xff && id->bInterfaceSubClass == 0x00)
  236                 return (UMATCH_VENDOR_IFACESUBCLASS);
  237 
  238         return (UMATCH_NONE);
  239 }
  240 
  241 static int
  242 ubser_attach(device_t self)
  243 {
  244         struct ubser_softc *sc = device_get_softc(self);
  245         struct usb_attach_arg *uaa = device_get_ivars(self);
  246         usbd_device_handle udev = uaa->device;
  247         usb_endpoint_descriptor_t *ed;
  248         usb_interface_descriptor_t *id;
  249         usb_device_request_t req;
  250         struct tty *tp;
  251         usbd_status err;
  252         int i;
  253         int alen;
  254         uint8_t epcount;
  255         struct ubser_port *pp;
  256 
  257         sc->sc_dev = self;
  258 
  259         DPRINTFN(10,("\nubser_attach: sc=%p\n", sc));
  260 
  261         sc->sc_udev = udev = uaa->device;
  262         sc->sc_iface = uaa->iface;
  263         sc->sc_numser = 0;
  264         sc->sc_port = NULL;
  265 
  266         /* get interface index */
  267         id = usbd_get_interface_descriptor(uaa->iface);
  268         if (id == NULL) {
  269                 printf("ubser: failed to get interface descriptor\n");
  270                 return (UMATCH_NONE);
  271         }
  272         sc->sc_ifaceno = id->bInterfaceNumber;
  273 
  274         /* get number of serials */
  275         req.bmRequestType = UT_READ_VENDOR_INTERFACE;
  276         req.bRequest = VENDOR_GET_NUMSER;
  277         USETW(req.wValue, 0);
  278         USETW(req.wIndex, sc->sc_ifaceno);
  279         USETW(req.wLength, 1);
  280         err = usbd_do_request_flags(udev, &req, &sc->sc_numser,
  281             USBD_SHORT_XFER_OK, &alen, USBD_DEFAULT_TIMEOUT);
  282         if (err) {
  283                 device_printf(self, "failed to get number of serials\n");
  284                 goto bad;
  285         } else if (alen != 1) {
  286                 device_printf(self, "bogus answer on get_numser\n");
  287                 goto bad;
  288         }
  289         if (sc->sc_numser > MAX_SER)
  290                 sc->sc_numser = MAX_SER;
  291         device_printf(self, "found %i serials\n", sc->sc_numser);
  292 
  293         sc->sc_port = malloc(sizeof(*sc->sc_port) * sc->sc_numser,
  294             M_USBDEV, M_WAITOK);
  295 
  296         /* find our bulk endpoints */
  297         epcount = 0;
  298         (void)usbd_endpoint_count(sc->sc_iface, &epcount);
  299         sc->sc_bulkin_no = -1;
  300         sc->sc_bulkout_no = -1;
  301         for (i = 0; i < epcount; i++) {
  302                 ed = usbd_interface2endpoint_descriptor(sc->sc_iface, i);
  303                 if (ed == NULL) {
  304                         device_printf(self, "couldn't get ep %d\n", i);
  305                         return ENXIO;
  306                 }
  307                 if (UE_GET_DIR(ed->bEndpointAddress) == UE_DIR_IN &&
  308                     UE_GET_XFERTYPE(ed->bmAttributes) == UE_BULK) {
  309                         sc->sc_bulkin_no = ed->bEndpointAddress;
  310                         sc->sc_ibufsizepad = UGETW(ed->wMaxPacketSize);
  311                         sc->sc_ibufsizepad = UGETW(ed->wMaxPacketSize) - 1;
  312                 } else if (UE_GET_DIR(ed->bEndpointAddress) == UE_DIR_OUT &&
  313                     UE_GET_XFERTYPE(ed->bmAttributes) == UE_BULK) {
  314                         sc->sc_bulkout_no = ed->bEndpointAddress;
  315                         sc->sc_obufsize = UGETW(ed->wMaxPacketSize) - 1;
  316                         sc->sc_opkthdrlen = 1;
  317                 }
  318         }
  319         if (sc->sc_bulkin_no == -1 || sc->sc_bulkout_no == -1) {
  320                 device_printf(self, "could not find bulk in/out endpoint\n");
  321                 sc->sc_dying = 1;
  322                 goto bad;
  323         }
  324 
  325         /* Open the bulk pipes */
  326         /* Bulk-in pipe */
  327         err = usbd_open_pipe(sc->sc_iface, sc->sc_bulkin_no, 0,
  328                              &sc->sc_bulkin_pipe);
  329         if (err) {
  330                 device_printf(self, "open bulk in error (addr %d): %s\n",
  331                     sc->sc_bulkin_no, usbd_errstr(err));
  332                 goto fail_0;
  333         }
  334         /* Bulk-out pipe */
  335         err = usbd_open_pipe(sc->sc_iface, sc->sc_bulkout_no,
  336                              USBD_EXCLUSIVE_USE, &sc->sc_bulkout_pipe);
  337         if (err) {
  338                 device_printf(self, "open bulk out error (addr %d): %s\n",
  339                     sc->sc_bulkout_no, usbd_errstr(err));
  340                 goto fail_1;
  341         }
  342 
  343         /* Allocate a request and an input buffer */
  344         sc->sc_ixfer = usbd_alloc_xfer(sc->sc_udev);
  345         if (sc->sc_ixfer == NULL) {
  346                 goto fail_2;
  347         }
  348 
  349         sc->sc_ibuf = usbd_alloc_buffer(sc->sc_ixfer,
  350                                         sc->sc_ibufsizepad);
  351         if (sc->sc_ibuf == NULL) {
  352                 goto fail_3;
  353         }
  354 
  355         for (i = 0; i < sc->sc_numser; i++) {
  356                 pp = &sc->sc_port[i];
  357                 pp->p_port = i;
  358                 pp->p_sc = sc;
  359                 tp = pp->p_tty = ttyalloc();
  360                 tp->t_sc = pp;
  361                 DPRINTF(("ubser_attach: tty_attach tp = %p\n", tp));
  362                 tp->t_oproc = ubserstart;
  363                 tp->t_param = ubserparam;
  364                 tp->t_stop = ubserstop;
  365                 tp->t_break = ubserbreak;
  366                 tp->t_open = ubseropen;
  367                 tp->t_close = ubserclose;
  368                 tp->t_modem = ubsermodem;
  369                 ttycreate(tp, 0, "y%r%r", device_get_unit(sc->sc_dev), i);
  370         }
  371 
  372 
  373         for (i = 0; i < sc->sc_numser; i++) {
  374                 sc->sc_port[i].p_oxfer = NULL;
  375                 sc->sc_port[i].p_obuf = NULL;
  376         }
  377         for (i = 0; i < sc->sc_numser; i++) {
  378                 sc->sc_port[i].p_oxfer = usbd_alloc_xfer(sc->sc_udev);
  379                 if (sc->sc_port[i].p_oxfer == NULL) {
  380                         goto fail_4;
  381                 }
  382 
  383                 sc->sc_port[i].p_obuf = usbd_alloc_buffer(sc->sc_port[i].p_oxfer,
  384                                                 sc->sc_obufsize +
  385                                                 sc->sc_opkthdrlen);
  386                 if (sc->sc_port[i].p_obuf == NULL) {
  387                         goto fail_4;
  388                 }
  389         }
  390 
  391         ubserstartread(sc);
  392         return 0;
  393 
  394 fail_4:
  395         for (i = 0; i < sc->sc_numser; i++) {
  396                 if (sc->sc_port[i].p_oxfer != NULL) {
  397                         usbd_free_xfer(sc->sc_port[i].p_oxfer);
  398                         sc->sc_port[i].p_oxfer = NULL;
  399                 }
  400         }
  401 fail_3:
  402         usbd_free_xfer(sc->sc_ixfer);
  403         sc->sc_ixfer = NULL;
  404 fail_2:
  405         usbd_close_pipe(sc->sc_bulkout_pipe);
  406         sc->sc_bulkout_pipe = NULL;
  407 fail_1:
  408         usbd_close_pipe(sc->sc_bulkin_pipe);
  409         sc->sc_bulkin_pipe = NULL;
  410 fail_0:
  411         sc->sc_opening = 0;
  412         wakeup(&sc->sc_opening);
  413 
  414 bad:
  415         ubser_cleanup(sc);
  416         if (sc->sc_port != NULL) {
  417                 for (i = 0; i < sc->sc_numser; i++) {
  418                         pp = &sc->sc_port[i];
  419                         if (pp->p_tty != NULL)
  420                                 ttyfree(pp->p_tty);
  421                 }
  422                 free(sc->sc_port, M_USBDEV);
  423                 sc->sc_port = NULL;
  424         }
  425 
  426         DPRINTF(("ubser_attach: ATTACH ERROR\n"));
  427         return ENXIO;
  428 }
  429 
  430 static int
  431 ubser_detach(device_t self)
  432 {
  433         struct ubser_softc *sc = device_get_softc(self);
  434         int i;
  435         struct ubser_port *pp;
  436 
  437         DPRINTF(("ubser_detach: sc=%p\n", sc));
  438 
  439         sc->sc_dying = 1;
  440         for (i = 0; i < sc->sc_numser; i++) {
  441                 pp = &sc->sc_port[i];
  442                 if (pp->p_tty != NULL)
  443                         ttygone(pp->p_tty);
  444         }
  445 
  446         if (sc->sc_bulkin_pipe != NULL)
  447                 usbd_abort_pipe(sc->sc_bulkin_pipe);
  448         if (sc->sc_bulkout_pipe != NULL)
  449                 usbd_abort_pipe(sc->sc_bulkout_pipe);
  450 
  451         if (sc->sc_port != NULL) {
  452                 for (i = 0; i < sc->sc_numser; i++) {
  453                         pp = &sc->sc_port[i];
  454                         if (pp->p_tty != NULL)
  455                                 ttyfree(pp->p_tty);
  456                 }
  457                 free(sc->sc_port, M_USBDEV);
  458                 sc->sc_port = NULL;
  459         }
  460 
  461         if (--sc->sc_refcnt >= 0) {
  462                 /* Wait for processes to go away. */
  463                 usb_detach_wait(sc->sc_dev);
  464         }
  465 
  466         return (0);
  467 }
  468 
  469 static int
  470 ubserparam(struct tty *tp, struct termios *t)
  471 {
  472         struct ubser_softc *sc;
  473         struct ubser_port *pp;
  474 
  475         pp = tp->t_sc;
  476         sc = pp->p_sc;
  477 
  478         if (sc->sc_dying)
  479                 return (EIO);
  480 
  481         DPRINTF(("ubserparam: sc = %p\n", sc));
  482 
  483         /*
  484          * The firmware on our devices can only do 8n1@9600bps
  485          * without handshake.
  486          * We refuse to accept other configurations.
  487          */
  488 
  489         /* enshure 9600bps */
  490         switch (t->c_ospeed) {
  491         case 9600:
  492                 break;
  493         default:
  494                 return (EINVAL);
  495         }
  496 
  497         /* 2 stop bits not possible */
  498         if (ISSET(t->c_cflag, CSTOPB))
  499                 return (EINVAL);
  500 
  501         /* XXX parity handling not possible with current firmware */
  502         if (ISSET(t->c_cflag, PARENB))
  503                 return (EINVAL);
  504 
  505         /* we can only do 8 data bits */
  506         switch (ISSET(t->c_cflag, CSIZE)) {
  507         case CS8:
  508                 break;
  509         default:
  510                 return (EINVAL);
  511         }
  512 
  513         /* we can't do any kind of hardware handshaking */
  514         if ((t->c_cflag &
  515             (CRTS_IFLOW | CDTR_IFLOW |CDSR_OFLOW |CCAR_OFLOW)) != 0)
  516                 return (EINVAL);
  517 
  518         /*
  519          * XXX xon/xoff not supported by the firmware!
  520          * This is handled within FreeBSD only and may overflow buffers
  521          * because of delayed reaction due to device buffering.
  522          */
  523 
  524         ttsetwater(tp);
  525 
  526         return (0);
  527 }
  528 
  529 static void
  530 ubserstart(struct tty *tp)
  531 {
  532         struct ubser_softc *sc;
  533         struct ubser_port *pp;
  534         struct cblock *cbp;
  535         usbd_status err;
  536         u_char *data;
  537         int cnt;
  538         uint8_t serial;
  539 
  540         pp = tp->t_sc;
  541         sc = pp->p_sc;
  542         serial = pp->p_port;
  543         DPRINTF(("ubserstart: sc = %p, tp = %p\n", sc, tp));
  544 
  545         if (sc->sc_dying)
  546                 return;
  547 
  548         if (ISSET(tp->t_state, TS_BUSY | TS_TIMEOUT | TS_TTSTOP)) {
  549                 ttwwakeup(tp);
  550                 DPRINTF(("ubserstart: stopped\n"));
  551                 return;
  552         }
  553 
  554         if (tp->t_outq.c_cc <= tp->t_olowat) {
  555                 if (ISSET(tp->t_state, TS_SO_OLOWAT)) {
  556                         CLR(tp->t_state, TS_SO_OLOWAT);
  557                         wakeup(TSA_OLOWAT(tp));
  558                 }
  559                 selwakeuppri(&tp->t_wsel, TTIPRI);
  560                 if (tp->t_outq.c_cc == 0) {
  561                         if (ISSET(tp->t_state, TS_BUSY | TS_SO_OCOMPLETE) ==
  562                             TS_SO_OCOMPLETE && tp->t_outq.c_cc == 0) {
  563                                 CLR(tp->t_state, TS_SO_OCOMPLETE);
  564                                 wakeup(TSA_OCOMPLETE(tp));
  565                         }
  566                         return;
  567                 }
  568         }
  569 
  570         /* Grab the first contiguous region of buffer space. */
  571         data = tp->t_outq.c_cf;
  572         cbp = (struct cblock *) ((intptr_t) tp->t_outq.c_cf & ~CROUND);
  573         cnt = min((char *) (cbp+1) - tp->t_outq.c_cf, tp->t_outq.c_cc);
  574 
  575         if (cnt == 0) {
  576                 DPRINTF(("ubserstart: cnt == 0\n"));
  577                 return;
  578         }
  579 
  580         SET(tp->t_state, TS_BUSY);
  581 
  582         if (cnt + sc->sc_opkthdrlen > sc->sc_obufsize) {
  583                 DPRINTF(("ubserstart: big buffer %d chars\n", cnt));
  584                 cnt = sc->sc_obufsize;
  585         }
  586         sc->sc_port[serial].p_obuf[0] = serial;
  587         memcpy(sc->sc_port[serial].p_obuf + sc->sc_opkthdrlen, data, cnt);
  588 
  589 
  590         DPRINTF(("ubserstart: %d chars\n", cnt));
  591         usbd_setup_xfer(sc->sc_port[serial].p_oxfer, sc->sc_bulkout_pipe,
  592                         (usbd_private_handle)tp, sc->sc_port[serial].p_obuf,
  593                         cnt + sc->sc_opkthdrlen,
  594                         USBD_NO_COPY, USBD_NO_TIMEOUT, ubserwritecb);
  595         /* What can we do on error? */
  596         err = usbd_transfer(sc->sc_port[serial].p_oxfer);
  597         if (err != USBD_IN_PROGRESS)
  598                 printf("ubserstart: err=%s\n", usbd_errstr(err));
  599 
  600         ttwwakeup(tp);
  601 }
  602 
  603 static void
  604 ubserstop(struct tty *tp, int flag)
  605 {
  606         struct ubser_softc *sc;
  607 
  608         sc = tp->t_sc;
  609 
  610         DPRINTF(("ubserstop: %d\n", flag));
  611 
  612         if (flag & FWRITE) {
  613                 DPRINTF(("ubserstop: write\n"));
  614                 if (ISSET(tp->t_state, TS_BUSY)) {
  615                         /* XXX do what? */
  616                         if (!ISSET(tp->t_state, TS_TTSTOP))
  617                                 SET(tp->t_state, TS_FLUSH);
  618                 }
  619         }
  620 
  621         DPRINTF(("ubserstop: done\n"));
  622 }
  623 
  624 static void
  625 ubserwritecb(usbd_xfer_handle xfer, usbd_private_handle p, usbd_status status)
  626 {
  627         struct tty *tp;
  628         struct ubser_softc *sc;
  629         struct ubser_port *pp;
  630         u_int32_t cc;
  631 
  632         tp = (struct tty *)p;
  633         pp = tp->t_sc;
  634         sc = pp->p_sc;
  635 
  636         DPRINTF(("ubserwritecb: status = %d\n", status));
  637 
  638         if (status == USBD_CANCELLED || sc->sc_dying)
  639                 goto error;
  640 
  641         if (status != USBD_NORMAL_COMPLETION) {
  642                 device_printf(sc->sc_dev, "ubserwritecb: %s\n",
  643                     usbd_errstr(status));
  644                 if (status == USBD_STALLED)
  645                         usbd_clear_endpoint_stall_async(sc->sc_bulkin_pipe);
  646                 /* XXX we should restart after some delay. */
  647                 goto error;
  648         }
  649 
  650         usbd_get_xfer_status(xfer, NULL, NULL, &cc, NULL);
  651         DPRINTF(("ubserwritecb: cc = %d\n", cc));
  652         if (cc <= sc->sc_opkthdrlen) {
  653                 device_printf(sc->sc_dev, "sent size too small, cc = %d\n",
  654                     cc);
  655                 goto error;
  656         }
  657 
  658         /* convert from USB bytes to tty bytes */
  659         cc -= sc->sc_opkthdrlen;
  660 
  661         CLR(tp->t_state, TS_BUSY);
  662         if (ISSET(tp->t_state, TS_FLUSH))
  663                 CLR(tp->t_state, TS_FLUSH);
  664         else
  665                 ndflush(&tp->t_outq, cc);
  666         ttyld_start(tp);
  667 
  668         return;
  669 
  670 error:
  671         CLR(tp->t_state, TS_BUSY);
  672         return;
  673 }
  674 
  675 static usbd_status
  676 ubserstartread(struct ubser_softc *sc)
  677 {
  678         usbd_status err;
  679 
  680         DPRINTF(("ubserstartread: start\n"));
  681 
  682         if (sc->sc_bulkin_pipe == NULL)
  683                 return (USBD_NORMAL_COMPLETION);
  684 
  685         usbd_setup_xfer(sc->sc_ixfer, sc->sc_bulkin_pipe,
  686                         (usbd_private_handle)sc,
  687                         sc->sc_ibuf, sc->sc_ibufsizepad,
  688                         USBD_SHORT_XFER_OK | USBD_NO_COPY,
  689                         USBD_NO_TIMEOUT, ubserreadcb);
  690 
  691         err = usbd_transfer(sc->sc_ixfer);
  692         if (err != USBD_IN_PROGRESS) {
  693                 DPRINTF(("ubserstartread: err = %s\n", usbd_errstr(err)));
  694                 return (err);
  695         }
  696 
  697         return (USBD_NORMAL_COMPLETION);
  698 }
  699 
  700 static void
  701 ubserreadcb(usbd_xfer_handle xfer, usbd_private_handle p, usbd_status status)
  702 {
  703         struct ubser_softc *sc = (struct ubser_softc *)p;
  704         struct tty *tp;
  705         usbd_status err;
  706         u_int32_t cc;
  707         u_char *cp;
  708         int lostcc;
  709 
  710         if (status == USBD_IOERROR) {
  711                 device_printf(sc->sc_dev, "ubserreadcb: %s - restarting\n",
  712                     usbd_errstr(status));
  713                 goto resubmit;
  714         }
  715 
  716         DPRINTF(("ubserreadcb: status = %d\n", status));
  717 
  718         if (status != USBD_NORMAL_COMPLETION) {
  719                 if (status != USBD_CANCELLED) {
  720                         device_printf(sc->sc_dev, "ubserreadcb: %s\n",
  721                             usbd_errstr(status));
  722                 }
  723                 if (status == USBD_STALLED)
  724                         usbd_clear_endpoint_stall_async(sc->sc_bulkin_pipe);
  725                 return;
  726         }
  727 
  728         usbd_get_xfer_status(xfer, NULL, (void **)&cp, &cc, NULL);
  729 
  730         DPRINTF(("ubserreadcb: got %d bytes from device\n", cc));
  731         if (cc == 0)
  732                 goto resubmit;
  733 
  734         if (cc > sc->sc_ibufsizepad) {
  735                 device_printf(sc->sc_dev, "invalid receive data size, %d chars\n",
  736                     cc);
  737                 goto resubmit;
  738         }
  739 
  740         /* parse header */
  741         if (cc < 1)
  742                 goto resubmit;
  743         DPRINTF(("ubserreadcb: got %d chars for serial %d\n", cc - 1, *cp));
  744         tp = sc->sc_port[*cp].p_tty;
  745         cp++;
  746         cc--;
  747 
  748         if (cc < 1)
  749                 goto resubmit;
  750 
  751         if (!(tp->t_state & TS_ISOPEN)) /* drop data for unused serials */
  752                 goto resubmit;
  753 
  754         if (tp->t_state & TS_CAN_BYPASS_L_RINT) {
  755                 if (tp->t_rawq.c_cc + cc > tp->t_ihiwat
  756                     && (tp->t_iflag & IXOFF)
  757                     && !(tp->t_state & TS_TBLOCK))
  758                         ttyblock(tp);
  759                 lostcc = b_to_q((char *)cp, cc, &tp->t_rawq);
  760                 tp->t_rawcc += cc;
  761                 ttwakeup(tp);
  762                 if (tp->t_state & TS_TTSTOP
  763                     && (tp->t_iflag & IXANY
  764                         || tp->t_cc[VSTART] == tp->t_cc[VSTOP])) {
  765                         tp->t_state &= ~TS_TTSTOP;
  766                         tp->t_lflag &= ~FLUSHO;
  767                         ubserstart(tp);
  768                 }
  769                 if (lostcc > 0)
  770                         device_printf(sc->sc_dev, "lost %d chars\n", lostcc);
  771         } else {
  772                 /* Give characters to tty layer. */
  773                 while (cc > 0) {
  774                         DPRINTFN(7, ("ubserreadcb: char = 0x%02x\n", *cp));
  775                         if (ttyld_rint(tp, *cp) == -1) {
  776                                 /* XXX what should we do? */
  777                                 device_printf(sc->sc_dev, "lost %d chars\n",
  778                                     cc);
  779                                 break;
  780                         }
  781                         cc--;
  782                         cp++;
  783                 }
  784         }
  785 
  786 resubmit:
  787         err = ubserstartread(sc);
  788         if (err) {
  789                 device_printf(sc->sc_dev, "read start failed\n");
  790                 /* XXX what should we do now? */
  791         }
  792 
  793 }
  794 
  795 static void
  796 ubser_cleanup(struct ubser_softc *sc)
  797 {
  798         int i;
  799         struct ubser_port *pp;
  800 
  801         DPRINTF(("ubser_cleanup: closing pipes\n"));
  802 
  803         if (sc->sc_bulkin_pipe != NULL) {
  804                 usbd_abort_pipe(sc->sc_bulkin_pipe);
  805                 usbd_close_pipe(sc->sc_bulkin_pipe);
  806                 sc->sc_bulkin_pipe = NULL;
  807         }
  808         if (sc->sc_bulkout_pipe != NULL) {
  809                 usbd_abort_pipe(sc->sc_bulkout_pipe);
  810                 usbd_close_pipe(sc->sc_bulkout_pipe);
  811                 sc->sc_bulkout_pipe = NULL;
  812         }
  813         if (sc->sc_ixfer != NULL) {
  814                 usbd_free_xfer(sc->sc_ixfer);
  815                 sc->sc_ixfer = NULL;
  816         }
  817         for (i = 0; i < sc->sc_numser; i++) {
  818                 pp = &sc->sc_port[i];
  819                 if (pp->p_oxfer != NULL) {
  820                         usbd_free_xfer(pp->p_oxfer);
  821                         pp->p_oxfer = NULL;
  822                 }
  823         }
  824 }
  825 
  826 static int
  827 ubseropen(struct tty *tp, struct cdev *dev)
  828 {
  829         struct ubser_softc *sc;
  830         struct ubser_port *pp;
  831 
  832         pp = tp->t_sc;
  833         sc = pp->p_sc;
  834 
  835         sc->sc_refcnt++;        /* XXX: wrong refcnt on error later on */
  836         return (0);
  837 }
  838 
  839 static void
  840 ubserclose(struct tty *tp)
  841 {
  842         struct ubser_softc *sc;
  843         struct ubser_port *pp;
  844 
  845         pp = tp->t_sc;
  846         sc = pp->p_sc;
  847         if (--sc->sc_refcnt < 0)
  848                 usb_detach_wakeup(sc->sc_dev);
  849 }
  850 
  851 static void
  852 ubserbreak(struct tty *tp, int sig)
  853 {
  854         usb_device_request_t req;
  855         struct ubser_softc *sc;
  856         struct ubser_port *pp;
  857         int error;
  858         int alen;
  859 
  860         pp = tp->t_sc;
  861         sc = pp->p_sc;
  862         if (sig) {
  863                 DPRINTF(("ubser_break: TIOCSBRK\n"));
  864                 req.bmRequestType = UT_READ_VENDOR_INTERFACE;
  865                 req.bRequest = VENDOR_SET_BREAK;
  866                 USETW(req.wValue, pp->p_port);
  867                 USETW(req.wIndex, sc->sc_ifaceno);
  868                 USETW(req.wLength, 0);
  869                 error = usbd_do_request_flags(sc->sc_udev, &req, &sc->sc_numser,
  870                     USBD_SHORT_XFER_OK, &alen, USBD_DEFAULT_TIMEOUT);
  871         }
  872 }
  873 
  874 static int
  875 ubsermodem(struct tty *tp, int sigon, int sigoff)
  876 {
  877 
  878         return (SER_DTR | SER_RTS | SER_DCD);
  879 }
  880 
  881 MODULE_DEPEND(ubser, usb, 1, 1, 1);
  882 DRIVER_MODULE(ubser, uhub, ubser_driver, ubser_devclass, usbd_driver_load, 0);

Cache object: b2ab3129396cbbdad19c2c5ab95d266a


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