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.40 2001/11/13 06:24:54 lukem Exp $  */
    2 
    3 /*-
    4  * Copyright (c) 2001-2003, 2005, 2008
    5  *      Shunsuke Akiyama <akiyama@jp.FreeBSD.org>.
    6  * All rights reserved.
    7  *
    8  * Redistribution and use in source and binary forms, with or without
    9  * modification, are permitted provided that the following conditions
   10  * are met:
   11  * 1. Redistributions of source code must retain the above copyright
   12  *    notice, this list of conditions and the following disclaimer.
   13  * 2. Redistributions in binary form must reproduce the above copyright
   14  *    notice, this list of conditions and the following disclaimer in the
   15  *    documentation and/or other materials provided with the distribution.
   16  *
   17  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
   18  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
   19  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
   20  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
   21  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
   22  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
   23  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
   24  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
   25  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
   26  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   27  * SUCH DAMAGE.
   28  */
   29 
   30 #include <sys/cdefs.h>
   31 __FBSDID("$FreeBSD: releng/7.3/sys/dev/usb/ucom.c 195499 2009-07-09 15:29:26Z n_hibma $");
   32 
   33 /*-
   34  * Copyright (c) 1998, 2000 The NetBSD Foundation, Inc.
   35  * All rights reserved.
   36  *
   37  * This code is derived from software contributed to The NetBSD Foundation
   38  * by Lennart Augustsson (lennart@augustsson.net) at
   39  * Carlstedt Research & Technology.
   40  *
   41  * Redistribution and use in source and binary forms, with or without
   42  * modification, are permitted provided that the following conditions
   43  * are met:
   44  * 1. Redistributions of source code must retain the above copyright
   45  *    notice, this list of conditions and the following disclaimer.
   46  * 2. Redistributions in binary form must reproduce the above copyright
   47  *    notice, this list of conditions and the following disclaimer in the
   48  *    documentation and/or other materials provided with the distribution.
   49  * 3. All advertising materials mentioning features or use of this software
   50  *    must display the following acknowledgement:
   51  *        This product includes software developed by the NetBSD
   52  *        Foundation, Inc. and its contributors.
   53  * 4. Neither the name of The NetBSD Foundation nor the names of its
   54  *    contributors may be used to endorse or promote products derived
   55  *    from this software without specific prior written permission.
   56  *
   57  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
   58  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
   59  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
   60  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
   61  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
   62  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
   63  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
   64  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
   65  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
   66  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
   67  * POSSIBILITY OF SUCH DAMAGE.
   68  */
   69 
   70 #include <sys/param.h>
   71 #include <sys/systm.h>
   72 #include <sys/kernel.h>
   73 #include <sys/malloc.h>
   74 #include <sys/module.h>
   75 #include <sys/bus.h>
   76 #include <sys/ioccom.h>
   77 #include <sys/fcntl.h>
   78 #include <sys/conf.h>
   79 #include <sys/serial.h>
   80 #include <sys/tty.h>
   81 #include <sys/clist.h>
   82 #include <sys/file.h>
   83 #include <sys/selinfo.h>
   84 #include <sys/proc.h>
   85 #include <sys/poll.h>
   86 #include <sys/sysctl.h>
   87 
   88 #include <dev/usb/usb.h>
   89 #include <dev/usb/usbcdc.h>
   90 
   91 #include <dev/usb/usbdi.h>
   92 #include <dev/usb/usbdi_util.h>
   93 #include "usbdevs.h"
   94 #include <dev/usb/usb_quirks.h>
   95 
   96 #include <dev/usb/ucomvar.h>
   97 
   98 static int      ucomdebug = 0;
   99 SYSCTL_NODE(_hw_usb, OID_AUTO, ucom, CTLFLAG_RW, 0, "USB ucom");
  100 SYSCTL_INT(_hw_usb_ucom, OID_AUTO, debug, CTLFLAG_RW,
  101            &ucomdebug, 0, "ucom debug level");
  102 #define DPRINTF(x)      do { \
  103                                 if (ucomdebug) \
  104                                         printf x; \
  105                         } while (0)
  106 
  107 #define DPRINTFN(n, x)  do { \
  108                                 if (ucomdebug > (n)) \
  109                                         printf x; \
  110                         } while (0)
  111 
  112 static int ucom_modevent(module_t, int, void *);
  113 static void ucom_cleanup(struct ucom_softc *);
  114 static int ucomparam(struct tty *, struct termios *);
  115 static void ucomstart(struct tty *);
  116 static void ucomstop(struct tty *, int);
  117 static void ucom_shutdown(struct ucom_softc *);
  118 static void ucom_dtr(struct ucom_softc *, int);
  119 static void ucom_rts(struct ucom_softc *, int);
  120 static void ucombreak(struct tty *, int);
  121 static usbd_status ucomstartread(struct ucom_softc *);
  122 static void ucomreadcb(usbd_xfer_handle, usbd_private_handle, usbd_status);
  123 static void ucomwritecb(usbd_xfer_handle, usbd_private_handle, usbd_status);
  124 static void ucomstopread(struct ucom_softc *);
  125 
  126 static t_open_t  ucomopen;
  127 static t_close_t ucomclose;
  128 static t_modem_t ucommodem;
  129 static t_ioctl_t ucomioctl;
  130 
  131 devclass_t ucom_devclass;
  132 
  133 static moduledata_t ucom_mod = {
  134         "ucom",
  135         ucom_modevent,
  136         NULL
  137 };
  138 
  139 DECLARE_MODULE(ucom, ucom_mod, SI_SUB_DRIVERS, SI_ORDER_MIDDLE);
  140 MODULE_DEPEND(ucom, usb, 1, 1, 1);
  141 MODULE_VERSION(ucom, UCOM_MODVER);
  142 
  143 static int
  144 ucom_modevent(module_t mod, int type, void *data)
  145 {
  146         switch (type) {
  147         case MOD_LOAD:
  148                 break;
  149         case MOD_UNLOAD:
  150                 break;
  151         default:
  152                 return (EOPNOTSUPP);
  153                 break;
  154         }
  155         return (0);
  156 }
  157 
  158 int
  159 ucom_attach_tty(struct ucom_softc *sc, int flags, char* fmt, int unit)
  160 {
  161         struct tty *tp;
  162 
  163         sc->sc_tty = tp = ttyalloc();
  164         tp->t_sc = sc;
  165         tp->t_oproc = ucomstart;
  166         tp->t_param = ucomparam;
  167         tp->t_stop = ucomstop;
  168         tp->t_break = ucombreak;
  169         tp->t_open = ucomopen;
  170         tp->t_close = ucomclose;
  171         tp->t_modem = ucommodem;
  172         tp->t_ioctl = ucomioctl;
  173 
  174         /* Leave the settings of this level to the drivers if needed. */
  175         tp->t_ispeedwat = (speed_t)-1;
  176         tp->t_ospeedwat = (speed_t)-1;
  177 
  178         return ttycreate(tp, flags, fmt, unit);
  179 }
  180 
  181 int
  182 ucom_attach(struct ucom_softc *sc)
  183 {
  184 
  185         ucom_attach_tty(sc, TS_CALLOUT,
  186             "U%d", device_get_unit(sc->sc_dev));
  187 
  188         DPRINTF(("ucom_attach: ttycreate: tp = %p, %s\n",
  189             sc->sc_tty, sc->sc_tty->t_dev->si_name));
  190 
  191         return (0);
  192 }
  193 
  194 int
  195 ucom_detach(struct ucom_softc *sc)
  196 {
  197         int s;
  198 
  199         DPRINTF(("ucom_detach: sc = %p, tp = %p\n", sc, sc->sc_tty));
  200 
  201         sc->sc_dying = 1;
  202         ttygone(sc->sc_tty);
  203         if (sc->sc_tty->t_state & TS_ISOPEN)
  204                 ucomclose(sc->sc_tty);
  205 
  206         if (sc->sc_bulkin_pipe != NULL)
  207                 usbd_abort_pipe(sc->sc_bulkin_pipe);
  208         if (sc->sc_bulkout_pipe != NULL)
  209                 usbd_abort_pipe(sc->sc_bulkout_pipe);
  210 
  211         ttyfree(sc->sc_tty);
  212 
  213         s = splusb();
  214         splx(s);
  215 
  216         return (0);
  217 }
  218 
  219 static void
  220 ucom_shutdown(struct ucom_softc *sc)
  221 {
  222         struct tty *tp = sc->sc_tty;
  223 
  224         DPRINTF(("ucom_shutdown\n"));
  225         /*
  226          * Hang up if necessary.  Wait a bit, so the other side has time to
  227          * notice even if we immediately open the port again.
  228          */
  229         if (ISSET(tp->t_cflag, HUPCL)) {
  230                 (void)ucommodem(tp, 0, SER_DTR);
  231                 (void)tsleep(sc, TTIPRI, "ucomsd", hz);
  232         }
  233 }
  234 
  235 static int
  236 ucomopen(struct tty *tp, struct cdev *dev)
  237 {
  238         struct ucom_softc *sc;
  239         usbd_status err;
  240         int error;
  241 
  242         sc = tp->t_sc;
  243 
  244         if (sc->sc_dying)
  245                 return (ENXIO);
  246 
  247         DPRINTF(("%s: ucomopen: tp = %p\n", device_get_nameunit(sc->sc_dev), tp));
  248 
  249         sc->sc_poll = 0;
  250         sc->sc_lsr = sc->sc_msr = sc->sc_mcr = 0;
  251 
  252         (void)ucommodem(tp, SER_DTR | SER_RTS, 0);
  253 
  254         /* Device specific open */
  255         if (sc->sc_callback->ucom_open != NULL) {
  256                 error = sc->sc_callback->ucom_open(sc->sc_parent,
  257                                                    sc->sc_portno);
  258                 if (error) {
  259                         ucom_cleanup(sc);
  260                         return (error);
  261                 }
  262         }
  263 
  264         DPRINTF(("ucomopen: open pipes in = %d out = %d\n",
  265                  sc->sc_bulkin_no, sc->sc_bulkout_no));
  266 
  267         /* Open the bulk pipes */
  268         /* Bulk-in pipe */
  269         err = usbd_open_pipe(sc->sc_iface, sc->sc_bulkin_no, 0,
  270                              &sc->sc_bulkin_pipe);
  271         if (err) {
  272                 printf("%s: open bulk in error (addr %d): %s\n",
  273                        device_get_nameunit(sc->sc_dev), sc->sc_bulkin_no,
  274                        usbd_errstr(err));
  275                 error = EIO;
  276                 goto fail;
  277         }
  278         /* Bulk-out pipe */
  279         err = usbd_open_pipe(sc->sc_iface, sc->sc_bulkout_no,
  280                              USBD_EXCLUSIVE_USE, &sc->sc_bulkout_pipe);
  281         if (err) {
  282                 printf("%s: open bulk out error (addr %d): %s\n",
  283                        device_get_nameunit(sc->sc_dev), sc->sc_bulkout_no,
  284                        usbd_errstr(err));
  285                 error = EIO;
  286                 goto fail;
  287         }
  288 
  289         /* Allocate a request and an input buffer and start reading. */
  290         sc->sc_ixfer = usbd_alloc_xfer(sc->sc_udev);
  291         if (sc->sc_ixfer == NULL) {
  292                 error = ENOMEM;
  293                 goto fail;
  294         }
  295 
  296         sc->sc_ibuf = usbd_alloc_buffer(sc->sc_ixfer,
  297                                         sc->sc_ibufsizepad);
  298         if (sc->sc_ibuf == NULL) {
  299                 error = ENOMEM;
  300                 goto fail;
  301         }
  302 
  303         sc->sc_oxfer = usbd_alloc_xfer(sc->sc_udev);
  304         if (sc->sc_oxfer == NULL) {
  305                 error = ENOMEM;
  306                 goto fail;
  307         }
  308 
  309         sc->sc_obuf = usbd_alloc_buffer(sc->sc_oxfer,
  310                                         sc->sc_obufsize +
  311                                         sc->sc_opkthdrlen);
  312         if (sc->sc_obuf == NULL) {
  313                 error = ENOMEM;
  314                 goto fail;
  315         }
  316 
  317         sc->sc_state |= UCS_RXSTOP;
  318         ucomstartread(sc);
  319 
  320         sc->sc_poll = 1;
  321 
  322         return (0);
  323 
  324 fail:
  325         ucom_cleanup(sc);
  326         return (error);
  327 }
  328 
  329 static void
  330 ucomclose(struct tty *tp)
  331 {
  332         struct ucom_softc *sc;
  333 
  334         sc = tp->t_sc;
  335 
  336         DPRINTF(("%s: ucomclose \n", device_get_nameunit(sc->sc_dev)));
  337 
  338         ucom_cleanup(sc);
  339 
  340         if (sc->sc_callback->ucom_close != NULL)
  341                 sc->sc_callback->ucom_close(sc->sc_parent, sc->sc_portno);
  342 }
  343 
  344 static int
  345 ucomioctl(struct tty *tp, u_long cmd, void *data, int flag, struct thread *p)
  346 {
  347         struct ucom_softc *sc;
  348         int error;
  349 
  350         sc = tp->t_sc;;
  351         if (sc->sc_dying)
  352                 return (EIO);
  353 
  354         DPRINTF(("ucomioctl: cmd = 0x%08lx\n", cmd));
  355 
  356         error = ENOTTY;
  357         if (sc->sc_callback->ucom_ioctl != NULL)
  358                 error = sc->sc_callback->ucom_ioctl(sc->sc_parent,
  359                                                     sc->sc_portno,
  360                                                     cmd, data, flag, p);
  361         return (error);
  362 }
  363 
  364 static int
  365 ucommodem(struct tty *tp, int sigon, int sigoff)
  366 {
  367         struct ucom_softc *sc;
  368         int     mcr;
  369         int     msr;
  370         int     onoff;
  371 
  372         sc = tp->t_sc;
  373 
  374         if (sigon == 0 && sigoff == 0) {
  375                 mcr = sc->sc_mcr;
  376                 if (ISSET(mcr, SER_DTR))
  377                         sigon |= SER_DTR;
  378                 if (ISSET(mcr, SER_RTS))
  379                         sigon |= SER_RTS;
  380 
  381                 msr = sc->sc_msr;
  382                 if (ISSET(msr, SER_CTS))
  383                         sigon |= SER_CTS;
  384                 if (ISSET(msr, SER_DCD))
  385                         sigon |= SER_DCD;
  386                 if (ISSET(msr, SER_DSR))
  387                         sigon |= SER_DSR;
  388                 if (ISSET(msr, SER_RI))
  389                         sigon |= SER_RI;
  390                 return (sigon);
  391         }
  392 
  393         mcr = sc->sc_mcr;
  394         if (ISSET(sigon, SER_DTR))
  395                 mcr |= SER_DTR;
  396         if (ISSET(sigoff, SER_DTR))
  397                 mcr &= ~SER_DTR;
  398         if (ISSET(sigon, SER_RTS))
  399                 mcr |= SER_RTS;
  400         if (ISSET(sigoff, SER_RTS))
  401                 mcr &= ~SER_RTS;
  402         sc->sc_mcr = mcr;
  403 
  404         onoff = ISSET(sc->sc_mcr, SER_DTR) ? 1 : 0;
  405         ucom_dtr(sc, onoff);
  406 
  407         onoff = ISSET(sc->sc_mcr, SER_RTS) ? 1 : 0;
  408         ucom_rts(sc, onoff);
  409 
  410         return (0);
  411 }
  412 
  413 static void
  414 ucombreak(struct tty *tp, int onoff)
  415 {
  416         struct ucom_softc *sc;
  417 
  418         sc = tp->t_sc;
  419         DPRINTF(("ucombreak: onoff = %d\n", onoff));
  420         if (sc->sc_callback->ucom_set == NULL)
  421                 return;
  422         sc->sc_callback->ucom_set(sc->sc_parent, sc->sc_portno,
  423                                   UCOM_SET_BREAK, onoff);
  424 }
  425 
  426 static void
  427 ucom_dtr(struct ucom_softc *sc, int onoff)
  428 {
  429         DPRINTF(("ucom_dtr: onoff = %d\n", onoff));
  430 
  431         if (sc->sc_callback->ucom_set == NULL)
  432                 return;
  433         sc->sc_callback->ucom_set(sc->sc_parent, sc->sc_portno,
  434                                   UCOM_SET_DTR, onoff);
  435 }
  436 
  437 static void
  438 ucom_rts(struct ucom_softc *sc, int onoff)
  439 {
  440         DPRINTF(("ucom_rts: onoff = %d\n", onoff));
  441 
  442         if (sc->sc_callback->ucom_set == NULL)
  443                 return;
  444         sc->sc_callback->ucom_set(sc->sc_parent, sc->sc_portno,
  445                                   UCOM_SET_RTS, onoff);
  446 }
  447 
  448 void
  449 ucom_status_change(struct ucom_softc *sc)
  450 {
  451         struct tty *tp = sc->sc_tty;
  452         u_char old_msr;
  453         int onoff;
  454 
  455         if (sc->sc_callback->ucom_get_status == NULL) {
  456                 sc->sc_lsr = 0;
  457                 sc->sc_msr = 0;
  458                 return;
  459         }
  460 
  461         old_msr = sc->sc_msr;
  462         sc->sc_callback->ucom_get_status(sc->sc_parent, sc->sc_portno,
  463                                          &sc->sc_lsr, &sc->sc_msr);
  464         if (ISSET((sc->sc_msr ^ old_msr), SER_DCD)) {
  465                 if (sc->sc_poll == 0)
  466                         return;
  467                 onoff = ISSET(sc->sc_msr, SER_DCD) ? 1 : 0;
  468                 DPRINTF(("ucom_status_change: DCD changed to %d\n", onoff));
  469                 ttyld_modem(tp, onoff);
  470         }
  471 }
  472 
  473 static int
  474 ucomparam(struct tty *tp, struct termios *t)
  475 {
  476         struct ucom_softc *sc;
  477         int error;
  478         usbd_status uerr;
  479 
  480         sc = tp->t_sc;
  481 
  482         if (sc->sc_dying)
  483                 return (EIO);
  484 
  485         DPRINTF(("ucomparam: sc = %p\n", sc));
  486 
  487         /* Check requested parameters. */
  488         if (t->c_ospeed < 0) {
  489                 DPRINTF(("ucomparam: negative ospeed\n"));
  490                 return (EINVAL);
  491         }
  492         if (t->c_ispeed && t->c_ispeed != t->c_ospeed) {
  493                 DPRINTF(("ucomparam: mismatch ispeed and ospeed\n"));
  494                 return (EINVAL);
  495         }
  496 
  497         /*
  498          * If there were no changes, don't do anything.  This avoids dropping
  499          * input and improves performance when all we did was frob things like
  500          * VMIN and VTIME.
  501          */
  502         if (tp->t_ospeed == t->c_ospeed &&
  503             tp->t_cflag == t->c_cflag)
  504                 return (0);
  505 
  506         /* And copy to tty. */
  507         tp->t_ispeed = t->c_ospeed;
  508         tp->t_ospeed = t->c_ospeed;
  509         tp->t_cflag = t->c_cflag;
  510 
  511         if (sc->sc_callback->ucom_param == NULL)
  512                 return (0);
  513 
  514         ucomstopread(sc);
  515 
  516         error = sc->sc_callback->ucom_param(sc->sc_parent, sc->sc_portno, t);
  517         if (error) {
  518                 DPRINTF(("ucomparam: callback: error = %d\n", error));
  519                 return (error);
  520         }
  521 
  522         ttsetwater(tp);
  523 
  524         if (t->c_cflag & CRTS_IFLOW) {
  525                 sc->sc_state |= UCS_RTS_IFLOW;
  526         } else if (sc->sc_state & UCS_RTS_IFLOW) {
  527                 sc->sc_state &= ~UCS_RTS_IFLOW;
  528                 (void)ucommodem(tp, SER_RTS, 0);
  529         }
  530 
  531         ttyldoptim(tp);
  532 
  533         uerr = ucomstartread(sc);
  534         if (uerr != USBD_NORMAL_COMPLETION)
  535                 return (EIO);
  536 
  537         return (0);
  538 }
  539 
  540 static void
  541 ucomstart(struct tty *tp)
  542 {
  543         struct ucom_softc *sc;
  544         struct cblock *cbp;
  545         usbd_status err;
  546         int s;
  547         u_char *data;
  548         int cnt;
  549 
  550         sc = tp->t_sc;
  551         DPRINTF(("ucomstart: sc = %p\n", sc));
  552 
  553         if (sc->sc_dying)
  554                 return;
  555 
  556         /*
  557          * If there's no sc_oxfer, then ucomclose has removed it.  The buffer
  558          * has just been flushed in the ttyflush() in ttyclose().  ttyflush()
  559          * then calls tt_stop().  ucomstop calls ucomstart, so the right thing
  560          * to do here is just abort if sc_oxfer is NULL, as everything else
  561          * is cleaned up elsewhere.
  562          */
  563         if (sc->sc_oxfer == NULL)
  564                 return;
  565 
  566         s = spltty();
  567 
  568         if (tp->t_state & TS_TBLOCK) {
  569                 if (ISSET(sc->sc_mcr, SER_RTS) &&
  570                     ISSET(sc->sc_state, UCS_RTS_IFLOW)) {
  571                         DPRINTF(("ucomstart: clear RTS\n"));
  572                         (void)ucommodem(tp, 0, SER_RTS);
  573                 }
  574         } else {
  575                 if (!ISSET(sc->sc_mcr, SER_RTS) &&
  576                     tp->t_rawq.c_cc <= tp->t_ilowat &&
  577                     ISSET(sc->sc_state, UCS_RTS_IFLOW)) {
  578                         DPRINTF(("ucomstart: set RTS\n"));
  579                         (void)ucommodem(tp, SER_RTS, 0);
  580                 }
  581         }
  582 
  583         if (ISSET(tp->t_state, TS_BUSY | TS_TIMEOUT | TS_TTSTOP)) {
  584                 ttwwakeup(tp);
  585                 DPRINTF(("ucomstart: stopped\n"));
  586                 goto out;
  587         }
  588 
  589         if (tp->t_outq.c_cc <= tp->t_olowat) {
  590                 if (ISSET(tp->t_state, TS_SO_OLOWAT)) {
  591                         CLR(tp->t_state, TS_SO_OLOWAT);
  592                         wakeup(TSA_OLOWAT(tp));
  593                 }
  594                 selwakeuppri(&tp->t_wsel, TTIPRI);
  595                 if (tp->t_outq.c_cc == 0) {
  596                         if (ISSET(tp->t_state, TS_BUSY | TS_SO_OCOMPLETE) ==
  597                             TS_SO_OCOMPLETE && tp->t_outq.c_cc == 0) {
  598                                 CLR(tp->t_state, TS_SO_OCOMPLETE);
  599                                 wakeup(TSA_OCOMPLETE(tp));
  600                         }
  601                         goto out;
  602                 }
  603         }
  604 
  605         /* Grab the first contiguous region of buffer space. */
  606         data = tp->t_outq.c_cf;
  607         cbp = (struct cblock *) ((intptr_t) tp->t_outq.c_cf & ~CROUND);
  608         cnt = min((char *) (cbp+1) - tp->t_outq.c_cf, tp->t_outq.c_cc);
  609 
  610         if (cnt == 0) {
  611                 DPRINTF(("ucomstart: cnt == 0\n"));
  612                 goto out;
  613         }
  614 
  615         SET(tp->t_state, TS_BUSY);
  616 
  617         if (cnt > sc->sc_obufsize) {
  618                 DPRINTF(("ucomstart: big buffer %d chars\n", cnt));
  619                 cnt = sc->sc_obufsize;
  620         }
  621         if (sc->sc_callback->ucom_write != NULL)
  622                 sc->sc_callback->ucom_write(sc->sc_parent, sc->sc_portno,
  623                                             sc->sc_obuf, data, &cnt);
  624         else
  625                 memcpy(sc->sc_obuf, data, cnt);
  626 
  627         DPRINTF(("ucomstart: %d chars\n", cnt));
  628         usbd_setup_xfer(sc->sc_oxfer, sc->sc_bulkout_pipe,
  629                         (usbd_private_handle)sc, sc->sc_obuf, cnt,
  630                         USBD_NO_COPY, USBD_NO_TIMEOUT, ucomwritecb);
  631         /* What can we do on error? */
  632         err = usbd_transfer(sc->sc_oxfer);
  633         if (err != USBD_IN_PROGRESS)
  634                 printf("ucomstart: err=%s\n", usbd_errstr(err));
  635 
  636         ttwwakeup(tp);
  637 
  638     out:
  639         splx(s);
  640 }
  641 
  642 static void
  643 ucomstop(struct tty *tp, int flag)
  644 {
  645         struct ucom_softc *sc;
  646         int s;
  647 
  648         sc = tp->t_sc;
  649 
  650         DPRINTF(("ucomstop: %d\n", flag));
  651 
  652         if ((flag & FREAD) && (sc->sc_state & UCS_RXSTOP) == 0) {
  653                 DPRINTF(("ucomstop: read\n"));
  654                 ucomstopread(sc);
  655                 ucomstartread(sc);
  656         }
  657 
  658         if (flag & FWRITE) {
  659                 DPRINTF(("ucomstop: write\n"));
  660                 s = spltty();
  661                 if (ISSET(tp->t_state, TS_BUSY)) {
  662                         /* XXX do what? */
  663                         if (!ISSET(tp->t_state, TS_TTSTOP))
  664                                 SET(tp->t_state, TS_FLUSH);
  665                 }
  666                 splx(s);
  667         }
  668 
  669         ucomstart(tp);
  670 
  671         DPRINTF(("ucomstop: done\n"));
  672 }
  673 
  674 static void
  675 ucomwritecb(usbd_xfer_handle xfer, usbd_private_handle p, usbd_status status)
  676 {
  677         struct ucom_softc *sc = (struct ucom_softc *)p;
  678         struct tty *tp = sc->sc_tty;
  679         u_int32_t cc;
  680         int s;
  681 
  682         DPRINTF(("ucomwritecb: status = %d\n", status));
  683 
  684         if (status == USBD_CANCELLED || sc->sc_dying)
  685                 goto error;
  686 
  687         if (status != USBD_NORMAL_COMPLETION) {
  688                 if (status == USBD_STALLED) {
  689                         printf("%s: ucomwritecb: STALLED; clearing.\n",
  690                                device_get_nameunit(sc->sc_dev));
  691                         usbd_clear_endpoint_stall_async(sc->sc_bulkout_pipe);
  692                 } else if (status == USBD_IOERROR) {
  693                         printf("%s: ucomwritecb: IOERROR; resetting device.\n",
  694                                device_get_nameunit(sc->sc_dev));
  695                         usbd_reset_device(sc->sc_udev);
  696                 } else if (status != USBD_CANCELLED) {
  697                         printf("%s: ucomwritecb: %s\n",
  698                                device_get_nameunit(sc->sc_dev),
  699                                usbd_errstr(status));
  700                 }
  701                 goto error;
  702         }
  703 
  704         usbd_get_xfer_status(xfer, NULL, NULL, &cc, NULL);
  705         DPRINTF(("ucomwritecb: cc = %d\n", cc));
  706         if (cc <= sc->sc_opkthdrlen) {
  707                 printf("%s: sent size too small, cc = %d\n",
  708                        device_get_nameunit(sc->sc_dev), cc);
  709                 goto error;
  710         }
  711 
  712         /* convert from USB bytes to tty bytes */
  713         cc -= sc->sc_opkthdrlen;
  714 
  715         s = spltty();
  716         CLR(tp->t_state, TS_BUSY);
  717         if (ISSET(tp->t_state, TS_FLUSH))
  718                 CLR(tp->t_state, TS_FLUSH);
  719         else
  720                 ndflush(&tp->t_outq, cc);
  721         ttyld_start(tp);
  722         splx(s);
  723 
  724         return;
  725 
  726   error:
  727         s = spltty();
  728         CLR(tp->t_state, TS_BUSY);
  729         splx(s);
  730         return;
  731 }
  732 
  733 static usbd_status
  734 ucomstartread(struct ucom_softc *sc)
  735 {
  736         usbd_status err;
  737 
  738         DPRINTF(("ucomstartread: start\n"));
  739 
  740         if (sc->sc_bulkin_pipe == NULL || (sc->sc_state & UCS_RXSTOP) == 0)
  741                 return (USBD_NORMAL_COMPLETION);
  742         sc->sc_state &= ~UCS_RXSTOP;
  743 
  744         usbd_setup_xfer(sc->sc_ixfer, sc->sc_bulkin_pipe,
  745                         (usbd_private_handle)sc,
  746                         sc->sc_ibuf, sc->sc_ibufsize,
  747                         USBD_SHORT_XFER_OK | USBD_NO_COPY,
  748                         USBD_NO_TIMEOUT, ucomreadcb);
  749 
  750         err = usbd_transfer(sc->sc_ixfer);
  751         if (err && err != USBD_IN_PROGRESS) {
  752                 sc->sc_state |= UCS_RXSTOP;
  753                 DPRINTF(("ucomstartread: err = %s\n", usbd_errstr(err)));
  754                 return (err);
  755         }
  756 
  757         return (USBD_NORMAL_COMPLETION);
  758 }
  759 
  760 static void
  761 ucomreadcb(usbd_xfer_handle xfer, usbd_private_handle p, usbd_status status)
  762 {
  763         struct ucom_softc *sc = (struct ucom_softc *)p;
  764         struct tty *tp = sc->sc_tty;
  765         usbd_status err;
  766         u_int32_t cc;
  767         u_char *cp;
  768         int lostcc;
  769         int s;
  770 
  771         DPRINTF(("ucomreadcb: status = %d\n", status));
  772 
  773         if (status != USBD_NORMAL_COMPLETION) {
  774                 if (!(sc->sc_state & UCS_RXSTOP))
  775                         printf("%s: ucomreadcb: %s\n",
  776                                device_get_nameunit(sc->sc_dev), usbd_errstr(status));
  777                 sc->sc_state |= UCS_RXSTOP;
  778                 if (status == USBD_STALLED)
  779                         usbd_clear_endpoint_stall_async(sc->sc_bulkin_pipe);
  780                 else if (status == USBD_IOERROR)
  781                         usbd_reset_device(sc->sc_udev);
  782                 if (status == USBD_STALLED) {
  783                         printf("%s: ucomreadcb: STALLED; clearing.\n",
  784                                device_get_nameunit(sc->sc_dev));
  785                         usbd_clear_endpoint_stall_async(sc->sc_bulkin_pipe);
  786                 } else if (status == USBD_IOERROR) {
  787                         printf("%s: ucomreadcb: IOERROR; resetting device.\n",
  788                                device_get_nameunit(sc->sc_dev));
  789                         usbd_reset_device(sc->sc_udev);
  790                 } else if (status != USBD_CANCELLED) {
  791                         printf("%s: ucomreadcb: %s\n",
  792                                device_get_nameunit(sc->sc_dev),
  793                                usbd_errstr(status));
  794                 }
  795                 return;
  796         }
  797         sc->sc_state |= UCS_RXSTOP;
  798 
  799         usbd_get_xfer_status(xfer, NULL, (void **)&cp, &cc, NULL);
  800         DPRINTF(("ucomreadcb: got %d chars, tp = %p\n", cc, tp));
  801         if (cc == 0)
  802                 goto resubmit;
  803 
  804         if (sc->sc_callback->ucom_read != NULL)
  805                 sc->sc_callback->ucom_read(sc->sc_parent, sc->sc_portno,
  806                                            &cp, &cc);
  807 
  808         if (cc > sc->sc_ibufsize) {
  809                 printf("%s: invalid receive data size, %d chars\n",
  810                        device_get_nameunit(sc->sc_dev), cc);
  811                 goto resubmit;
  812         }
  813         if (cc < 1)
  814                 goto resubmit;
  815 
  816         s = spltty();
  817         if (tp->t_state & TS_CAN_BYPASS_L_RINT) {
  818                 if (tp->t_rawq.c_cc + cc > tp->t_ihiwat
  819                     && (sc->sc_state & UCS_RTS_IFLOW
  820                         || tp->t_iflag & IXOFF)
  821                     && !(tp->t_state & TS_TBLOCK))
  822                         ttyblock(tp);
  823                 lostcc = b_to_q((char *)cp, cc, &tp->t_rawq);
  824                 tp->t_rawcc += cc;
  825                 ttwakeup(tp);
  826                 if (tp->t_state & TS_TTSTOP
  827                     && (tp->t_iflag & IXANY
  828                         || tp->t_cc[VSTART] == tp->t_cc[VSTOP])) {
  829                         tp->t_state &= ~TS_TTSTOP;
  830                         tp->t_lflag &= ~FLUSHO;
  831                         ucomstart(tp);
  832                 }
  833                 if (lostcc > 0)
  834                         printf("%s: lost %d chars (t_rawq)\n", device_get_nameunit(sc->sc_dev),
  835                                lostcc);
  836         } else {
  837                 /* Give characters to tty layer. */
  838                 while (cc > 0) {
  839                         DPRINTFN(7, ("ucomreadcb: char = 0x%02x\n", *cp));
  840                         if (ttyld_rint(tp, *cp) == -1) {
  841                                 /* XXX what should we do? */
  842                                 printf("%s: lost %d chars (ttyld_rint)\n",
  843                                        device_get_nameunit(sc->sc_dev), cc);
  844                                 break;
  845                         }
  846                         cc--;
  847                         cp++;
  848                 }
  849         }
  850         splx(s);
  851 
  852     resubmit:
  853         err = ucomstartread(sc);
  854         if (err) {
  855                 printf("%s: read start failed\n", device_get_nameunit(sc->sc_dev));
  856                 /* XXX what should we dow now? */
  857         }
  858 
  859         if ((sc->sc_state & UCS_RTS_IFLOW) && !ISSET(sc->sc_mcr, SER_RTS)
  860             && !(tp->t_state & TS_TBLOCK))
  861                 ucommodem(tp, SER_RTS, 0);
  862 }
  863 
  864 static void
  865 ucom_cleanup(struct ucom_softc *sc)
  866 {
  867         DPRINTF(("ucom_cleanup: closing pipes\n"));
  868 
  869         ucom_shutdown(sc);
  870         if (sc->sc_bulkin_pipe != NULL) {
  871                 sc->sc_state |= UCS_RXSTOP;
  872                 usbd_abort_pipe(sc->sc_bulkin_pipe);
  873                 usbd_close_pipe(sc->sc_bulkin_pipe);
  874                 sc->sc_bulkin_pipe = NULL;
  875         }
  876         if (sc->sc_bulkout_pipe != NULL) {
  877                 usbd_abort_pipe(sc->sc_bulkout_pipe);
  878                 usbd_close_pipe(sc->sc_bulkout_pipe);
  879                 sc->sc_bulkout_pipe = NULL;
  880         }
  881         if (sc->sc_ixfer != NULL) {
  882                 usbd_free_xfer(sc->sc_ixfer);
  883                 sc->sc_ixfer = NULL;
  884         }
  885         if (sc->sc_oxfer != NULL) {
  886                 usbd_free_xfer(sc->sc_oxfer);
  887                 sc->sc_oxfer = NULL;
  888         }
  889 }
  890 
  891 static void
  892 ucomstopread(struct ucom_softc *sc)
  893 {
  894         usbd_status err;
  895 
  896         DPRINTF(("ucomstopread: enter\n"));
  897 
  898         if (!(sc->sc_state & UCS_RXSTOP)) {
  899                 sc->sc_state |= UCS_RXSTOP;
  900                 if (sc->sc_bulkin_pipe == NULL) {
  901                         DPRINTF(("ucomstopread: bulkin pipe NULL\n"));
  902                         return;
  903                 }
  904                 err = usbd_abort_pipe(sc->sc_bulkin_pipe);
  905                 if (err) {
  906                         DPRINTF(("ucomstopread: err = %s\n",
  907                                  usbd_errstr(err)));
  908                 }
  909         }
  910 
  911         DPRINTF(("ucomstopread: leave\n"));
  912 }

Cache object: b799902fb566458b4098eb31084e07fb


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