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 "virtio-serial.h"
15:
16: typedef struct VirtConsole {
17: VirtIOSerialPort port;
18: CharDriverState *chr;
19: } VirtConsole;
20:
21:
22: /* Callback function that's called when the guest sends us data */
23: static void flush_buf(VirtIOSerialPort *port, const uint8_t *buf, size_t len)
24: {
25: VirtConsole *vcon = DO_UPCAST(VirtConsole, port, port);
26:
27: qemu_chr_write(vcon->chr, buf, len);
28: }
29:
30: /* Readiness of the guest to accept data on a port */
31: static int chr_can_read(void *opaque)
32: {
33: VirtConsole *vcon = opaque;
34:
35: return virtio_serial_guest_ready(&vcon->port);
36: }
37:
38: /* Send data from a char device over to the guest */
39: static void chr_read(void *opaque, const uint8_t *buf, int size)
40: {
41: VirtConsole *vcon = opaque;
42:
43: virtio_serial_write(&vcon->port, buf, size);
44: }
45:
46: static void chr_event(void *opaque, int event)
47: {
48: VirtConsole *vcon = opaque;
49:
50: switch (event) {
51: case CHR_EVENT_OPENED: {
52: virtio_serial_open(&vcon->port);
53: break;
54: }
55: case CHR_EVENT_CLOSED:
56: virtio_serial_close(&vcon->port);
57: break;
58: }
59: }
60:
61: /* Virtio Console Ports */
62: static int virtconsole_initfn(VirtIOSerialDevice *dev)
63: {
64: VirtIOSerialPort *port = DO_UPCAST(VirtIOSerialPort, dev, &dev->qdev);
65: VirtConsole *vcon = DO_UPCAST(VirtConsole, port, port);
66:
67: port->info = dev->info;
68:
69: port->is_console = true;
70:
71: if (vcon->chr) {
72: qemu_chr_add_handlers(vcon->chr, chr_can_read, chr_read, chr_event,
73: vcon);
74: port->info->have_data = flush_buf;
75: }
76: return 0;
77: }
78:
79: static int virtconsole_exitfn(VirtIOSerialDevice *dev)
80: {
81: VirtIOSerialPort *port = DO_UPCAST(VirtIOSerialPort, dev, &dev->qdev);
82: VirtConsole *vcon = DO_UPCAST(VirtConsole, port, port);
83:
84: if (vcon->chr) {
85: port->info->have_data = NULL;
86: qemu_chr_close(vcon->chr);
87: }
88:
89: return 0;
90: }
91:
92: static VirtIOSerialPortInfo virtconsole_info = {
93: .qdev.name = "virtconsole",
94: .qdev.size = sizeof(VirtConsole),
95: .init = virtconsole_initfn,
96: .exit = virtconsole_exitfn,
97: .qdev.props = (Property[]) {
98: DEFINE_PROP_UINT8("is_console", VirtConsole, port.is_console, 1),
99: DEFINE_PROP_UINT32("nr", VirtConsole, port.id, VIRTIO_CONSOLE_BAD_ID),
100: DEFINE_PROP_CHR("chardev", VirtConsole, chr),
101: DEFINE_PROP_STRING("name", VirtConsole, port.name),
102: DEFINE_PROP_END_OF_LIST(),
103: },
104: };
105:
106: static void virtconsole_register(void)
107: {
108: virtio_serial_port_qdev_register(&virtconsole_info);
109: }
110: device_init(virtconsole_register)
111:
112: /* Generic Virtio Serial Ports */
113: static int virtserialport_initfn(VirtIOSerialDevice *dev)
114: {
115: VirtIOSerialPort *port = DO_UPCAST(VirtIOSerialPort, dev, &dev->qdev);
116: VirtConsole *vcon = DO_UPCAST(VirtConsole, port, port);
117:
118: port->info = dev->info;
119:
120: if (vcon->chr) {
121: qemu_chr_add_handlers(vcon->chr, chr_can_read, chr_read, chr_event,
122: vcon);
123: port->info->have_data = flush_buf;
124: }
125: return 0;
126: }
127:
128: static VirtIOSerialPortInfo virtserialport_info = {
129: .qdev.name = "virtserialport",
130: .qdev.size = sizeof(VirtConsole),
131: .init = virtserialport_initfn,
132: .exit = virtconsole_exitfn,
133: .qdev.props = (Property[]) {
134: DEFINE_PROP_UINT32("nr", VirtConsole, port.id, VIRTIO_CONSOLE_BAD_ID),
135: DEFINE_PROP_CHR("chardev", VirtConsole, chr),
136: DEFINE_PROP_STRING("name", VirtConsole, port.name),
137: DEFINE_PROP_END_OF_LIST(),
138: },
139: };
140:
141: static void virtserialport_register(void)
142: {
143: virtio_serial_port_qdev_register(&virtserialport_info);
144: }
145: device_init(virtserialport_register)
unix.superglobalmegacorp.com