linux/drivers/char/hvc_xen.c
<<
>>
Prefs
   1/*
   2 * xen console driver interface to hvc_console.c
   3 *
   4 * (c) 2007 Gerd Hoffmann <kraxel@suse.de>
   5 *
   6 * This program is free software; you can redistribute it and/or modify
   7 * it under the terms of the GNU General Public License as published by
   8 * the Free Software Foundation; either version 2 of the License, or
   9 * (at your option) any later version.
  10 *
  11 * This program is distributed in the hope that it will be useful,
  12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
  13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  14 * GNU General Public License for more details.
  15 *
  16 * You should have received a copy of the GNU General Public License
  17 * along with this program; if not, write to the Free Software
  18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
  19 */
  20
  21#include <linux/console.h>
  22#include <linux/delay.h>
  23#include <linux/err.h>
  24#include <linux/init.h>
  25#include <linux/types.h>
  26
  27#include <asm/xen/hypervisor.h>
  28#include <xen/page.h>
  29#include <xen/events.h>
  30#include <xen/interface/io/console.h>
  31#include <xen/hvc-console.h>
  32
  33#include "hvc_console.h"
  34
  35#define HVC_COOKIE   0x58656e /* "Xen" in hex */
  36
  37static struct hvc_struct *hvc;
  38static int xencons_irq;
  39
  40/* ------------------------------------------------------------------ */
  41
  42static inline struct xencons_interface *xencons_interface(void)
  43{
  44        return mfn_to_virt(xen_start_info->console.domU.mfn);
  45}
  46
  47static inline void notify_daemon(void)
  48{
  49        /* Use evtchn: this is called early, before irq is set up. */
  50        notify_remote_via_evtchn(xen_start_info->console.domU.evtchn);
  51}
  52
  53static int write_console(uint32_t vtermno, const char *data, int len)
  54{
  55        struct xencons_interface *intf = xencons_interface();
  56        XENCONS_RING_IDX cons, prod;
  57        int sent = 0;
  58
  59        cons = intf->out_cons;
  60        prod = intf->out_prod;
  61        mb();                   /* update queue values before going on */
  62        BUG_ON((prod - cons) > sizeof(intf->out));
  63
  64        while ((sent < len) && ((prod - cons) < sizeof(intf->out)))
  65                intf->out[MASK_XENCONS_IDX(prod++, intf->out)] = data[sent++];
  66
  67        wmb();                  /* write ring before updating pointer */
  68        intf->out_prod = prod;
  69
  70        notify_daemon();
  71        return sent;
  72}
  73
  74static int read_console(uint32_t vtermno, char *buf, int len)
  75{
  76        struct xencons_interface *intf = xencons_interface();
  77        XENCONS_RING_IDX cons, prod;
  78        int recv = 0;
  79
  80        cons = intf->in_cons;
  81        prod = intf->in_prod;
  82        mb();                   /* get pointers before reading ring */
  83        BUG_ON((prod - cons) > sizeof(intf->in));
  84
  85        while (cons != prod && recv < len)
  86                buf[recv++] = intf->in[MASK_XENCONS_IDX(cons++, intf->in)];
  87
  88        mb();                   /* read ring before consuming */
  89        intf->in_cons = cons;
  90
  91        notify_daemon();
  92        return recv;
  93}
  94
  95static struct hv_ops hvc_ops = {
  96        .get_chars = read_console,
  97        .put_chars = write_console,
  98};
  99
 100static int __init xen_init(void)
 101{
 102        struct hvc_struct *hp;
 103
 104        if (!is_running_on_xen())
 105                return 0;
 106
 107        xencons_irq = bind_evtchn_to_irq(xen_start_info->console.domU.evtchn);
 108        if (xencons_irq < 0)
 109                xencons_irq = 0 /* NO_IRQ */;
 110        hp = hvc_alloc(HVC_COOKIE, xencons_irq, &hvc_ops, 256);
 111        if (IS_ERR(hp))
 112                return PTR_ERR(hp);
 113
 114        hvc = hp;
 115        return 0;
 116}
 117
 118static void __exit xen_fini(void)
 119{
 120        if (hvc)
 121                hvc_remove(hvc);
 122}
 123
 124static int xen_cons_init(void)
 125{
 126        if (!is_running_on_xen())
 127                return 0;
 128
 129        hvc_instantiate(HVC_COOKIE, 0, &hvc_ops);
 130        return 0;
 131}
 132
 133module_init(xen_init);
 134module_exit(xen_fini);
 135console_initcall(xen_cons_init);
 136
 137static void xenboot_write_console(struct console *console, const char *string,
 138                                  unsigned len)
 139{
 140        unsigned int linelen, off = 0;
 141        const char *pos;
 142
 143        while (off < len && NULL != (pos = strchr(string+off, '\n'))) {
 144                linelen = pos-string+off;
 145                if (off + linelen > len)
 146                        break;
 147                write_console(0, string+off, linelen);
 148                write_console(0, "\r\n", 2);
 149                off += linelen + 1;
 150        }
 151        if (off < len)
 152                write_console(0, string+off, len-off);
 153}
 154
 155struct console xenboot_console = {
 156        .name           = "xenboot",
 157        .write          = xenboot_write_console,
 158        .flags          = CON_PRINTBUFFER | CON_BOOT,
 159};
 160