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/uart/uart_core.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) 2003 Marcel Moolenaar
    3  * All rights reserved.
    4  *
    5  * Redistribution and use in source and binary forms, with or without
    6  * modification, are permitted provided that the following conditions
    7  * are met:
    8  *
    9  * 1. Redistributions of source code must retain the above copyright
   10  *    notice, this list of conditions and the following disclaimer.
   11  * 2. Redistributions in binary form must reproduce the above copyright
   12  *    notice, this list of conditions and the following disclaimer in the
   13  *    documentation and/or other materials provided with the distribution.
   14  *
   15  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
   16  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
   17  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
   18  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
   19  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
   20  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
   21  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
   22  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
   23  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
   24  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
   25  */
   26 
   27 #include <sys/cdefs.h>
   28 __FBSDID("$FreeBSD: releng/8.4/sys/dev/uart/uart_core.c 235121 2012-05-07 07:04:41Z marius $");
   29 
   30 #include <sys/param.h>
   31 #include <sys/systm.h>
   32 #include <sys/bus.h>
   33 #include <sys/conf.h>
   34 #include <sys/cons.h>
   35 #include <sys/fcntl.h>
   36 #include <sys/interrupt.h>
   37 #include <sys/kdb.h>
   38 #include <sys/kernel.h>
   39 #include <sys/malloc.h>
   40 #include <sys/queue.h>
   41 #include <sys/reboot.h>
   42 #include <machine/bus.h>
   43 #include <sys/rman.h>
   44 #include <sys/termios.h>
   45 #include <machine/resource.h>
   46 #include <machine/stdarg.h>
   47 
   48 #include <dev/uart/uart.h>
   49 #include <dev/uart/uart_bus.h>
   50 #include <dev/uart/uart_cpu.h>
   51 
   52 #include "uart_if.h"
   53 
   54 devclass_t uart_devclass;
   55 char uart_driver_name[] = "uart";
   56 
   57 SLIST_HEAD(uart_devinfo_list, uart_devinfo) uart_sysdevs =
   58     SLIST_HEAD_INITIALIZER(uart_sysdevs);
   59 
   60 MALLOC_DEFINE(M_UART, "UART", "UART driver");
   61 
   62 void
   63 uart_add_sysdev(struct uart_devinfo *di)
   64 {
   65         SLIST_INSERT_HEAD(&uart_sysdevs, di, next);
   66 }
   67 
   68 const char *
   69 uart_getname(struct uart_class *uc)
   70 {
   71         return ((uc != NULL) ? uc->name : NULL);
   72 }
   73 
   74 struct uart_ops *
   75 uart_getops(struct uart_class *uc)
   76 {
   77         return ((uc != NULL) ? uc->uc_ops : NULL);
   78 }
   79 
   80 int
   81 uart_getrange(struct uart_class *uc)
   82 {
   83         return ((uc != NULL) ? uc->uc_range : 0);
   84 }
   85 
   86 /*
   87  * Schedule a soft interrupt. We do this on the 0 to !0 transition
   88  * of the TTY pending interrupt status.
   89  */
   90 void
   91 uart_sched_softih(struct uart_softc *sc, uint32_t ipend)
   92 {
   93         uint32_t new, old;
   94 
   95         do {
   96                 old = sc->sc_ttypend;
   97                 new = old | ipend;
   98         } while (!atomic_cmpset_32(&sc->sc_ttypend, old, new));
   99 
  100         if ((old & SER_INT_MASK) == 0)
  101                 swi_sched(sc->sc_softih, 0);
  102 }
  103 
  104 /*
  105  * A break condition has been detected. We treat the break condition as
  106  * a special case that should not happen during normal operation. When
  107  * the break condition is to be passed to higher levels in the form of
  108  * a NUL character, we really want the break to be in the right place in
  109  * the input stream. The overhead to achieve that is not in relation to
  110  * the exceptional nature of the break condition, so we permit ourselves
  111  * to be sloppy.
  112  */
  113 static __inline int
  114 uart_intr_break(void *arg)
  115 {
  116         struct uart_softc *sc = arg;
  117 
  118 #if defined(KDB)
  119         if (sc->sc_sysdev != NULL && sc->sc_sysdev->type == UART_DEV_CONSOLE) {
  120                 if (kdb_break())
  121                         return (0);
  122         }
  123 #endif
  124         if (sc->sc_opened)
  125                 uart_sched_softih(sc, SER_INT_BREAK);
  126         return (0);
  127 }
  128 
  129 /*
  130  * Handle a receiver overrun situation. We lost at least 1 byte in the
  131  * input stream and it's our job to contain the situation. We grab as
  132  * much of the data we can, but otherwise flush the receiver FIFO to
  133  * create some breathing room. The net effect is that we avoid the
  134  * overrun condition to happen for the next X characters, where X is
  135  * related to the FIFO size at the cost of loosing data right away.
  136  * So, instead of having multiple overrun interrupts in close proximity
  137  * to each other and possibly pessimizing UART interrupt latency for
  138  * other UARTs in a multiport configuration, we create a longer segment
  139  * of missing characters by freeing up the FIFO.
  140  * Each overrun condition is marked in the input buffer by a token. The
  141  * token represents the loss of at least one, but possible more bytes in
  142  * the input stream.
  143  */
  144 static __inline int
  145 uart_intr_overrun(void *arg)
  146 {
  147         struct uart_softc *sc = arg;
  148 
  149         if (sc->sc_opened) {
  150                 UART_RECEIVE(sc);
  151                 if (uart_rx_put(sc, UART_STAT_OVERRUN))
  152                         sc->sc_rxbuf[sc->sc_rxput] = UART_STAT_OVERRUN;
  153                 uart_sched_softih(sc, SER_INT_RXREADY);
  154         }
  155         UART_FLUSH(sc, UART_FLUSH_RECEIVER);
  156         return (0);
  157 }
  158 
  159 /*
  160  * Received data ready.
  161  */
  162 static __inline int
  163 uart_intr_rxready(void *arg)
  164 {
  165         struct uart_softc *sc = arg;
  166         int rxp;
  167 
  168         rxp = sc->sc_rxput;
  169         UART_RECEIVE(sc);
  170 #if defined(KDB)
  171         if (sc->sc_sysdev != NULL && sc->sc_sysdev->type == UART_DEV_CONSOLE) {
  172                 while (rxp != sc->sc_rxput) {
  173                         kdb_alt_break(sc->sc_rxbuf[rxp++], &sc->sc_altbrk);
  174                         if (rxp == sc->sc_rxbufsz)
  175                                 rxp = 0;
  176                 }
  177         }
  178 #endif
  179         if (sc->sc_opened)
  180                 uart_sched_softih(sc, SER_INT_RXREADY);
  181         else
  182                 sc->sc_rxput = sc->sc_rxget;    /* Ignore received data. */
  183         return (1);
  184 }
  185 
  186 /*
  187  * Line or modem status change (OOB signalling).
  188  * We pass the signals to the software interrupt handler for further
  189  * processing. Note that we merge the delta bits, but set the state
  190  * bits. This is to avoid loosing state transitions due to having more
  191  * than 1 hardware interrupt between software interrupts.
  192  */
  193 static __inline int
  194 uart_intr_sigchg(void *arg)
  195 {
  196         struct uart_softc *sc = arg;
  197         int new, old, sig;
  198 
  199         sig = UART_GETSIG(sc);
  200 
  201         if (sc->sc_pps.ppsparam.mode & PPS_CAPTUREBOTH) {
  202                 if (sig & UART_SIG_DPPS) {
  203                         pps_capture(&sc->sc_pps);
  204                         pps_event(&sc->sc_pps, (sig & UART_SIG_PPS) ?
  205                             PPS_CAPTUREASSERT : PPS_CAPTURECLEAR);
  206                 }
  207         }
  208 
  209         /*
  210          * Keep track of signal changes, even when the device is not
  211          * opened. This allows us to inform upper layers about a
  212          * possible loss of DCD and thus the existence of a (possibly)
  213          * different connection when we have DCD back, during the time
  214          * that the device was closed.
  215          */
  216         do {
  217                 old = sc->sc_ttypend;
  218                 new = old & ~SER_MASK_STATE;
  219                 new |= sig & SER_INT_SIGMASK;
  220         } while (!atomic_cmpset_32(&sc->sc_ttypend, old, new));
  221 
  222         if (sc->sc_opened)
  223                 uart_sched_softih(sc, SER_INT_SIGCHG);
  224         return (1);
  225 }
  226 
  227 /*
  228  * The transmitter can accept more data.
  229  */
  230 static __inline int
  231 uart_intr_txidle(void *arg)
  232 {
  233         struct uart_softc *sc = arg;
  234 
  235         if (sc->sc_txbusy) {
  236                 sc->sc_txbusy = 0;
  237                 uart_sched_softih(sc, SER_INT_TXIDLE);
  238         }
  239         return (0);
  240 }
  241 
  242 static int
  243 uart_intr(void *arg)
  244 {
  245         struct uart_softc *sc = arg;
  246         int flag = 0, ipend;
  247 
  248         while (!sc->sc_leaving && (ipend = UART_IPEND(sc)) != 0) {
  249                 flag = 1;
  250                 if (ipend & SER_INT_OVERRUN)
  251                         uart_intr_overrun(sc);
  252                 if (ipend & SER_INT_BREAK)
  253                         uart_intr_break(sc);
  254                 if (ipend & SER_INT_RXREADY)
  255                         uart_intr_rxready(sc);
  256                 if (ipend & SER_INT_SIGCHG)
  257                         uart_intr_sigchg(sc);
  258                 if (ipend & SER_INT_TXIDLE)
  259                         uart_intr_txidle(sc);           
  260         }
  261         return((flag)?FILTER_HANDLED:FILTER_STRAY);
  262 }
  263 
  264 serdev_intr_t *
  265 uart_bus_ihand(device_t dev, int ipend)
  266 {
  267 
  268         switch (ipend) {
  269         case SER_INT_BREAK:
  270                 return (uart_intr_break);
  271         case SER_INT_OVERRUN:
  272                 return (uart_intr_overrun);
  273         case SER_INT_RXREADY:
  274                 return (uart_intr_rxready);
  275         case SER_INT_SIGCHG:
  276                 return (uart_intr_sigchg);
  277         case SER_INT_TXIDLE:
  278                 return (uart_intr_txidle);
  279         }
  280         return (NULL);
  281 }
  282 
  283 int
  284 uart_bus_ipend(device_t dev)
  285 {
  286         struct uart_softc *sc;
  287 
  288         sc = device_get_softc(dev);
  289         return (UART_IPEND(sc));
  290 }
  291 
  292 int
  293 uart_bus_sysdev(device_t dev)
  294 {
  295         struct uart_softc *sc;
  296 
  297         sc = device_get_softc(dev);
  298         return ((sc->sc_sysdev != NULL) ? 1 : 0);
  299 }
  300 
  301 int
  302 uart_bus_probe(device_t dev, int regshft, int rclk, int rid, int chan)
  303 {
  304         struct uart_softc *sc;
  305         struct uart_devinfo *sysdev;
  306         int error;
  307 
  308         sc = device_get_softc(dev);
  309 
  310         /*
  311          * All uart_class references are weak. Check that the needed
  312          * class has been compiled-in. Fail if not.
  313          */
  314         if (sc->sc_class == NULL)
  315                 return (ENXIO);
  316 
  317         /*
  318          * Initialize the instance. Note that the instance (=softc) does
  319          * not necessarily match the hardware specific softc. We can't do
  320          * anything about it now, because we may not attach to the device.
  321          * Hardware drivers cannot use any of the class specific fields
  322          * while probing.
  323          */
  324         kobj_init((kobj_t)sc, (kobj_class_t)sc->sc_class);
  325         sc->sc_dev = dev;
  326         if (device_get_desc(dev) == NULL)
  327                 device_set_desc(dev, uart_getname(sc->sc_class));
  328 
  329         /*
  330          * Allocate the register resource. We assume that all UARTs have
  331          * a single register window in either I/O port space or memory
  332          * mapped I/O space. Any UART that needs multiple windows will
  333          * consequently not be supported by this driver as-is. We try I/O
  334          * port space first because that's the common case.
  335          */
  336         sc->sc_rrid = rid;
  337         sc->sc_rtype = SYS_RES_IOPORT;
  338         sc->sc_rres = bus_alloc_resource(dev, sc->sc_rtype, &sc->sc_rrid,
  339             0, ~0, uart_getrange(sc->sc_class), RF_ACTIVE);
  340         if (sc->sc_rres == NULL) {
  341                 sc->sc_rrid = rid;
  342                 sc->sc_rtype = SYS_RES_MEMORY;
  343                 sc->sc_rres = bus_alloc_resource(dev, sc->sc_rtype,
  344                     &sc->sc_rrid, 0, ~0, uart_getrange(sc->sc_class),
  345                     RF_ACTIVE);
  346                 if (sc->sc_rres == NULL)
  347                         return (ENXIO);
  348         }
  349 
  350         /*
  351          * Fill in the bus access structure and compare this device with
  352          * a possible console device and/or a debug port. We set the flags
  353          * in the softc so that the hardware dependent probe can adjust
  354          * accordingly. In general, you don't want to permanently disrupt
  355          * console I/O.
  356          */
  357         sc->sc_bas.bsh = rman_get_bushandle(sc->sc_rres);
  358         sc->sc_bas.bst = rman_get_bustag(sc->sc_rres);
  359         sc->sc_bas.chan = chan;
  360         sc->sc_bas.regshft = regshft;
  361         sc->sc_bas.rclk = (rclk == 0) ? sc->sc_class->uc_rclk : rclk;
  362 
  363         SLIST_FOREACH(sysdev, &uart_sysdevs, next) {
  364                 if (chan == sysdev->bas.chan &&
  365                     uart_cpu_eqres(&sc->sc_bas, &sysdev->bas)) {
  366                         /* XXX check if ops matches class. */
  367                         sc->sc_sysdev = sysdev;
  368                         sysdev->bas.rclk = sc->sc_bas.rclk;
  369                 }
  370         }
  371 
  372         error = UART_PROBE(sc);
  373         bus_release_resource(dev, sc->sc_rtype, sc->sc_rrid, sc->sc_rres);
  374         return ((error) ? error : BUS_PROBE_DEFAULT);
  375 }
  376 
  377 int
  378 uart_bus_attach(device_t dev)
  379 {
  380         struct uart_softc *sc, *sc0;
  381         const char *sep;
  382         int error;
  383 
  384         /*
  385          * The sc_class field defines the type of UART we're going to work
  386          * with and thus the size of the softc. Replace the generic softc
  387          * with one that matches the UART now that we're certain we handle
  388          * the device.
  389          */
  390         sc0 = device_get_softc(dev);
  391         if (sc0->sc_class->size > sizeof(*sc)) {
  392                 sc = malloc(sc0->sc_class->size, M_UART, M_WAITOK|M_ZERO);
  393                 bcopy(sc0, sc, sizeof(*sc));
  394                 device_set_softc(dev, sc);
  395         } else
  396                 sc = sc0;
  397 
  398         /*
  399          * Protect ourselves against interrupts while we're not completely
  400          * finished attaching and initializing. We don't expect interrupts
  401          * until after UART_ATTACH() though.
  402          */
  403         sc->sc_leaving = 1;
  404 
  405         mtx_init(&sc->sc_hwmtx_s, "uart_hwmtx", NULL, MTX_SPIN);
  406         if (sc->sc_hwmtx == NULL)
  407                 sc->sc_hwmtx = &sc->sc_hwmtx_s;
  408 
  409         /*
  410          * Re-allocate. We expect that the softc contains the information
  411          * collected by uart_bus_probe() intact.
  412          */
  413         sc->sc_rres = bus_alloc_resource(dev, sc->sc_rtype, &sc->sc_rrid,
  414             0, ~0, uart_getrange(sc->sc_class), RF_ACTIVE);
  415         if (sc->sc_rres == NULL) {
  416                 mtx_destroy(&sc->sc_hwmtx_s);
  417                 return (ENXIO);
  418         }
  419         sc->sc_bas.bsh = rman_get_bushandle(sc->sc_rres);
  420         sc->sc_bas.bst = rman_get_bustag(sc->sc_rres);
  421 
  422         sc->sc_irid = 0;
  423         sc->sc_ires = bus_alloc_resource_any(dev, SYS_RES_IRQ, &sc->sc_irid,
  424             RF_ACTIVE | RF_SHAREABLE);
  425         if (sc->sc_ires != NULL) {
  426                 error = bus_setup_intr(dev,
  427                     sc->sc_ires, INTR_TYPE_TTY, 
  428                     uart_intr, NULL, sc, &sc->sc_icookie);                  
  429                 if (error)
  430                         error = bus_setup_intr(dev,
  431                             sc->sc_ires, INTR_TYPE_TTY | INTR_MPSAFE,
  432                             NULL, (driver_intr_t *)uart_intr, sc, &sc->sc_icookie);
  433                 else
  434                         sc->sc_fastintr = 1;
  435 
  436                 if (error) {
  437                         device_printf(dev, "could not activate interrupt\n");
  438                         bus_release_resource(dev, SYS_RES_IRQ, sc->sc_irid,
  439                             sc->sc_ires);
  440                         sc->sc_ires = NULL;
  441                 }
  442         }
  443         if (sc->sc_ires == NULL) {
  444                 /* XXX no interrupt resource. Force polled mode. */
  445                 sc->sc_polled = 1;
  446         }
  447 
  448         sc->sc_rxbufsz = 384;
  449         sc->sc_rxbuf = malloc(sc->sc_rxbufsz * sizeof(*sc->sc_rxbuf),
  450             M_UART, M_WAITOK);
  451         sc->sc_txbuf = malloc(sc->sc_txfifosz * sizeof(*sc->sc_txbuf),
  452             M_UART, M_WAITOK);
  453 
  454         error = UART_ATTACH(sc);
  455         if (error)
  456                 goto fail;
  457 
  458         if (sc->sc_hwiflow || sc->sc_hwoflow) {
  459                 sep = "";
  460                 device_print_prettyname(dev);
  461                 if (sc->sc_hwiflow) {
  462                         printf("%sRTS iflow", sep);
  463                         sep = ", ";
  464                 }
  465                 if (sc->sc_hwoflow) {
  466                         printf("%sCTS oflow", sep);
  467                         sep = ", ";
  468                 }
  469                 printf("\n");
  470         }
  471 
  472         if (bootverbose && (sc->sc_fastintr || sc->sc_polled)) {
  473                 sep = "";
  474                 device_print_prettyname(dev);
  475                 if (sc->sc_fastintr) {
  476                         printf("%sfast interrupt", sep);
  477                         sep = ", ";
  478                 }
  479                 if (sc->sc_polled) {
  480                         printf("%spolled mode", sep);
  481                         sep = ", ";
  482                 }
  483                 printf("\n");
  484         }
  485 
  486         if (sc->sc_sysdev != NULL) {
  487                 if (sc->sc_sysdev->baudrate == 0) {
  488                         if (UART_IOCTL(sc, UART_IOCTL_BAUD,
  489                             (intptr_t)&sc->sc_sysdev->baudrate) != 0)
  490                                 sc->sc_sysdev->baudrate = -1;
  491                 }
  492                 switch (sc->sc_sysdev->type) {
  493                 case UART_DEV_CONSOLE:
  494                         device_printf(dev, "console");
  495                         break;
  496                 case UART_DEV_DBGPORT:
  497                         device_printf(dev, "debug port");
  498                         break;
  499                 case UART_DEV_KEYBOARD:
  500                         device_printf(dev, "keyboard");
  501                         break;
  502                 default:
  503                         device_printf(dev, "unknown system device");
  504                         break;
  505                 }
  506                 printf(" (%d,%c,%d,%d)\n", sc->sc_sysdev->baudrate,
  507                     "noems"[sc->sc_sysdev->parity], sc->sc_sysdev->databits,
  508                     sc->sc_sysdev->stopbits);
  509         }
  510 
  511         sc->sc_pps.ppscap = PPS_CAPTUREBOTH;
  512         pps_init(&sc->sc_pps);
  513 
  514         error = (sc->sc_sysdev != NULL && sc->sc_sysdev->attach != NULL)
  515             ? (*sc->sc_sysdev->attach)(sc) : uart_tty_attach(sc);
  516         if (error)
  517                 goto fail;
  518 
  519         if (sc->sc_sysdev != NULL)
  520                 sc->sc_sysdev->hwmtx = sc->sc_hwmtx;
  521 
  522         sc->sc_leaving = 0;
  523         uart_intr(sc);
  524         return (0);
  525 
  526  fail:
  527         free(sc->sc_txbuf, M_UART);
  528         free(sc->sc_rxbuf, M_UART);
  529 
  530         if (sc->sc_ires != NULL) {
  531                 bus_teardown_intr(dev, sc->sc_ires, sc->sc_icookie);
  532                 bus_release_resource(dev, SYS_RES_IRQ, sc->sc_irid,
  533                     sc->sc_ires);
  534         }
  535         bus_release_resource(dev, sc->sc_rtype, sc->sc_rrid, sc->sc_rres);
  536 
  537         mtx_destroy(&sc->sc_hwmtx_s);
  538 
  539         return (error);
  540 }
  541 
  542 int
  543 uart_bus_detach(device_t dev)
  544 {
  545         struct uart_softc *sc;
  546 
  547         sc = device_get_softc(dev);
  548 
  549         sc->sc_leaving = 1;
  550 
  551         if (sc->sc_sysdev != NULL)
  552                 sc->sc_sysdev->hwmtx = NULL;
  553 
  554         UART_DETACH(sc);
  555 
  556         if (sc->sc_sysdev != NULL && sc->sc_sysdev->detach != NULL)
  557                 (*sc->sc_sysdev->detach)(sc);
  558         else
  559                 uart_tty_detach(sc);
  560 
  561         free(sc->sc_txbuf, M_UART);
  562         free(sc->sc_rxbuf, M_UART);
  563 
  564         if (sc->sc_ires != NULL) {
  565                 bus_teardown_intr(dev, sc->sc_ires, sc->sc_icookie);
  566                 bus_release_resource(dev, SYS_RES_IRQ, sc->sc_irid,
  567                     sc->sc_ires);
  568         }
  569         bus_release_resource(dev, sc->sc_rtype, sc->sc_rrid, sc->sc_rres);
  570 
  571         mtx_destroy(&sc->sc_hwmtx_s);
  572 
  573         if (sc->sc_class->size > sizeof(*sc)) {
  574                 device_set_softc(dev, NULL);
  575                 free(sc, M_UART);
  576         } else
  577                 device_set_softc(dev, NULL);
  578 
  579         return (0);
  580 }

Cache object: 7fe5325b0740064fcbcacab97b44212d


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