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/ucom.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: ucom.c,v 1.52 2003/11/24 19:47:07 nathanw Exp $        */
    2 
    3 /*
    4  * Copyright (c) 1998, 2000 The NetBSD Foundation, Inc.
    5  * All rights reserved.
    6  *
    7  * This code is derived from software contributed to The NetBSD Foundation
    8  * by Lennart Augustsson (lennart@augustsson.net) at
    9  * Carlstedt Research & Technology.
   10  *
   11  * Redistribution and use in source and binary forms, with or without
   12  * modification, are permitted provided that the following conditions
   13  * are met:
   14  * 1. Redistributions of source code must retain the above copyright
   15  *    notice, this list of conditions and the following disclaimer.
   16  * 2. Redistributions in binary form must reproduce the above copyright
   17  *    notice, this list of conditions and the following disclaimer in the
   18  *    documentation and/or other materials provided with the distribution.
   19  * 3. All advertising materials mentioning features or use of this software
   20  *    must display the following acknowledgement:
   21  *        This product includes software developed by the NetBSD
   22  *        Foundation, Inc. and its contributors.
   23  * 4. Neither the name of The NetBSD Foundation nor the names of its
   24  *    contributors may be used to endorse or promote products derived
   25  *    from this software without specific prior written permission.
   26  *
   27  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
   28  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
   29  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
   30  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
   31  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
   32  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
   33  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
   34  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
   35  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
   36  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
   37  * POSSIBILITY OF SUCH DAMAGE.
   38  */
   39 /*
   40  * This code is very heavily based on the 16550 driver, com.c.
   41  */
   42 
   43 #include <sys/cdefs.h>
   44 __KERNEL_RCSID(0, "$NetBSD: ucom.c,v 1.52 2003/11/24 19:47:07 nathanw Exp $");
   45 
   46 #include <sys/param.h>
   47 #include <sys/systm.h>
   48 #include <sys/kernel.h>
   49 #include <sys/ioctl.h>
   50 #include <sys/conf.h>
   51 #include <sys/tty.h>
   52 #include <sys/file.h>
   53 #include <sys/select.h>
   54 #include <sys/proc.h>
   55 #include <sys/vnode.h>
   56 #include <sys/device.h>
   57 #include <sys/poll.h>
   58 #if defined(__NetBSD__)
   59 #include "rnd.h"
   60 #if NRND > 0
   61 #include <sys/rnd.h>
   62 #endif
   63 #endif
   64 
   65 #include <dev/usb/usb.h>
   66 
   67 #include <dev/usb/usbdi.h>
   68 #include <dev/usb/usbdi_util.h>
   69 #include <dev/usb/usbdevs.h>
   70 #include <dev/usb/usb_quirks.h>
   71 
   72 #include <dev/usb/ucomvar.h>
   73 
   74 #include "ucom.h"
   75 
   76 #if NUCOM > 0
   77 
   78 #ifdef UCOM_DEBUG
   79 #define DPRINTFN(n, x)  if (ucomdebug > (n)) logprintf x
   80 int ucomdebug = 0;
   81 #else
   82 #define DPRINTFN(n, x)
   83 #endif
   84 #define DPRINTF(x) DPRINTFN(0, x)
   85 
   86 #define UCOMUNIT_MASK           0x3ffff
   87 #define UCOMDIALOUT_MASK        0x80000
   88 #define UCOMCALLUNIT_MASK       0x40000
   89 
   90 #define UCOMUNIT(x)             (minor(x) & UCOMUNIT_MASK)
   91 #define UCOMDIALOUT(x)          (minor(x) & UCOMDIALOUT_MASK)
   92 #define UCOMCALLUNIT(x)         (minor(x) & UCOMCALLUNIT_MASK)
   93 
   94 struct ucom_softc {
   95         USBBASEDEVICE           sc_dev;         /* base device */
   96 
   97         usbd_device_handle      sc_udev;        /* USB device */
   98 
   99         usbd_interface_handle   sc_iface;       /* data interface */
  100 
  101         int                     sc_bulkin_no;   /* bulk in endpoint address */
  102         usbd_pipe_handle        sc_bulkin_pipe; /* bulk in pipe */
  103         usbd_xfer_handle        sc_ixfer;       /* read request */
  104         u_char                  *sc_ibuf;       /* read buffer */
  105         u_int                   sc_ibufsize;    /* read buffer size */
  106         u_int                   sc_ibufsizepad; /* read buffer size padded */
  107 
  108         int                     sc_bulkout_no;  /* bulk out endpoint address */
  109         usbd_pipe_handle        sc_bulkout_pipe;/* bulk out pipe */
  110         usbd_xfer_handle        sc_oxfer;       /* write request */
  111         u_char                  *sc_obuf;       /* write buffer */
  112         u_int                   sc_obufsize;    /* write buffer size */
  113         u_int                   sc_opkthdrlen;  /* header length of
  114                                                  * output packet */
  115 
  116         struct ucom_methods     *sc_methods;
  117         void                    *sc_parent;
  118         int                     sc_portno;
  119 
  120         struct tty              *sc_tty;        /* our tty */
  121         u_char                  sc_lsr;
  122         u_char                  sc_msr;
  123         u_char                  sc_mcr;
  124         u_char                  sc_tx_stopped;
  125         int                     sc_swflags;
  126 
  127         u_char                  sc_opening;     /* lock during open */
  128         int                     sc_refcnt;
  129         u_char                  sc_dying;       /* disconnecting */
  130 
  131 #if defined(__NetBSD__) && NRND > 0
  132         rndsource_element_t     sc_rndsource;   /* random source */
  133 #endif
  134 };
  135 
  136 dev_type_open(ucomopen);
  137 dev_type_close(ucomclose);
  138 dev_type_read(ucomread);
  139 dev_type_write(ucomwrite);
  140 dev_type_ioctl(ucomioctl);
  141 dev_type_stop(ucomstop);
  142 dev_type_tty(ucomtty);
  143 dev_type_poll(ucompoll);
  144 
  145 const struct cdevsw ucom_cdevsw = {
  146         ucomopen, ucomclose, ucomread, ucomwrite, ucomioctl,
  147         ucomstop, ucomtty, ucompoll, nommap, ttykqfilter, D_TTY
  148 };
  149 
  150 Static void     ucom_cleanup(struct ucom_softc *);
  151 Static void     ucom_hwiflow(struct ucom_softc *);
  152 Static int      ucomparam(struct tty *, struct termios *);
  153 Static void     ucomstart(struct tty *);
  154 Static void     ucom_shutdown(struct ucom_softc *);
  155 Static int      ucom_do_ioctl(struct ucom_softc *, u_long, caddr_t,
  156                               int, usb_proc_ptr);
  157 Static void     ucom_dtr(struct ucom_softc *, int);
  158 Static void     ucom_rts(struct ucom_softc *, int);
  159 Static void     ucom_break(struct ucom_softc *, int);
  160 Static usbd_status ucomstartread(struct ucom_softc *);
  161 Static void     ucomreadcb(usbd_xfer_handle, usbd_private_handle, usbd_status);
  162 Static void     ucomwritecb(usbd_xfer_handle, usbd_private_handle, usbd_status);
  163 Static void     tiocm_to_ucom(struct ucom_softc *, u_long, int);
  164 Static int      ucom_to_tiocm(struct ucom_softc *);
  165 
  166 USB_DECLARE_DRIVER(ucom);
  167 
  168 USB_MATCH(ucom)
  169 {
  170         return (1);
  171 }
  172 
  173 USB_ATTACH(ucom)
  174 {
  175         struct ucom_softc *sc = (struct ucom_softc *)self;
  176         struct ucom_attach_args *uca = aux;
  177         struct tty *tp;
  178 
  179         if (uca->portno != UCOM_UNK_PORTNO)
  180                 printf(": portno %d", uca->portno);
  181         if (uca->info != NULL)
  182                 printf(", %s", uca->info);
  183         printf("\n");
  184 
  185         sc->sc_udev = uca->device;
  186         sc->sc_iface = uca->iface;
  187         sc->sc_bulkout_no = uca->bulkout;
  188         sc->sc_bulkin_no = uca->bulkin;
  189         sc->sc_ibufsize = uca->ibufsize;
  190         sc->sc_ibufsizepad = uca->ibufsizepad;
  191         sc->sc_obufsize = uca->obufsize;
  192         sc->sc_opkthdrlen = uca->opkthdrlen;
  193         sc->sc_methods = uca->methods;
  194         sc->sc_parent = uca->arg;
  195         sc->sc_portno = uca->portno;
  196 
  197         tp = ttymalloc();
  198         tp->t_oproc = ucomstart;
  199         tp->t_param = ucomparam;
  200         sc->sc_tty = tp;
  201 
  202         DPRINTF(("ucom_attach: tty_attach %p\n", tp));
  203         tty_attach(tp);
  204 
  205 #if defined(__NetBSD__) && NRND > 0
  206         rnd_attach_source(&sc->sc_rndsource, USBDEVNAME(sc->sc_dev),
  207                           RND_TYPE_TTY, 0);
  208 #endif
  209 
  210         USB_ATTACH_SUCCESS_RETURN;
  211 }
  212 
  213 USB_DETACH(ucom)
  214 {
  215         struct ucom_softc *sc = (struct ucom_softc *)self;
  216         struct tty *tp = sc->sc_tty;
  217         int maj, mn;
  218         int s;
  219 
  220         DPRINTF(("ucom_detach: sc=%p flags=%d tp=%p, pipe=%d,%d\n",
  221                  sc, flags, tp, sc->sc_bulkin_no, sc->sc_bulkout_no));
  222 
  223         sc->sc_dying = 1;
  224 
  225         if (sc->sc_bulkin_pipe != NULL)
  226                 usbd_abort_pipe(sc->sc_bulkin_pipe);
  227         if (sc->sc_bulkout_pipe != NULL)
  228                 usbd_abort_pipe(sc->sc_bulkout_pipe);
  229 
  230         s = splusb();
  231         if (--sc->sc_refcnt >= 0) {
  232                 /* Wake up anyone waiting */
  233                 if (tp != NULL) {
  234                         CLR(tp->t_state, TS_CARR_ON);
  235                         CLR(tp->t_cflag, CLOCAL | MDMBUF);
  236                         ttyflush(tp, FREAD|FWRITE);
  237                 }
  238                 /* Wait for processes to go away. */
  239                 usb_detach_wait(USBDEV(sc->sc_dev));
  240         }
  241         splx(s);
  242 
  243         /* locate the major number */
  244         maj = cdevsw_lookup_major(&ucom_cdevsw);
  245 
  246         /* Nuke the vnodes for any open instances. */
  247         mn = self->dv_unit;
  248         DPRINTF(("ucom_detach: maj=%d mn=%d\n", maj, mn));
  249         vdevgone(maj, mn, mn, VCHR);
  250         vdevgone(maj, mn | UCOMDIALOUT_MASK, mn | UCOMDIALOUT_MASK, VCHR);
  251         vdevgone(maj, mn | UCOMCALLUNIT_MASK, mn | UCOMCALLUNIT_MASK, VCHR);
  252 
  253         /* Detach and free the tty. */
  254         if (tp != NULL) {
  255                 tty_detach(tp);
  256                 ttyfree(tp);
  257                 sc->sc_tty = NULL;
  258         }
  259 
  260         /* Detach the random source */
  261 #if defined(__NetBSD__) && NRND > 0
  262         rnd_detach_source(&sc->sc_rndsource);
  263 #endif
  264 
  265         return (0);
  266 }
  267 
  268 int
  269 ucom_activate(device_ptr_t self, enum devact act)
  270 {
  271         struct ucom_softc *sc = (struct ucom_softc *)self;
  272 
  273         DPRINTFN(5,("ucom_activate: %d\n", act));
  274 
  275         switch (act) {
  276         case DVACT_ACTIVATE:
  277                 return (EOPNOTSUPP);
  278 
  279         case DVACT_DEACTIVATE:
  280                 sc->sc_dying = 1;
  281                 break;
  282         }
  283         return (0);
  284 }
  285 
  286 void
  287 ucom_shutdown(struct ucom_softc *sc)
  288 {
  289         struct tty *tp = sc->sc_tty;
  290 
  291         DPRINTF(("ucom_shutdown\n"));
  292         /*
  293          * Hang up if necessary.  Wait a bit, so the other side has time to
  294          * notice even if we immediately open the port again.
  295          */
  296         if (ISSET(tp->t_cflag, HUPCL)) {
  297                 ucom_dtr(sc, 0);
  298                 (void)tsleep(sc, TTIPRI, ttclos, hz);
  299         }
  300 }
  301 
  302 int
  303 ucomopen(dev_t dev, int flag, int mode, usb_proc_ptr p)
  304 {
  305         int unit = UCOMUNIT(dev);
  306         usbd_status err;
  307         struct ucom_softc *sc;
  308         struct tty *tp;
  309         int s;
  310         int error;
  311 
  312         if (unit >= ucom_cd.cd_ndevs)
  313                 return (ENXIO);
  314         sc = ucom_cd.cd_devs[unit];
  315         if (sc == NULL)
  316                 return (ENXIO);
  317 
  318         if (sc->sc_dying)
  319                 return (EIO);
  320 
  321         if (ISSET(sc->sc_dev.dv_flags, DVF_ACTIVE) == 0)
  322                 return (ENXIO);
  323 
  324         tp = sc->sc_tty;
  325 
  326         DPRINTF(("ucomopen: unit=%d, tp=%p\n", unit, tp));
  327 
  328         if (ISSET(tp->t_state, TS_ISOPEN) &&
  329             ISSET(tp->t_state, TS_XCLUDE) &&
  330             p->p_ucred->cr_uid != 0)
  331                 return (EBUSY);
  332 
  333         s = spltty();
  334 
  335         /*
  336          * Do the following iff this is a first open.
  337          */
  338         while (sc->sc_opening)
  339                 tsleep(&sc->sc_opening, PRIBIO, "ucomop", 0);
  340 
  341         if (sc->sc_dying) {
  342                 splx(s);
  343                 return (EIO);
  344         }
  345         sc->sc_opening = 1;
  346 
  347         if (!ISSET(tp->t_state, TS_ISOPEN) && tp->t_wopen == 0) {
  348                 struct termios t;
  349 
  350                 tp->t_dev = dev;
  351 
  352                 if (sc->sc_methods->ucom_open != NULL) {
  353                         error = sc->sc_methods->ucom_open(sc->sc_parent,
  354                                                           sc->sc_portno);
  355                         if (error) {
  356                                 ucom_cleanup(sc);
  357                                 sc->sc_opening = 0;
  358                                 wakeup(&sc->sc_opening);
  359                                 splx(s);
  360                                 return (error);
  361                         }
  362                 }
  363 
  364                 ucom_status_change(sc);
  365 
  366                 /*
  367                  * Initialize the termios status to the defaults.  Add in the
  368                  * sticky bits from TIOCSFLAGS.
  369                  */
  370                 t.c_ispeed = 0;
  371                 t.c_ospeed = TTYDEF_SPEED;
  372                 t.c_cflag = TTYDEF_CFLAG;
  373                 if (ISSET(sc->sc_swflags, TIOCFLAG_CLOCAL))
  374                         SET(t.c_cflag, CLOCAL);
  375                 if (ISSET(sc->sc_swflags, TIOCFLAG_CRTSCTS))
  376                         SET(t.c_cflag, CRTSCTS);
  377                 if (ISSET(sc->sc_swflags, TIOCFLAG_MDMBUF))
  378                         SET(t.c_cflag, MDMBUF);
  379                 /* Make sure ucomparam() will do something. */
  380                 tp->t_ospeed = 0;
  381                 (void) ucomparam(tp, &t);
  382                 tp->t_iflag = TTYDEF_IFLAG;
  383                 tp->t_oflag = TTYDEF_OFLAG;
  384                 tp->t_lflag = TTYDEF_LFLAG;
  385                 ttychars(tp);
  386                 ttsetwater(tp);
  387 
  388                 /*
  389                  * Turn on DTR.  We must always do this, even if carrier is not
  390                  * present, because otherwise we'd have to use TIOCSDTR
  391                  * immediately after setting CLOCAL, which applications do not
  392                  * expect.  We always assert DTR while the device is open
  393                  * unless explicitly requested to deassert it.
  394                  */
  395                 ucom_dtr(sc, 1);
  396 
  397                 /* XXX CLR(sc->sc_rx_flags, RX_ANY_BLOCK);*/
  398                 ucom_hwiflow(sc);
  399 
  400                 DPRINTF(("ucomopen: open pipes in=%d out=%d\n",
  401                          sc->sc_bulkin_no, sc->sc_bulkout_no));
  402 
  403                 /* Open the bulk pipes */
  404                 err = usbd_open_pipe(sc->sc_iface, sc->sc_bulkin_no, 0,
  405                                      &sc->sc_bulkin_pipe);
  406                 if (err) {
  407                         DPRINTF(("%s: open bulk in error (addr %d), err=%s\n",
  408                                  USBDEVNAME(sc->sc_dev), sc->sc_bulkin_no,
  409                                  usbd_errstr(err)));
  410                         error = EIO;
  411                         goto fail_0;
  412                 }
  413                 err = usbd_open_pipe(sc->sc_iface, sc->sc_bulkout_no,
  414                                      USBD_EXCLUSIVE_USE, &sc->sc_bulkout_pipe);
  415                 if (err) {
  416                         DPRINTF(("%s: open bulk out error (addr %d), err=%s\n",
  417                                  USBDEVNAME(sc->sc_dev), sc->sc_bulkout_no,
  418                                  usbd_errstr(err)));
  419                         error = EIO;
  420                         goto fail_1;
  421                 }
  422 
  423                 /* Allocate a request and an input buffer and start reading. */
  424                 sc->sc_ixfer = usbd_alloc_xfer(sc->sc_udev);
  425                 if (sc->sc_ixfer == NULL) {
  426                         error = ENOMEM;
  427                         goto fail_2;
  428                 }
  429 
  430                 sc->sc_ibuf = usbd_alloc_buffer(sc->sc_ixfer,
  431                                                 sc->sc_ibufsizepad);
  432                 if (sc->sc_ibuf == NULL) {
  433                         error = ENOMEM;
  434                         goto fail_3;
  435                 }
  436 
  437                 sc->sc_oxfer = usbd_alloc_xfer(sc->sc_udev);
  438                 if (sc->sc_oxfer == NULL) {
  439                         error = ENOMEM;
  440                         goto fail_3;
  441                 }
  442 
  443                 sc->sc_obuf = usbd_alloc_buffer(sc->sc_oxfer,
  444                                                 sc->sc_obufsize +
  445                                                 sc->sc_opkthdrlen);
  446                 if (sc->sc_obuf == NULL) {
  447                         error = ENOMEM;
  448                         goto fail_4;
  449                 }
  450 
  451                 ucomstartread(sc);
  452         }
  453         sc->sc_opening = 0;
  454         wakeup(&sc->sc_opening);
  455         splx(s);
  456 
  457         error = ttyopen(tp, UCOMDIALOUT(dev), ISSET(flag, O_NONBLOCK));
  458         if (error)
  459                 goto bad;
  460 
  461         error = (*tp->t_linesw->l_open)(dev, tp);
  462         if (error)
  463                 goto bad;
  464 
  465         return (0);
  466 
  467 fail_4:
  468         usbd_free_xfer(sc->sc_oxfer);
  469         sc->sc_oxfer = NULL;
  470 fail_3:
  471         usbd_free_xfer(sc->sc_ixfer);
  472         sc->sc_ixfer = NULL;
  473 fail_2:
  474         usbd_close_pipe(sc->sc_bulkout_pipe);
  475         sc->sc_bulkout_pipe = NULL;
  476 fail_1:
  477         usbd_close_pipe(sc->sc_bulkin_pipe);
  478         sc->sc_bulkin_pipe = NULL;
  479 fail_0:
  480         sc->sc_opening = 0;
  481         wakeup(&sc->sc_opening);
  482         splx(s);
  483         return (error);
  484 
  485 bad:
  486         if (!ISSET(tp->t_state, TS_ISOPEN) && tp->t_wopen == 0) {
  487                 /*
  488                  * We failed to open the device, and nobody else had it opened.
  489                  * Clean up the state as appropriate.
  490                  */
  491                 ucom_cleanup(sc);
  492         }
  493 
  494         return (error);
  495 }
  496 
  497 int
  498 ucomclose(dev_t dev, int flag, int mode, usb_proc_ptr p)
  499 {
  500         struct ucom_softc *sc = ucom_cd.cd_devs[UCOMUNIT(dev)];
  501         struct tty *tp = sc->sc_tty;
  502 
  503         DPRINTF(("ucomclose: unit=%d\n", UCOMUNIT(dev)));
  504         if (!ISSET(tp->t_state, TS_ISOPEN))
  505                 return (0);
  506 
  507         sc->sc_refcnt++;
  508 
  509         (*tp->t_linesw->l_close)(tp, flag);
  510         ttyclose(tp);
  511 
  512         if (!ISSET(tp->t_state, TS_ISOPEN) && tp->t_wopen == 0) {
  513                 /*
  514                  * Although we got a last close, the device may still be in
  515                  * use; e.g. if this was the dialout node, and there are still
  516                  * processes waiting for carrier on the non-dialout node.
  517                  */
  518                 ucom_cleanup(sc);
  519         }
  520 
  521         if (sc->sc_methods->ucom_close != NULL)
  522                 sc->sc_methods->ucom_close(sc->sc_parent, sc->sc_portno);
  523 
  524         if (--sc->sc_refcnt < 0)
  525                 usb_detach_wakeup(USBDEV(sc->sc_dev));
  526 
  527         return (0);
  528 }
  529 
  530 int
  531 ucomread(dev_t dev, struct uio *uio, int flag)
  532 {
  533         struct ucom_softc *sc = ucom_cd.cd_devs[UCOMUNIT(dev)];
  534         struct tty *tp = sc->sc_tty;
  535         int error;
  536 
  537         if (sc->sc_dying)
  538                 return (EIO);
  539 
  540         sc->sc_refcnt++;
  541         error = ((*tp->t_linesw->l_read)(tp, uio, flag));
  542         if (--sc->sc_refcnt < 0)
  543                 usb_detach_wakeup(USBDEV(sc->sc_dev));
  544         return (error);
  545 }
  546 
  547 int
  548 ucomwrite(dev_t dev, struct uio *uio, int flag)
  549 {
  550         struct ucom_softc *sc = ucom_cd.cd_devs[UCOMUNIT(dev)];
  551         struct tty *tp = sc->sc_tty;
  552         int error;
  553 
  554         if (sc->sc_dying)
  555                 return (EIO);
  556 
  557         sc->sc_refcnt++;
  558         error = ((*tp->t_linesw->l_write)(tp, uio, flag));
  559         if (--sc->sc_refcnt < 0)
  560                 usb_detach_wakeup(USBDEV(sc->sc_dev));
  561         return (error);
  562 }
  563 
  564 int
  565 ucompoll(dev_t dev, int events, usb_proc_ptr p)
  566 {
  567         struct ucom_softc *sc = ucom_cd.cd_devs[UCOMUNIT(dev)];
  568         struct tty *tp = sc->sc_tty;
  569         int error;
  570 
  571         if (sc->sc_dying)
  572                 return (EIO);
  573 
  574         sc->sc_refcnt++;
  575         error = ((*tp->t_linesw->l_poll)(tp, events, p));
  576         if (--sc->sc_refcnt < 0)
  577                 usb_detach_wakeup(USBDEV(sc->sc_dev));
  578         return (error);
  579 }
  580 
  581 struct tty *
  582 ucomtty(dev_t dev)
  583 {
  584         struct ucom_softc *sc = ucom_cd.cd_devs[UCOMUNIT(dev)];
  585         struct tty *tp = sc->sc_tty;
  586 
  587         return (tp);
  588 }
  589 
  590 int
  591 ucomioctl(dev_t dev, u_long cmd, caddr_t data, int flag, usb_proc_ptr p)
  592 {
  593         struct ucom_softc *sc = ucom_cd.cd_devs[UCOMUNIT(dev)];
  594         int error;
  595 
  596         sc->sc_refcnt++;
  597         error = ucom_do_ioctl(sc, cmd, data, flag, p);
  598         if (--sc->sc_refcnt < 0)
  599                 usb_detach_wakeup(USBDEV(sc->sc_dev));
  600         return (error);
  601 }
  602 
  603 Static int
  604 ucom_do_ioctl(struct ucom_softc *sc, u_long cmd, caddr_t data,
  605               int flag, usb_proc_ptr p)
  606 {
  607         struct tty *tp = sc->sc_tty;
  608         int error;
  609         int s;
  610 
  611         if (sc->sc_dying)
  612                 return (EIO);
  613 
  614         DPRINTF(("ucomioctl: cmd=0x%08lx\n", cmd));
  615 
  616         error = (*tp->t_linesw->l_ioctl)(tp, cmd, data, flag, p);
  617         if (error != EPASSTHROUGH)
  618                 return (error);
  619 
  620         error = ttioctl(tp, cmd, data, flag, p);
  621         if (error != EPASSTHROUGH)
  622                 return (error);
  623 
  624         if (sc->sc_methods->ucom_ioctl != NULL) {
  625                 error = sc->sc_methods->ucom_ioctl(sc->sc_parent,
  626                             sc->sc_portno, cmd, data, flag, p);
  627                 if (error != EPASSTHROUGH)
  628                         return (error);
  629         }
  630 
  631         error = 0;
  632 
  633         DPRINTF(("ucomioctl: our cmd=0x%08lx\n", cmd));
  634         s = spltty();
  635 
  636         switch (cmd) {
  637         case TIOCSBRK:
  638                 ucom_break(sc, 1);
  639                 break;
  640 
  641         case TIOCCBRK:
  642                 ucom_break(sc, 0);
  643                 break;
  644 
  645         case TIOCSDTR:
  646                 ucom_dtr(sc, 1);
  647                 break;
  648 
  649         case TIOCCDTR:
  650                 ucom_dtr(sc, 0);
  651                 break;
  652 
  653         case TIOCGFLAGS:
  654                 *(int *)data = sc->sc_swflags;
  655                 break;
  656 
  657         case TIOCSFLAGS:
  658                 error = suser(p->p_ucred, &p->p_acflag);
  659                 if (error)
  660                         break;
  661                 sc->sc_swflags = *(int *)data;
  662                 break;
  663 
  664         case TIOCMSET:
  665         case TIOCMBIS:
  666         case TIOCMBIC:
  667                 tiocm_to_ucom(sc, cmd, *(int *)data);
  668                 break;
  669 
  670         case TIOCMGET:
  671                 *(int *)data = ucom_to_tiocm(sc);
  672                 break;
  673 
  674         default:
  675                 error = EPASSTHROUGH;
  676                 break;
  677         }
  678 
  679         splx(s);
  680 
  681         return (error);
  682 }
  683 
  684 Static void
  685 tiocm_to_ucom(struct ucom_softc *sc, u_long how, int ttybits)
  686 {
  687         u_char combits;
  688 
  689         combits = 0;
  690         if (ISSET(ttybits, TIOCM_DTR))
  691                 SET(combits, UMCR_DTR);
  692         if (ISSET(ttybits, TIOCM_RTS))
  693                 SET(combits, UMCR_RTS);
  694 
  695         switch (how) {
  696         case TIOCMBIC:
  697                 CLR(sc->sc_mcr, combits);
  698                 break;
  699 
  700         case TIOCMBIS:
  701                 SET(sc->sc_mcr, combits);
  702                 break;
  703 
  704         case TIOCMSET:
  705                 CLR(sc->sc_mcr, UMCR_DTR | UMCR_RTS);
  706                 SET(sc->sc_mcr, combits);
  707                 break;
  708         }
  709 
  710         if (how == TIOCMSET || ISSET(combits, UMCR_DTR))
  711                 ucom_dtr(sc, (sc->sc_mcr & UMCR_DTR) != 0);
  712         if (how == TIOCMSET || ISSET(combits, UMCR_RTS))
  713                 ucom_rts(sc, (sc->sc_mcr & UMCR_RTS) != 0);
  714 }
  715 
  716 Static int
  717 ucom_to_tiocm(struct ucom_softc *sc)
  718 {
  719         u_char combits;
  720         int ttybits = 0;
  721 
  722         combits = sc->sc_mcr;
  723         if (ISSET(combits, UMCR_DTR))
  724                 SET(ttybits, TIOCM_DTR);
  725         if (ISSET(combits, UMCR_RTS))
  726                 SET(ttybits, TIOCM_RTS);
  727 
  728         combits = sc->sc_msr;
  729         if (ISSET(combits, UMSR_DCD))
  730                 SET(ttybits, TIOCM_CD);
  731         if (ISSET(combits, UMSR_CTS))
  732                 SET(ttybits, TIOCM_CTS);
  733         if (ISSET(combits, UMSR_DSR))
  734                 SET(ttybits, TIOCM_DSR);
  735         if (ISSET(combits, UMSR_RI | UMSR_TERI))
  736                 SET(ttybits, TIOCM_RI);
  737 
  738 #if 0
  739 XXX;
  740         if (sc->sc_ier != 0)
  741                 SET(ttybits, TIOCM_LE);
  742 #endif
  743 
  744         return (ttybits);
  745 }
  746 
  747 Static void
  748 ucom_break(sc, onoff)
  749         struct ucom_softc *sc;
  750         int onoff;
  751 {
  752         DPRINTF(("ucom_break: onoff=%d\n", onoff));
  753 
  754         if (sc->sc_methods->ucom_set != NULL)
  755                 sc->sc_methods->ucom_set(sc->sc_parent, sc->sc_portno,
  756                     UCOM_SET_BREAK, onoff);
  757 }
  758 
  759 Static void
  760 ucom_dtr(struct ucom_softc *sc, int onoff)
  761 {
  762         DPRINTF(("ucom_dtr: onoff=%d\n", onoff));
  763 
  764         if (sc->sc_methods->ucom_set != NULL)
  765                 sc->sc_methods->ucom_set(sc->sc_parent, sc->sc_portno,
  766                     UCOM_SET_DTR, onoff);
  767 }
  768 
  769 Static void
  770 ucom_rts(struct ucom_softc *sc, int onoff)
  771 {
  772         DPRINTF(("ucom_rts: onoff=%d\n", onoff));
  773 
  774         if (sc->sc_methods->ucom_set != NULL)
  775                 sc->sc_methods->ucom_set(sc->sc_parent, sc->sc_portno,
  776                     UCOM_SET_RTS, onoff);
  777 }
  778 
  779 void
  780 ucom_status_change(struct ucom_softc *sc)
  781 {
  782         struct tty *tp = sc->sc_tty;
  783         u_char old_msr;
  784 
  785         if (sc->sc_methods->ucom_get_status != NULL) {
  786                 old_msr = sc->sc_msr;
  787                 sc->sc_methods->ucom_get_status(sc->sc_parent, sc->sc_portno,
  788                     &sc->sc_lsr, &sc->sc_msr);
  789                 if (ISSET((sc->sc_msr ^ old_msr), UMSR_DCD))
  790                         (*tp->t_linesw->l_modem)(tp,
  791                             ISSET(sc->sc_msr, UMSR_DCD));
  792         } else {
  793                 sc->sc_lsr = 0;
  794                 sc->sc_msr = 0;
  795         }
  796 }
  797 
  798 Static int
  799 ucomparam(struct tty *tp, struct termios *t)
  800 {
  801         struct ucom_softc *sc = ucom_cd.cd_devs[UCOMUNIT(tp->t_dev)];
  802         int error;
  803 
  804         if (sc->sc_dying)
  805                 return (EIO);
  806 
  807         /* Check requested parameters. */
  808         if (t->c_ispeed && t->c_ispeed != t->c_ospeed)
  809                 return (EINVAL);
  810 
  811         /*
  812          * For the console, always force CLOCAL and !HUPCL, so that the port
  813          * is always active.
  814          */
  815         if (ISSET(sc->sc_swflags, TIOCFLAG_SOFTCAR)) {
  816                 SET(t->c_cflag, CLOCAL);
  817                 CLR(t->c_cflag, HUPCL);
  818         }
  819 
  820         /*
  821          * If there were no changes, don't do anything.  This avoids dropping
  822          * input and improves performance when all we did was frob things like
  823          * VMIN and VTIME.
  824          */
  825         if (tp->t_ospeed == t->c_ospeed &&
  826             tp->t_cflag == t->c_cflag)
  827                 return (0);
  828 
  829         /* XXX lcr = ISSET(sc->sc_lcr, LCR_SBREAK) | cflag2lcr(t->c_cflag); */
  830 
  831         /* And copy to tty. */
  832         tp->t_ispeed = 0;
  833         tp->t_ospeed = t->c_ospeed;
  834         tp->t_cflag = t->c_cflag;
  835 
  836         if (sc->sc_methods->ucom_param != NULL) {
  837                 error = sc->sc_methods->ucom_param(sc->sc_parent, sc->sc_portno,
  838                             t);
  839                 if (error)
  840                         return (error);
  841         }
  842 
  843         /* XXX worry about CHWFLOW */
  844 
  845         /*
  846          * Update the tty layer's idea of the carrier bit, in case we changed
  847          * CLOCAL or MDMBUF.  We don't hang up here; we only do that by
  848          * explicit request.
  849          */
  850         DPRINTF(("ucomparam: l_modem\n"));
  851         (void) (*tp->t_linesw->l_modem)(tp, 1 /* XXX carrier */ );
  852 
  853 #if 0
  854 XXX what if the hardware is not open
  855         if (!ISSET(t->c_cflag, CHWFLOW)) {
  856                 if (sc->sc_tx_stopped) {
  857                         sc->sc_tx_stopped = 0;
  858                         ucomstart(tp);
  859                 }
  860         }
  861 #endif
  862 
  863         return (0);
  864 }
  865 
  866 /*
  867  * (un)block input via hw flowcontrol
  868  */
  869 Static void
  870 ucom_hwiflow(struct ucom_softc *sc)
  871 {
  872         DPRINTF(("ucom_hwiflow:\n"));
  873 #if 0
  874 XXX
  875         bus_space_tag_t iot = sc->sc_iot;
  876         bus_space_handle_t ioh = sc->sc_ioh;
  877 
  878         if (sc->sc_mcr_rts == 0)
  879                 return;
  880 
  881         if (ISSET(sc->sc_rx_flags, RX_ANY_BLOCK)) {
  882                 CLR(sc->sc_mcr, sc->sc_mcr_rts);
  883                 CLR(sc->sc_mcr_active, sc->sc_mcr_rts);
  884         } else {
  885                 SET(sc->sc_mcr, sc->sc_mcr_rts);
  886                 SET(sc->sc_mcr_active, sc->sc_mcr_rts);
  887         }
  888         bus_space_write_1(iot, ioh, com_mcr, sc->sc_mcr_active);
  889 #endif
  890 }
  891 
  892 Static void
  893 ucomstart(struct tty *tp)
  894 {
  895         struct ucom_softc *sc = ucom_cd.cd_devs[UCOMUNIT(tp->t_dev)];
  896         usbd_status err;
  897         int s;
  898         u_char *data;
  899         int cnt;
  900 
  901         if (sc->sc_dying)
  902                 return;
  903 
  904         s = spltty();
  905         if (ISSET(tp->t_state, TS_BUSY | TS_TIMEOUT | TS_TTSTOP)) {
  906                 DPRINTFN(4,("ucomstart: no go, state=0x%x\n", tp->t_state));
  907                 goto out;
  908         }
  909         if (sc->sc_tx_stopped)
  910                 goto out;
  911 
  912         if (tp->t_outq.c_cc <= tp->t_lowat) {
  913                 if (ISSET(tp->t_state, TS_ASLEEP)) {
  914                         CLR(tp->t_state, TS_ASLEEP);
  915                         wakeup(&tp->t_outq);
  916                 }
  917                 selwakeup(&tp->t_wsel);
  918                 if (tp->t_outq.c_cc == 0)
  919                         goto out;
  920         }
  921 
  922         /* Grab the first contiguous region of buffer space. */
  923         data = tp->t_outq.c_cf;
  924         cnt = ndqb(&tp->t_outq, 0);
  925 
  926         if (cnt == 0) {
  927                 DPRINTF(("ucomstart: cnt==0\n"));
  928                 goto out;
  929         }
  930 
  931         SET(tp->t_state, TS_BUSY);
  932 
  933         if (cnt > sc->sc_obufsize) {
  934                 DPRINTF(("ucomstart: big buffer %d chars\n", cnt));
  935                 cnt = sc->sc_obufsize;
  936         }
  937         if (sc->sc_methods->ucom_write != NULL)
  938                 sc->sc_methods->ucom_write(sc->sc_parent, sc->sc_portno,
  939                                            sc->sc_obuf, data, &cnt);
  940         else
  941                 memcpy(sc->sc_obuf, data, cnt);
  942 
  943         DPRINTFN(4,("ucomstart: %d chars\n", cnt));
  944         usbd_setup_xfer(sc->sc_oxfer, sc->sc_bulkout_pipe,
  945                         (usbd_private_handle)sc, sc->sc_obuf, cnt,
  946                         USBD_NO_COPY, USBD_NO_TIMEOUT, ucomwritecb);
  947         /* What can we do on error? */
  948         err = usbd_transfer(sc->sc_oxfer);
  949 #ifdef DIAGNOSTIC
  950         if (err != USBD_IN_PROGRESS)
  951                 printf("ucomstart: err=%s\n", usbd_errstr(err));
  952 #endif
  953 
  954 out:
  955         splx(s);
  956 }
  957 
  958 void
  959 ucomstop(struct tty *tp, int flag)
  960 {
  961         DPRINTF(("ucomstop: flag=%d\n", flag));
  962 #if 0
  963         /*struct ucom_softc *sc = ucom_cd.cd_devs[UCOMUNIT(tp->t_dev)];*/
  964         int s;
  965 
  966         s = spltty();
  967         if (ISSET(tp->t_state, TS_BUSY)) {
  968                 DPRINTF(("ucomstop: XXX\n"));
  969                 /* sc->sc_tx_stopped = 1; */
  970                 if (!ISSET(tp->t_state, TS_TTSTOP))
  971                         SET(tp->t_state, TS_FLUSH);
  972         }
  973         splx(s);
  974 #endif
  975 }
  976 
  977 Static void
  978 ucomwritecb(usbd_xfer_handle xfer, usbd_private_handle p, usbd_status status)
  979 {
  980         struct ucom_softc *sc = (struct ucom_softc *)p;
  981         struct tty *tp = sc->sc_tty;
  982         u_int32_t cc;
  983         int s;
  984 
  985         DPRINTFN(5,("ucomwritecb: status=%d\n", status));
  986 
  987         if (status == USBD_CANCELLED || sc->sc_dying)
  988                 goto error;
  989 
  990         if (status) {
  991                 DPRINTF(("ucomwritecb: status=%d\n", status));
  992                 usbd_clear_endpoint_stall_async(sc->sc_bulkin_pipe);
  993                 /* XXX we should restart after some delay. */
  994                 goto error;
  995         }
  996 
  997         usbd_get_xfer_status(xfer, NULL, NULL, &cc, NULL);
  998 #if defined(__NetBSD__) && NRND > 0
  999         rnd_add_uint32(&sc->sc_rndsource, cc);
 1000 #endif
 1001         DPRINTFN(5,("ucomwritecb: cc=%d\n", cc));
 1002         /* convert from USB bytes to tty bytes */
 1003         cc -= sc->sc_opkthdrlen;
 1004 
 1005         s = spltty();
 1006         CLR(tp->t_state, TS_BUSY);
 1007         if (ISSET(tp->t_state, TS_FLUSH))
 1008                 CLR(tp->t_state, TS_FLUSH);
 1009         else
 1010                 ndflush(&tp->t_outq, cc);
 1011         (*tp->t_linesw->l_start)(tp);
 1012         splx(s);
 1013         return;
 1014 
 1015 error:
 1016         s = spltty();
 1017         CLR(tp->t_state, TS_BUSY);
 1018         splx(s);
 1019 }
 1020 
 1021 Static usbd_status
 1022 ucomstartread(struct ucom_softc *sc)
 1023 {
 1024         usbd_status err;
 1025 
 1026         DPRINTFN(5,("ucomstartread: start\n"));
 1027         usbd_setup_xfer(sc->sc_ixfer, sc->sc_bulkin_pipe,
 1028                         (usbd_private_handle)sc,
 1029                         sc->sc_ibuf, sc->sc_ibufsize,
 1030                         USBD_SHORT_XFER_OK | USBD_NO_COPY,
 1031                         USBD_NO_TIMEOUT, ucomreadcb);
 1032         err = usbd_transfer(sc->sc_ixfer);
 1033         if (err != USBD_IN_PROGRESS) {
 1034                 DPRINTF(("ucomstartread: err=%s\n", usbd_errstr(err)));
 1035                 return (err);
 1036         }
 1037         return (USBD_NORMAL_COMPLETION);
 1038 }
 1039 
 1040 Static void
 1041 ucomreadcb(usbd_xfer_handle xfer, usbd_private_handle p, usbd_status status)
 1042 {
 1043         struct ucom_softc *sc = (struct ucom_softc *)p;
 1044         struct tty *tp = sc->sc_tty;
 1045         int (*rint)(int c, struct tty *tp) = tp->t_linesw->l_rint;
 1046         usbd_status err;
 1047         u_int32_t cc;
 1048         u_char *cp;
 1049         int s;
 1050 
 1051         DPRINTFN(5,("ucomreadcb: status=%d\n", status));
 1052 
 1053         if (status == USBD_CANCELLED || status == USBD_IOERROR ||
 1054             sc->sc_dying) {
 1055                 DPRINTF(("ucomreadcb: dying\n"));
 1056                 /* Send something to wake upper layer */
 1057                 s = spltty();
 1058                 (*rint)('\n', tp);
 1059                 ttwakeup(tp);
 1060                 splx(s);
 1061                 return;
 1062         }
 1063 
 1064         if (status) {
 1065                 usbd_clear_endpoint_stall_async(sc->sc_bulkin_pipe);
 1066                 /* XXX we should restart after some delay. */
 1067                 return;
 1068         }
 1069 
 1070         usbd_get_xfer_status(xfer, NULL, (void *)&cp, &cc, NULL);
 1071 #if defined(__NetBSD__) && NRND > 0
 1072         rnd_add_uint32(&sc->sc_rndsource, cc);
 1073 #endif
 1074         DPRINTFN(5,("ucomreadcb: got %d chars, tp=%p\n", cc, tp));
 1075         if (sc->sc_methods->ucom_read != NULL)
 1076                 sc->sc_methods->ucom_read(sc->sc_parent, sc->sc_portno,
 1077                                           &cp, &cc);
 1078 
 1079         s = spltty();
 1080         /* Give characters to tty layer. */
 1081         while (cc-- > 0) {
 1082                 DPRINTFN(7,("ucomreadcb: char=0x%02x\n", *cp));
 1083                 if ((*rint)(*cp++, tp) == -1) {
 1084                         /* XXX what should we do? */
 1085                         printf("%s: lost %d chars\n", USBDEVNAME(sc->sc_dev),
 1086                                cc);
 1087                         break;
 1088                 }
 1089         }
 1090         splx(s);
 1091 
 1092         err = ucomstartread(sc);
 1093         if (err) {
 1094                 printf("%s: read start failed\n", USBDEVNAME(sc->sc_dev));
 1095                 /* XXX what should we dow now? */
 1096         }
 1097 }
 1098 
 1099 Static void
 1100 ucom_cleanup(struct ucom_softc *sc)
 1101 {
 1102         DPRINTF(("ucom_cleanup: closing pipes\n"));
 1103 
 1104         ucom_shutdown(sc);
 1105         if (sc->sc_bulkin_pipe != NULL) {
 1106                 usbd_abort_pipe(sc->sc_bulkin_pipe);
 1107                 usbd_close_pipe(sc->sc_bulkin_pipe);
 1108                 sc->sc_bulkin_pipe = NULL;
 1109         }
 1110         if (sc->sc_bulkout_pipe != NULL) {
 1111                 usbd_abort_pipe(sc->sc_bulkout_pipe);
 1112                 usbd_close_pipe(sc->sc_bulkout_pipe);
 1113                 sc->sc_bulkout_pipe = NULL;
 1114         }
 1115         if (sc->sc_ixfer != NULL) {
 1116                 usbd_free_xfer(sc->sc_ixfer);
 1117                 sc->sc_ixfer = NULL;
 1118         }
 1119         if (sc->sc_oxfer != NULL) {
 1120                 usbd_free_xfer(sc->sc_oxfer);
 1121                 sc->sc_oxfer = NULL;
 1122         }
 1123 }
 1124 
 1125 #endif /* NUCOM > 0 */
 1126 
 1127 int
 1128 ucomprint(void *aux, const char *pnp)
 1129 {
 1130         struct ucom_attach_args *uca = aux;
 1131 
 1132         if (pnp)
 1133                 aprint_normal("ucom at %s", pnp);
 1134         if (uca->portno != UCOM_UNK_PORTNO)
 1135                 aprint_normal(" portno %d", uca->portno);
 1136         return (UNCONF);
 1137 }
 1138 
 1139 int
 1140 ucomsubmatch(struct device *parent, struct cfdata *cf, void *aux)
 1141 {
 1142         struct ucom_attach_args *uca = aux;
 1143 
 1144         if (uca->portno != UCOM_UNK_PORTNO &&
 1145             cf->ucomcf_portno != UCOM_UNK_PORTNO &&
 1146             cf->ucomcf_portno != uca->portno)
 1147                 return (0);
 1148         return (config_match(parent, cf, aux));
 1149 }

Cache object: f31c4d36136bf02df8773514aa111dee


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