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/xen/console/xen_console.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) 2015 Julien Grall <julien.grall@citrix.com>
    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  * 1. Redistributions of source code must retain the above copyright
    9  *    notice, this list of conditions and the following disclaimer.
   10  * 2. Redistributions in binary form must reproduce the above copyright
   11  *    notice, this list of conditions and the following disclaimer in the
   12  *    documentation and/or other materials provided with the distribution.
   13  *
   14  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS AS IS'' AND
   15  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
   16  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
   17  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
   18  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
   19  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
   20  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
   21  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
   22  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
   23  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   24  * SUCH DAMAGE.
   25  */
   26 
   27 #include <sys/cdefs.h>
   28 __FBSDID("$FreeBSD$");
   29 
   30 #include <sys/param.h>
   31 #include <sys/module.h>
   32 #include <sys/systm.h>
   33 #include <sys/eventhandler.h>
   34 #include <sys/consio.h>
   35 #include <sys/priv.h>
   36 #include <sys/proc.h>
   37 #include <sys/uio.h>
   38 #include <sys/tty.h>
   39 #include <sys/systm.h>
   40 #include <sys/taskqueue.h>
   41 #include <sys/conf.h>
   42 #include <sys/kernel.h>
   43 #include <sys/bus.h>
   44 #include <sys/cons.h>
   45 #include <sys/kdb.h>
   46 #include <sys/proc.h>
   47 #include <sys/reboot.h>
   48 
   49 #include <machine/stdarg.h>
   50 
   51 #include <vm/vm.h>
   52 #include <vm/pmap.h>
   53 
   54 #include <xen/xen-os.h>
   55 #include <xen/hypervisor.h>
   56 #include <xen/xen_intr.h>
   57 #include <contrib/xen/io/console.h>
   58 
   59 #include "opt_ddb.h"
   60 #include "opt_printf.h"
   61 
   62 #ifdef DDB
   63 #include <ddb/ddb.h>
   64 #endif
   65 
   66 static char driver_name[] = "xc";
   67 
   68 struct xencons_priv;
   69 
   70 typedef void xencons_early_init_t(struct xencons_priv *cons);
   71 typedef int xencons_init_t(device_t dev, struct tty *tp,
   72     driver_intr_t intr_handler);
   73 typedef int xencons_read_t(struct xencons_priv *cons, char *buffer,
   74     unsigned int size);
   75 typedef int xencons_write_t(struct xencons_priv *cons, const char *buffer,
   76     unsigned int size);
   77 
   78 struct xencons_ops {
   79         /*
   80          * Called by the low-level driver during early boot.
   81          * Only the minimal set up to get a console should be done here.
   82          */
   83         xencons_early_init_t    *early_init;
   84         /* Prepare the console to be fully use */
   85         xencons_init_t          *init;
   86         /* Read/write helpers */
   87         xencons_read_t          *read;
   88         xencons_write_t         *write;
   89 };
   90 
   91 struct xencons_priv {
   92         /* Mutex to protect the shared ring and the internal buffers */
   93         struct mtx                      mtx;
   94         /* Interrupt handler used for notify the backend */
   95         xen_intr_handle_t               intr_handle;
   96         /* KDB internal state */
   97 #ifdef KDB
   98         int                             altbrk;
   99 #endif
  100         /* Status of the tty */
  101         bool                            opened;
  102         /* Callout used when the write buffer is full */
  103         struct callout                  callout;
  104 
  105         /* Internal buffers must be used with mtx locked */
  106 #define WBUF_SIZE     4096
  107 #define WBUF_MASK(_i) ((_i)&(WBUF_SIZE-1))
  108         char                            wbuf[WBUF_SIZE];
  109         unsigned int                    wc, wp; /* Consumer/producer wbuf */
  110 
  111 #define RBUF_SIZE     1024
  112 #define RBUF_MASK(_i) ((_i)&(RBUF_SIZE-1))
  113         char                            rbuf[RBUF_SIZE];
  114         unsigned int                    rc, rp; /* Consumer/producer rbuf */
  115 
  116         /* Pointer to the console operations */
  117         const struct xencons_ops        *ops;
  118 
  119         /*
  120          * Ring specific fields
  121          * XXX: make an union?
  122          */
  123         /* Event channel number for early notification (PV only) */
  124         uint32_t                        evtchn;
  125         /* Console shared page */
  126         struct xencons_interface        *intf;
  127 };
  128 
  129 /*
  130  * Data for the main console
  131  * Necessary to support low-level console driver
  132  */
  133 static struct xencons_priv main_cons;
  134 
  135 #define XC_POLLTIME     (hz/10)
  136 
  137 /*----------------------------- Debug function ------------------------------*/
  138 struct putchar_arg {
  139         char    *buf;
  140         size_t  size;
  141         size_t  n_next;
  142 };
  143 
  144 static void
  145 putchar(int c, void *arg)
  146 {
  147         struct putchar_arg *pca;
  148 
  149         pca = (struct putchar_arg *)arg;
  150 
  151         if (pca->buf == NULL) {
  152                 /*
  153                  * We have no buffer, output directly to the
  154                  * console char by char.
  155                  */
  156                 HYPERVISOR_console_write((char *)&c, 1);
  157         } else {
  158                 pca->buf[pca->n_next++] = c;
  159                 if ((pca->size == pca->n_next) || (c = '\0')) {
  160                         /* Flush the buffer */
  161                         HYPERVISOR_console_write(pca->buf, pca->n_next);
  162                         pca->n_next = 0;
  163                 }
  164         }
  165 }
  166 
  167 void
  168 xc_printf(const char *fmt, ...)
  169 {
  170         va_list ap;
  171         struct putchar_arg pca;
  172 #ifdef PRINTF_BUFR_SIZE
  173         char buf[PRINTF_BUFR_SIZE];
  174 
  175         pca.buf = buf;
  176         pca.size = sizeof(buf);
  177         pca.n_next = 0;
  178 #else
  179         pca.buf = NULL;
  180         pca.size = 0;
  181 #endif
  182 
  183         KASSERT((xen_domain()), ("call to xc_printf from non Xen guest"));
  184 
  185         va_start(ap, fmt);
  186         kvprintf(fmt, putchar, &pca, 10, ap);
  187         va_end(ap);
  188 
  189 #ifdef PRINTF_BUFR_SIZE
  190         if (pca.n_next != 0)
  191                 HYPERVISOR_console_write(buf, pca.n_next);
  192 #endif
  193 }
  194 
  195 /*---------------------- Helpers for the console lock -----------------------*/
  196 /*
  197  * The lock is not used when the kernel is panicing as it will never recover
  198  * and we want to output no matter what it costs.
  199  */
  200 static inline void xencons_lock(struct xencons_priv *cons)
  201 {
  202 
  203         if (!KERNEL_PANICKED())
  204                 mtx_lock_spin(&cons->mtx);
  205 
  206 }
  207 
  208 static inline void xencons_unlock(struct xencons_priv *cons)
  209 {
  210 
  211         if (!KERNEL_PANICKED())
  212                 mtx_unlock_spin(&cons->mtx);
  213 }
  214 
  215 #define xencons_lock_assert(cons)       mtx_assert(&(cons)->mtx, MA_OWNED)
  216 
  217 /*------------------ Helpers for the hypervisor console ---------------------*/
  218 static void
  219 xencons_early_init_hypervisor(struct xencons_priv *cons)
  220 {
  221         /*
  222          * Nothing to setup for the low-level console when using
  223          * the hypervisor console.
  224          */
  225 }
  226 
  227 static int
  228 xencons_init_hypervisor(device_t dev, struct tty *tp,
  229     driver_intr_t intr_handler)
  230 {
  231         struct xencons_priv *cons;
  232         int err;
  233 
  234         cons = tty_softc(tp);
  235 
  236         err = xen_intr_bind_virq(dev, VIRQ_CONSOLE, 0, NULL,
  237             intr_handler, tp, INTR_TYPE_TTY | INTR_MPSAFE, &cons->intr_handle);
  238         if (err != 0)
  239                 device_printf(dev, "Can't register console interrupt\n");
  240 
  241         return (err);
  242 }
  243 
  244 static int
  245 xencons_write_hypervisor(struct xencons_priv *cons, const char *buffer,
  246     unsigned int size)
  247 {
  248 
  249         HYPERVISOR_console_io(CONSOLEIO_write, size, buffer);
  250 
  251         return (size);
  252 }
  253 
  254 static int
  255 xencons_read_hypervisor(struct xencons_priv *cons, char *buffer,
  256     unsigned int size)
  257 {
  258 
  259         xencons_lock_assert(cons);
  260 
  261         return (HYPERVISOR_console_io(CONSOLEIO_read, size, buffer));
  262 }
  263 
  264 static const struct xencons_ops xencons_hypervisor_ops = {
  265         .early_init     = xencons_early_init_hypervisor,
  266         .init           = xencons_init_hypervisor,
  267         .read           = xencons_read_hypervisor,
  268         .write          = xencons_write_hypervisor,
  269 };
  270 
  271 /*------------------ Helpers for the ring console ---------------------------*/
  272 static void
  273 xencons_early_init_ring(struct xencons_priv *cons)
  274 {
  275         cons->intf = pmap_mapdev_attr(ptoa(xen_get_console_mfn()), PAGE_SIZE,
  276             VM_MEMATTR_XEN);
  277         cons->evtchn = xen_get_console_evtchn();
  278 }
  279 
  280 static int
  281 xencons_init_ring(device_t dev, struct tty *tp, driver_intr_t intr_handler)
  282 {
  283         struct xencons_priv *cons;
  284         int err;
  285 
  286         cons = tty_softc(tp);
  287 
  288         if (cons->evtchn == 0)
  289                 return (ENODEV);
  290 
  291         err = xen_intr_bind_local_port(dev, cons->evtchn, NULL,
  292             intr_handler, tp, INTR_TYPE_TTY | INTR_MPSAFE, &cons->intr_handle);
  293         if (err != 0)
  294                 return (err);
  295 
  296         return (0);
  297 }
  298 
  299 static void
  300 xencons_notify_ring(struct xencons_priv *cons)
  301 {
  302         /*
  303          * The console may be used before the ring interrupt is properly
  304          * initialized.
  305          * If so, fallback to directly use the event channel hypercall.
  306          */
  307         if (__predict_true(cons->intr_handle != NULL))
  308                 xen_intr_signal(cons->intr_handle);
  309         else {
  310                 struct evtchn_send send = {
  311                         .port = cons->evtchn
  312                 };
  313 
  314                 HYPERVISOR_event_channel_op(EVTCHNOP_send, &send);
  315         }
  316 }
  317 
  318 static int
  319 xencons_write_ring(struct xencons_priv *cons, const char *buffer,
  320     unsigned int size)
  321 {
  322         struct xencons_interface *intf;
  323         XENCONS_RING_IDX wcons, wprod;
  324         int sent;
  325 
  326         intf = cons->intf;
  327 
  328         xencons_lock_assert(cons);
  329 
  330         wcons = intf->out_cons;
  331         wprod = intf->out_prod;
  332 
  333         mb();
  334         KASSERT((wprod - wcons) <= sizeof(intf->out),
  335                 ("console send ring inconsistent"));
  336 
  337         for (sent = 0; sent < size; sent++, wprod++) {
  338                 if ((wprod - wcons) >= sizeof(intf->out))
  339                         break;
  340                 intf->out[MASK_XENCONS_IDX(wprod, intf->out)] = buffer[sent];
  341         }
  342 
  343         wmb();
  344         intf->out_prod = wprod;
  345 
  346         xencons_notify_ring(cons);
  347 
  348         return (sent);
  349 }
  350 
  351 static int
  352 xencons_read_ring(struct xencons_priv *cons, char *buffer, unsigned int size)
  353 {
  354         struct xencons_interface *intf;
  355         XENCONS_RING_IDX rcons, rprod;
  356         unsigned int rsz;
  357 
  358         intf = cons->intf;
  359 
  360         xencons_lock_assert(cons);
  361 
  362         rcons = intf->in_cons;
  363         rprod = intf->in_prod;
  364         rmb();
  365 
  366         for (rsz = 0; rsz < size; rsz++, rcons++) {
  367                 if (rprod == rcons)
  368                         break;
  369                 buffer[rsz] = intf->in[MASK_XENCONS_IDX(rcons, intf->in)];
  370         }
  371 
  372         wmb();
  373         intf->in_cons = rcons;
  374 
  375         /* No need to notify the backend if nothing has been read */
  376         if (rsz != 0)
  377                 xencons_notify_ring(cons);
  378 
  379         return (rsz);
  380 }
  381 
  382 static const struct xencons_ops xencons_ring_ops = {
  383         .early_init     = xencons_early_init_ring,
  384         .init           = xencons_init_ring,
  385         .read           = xencons_read_ring,
  386         .write          = xencons_write_ring,
  387 };
  388 
  389 /*------------------ Common implementation of the console -------------------*/
  390 
  391 /*
  392  * Called by the low-level driver during early boot to initialize the
  393  * main console driver.
  394  * Only the minimal set up to get a console should be done here.
  395  */
  396 static void
  397 xencons_early_init(void)
  398 {
  399 
  400         mtx_init(&main_cons.mtx, "XCONS LOCK", NULL, MTX_SPIN);
  401 
  402         if (xen_get_console_evtchn() == 0)
  403                 main_cons.ops = &xencons_hypervisor_ops;
  404         else
  405                 main_cons.ops = &xencons_ring_ops;
  406 
  407         main_cons.ops->early_init(&main_cons);
  408 }
  409 
  410 /*
  411  * Receive character from the console and put them in the internal buffer
  412  * XXX: Handle overflow of the internal buffer
  413  */
  414 static void
  415 xencons_rx(struct xencons_priv *cons)
  416 {
  417         char buf[16];
  418         int sz;
  419 
  420         xencons_lock(cons);
  421         while ((sz = cons->ops->read(cons, buf, sizeof(buf))) > 0) {
  422                 int i;
  423 
  424                 for (i = 0; i < sz; i++)
  425                         cons->rbuf[RBUF_MASK(cons->rp++)] = buf[i];
  426         }
  427         xencons_unlock(cons);
  428 }
  429 
  430 /* Return true if the write buffer is full */
  431 static bool
  432 xencons_tx_full(struct xencons_priv *cons)
  433 {
  434         unsigned int used;
  435 
  436         xencons_lock(cons);
  437         used = cons->wp - cons->wc;
  438         xencons_unlock(cons);
  439 
  440         return (used >= WBUF_SIZE);
  441 }
  442 
  443 static void
  444 xencons_tx_flush(struct xencons_priv *cons, int force)
  445 {
  446         int        sz;
  447 
  448         xencons_lock(cons);
  449         while (cons->wc != cons->wp) {
  450                 int sent;
  451                 sz = cons->wp - cons->wc;
  452                 if (sz > (WBUF_SIZE - WBUF_MASK(cons->wc)))
  453                         sz = WBUF_SIZE - WBUF_MASK(cons->wc);
  454                 sent = cons->ops->write(cons, &cons->wbuf[WBUF_MASK(cons->wc)],
  455                     sz);
  456 
  457                 /*
  458                  * The other end may not have been initialized. Ignore
  459                  * the force.
  460                  */
  461                 if (__predict_false(sent < 0))
  462                         break;
  463 
  464                 /*
  465                  * If force is set, spin until the console data is
  466                  * flushed through the domain controller.
  467                  */
  468                 if (sent == 0 && __predict_true(!force))
  469                         break;
  470 
  471                 cons->wc += sent;
  472         }
  473         xencons_unlock(cons);
  474 }
  475 
  476 static bool
  477 xencons_putc(struct xencons_priv *cons, int c, bool force_flush)
  478 {
  479 
  480         xencons_lock(cons);
  481         if ((cons->wp - cons->wc) < WBUF_SIZE)
  482                 cons->wbuf[WBUF_MASK(cons->wp++)] = c;
  483         xencons_unlock(cons);
  484 
  485         xencons_tx_flush(cons, force_flush);
  486 
  487         return (xencons_tx_full(cons));
  488 }
  489 
  490 static int
  491 xencons_getc(struct xencons_priv *cons)
  492 {
  493         int ret;
  494 
  495         xencons_lock(cons);
  496         if (cons->rp != cons->rc) {
  497                 /* We need to return only one char */
  498                 ret = (int)cons->rbuf[RBUF_MASK(cons->rc)];
  499                 cons->rc++;
  500         } else {
  501                 ret = -1;
  502         }
  503 
  504         xencons_unlock(cons);
  505 
  506         return (ret);
  507 }
  508 
  509 static bool
  510 xencons_tx(struct tty *tp)
  511 {
  512         bool cons_full;
  513         char c;
  514         struct xencons_priv *cons;
  515 
  516         cons = tty_softc(tp);
  517 
  518         tty_assert_locked(tp);
  519 
  520         /*
  521          * Don't transmit any character if the buffer is full. Otherwise,
  522          * characters may be lost
  523          */
  524         if (xencons_tx_full(cons))
  525                 return (false);
  526 
  527         cons_full = false;
  528         while (!cons_full && ttydisc_getc(tp, &c, 1) == 1)
  529                 cons_full = xencons_putc(cons, c, false);
  530 
  531         return (!cons_full);
  532 }
  533 
  534 static void
  535 xencons_intr(void *arg)
  536 {
  537         struct tty *tp;
  538         struct xencons_priv *cons;
  539         int ret;
  540 
  541         tp = arg;
  542         cons = tty_softc(tp);
  543 
  544         /*
  545          * The input will be used by the low-level console when KDB is active
  546          */
  547         if (kdb_active)
  548                 return;
  549 
  550         /*
  551          * It's not necessary to retrieve input when the tty is not opened
  552          */
  553         if (!cons->opened)
  554                 return;
  555 
  556         xencons_rx(cons);
  557 
  558         tty_lock(tp);
  559         while ((ret = xencons_getc(cons)) != -1) {
  560 #ifdef KDB
  561                 kdb_alt_break(ret, &cons->altbrk);
  562 #endif
  563                 ttydisc_rint(tp, ret, 0);
  564         }
  565         ttydisc_rint_done(tp);
  566         tty_unlock(tp);
  567 
  568         /* Try to flush remaining characters if necessary */
  569         xencons_tx_flush(cons, 0);
  570 }
  571 
  572 /*
  573  * Helpers to call while shutting down:
  574  *      - Force flush all output
  575  */
  576 static void
  577 xencons_shutdown(void *arg, int howto)
  578 {
  579         struct tty *tp;
  580 
  581         tp = arg;
  582 
  583         xencons_tx_flush(tty_softc(tp), 1);
  584 }
  585 
  586 /*---------------------- Low-level console driver ---------------------------*/
  587 static void
  588 xencons_cnprobe(struct consdev *cp)
  589 {
  590 
  591         if (!xen_domain())
  592                 return;
  593 
  594         cp->cn_pri = (boothowto & RB_SERIAL) ? CN_REMOTE : CN_NORMAL;
  595         sprintf(cp->cn_name, "%s0", driver_name);
  596 }
  597 
  598 static void
  599 xencons_cninit(struct consdev *cp)
  600 {
  601 
  602         xencons_early_init();
  603 }
  604 
  605 static void
  606 xencons_cnterm(struct consdev *cp)
  607 {
  608 }
  609 
  610 static void
  611 xencons_cngrab(struct consdev *cp)
  612 {
  613 }
  614 
  615 static void
  616 xencons_cnungrab(struct consdev *cp)
  617 {
  618 }
  619 
  620 static int
  621 xencons_cngetc(struct consdev *dev)
  622 {
  623 
  624         xencons_rx(&main_cons);
  625 
  626         return (xencons_getc(&main_cons));
  627 }
  628 
  629 static void
  630 xencons_cnputc(struct consdev *dev, int c)
  631 {
  632         /*
  633          * The low-level console is used by KDB and panic. We have to ensure
  634          * that any character sent will be seen by the backend.
  635          */
  636         xencons_putc(&main_cons, c, true);
  637 }
  638 
  639 CONSOLE_DRIVER(xencons);
  640 
  641 /*----------------------------- TTY driver ---------------------------------*/
  642 
  643 static int
  644 xencons_tty_open(struct tty *tp)
  645 {
  646         struct xencons_priv *cons;
  647 
  648         cons = tty_softc(tp);
  649 
  650         cons->opened = true;
  651 
  652         return (0);
  653 }
  654 
  655 static void
  656 xencons_tty_close(struct tty *tp)
  657 {
  658         struct xencons_priv *cons;
  659 
  660         cons = tty_softc(tp);
  661 
  662         cons->opened = false;
  663 }
  664 
  665 static void
  666 xencons_timeout(void *v)
  667 {
  668         struct tty *tp;
  669         struct xencons_priv *cons;
  670 
  671         tp = v;
  672         cons = tty_softc(tp);
  673 
  674         if (!xencons_tx(tp))
  675                 callout_reset(&cons->callout, XC_POLLTIME,
  676                     xencons_timeout, tp);
  677 }
  678 
  679 static void
  680 xencons_tty_outwakeup(struct tty *tp)
  681 {
  682         struct xencons_priv *cons;
  683 
  684         cons = tty_softc(tp);
  685 
  686         callout_stop(&cons->callout);
  687 
  688         if (!xencons_tx(tp))
  689                 callout_reset(&cons->callout, XC_POLLTIME,
  690                     xencons_timeout, tp);
  691 }
  692 
  693 static struct ttydevsw xencons_ttydevsw = {
  694         .tsw_flags      = TF_NOPREFIX,
  695         .tsw_open       = xencons_tty_open,
  696         .tsw_close      = xencons_tty_close,
  697         .tsw_outwakeup  = xencons_tty_outwakeup,
  698 };
  699 
  700 /*------------------------ Main console driver ------------------------------*/
  701 static void
  702 xencons_identify(driver_t *driver, device_t parent)
  703 {
  704         device_t child __unused;
  705 
  706         if (main_cons.ops == NULL)
  707                 return;
  708 
  709         child = BUS_ADD_CHILD(parent, 0, driver_name, 0);
  710 }
  711 
  712 static int
  713 xencons_probe(device_t dev)
  714 {
  715 
  716         device_set_desc(dev, "Xen Console");
  717         return (BUS_PROBE_NOWILDCARD);
  718 }
  719 
  720 static int
  721 xencons_attach(device_t dev)
  722 {
  723         struct tty *tp;
  724         /*
  725          * The main console is already allocated statically in order to
  726          * support low-level console
  727          */
  728         struct xencons_priv *cons;
  729         int err;
  730 
  731         cons = &main_cons;
  732 
  733         tp = tty_alloc(&xencons_ttydevsw, cons);
  734         tty_makedev(tp, NULL, "%s%r", driver_name, 0);
  735         device_set_softc(dev, tp);
  736 
  737         callout_init_mtx(&cons->callout, tty_getlock(tp), 0);
  738 
  739         err = cons->ops->init(dev, tp, xencons_intr);
  740         if (err != 0) {
  741                 device_printf(dev, "Unable to initialize the console (%d)\n",
  742                     err);
  743                 return (err);
  744         }
  745 
  746         /* register handler to flush console on shutdown */
  747         if ((EVENTHANDLER_REGISTER(shutdown_post_sync, xencons_shutdown,
  748             tp, SHUTDOWN_PRI_DEFAULT)) == NULL)
  749                 device_printf(dev, "shutdown event registration failed!\n");
  750 
  751         return (0);
  752 }
  753 
  754 static int
  755 xencons_resume(device_t dev)
  756 {
  757         struct xencons_priv *cons;
  758         struct tty *tp;
  759         int err;
  760 
  761         tp = device_get_softc(dev);
  762         cons = tty_softc(tp);
  763         xen_intr_unbind(&cons->intr_handle);
  764 
  765         err = cons->ops->init(dev, tp, xencons_intr);
  766         if (err != 0) {
  767                 device_printf(dev, "Unable to resume the console (%d)\n", err);
  768                 return (err);
  769         }
  770 
  771         return (0);
  772 }
  773 
  774 static device_method_t xencons_methods[] = {
  775         DEVMETHOD(device_identify, xencons_identify),
  776         DEVMETHOD(device_probe, xencons_probe),
  777         DEVMETHOD(device_attach, xencons_attach),
  778         DEVMETHOD(device_resume, xencons_resume),
  779 
  780         DEVMETHOD_END
  781 };
  782 
  783 static driver_t xencons_driver = {
  784         driver_name,
  785         xencons_methods,
  786         0,
  787 };
  788 
  789 DRIVER_MODULE(xc, xenpv, xencons_driver, 0, 0);

Cache object: 379b22bd0453826c7823b21c939863fc


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