File:  [Qemu by Fabrice Bellard] / qemu / hw / virtio-console.c
Revision 1.1.1.6 (vendor branch): download - view: text, annotated - select for diffs
Tue Apr 24 19:01:36 2018 UTC (18 months, 2 weeks ago) by root
Branches: qemu, MAIN
CVS tags: qemu1000, qemu0151, HEAD
qemu 0.15.1

    1: /*
    2:  * Virtio Console and Generic Serial Port Devices
    3:  *
    4:  * Copyright Red Hat, Inc. 2009, 2010
    5:  *
    6:  * Authors:
    7:  *  Amit Shah <amit.shah@redhat.com>
    8:  *
    9:  * This work is licensed under the terms of the GNU GPL, version 2.  See
   10:  * the COPYING file in the top-level directory.
   11:  */
   12: 
   13: #include "qemu-char.h"
   14: #include "qemu-error.h"
   15: #include "trace.h"
   16: #include "virtio-serial.h"
   17: 
   18: typedef struct VirtConsole {
   19:     VirtIOSerialPort port;
   20:     CharDriverState *chr;
   21: } VirtConsole;
   22: 
   23: 
   24: /* Callback function that's called when the guest sends us data */
   25: static ssize_t flush_buf(VirtIOSerialPort *port, const uint8_t *buf, size_t len)
   26: {
   27:     VirtConsole *vcon = DO_UPCAST(VirtConsole, port, port);
   28:     ssize_t ret;
   29: 
   30:     ret = qemu_chr_write(vcon->chr, buf, len);
   31:     trace_virtio_console_flush_buf(port->id, len, ret);
   32: 
   33:     if (ret < 0) {
   34:         /*
   35:          * Ideally we'd get a better error code than just -1, but
   36:          * that's what the chardev interface gives us right now.  If
   37:          * we had a finer-grained message, like -EPIPE, we could close
   38:          * this connection.  Absent such error messages, the most we
   39:          * can do is to return 0 here.
   40:          *
   41:          * This will prevent stray -1 values to go to
   42:          * virtio-serial-bus.c and cause abort()s in
   43:          * do_flush_queued_data().
   44:          */
   45:         ret = 0;
   46:     }
   47:     return ret;
   48: }
   49: 
   50: /* Callback function that's called when the guest opens the port */
   51: static void guest_open(VirtIOSerialPort *port)
   52: {
   53:     VirtConsole *vcon = DO_UPCAST(VirtConsole, port, port);
   54: 
   55:     qemu_chr_guest_open(vcon->chr);
   56: }
   57: 
   58: /* Callback function that's called when the guest closes the port */
   59: static void guest_close(VirtIOSerialPort *port)
   60: {
   61:     VirtConsole *vcon = DO_UPCAST(VirtConsole, port, port);
   62: 
   63:     qemu_chr_guest_close(vcon->chr);
   64: }
   65: 
   66: /* Readiness of the guest to accept data on a port */
   67: static int chr_can_read(void *opaque)
   68: {
   69:     VirtConsole *vcon = opaque;
   70: 
   71:     return virtio_serial_guest_ready(&vcon->port);
   72: }
   73: 
   74: /* Send data from a char device over to the guest */
   75: static void chr_read(void *opaque, const uint8_t *buf, int size)
   76: {
   77:     VirtConsole *vcon = opaque;
   78: 
   79:     trace_virtio_console_chr_read(vcon->port.id, size);
   80:     virtio_serial_write(&vcon->port, buf, size);
   81: }
   82: 
   83: static void chr_event(void *opaque, int event)
   84: {
   85:     VirtConsole *vcon = opaque;
   86: 
   87:     trace_virtio_console_chr_event(vcon->port.id, event);
   88:     switch (event) {
   89:     case CHR_EVENT_OPENED:
   90:         virtio_serial_open(&vcon->port);
   91:         break;
   92:     case CHR_EVENT_CLOSED:
   93:         virtio_serial_close(&vcon->port);
   94:         break;
   95:     }
   96: }
   97: 
   98: static int virtconsole_initfn(VirtIOSerialPort *port)
   99: {
  100:     VirtConsole *vcon = DO_UPCAST(VirtConsole, port, port);
  101:     VirtIOSerialPortInfo *info = DO_UPCAST(VirtIOSerialPortInfo, qdev,
  102:                                            vcon->port.dev.info);
  103: 
  104:     if (port->id == 0 && !info->is_console) {
  105:         error_report("Port number 0 on virtio-serial devices reserved for virtconsole devices for backward compatibility.");
  106:         return -1;
  107:     }
  108: 
  109:     if (vcon->chr) {
  110:         qemu_chr_add_handlers(vcon->chr, chr_can_read, chr_read, chr_event,
  111:                               vcon);
  112:         info->have_data = flush_buf;
  113:         info->guest_open = guest_open;
  114:         info->guest_close = guest_close;
  115:     }
  116: 
  117:     return 0;
  118: }
  119: 
  120: static int virtconsole_exitfn(VirtIOSerialPort *port)
  121: {
  122:     VirtConsole *vcon = DO_UPCAST(VirtConsole, port, port);
  123: 
  124:     if (vcon->chr) {
  125: 	/*
  126: 	 * Instead of closing the chardev, free it so it can be used
  127: 	 * for other purposes.
  128: 	 */
  129: 	qemu_chr_add_handlers(vcon->chr, NULL, NULL, NULL, NULL);
  130:     }
  131: 
  132:     return 0;
  133: }
  134: 
  135: static VirtIOSerialPortInfo virtconsole_info = {
  136:     .qdev.name     = "virtconsole",
  137:     .qdev.size     = sizeof(VirtConsole),
  138:     .is_console    = true,
  139:     .init          = virtconsole_initfn,
  140:     .exit          = virtconsole_exitfn,
  141:     .qdev.props = (Property[]) {
  142:         DEFINE_PROP_CHR("chardev", VirtConsole, chr),
  143:         DEFINE_PROP_END_OF_LIST(),
  144:     },
  145: };
  146: 
  147: static void virtconsole_register(void)
  148: {
  149:     virtio_serial_port_qdev_register(&virtconsole_info);
  150: }
  151: device_init(virtconsole_register)
  152: 
  153: static VirtIOSerialPortInfo virtserialport_info = {
  154:     .qdev.name     = "virtserialport",
  155:     .qdev.size     = sizeof(VirtConsole),
  156:     .init          = virtconsole_initfn,
  157:     .exit          = virtconsole_exitfn,
  158:     .qdev.props = (Property[]) {
  159:         DEFINE_PROP_CHR("chardev", VirtConsole, chr),
  160:         DEFINE_PROP_END_OF_LIST(),
  161:     },
  162: };
  163: 
  164: static void virtserialport_register(void)
  165: {
  166:     virtio_serial_port_qdev_register(&virtserialport_info);
  167: }
  168: device_init(virtserialport_register)

unix.superglobalmegacorp.com