chardev: qom-ify
Turn Chardev into Object. qemu_chr_alloc() is replaced by the qemu_chardev_new() constructor. It will call qemu_char_open() to open/intialize the chardev with the ChardevCommon *backend settings. The CharDriver::create() callback is turned into a ChardevClass::open() which is called from the newly introduced qemu_chardev_open(). "chardev-gdb" and "chardev-hci" are internal chardev and aren't creatable directly with -chardev. Use a new internal flag to disable them. We may want to use TYPE_USER_CREATABLE interface instead, or perhaps allow -chardev usage. Although in general we keep typename and macros private, unless the type is being used by some other file, in this patch, all types and common helper macros for qemu-char.c are in char.h. This is to help transition now (some types must be declared early, while some aren't shared) and when splitting in several units. This is to be improved later. Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com> Reviewed-by: Eric Blake <eblake@redhat.com> Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
This commit is contained in:
parent
5bf5adaeb7
commit
777357d758
@ -100,6 +100,9 @@ typedef struct {
|
|||||||
QEMUTimer *cellCount_timer;
|
QEMUTimer *cellCount_timer;
|
||||||
} BaumChardev;
|
} BaumChardev;
|
||||||
|
|
||||||
|
#define TYPE_CHARDEV_BRAILLE "chardev-braille"
|
||||||
|
#define BAUM_CHARDEV(obj) OBJECT_CHECK(BaumChardev, (obj), TYPE_CHARDEV_BRAILLE)
|
||||||
|
|
||||||
/* Let's assume NABCC by default */
|
/* Let's assume NABCC by default */
|
||||||
enum way {
|
enum way {
|
||||||
DOTS2ASCII,
|
DOTS2ASCII,
|
||||||
@ -255,7 +258,7 @@ static int baum_deferred_init(BaumChardev *baum)
|
|||||||
/* The serial port can receive more of our data */
|
/* The serial port can receive more of our data */
|
||||||
static void baum_chr_accept_input(struct Chardev *chr)
|
static void baum_chr_accept_input(struct Chardev *chr)
|
||||||
{
|
{
|
||||||
BaumChardev *baum = (BaumChardev *)chr;
|
BaumChardev *baum = BAUM_CHARDEV(chr);
|
||||||
int room, first;
|
int room, first;
|
||||||
|
|
||||||
if (!baum->out_buf_used)
|
if (!baum->out_buf_used)
|
||||||
@ -281,7 +284,7 @@ static void baum_chr_accept_input(struct Chardev *chr)
|
|||||||
/* We want to send a packet */
|
/* We want to send a packet */
|
||||||
static void baum_write_packet(BaumChardev *baum, const uint8_t *buf, int len)
|
static void baum_write_packet(BaumChardev *baum, const uint8_t *buf, int len)
|
||||||
{
|
{
|
||||||
Chardev *chr = (Chardev *)baum;
|
Chardev *chr = CHARDEV(baum);
|
||||||
uint8_t io_buf[1 + 2 * len], *cur = io_buf;
|
uint8_t io_buf[1 + 2 * len], *cur = io_buf;
|
||||||
int room;
|
int room;
|
||||||
*cur++ = ESC;
|
*cur++ = ESC;
|
||||||
@ -322,7 +325,7 @@ static void baum_write_packet(BaumChardev *baum, const uint8_t *buf, int len)
|
|||||||
/* Called when the other end seems to have a wrong idea of our display size */
|
/* Called when the other end seems to have a wrong idea of our display size */
|
||||||
static void baum_cellCount_timer_cb(void *opaque)
|
static void baum_cellCount_timer_cb(void *opaque)
|
||||||
{
|
{
|
||||||
BaumChardev *baum = opaque;
|
BaumChardev *baum = BAUM_CHARDEV(opaque);
|
||||||
uint8_t cell_count[] = { BAUM_RSP_CellCount, baum->x * baum->y };
|
uint8_t cell_count[] = { BAUM_RSP_CellCount, baum->x * baum->y };
|
||||||
DPRINTF("Timeout waiting for DisplayData, sending cell count\n");
|
DPRINTF("Timeout waiting for DisplayData, sending cell count\n");
|
||||||
baum_write_packet(baum, cell_count, sizeof(cell_count));
|
baum_write_packet(baum, cell_count, sizeof(cell_count));
|
||||||
@ -472,7 +475,7 @@ static int baum_eat_packet(BaumChardev *baum, const uint8_t *buf, int len)
|
|||||||
/* The other end is writing some data. Store it and try to interpret */
|
/* The other end is writing some data. Store it and try to interpret */
|
||||||
static int baum_chr_write(Chardev *chr, const uint8_t *buf, int len)
|
static int baum_chr_write(Chardev *chr, const uint8_t *buf, int len)
|
||||||
{
|
{
|
||||||
BaumChardev *baum = (BaumChardev *)chr;
|
BaumChardev *baum = BAUM_CHARDEV(chr);
|
||||||
int tocopy, cur, eaten, orig_len = len;
|
int tocopy, cur, eaten, orig_len = len;
|
||||||
|
|
||||||
if (!len)
|
if (!len)
|
||||||
@ -529,7 +532,7 @@ static void baum_send_key2(BaumChardev *baum, uint8_t type, uint8_t value,
|
|||||||
/* We got some data on the BrlAPI socket */
|
/* We got some data on the BrlAPI socket */
|
||||||
static void baum_chr_read(void *opaque)
|
static void baum_chr_read(void *opaque)
|
||||||
{
|
{
|
||||||
BaumChardev *baum = opaque;
|
BaumChardev *baum = BAUM_CHARDEV(opaque);
|
||||||
brlapi_keyCode_t code;
|
brlapi_keyCode_t code;
|
||||||
int ret;
|
int ret;
|
||||||
if (!baum->brlapi)
|
if (!baum->brlapi)
|
||||||
@ -613,9 +616,9 @@ static void baum_chr_read(void *opaque)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void baum_chr_free(struct Chardev *chr)
|
static void baum_chr_free(Chardev *chr)
|
||||||
{
|
{
|
||||||
BaumChardev *baum = (BaumChardev *)chr;
|
BaumChardev *baum = BAUM_CHARDEV(chr);
|
||||||
|
|
||||||
timer_free(baum->cellCount_timer);
|
timer_free(baum->cellCount_timer);
|
||||||
if (baum->brlapi) {
|
if (baum->brlapi) {
|
||||||
@ -624,24 +627,14 @@ static void baum_chr_free(struct Chardev *chr)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static Chardev *baum_chr_init(const CharDriver *driver,
|
static void baum_chr_open(Chardev *chr,
|
||||||
const char *id,
|
|
||||||
ChardevBackend *backend,
|
ChardevBackend *backend,
|
||||||
ChardevReturn *ret,
|
|
||||||
bool *be_opened,
|
bool *be_opened,
|
||||||
Error **errp)
|
Error **errp)
|
||||||
{
|
{
|
||||||
ChardevCommon *common = backend->u.braille.data;
|
BaumChardev *baum = BAUM_CHARDEV(chr);
|
||||||
BaumChardev *baum;
|
|
||||||
Chardev *chr;
|
|
||||||
brlapi_handle_t *handle;
|
brlapi_handle_t *handle;
|
||||||
|
|
||||||
chr = qemu_chr_alloc(driver, common, errp);
|
|
||||||
if (!chr) {
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
baum = (BaumChardev *)chr;
|
|
||||||
|
|
||||||
handle = g_malloc0(brlapi_getHandleSize());
|
handle = g_malloc0(brlapi_getHandleSize());
|
||||||
baum->brlapi = handle;
|
baum->brlapi = handle;
|
||||||
|
|
||||||
@ -649,34 +642,41 @@ static Chardev *baum_chr_init(const CharDriver *driver,
|
|||||||
if (baum->brlapi_fd == -1) {
|
if (baum->brlapi_fd == -1) {
|
||||||
error_setg(errp, "brlapi__openConnection: %s",
|
error_setg(errp, "brlapi__openConnection: %s",
|
||||||
brlapi_strerror(brlapi_error_location()));
|
brlapi_strerror(brlapi_error_location()));
|
||||||
goto fail_handle;
|
g_free(handle);
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
baum->deferred_init = 0;
|
baum->deferred_init = 0;
|
||||||
|
|
||||||
baum->cellCount_timer = timer_new_ns(QEMU_CLOCK_VIRTUAL, baum_cellCount_timer_cb, baum);
|
baum->cellCount_timer = timer_new_ns(QEMU_CLOCK_VIRTUAL, baum_cellCount_timer_cb, baum);
|
||||||
|
|
||||||
qemu_set_fd_handler(baum->brlapi_fd, baum_chr_read, NULL, baum);
|
qemu_set_fd_handler(baum->brlapi_fd, baum_chr_read, NULL, baum);
|
||||||
|
|
||||||
return chr;
|
|
||||||
|
|
||||||
fail_handle:
|
|
||||||
g_free(handle);
|
|
||||||
g_free(chr);
|
|
||||||
return NULL;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void char_braille_class_init(ObjectClass *oc, void *data)
|
||||||
|
{
|
||||||
|
ChardevClass *cc = CHARDEV_CLASS(oc);
|
||||||
|
|
||||||
|
cc->open = baum_chr_open;
|
||||||
|
cc->chr_write = baum_chr_write;
|
||||||
|
cc->chr_accept_input = baum_chr_accept_input;
|
||||||
|
cc->chr_free = baum_chr_free;
|
||||||
|
}
|
||||||
|
|
||||||
|
static const TypeInfo char_braille_type_info = {
|
||||||
|
.name = TYPE_CHARDEV_BRAILLE,
|
||||||
|
.parent = TYPE_CHARDEV,
|
||||||
|
.instance_size = sizeof(BaumChardev),
|
||||||
|
.class_init = char_braille_class_init,
|
||||||
|
};
|
||||||
|
|
||||||
static void register_types(void)
|
static void register_types(void)
|
||||||
{
|
{
|
||||||
static const CharDriver driver = {
|
static const CharDriver driver = {
|
||||||
.instance_size = sizeof(BaumChardev),
|
|
||||||
.kind = CHARDEV_BACKEND_KIND_BRAILLE,
|
.kind = CHARDEV_BACKEND_KIND_BRAILLE,
|
||||||
.create = baum_chr_init,
|
|
||||||
.chr_write = baum_chr_write,
|
|
||||||
.chr_accept_input = baum_chr_accept_input,
|
|
||||||
.chr_free = baum_chr_free,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
register_char_driver(&driver);
|
register_char_driver(&driver);
|
||||||
|
type_register_static(&char_braille_type_info);
|
||||||
}
|
}
|
||||||
|
|
||||||
type_init(register_types);
|
type_init(register_types);
|
||||||
|
@ -41,9 +41,13 @@ typedef struct {
|
|||||||
int outlen;
|
int outlen;
|
||||||
} MouseChardev;
|
} MouseChardev;
|
||||||
|
|
||||||
|
#define TYPE_CHARDEV_MSMOUSE "chardev-msmouse"
|
||||||
|
#define MOUSE_CHARDEV(obj) \
|
||||||
|
OBJECT_CHECK(MouseChardev, (obj), TYPE_CHARDEV_MSMOUSE)
|
||||||
|
|
||||||
static void msmouse_chr_accept_input(Chardev *chr)
|
static void msmouse_chr_accept_input(Chardev *chr)
|
||||||
{
|
{
|
||||||
MouseChardev *mouse = (MouseChardev *)chr;
|
MouseChardev *mouse = MOUSE_CHARDEV(chr);
|
||||||
int len;
|
int len;
|
||||||
|
|
||||||
len = qemu_chr_be_can_write(chr);
|
len = qemu_chr_be_can_write(chr);
|
||||||
@ -98,7 +102,7 @@ static void msmouse_queue_event(MouseChardev *mouse)
|
|||||||
static void msmouse_input_event(DeviceState *dev, QemuConsole *src,
|
static void msmouse_input_event(DeviceState *dev, QemuConsole *src,
|
||||||
InputEvent *evt)
|
InputEvent *evt)
|
||||||
{
|
{
|
||||||
MouseChardev *mouse = (MouseChardev *)dev;
|
MouseChardev *mouse = MOUSE_CHARDEV(dev);
|
||||||
InputMoveEvent *move;
|
InputMoveEvent *move;
|
||||||
InputBtnEvent *btn;
|
InputBtnEvent *btn;
|
||||||
|
|
||||||
@ -122,8 +126,8 @@ static void msmouse_input_event(DeviceState *dev, QemuConsole *src,
|
|||||||
|
|
||||||
static void msmouse_input_sync(DeviceState *dev)
|
static void msmouse_input_sync(DeviceState *dev)
|
||||||
{
|
{
|
||||||
MouseChardev *mouse = (MouseChardev *)dev;
|
MouseChardev *mouse = MOUSE_CHARDEV(dev);
|
||||||
Chardev *chr = (Chardev *)dev;
|
Chardev *chr = CHARDEV(dev);
|
||||||
|
|
||||||
msmouse_queue_event(mouse);
|
msmouse_queue_event(mouse);
|
||||||
msmouse_chr_accept_input(chr);
|
msmouse_chr_accept_input(chr);
|
||||||
@ -137,7 +141,7 @@ static int msmouse_chr_write(struct Chardev *s, const uint8_t *buf, int len)
|
|||||||
|
|
||||||
static void msmouse_chr_free(struct Chardev *chr)
|
static void msmouse_chr_free(struct Chardev *chr)
|
||||||
{
|
{
|
||||||
MouseChardev *mouse = (MouseChardev *)chr;
|
MouseChardev *mouse = MOUSE_CHARDEV(chr);
|
||||||
|
|
||||||
qemu_input_handler_unregister(mouse->hs);
|
qemu_input_handler_unregister(mouse->hs);
|
||||||
}
|
}
|
||||||
@ -149,42 +153,43 @@ static QemuInputHandler msmouse_handler = {
|
|||||||
.sync = msmouse_input_sync,
|
.sync = msmouse_input_sync,
|
||||||
};
|
};
|
||||||
|
|
||||||
static Chardev *qemu_chr_open_msmouse(const CharDriver *driver,
|
static void msmouse_chr_open(Chardev *chr,
|
||||||
const char *id,
|
|
||||||
ChardevBackend *backend,
|
ChardevBackend *backend,
|
||||||
ChardevReturn *ret,
|
|
||||||
bool *be_opened,
|
bool *be_opened,
|
||||||
Error **errp)
|
Error **errp)
|
||||||
{
|
{
|
||||||
ChardevCommon *common = backend->u.msmouse.data;
|
MouseChardev *mouse = MOUSE_CHARDEV(chr);
|
||||||
MouseChardev *mouse;
|
|
||||||
Chardev *chr;
|
|
||||||
|
|
||||||
chr = qemu_chr_alloc(driver, common, errp);
|
|
||||||
if (!chr) {
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
*be_opened = false;
|
*be_opened = false;
|
||||||
|
|
||||||
mouse = (MouseChardev *)chr;
|
|
||||||
mouse->hs = qemu_input_handler_register((DeviceState *)mouse,
|
mouse->hs = qemu_input_handler_register((DeviceState *)mouse,
|
||||||
&msmouse_handler);
|
&msmouse_handler);
|
||||||
|
|
||||||
|
|
||||||
return chr;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void char_msmouse_class_init(ObjectClass *oc, void *data)
|
||||||
|
{
|
||||||
|
ChardevClass *cc = CHARDEV_CLASS(oc);
|
||||||
|
|
||||||
|
cc->open = msmouse_chr_open;
|
||||||
|
cc->chr_write = msmouse_chr_write;
|
||||||
|
cc->chr_accept_input = msmouse_chr_accept_input;
|
||||||
|
cc->chr_free = msmouse_chr_free;
|
||||||
|
}
|
||||||
|
|
||||||
|
static const TypeInfo char_msmouse_type_info = {
|
||||||
|
.name = TYPE_CHARDEV_MSMOUSE,
|
||||||
|
.parent = TYPE_CHARDEV,
|
||||||
|
.instance_size = sizeof(MouseChardev),
|
||||||
|
.class_init = char_msmouse_class_init,
|
||||||
|
};
|
||||||
|
|
||||||
static void register_types(void)
|
static void register_types(void)
|
||||||
{
|
{
|
||||||
static const CharDriver driver = {
|
static const CharDriver driver = {
|
||||||
.instance_size = sizeof(MouseChardev),
|
|
||||||
.kind = CHARDEV_BACKEND_KIND_MSMOUSE,
|
.kind = CHARDEV_BACKEND_KIND_MSMOUSE,
|
||||||
.create = qemu_chr_open_msmouse,
|
|
||||||
.chr_write = msmouse_chr_write,
|
|
||||||
.chr_accept_input = msmouse_chr_accept_input,
|
|
||||||
.chr_free = msmouse_chr_free,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
register_char_driver(&driver);
|
register_char_driver(&driver);
|
||||||
|
type_register_static(&char_msmouse_type_info);
|
||||||
}
|
}
|
||||||
|
|
||||||
type_init(register_types);
|
type_init(register_types);
|
||||||
|
@ -36,6 +36,10 @@ typedef struct {
|
|||||||
int in_buf_used;
|
int in_buf_used;
|
||||||
} TestdevChardev;
|
} TestdevChardev;
|
||||||
|
|
||||||
|
#define TYPE_CHARDEV_TESTDEV "chardev-testdev"
|
||||||
|
#define TESTDEV_CHARDEV(obj) \
|
||||||
|
OBJECT_CHECK(TestdevChardev, (obj), TYPE_CHARDEV_TESTDEV)
|
||||||
|
|
||||||
/* Try to interpret a whole incoming packet */
|
/* Try to interpret a whole incoming packet */
|
||||||
static int testdev_eat_packet(TestdevChardev *testdev)
|
static int testdev_eat_packet(TestdevChardev *testdev)
|
||||||
{
|
{
|
||||||
@ -78,9 +82,9 @@ static int testdev_eat_packet(TestdevChardev *testdev)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* The other end is writing some data. Store it and try to interpret */
|
/* The other end is writing some data. Store it and try to interpret */
|
||||||
static int testdev_write(Chardev *chr, const uint8_t *buf, int len)
|
static int testdev_chr_write(Chardev *chr, const uint8_t *buf, int len)
|
||||||
{
|
{
|
||||||
TestdevChardev *testdev = (TestdevChardev *)chr;
|
TestdevChardev *testdev = TESTDEV_CHARDEV(chr);
|
||||||
int tocopy, eaten, orig_len = len;
|
int tocopy, eaten, orig_len = len;
|
||||||
|
|
||||||
while (len) {
|
while (len) {
|
||||||
@ -103,30 +107,28 @@ static int testdev_write(Chardev *chr, const uint8_t *buf, int len)
|
|||||||
return orig_len;
|
return orig_len;
|
||||||
}
|
}
|
||||||
|
|
||||||
static Chardev *chr_testdev_init(const CharDriver *driver,
|
static void char_testdev_class_init(ObjectClass *oc, void *data)
|
||||||
const char *id,
|
|
||||||
ChardevBackend *backend,
|
|
||||||
ChardevReturn *ret,
|
|
||||||
bool *be_opened,
|
|
||||||
Error **errp)
|
|
||||||
{
|
{
|
||||||
TestdevChardev *testdev = g_new0(TestdevChardev, 1);;
|
ChardevClass *cc = CHARDEV_CLASS(oc);
|
||||||
Chardev *chr = (Chardev *)testdev;
|
|
||||||
|
|
||||||
chr->driver = driver;
|
cc->chr_write = testdev_chr_write;
|
||||||
|
|
||||||
return chr;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static const TypeInfo char_testdev_type_info = {
|
||||||
|
.name = TYPE_CHARDEV_TESTDEV,
|
||||||
|
.parent = TYPE_CHARDEV,
|
||||||
|
.instance_size = sizeof(TestdevChardev),
|
||||||
|
.class_init = char_testdev_class_init,
|
||||||
|
};
|
||||||
|
|
||||||
static void register_types(void)
|
static void register_types(void)
|
||||||
{
|
{
|
||||||
static const CharDriver driver = {
|
static const CharDriver driver = {
|
||||||
.instance_size = sizeof(TestdevChardev),
|
|
||||||
.kind = CHARDEV_BACKEND_KIND_TESTDEV,
|
.kind = CHARDEV_BACKEND_KIND_TESTDEV,
|
||||||
.create = chr_testdev_init,
|
|
||||||
.chr_write = testdev_write,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
register_char_driver(&driver);
|
register_char_driver(&driver);
|
||||||
|
type_register_static(&char_testdev_type_info);
|
||||||
}
|
}
|
||||||
|
|
||||||
type_init(register_types);
|
type_init(register_types);
|
||||||
|
39
gdbstub.c
39
gdbstub.c
@ -1725,18 +1725,35 @@ static void gdb_sigterm_handler(int signal)
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
static void gdb_monitor_open(Chardev *chr, ChardevBackend *backend,
|
||||||
|
bool *be_opened, Error **errp)
|
||||||
|
{
|
||||||
|
*be_opened = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void char_gdb_class_init(ObjectClass *oc, void *data)
|
||||||
|
{
|
||||||
|
ChardevClass *cc = CHARDEV_CLASS(oc);
|
||||||
|
|
||||||
|
cc->internal = true;
|
||||||
|
cc->open = gdb_monitor_open;
|
||||||
|
cc->chr_write = gdb_monitor_write;
|
||||||
|
}
|
||||||
|
|
||||||
|
#define TYPE_CHARDEV_GDB "chardev-gdb"
|
||||||
|
|
||||||
|
static const TypeInfo char_gdb_type_info = {
|
||||||
|
.name = TYPE_CHARDEV_GDB,
|
||||||
|
.parent = TYPE_CHARDEV,
|
||||||
|
.class_init = char_gdb_class_init,
|
||||||
|
};
|
||||||
|
|
||||||
int gdbserver_start(const char *device)
|
int gdbserver_start(const char *device)
|
||||||
{
|
{
|
||||||
GDBState *s;
|
GDBState *s;
|
||||||
char gdbstub_device_name[128];
|
char gdbstub_device_name[128];
|
||||||
Chardev *chr = NULL;
|
Chardev *chr = NULL;
|
||||||
Chardev *mon_chr;
|
Chardev *mon_chr;
|
||||||
ChardevCommon common = { 0 };
|
|
||||||
static const CharDriver driver = {
|
|
||||||
.instance_size = sizeof(Chardev),
|
|
||||||
.kind = -1,
|
|
||||||
.chr_write = gdb_monitor_write,
|
|
||||||
};
|
|
||||||
|
|
||||||
if (!first_cpu) {
|
if (!first_cpu) {
|
||||||
error_report("gdbstub: meaningless to attach gdb to a "
|
error_report("gdbstub: meaningless to attach gdb to a "
|
||||||
@ -1775,7 +1792,8 @@ int gdbserver_start(const char *device)
|
|||||||
qemu_add_vm_change_state_handler(gdb_vm_state_change, NULL);
|
qemu_add_vm_change_state_handler(gdb_vm_state_change, NULL);
|
||||||
|
|
||||||
/* Initialize a monitor terminal for gdb */
|
/* Initialize a monitor terminal for gdb */
|
||||||
mon_chr = qemu_chr_alloc(&driver, &common, &error_abort);
|
mon_chr = qemu_chardev_new(NULL, TYPE_CHARDEV_GDB,
|
||||||
|
NULL, &error_abort);
|
||||||
monitor_init(mon_chr, 0);
|
monitor_init(mon_chr, 0);
|
||||||
} else {
|
} else {
|
||||||
if (qemu_chr_fe_get_driver(&s->chr)) {
|
if (qemu_chr_fe_get_driver(&s->chr)) {
|
||||||
@ -1798,4 +1816,11 @@ int gdbserver_start(const char *device)
|
|||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void register_types(void)
|
||||||
|
{
|
||||||
|
type_register_static(&char_gdb_type_info);
|
||||||
|
}
|
||||||
|
|
||||||
|
type_init(register_types);
|
||||||
#endif
|
#endif
|
||||||
|
@ -55,6 +55,9 @@ struct csrhci_s {
|
|||||||
struct HCIInfo *hci;
|
struct HCIInfo *hci;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
#define TYPE_CHARDEV_HCI "chardev-hci"
|
||||||
|
#define HCI_CHARDEV(obj) OBJECT_CHECK(struct csrhci_s, (obj), TYPE_CHARDEV_HCI)
|
||||||
|
|
||||||
/* H4+ packet types */
|
/* H4+ packet types */
|
||||||
enum {
|
enum {
|
||||||
H4_CMD_PKT = 1,
|
H4_CMD_PKT = 1,
|
||||||
@ -462,23 +465,12 @@ qemu_irq *csrhci_pins_get(Chardev *chr)
|
|||||||
return s->pins;
|
return s->pins;
|
||||||
}
|
}
|
||||||
|
|
||||||
Chardev *uart_hci_init(void)
|
static void csrhci_open(Chardev *chr,
|
||||||
|
ChardevBackend *backend,
|
||||||
|
bool *be_opened,
|
||||||
|
Error **errp)
|
||||||
{
|
{
|
||||||
static const CharDriver hci_driver = {
|
struct csrhci_s *s = HCI_CHARDEV(chr);
|
||||||
.instance_size = sizeof(struct csrhci_s),
|
|
||||||
.kind = -1,
|
|
||||||
.chr_write = csrhci_write,
|
|
||||||
.chr_ioctl = csrhci_ioctl,
|
|
||||||
};
|
|
||||||
Error *err = NULL;
|
|
||||||
ChardevCommon common = { 0, };
|
|
||||||
Chardev *chr = qemu_chr_alloc(&hci_driver, &common, &err);
|
|
||||||
struct csrhci_s *s = (struct csrhci_s *)chr;
|
|
||||||
|
|
||||||
if (err) {
|
|
||||||
error_report_err(err);
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
s->hci = qemu_next_hci();
|
s->hci = qemu_next_hci();
|
||||||
s->hci->opaque = s;
|
s->hci->opaque = s;
|
||||||
@ -488,6 +480,35 @@ Chardev *uart_hci_init(void)
|
|||||||
s->out_tm = timer_new_ns(QEMU_CLOCK_VIRTUAL, csrhci_out_tick, s);
|
s->out_tm = timer_new_ns(QEMU_CLOCK_VIRTUAL, csrhci_out_tick, s);
|
||||||
s->pins = qemu_allocate_irqs(csrhci_pins, s, __csrhci_pins);
|
s->pins = qemu_allocate_irqs(csrhci_pins, s, __csrhci_pins);
|
||||||
csrhci_reset(s);
|
csrhci_reset(s);
|
||||||
|
*be_opened = false;
|
||||||
return chr;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void char_hci_class_init(ObjectClass *oc, void *data)
|
||||||
|
{
|
||||||
|
ChardevClass *cc = CHARDEV_CLASS(oc);
|
||||||
|
|
||||||
|
cc->internal = true;
|
||||||
|
cc->open = csrhci_open;
|
||||||
|
cc->chr_write = csrhci_write;
|
||||||
|
cc->chr_ioctl = csrhci_ioctl;
|
||||||
|
}
|
||||||
|
|
||||||
|
static const TypeInfo char_hci_type_info = {
|
||||||
|
.name = TYPE_CHARDEV_HCI,
|
||||||
|
.parent = TYPE_CHARDEV,
|
||||||
|
.instance_size = sizeof(struct csrhci_s),
|
||||||
|
.class_init = char_hci_class_init,
|
||||||
|
};
|
||||||
|
|
||||||
|
Chardev *uart_hci_init(void)
|
||||||
|
{
|
||||||
|
return qemu_chardev_new(NULL, TYPE_CHARDEV_HCI,
|
||||||
|
NULL, &error_abort);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void register_types(void)
|
||||||
|
{
|
||||||
|
type_register_static(&char_hci_type_info);
|
||||||
|
}
|
||||||
|
|
||||||
|
type_init(register_types);
|
||||||
|
@ -10,6 +10,7 @@
|
|||||||
#include "qapi/qmp/qstring.h"
|
#include "qapi/qmp/qstring.h"
|
||||||
#include "qemu/main-loop.h"
|
#include "qemu/main-loop.h"
|
||||||
#include "qemu/bitmap.h"
|
#include "qemu/bitmap.h"
|
||||||
|
#include "qom/object.h"
|
||||||
|
|
||||||
/* character device */
|
/* character device */
|
||||||
|
|
||||||
@ -90,7 +91,8 @@ typedef struct CharBackend {
|
|||||||
typedef struct CharDriver CharDriver;
|
typedef struct CharDriver CharDriver;
|
||||||
|
|
||||||
struct Chardev {
|
struct Chardev {
|
||||||
const CharDriver *driver;
|
Object parent_obj;
|
||||||
|
|
||||||
QemuMutex chr_write_lock;
|
QemuMutex chr_write_lock;
|
||||||
CharBackend *be;
|
CharBackend *be;
|
||||||
char *label;
|
char *label;
|
||||||
@ -102,18 +104,6 @@ struct Chardev {
|
|||||||
QTAILQ_ENTRY(Chardev) next;
|
QTAILQ_ENTRY(Chardev) next;
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
|
||||||
* qemu_chr_alloc:
|
|
||||||
* @backend: the common backend config
|
|
||||||
* @errp: pointer to a NULL-initialized error object
|
|
||||||
*
|
|
||||||
* Allocate and initialize a new Chardev.
|
|
||||||
*
|
|
||||||
* Returns: a newly allocated Chardev, or NULL on error.
|
|
||||||
*/
|
|
||||||
Chardev *qemu_chr_alloc(const CharDriver *driver,
|
|
||||||
ChardevCommon *backend, Error **errp);
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @qemu_chr_new_from_opts:
|
* @qemu_chr_new_from_opts:
|
||||||
*
|
*
|
||||||
@ -455,54 +445,73 @@ void qemu_chr_fe_accept_input(CharBackend *be);
|
|||||||
int qemu_chr_add_client(Chardev *s, int fd);
|
int qemu_chr_add_client(Chardev *s, int fd);
|
||||||
Chardev *qemu_chr_find(const char *name);
|
Chardev *qemu_chr_find(const char *name);
|
||||||
|
|
||||||
/**
|
|
||||||
* @qemu_chr_get_kind:
|
|
||||||
*
|
|
||||||
* Returns the kind of char backend, or -1 if unspecified.
|
|
||||||
*/
|
|
||||||
ChardevBackendKind qemu_chr_get_kind(const Chardev *chr);
|
|
||||||
|
|
||||||
static inline bool qemu_chr_is_ringbuf(const Chardev *chr)
|
|
||||||
{
|
|
||||||
return qemu_chr_get_kind(chr) == CHARDEV_BACKEND_KIND_RINGBUF ||
|
|
||||||
qemu_chr_get_kind(chr) == CHARDEV_BACKEND_KIND_MEMORY;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool qemu_chr_has_feature(Chardev *chr,
|
bool qemu_chr_has_feature(Chardev *chr,
|
||||||
CharDriverFeature feature);
|
CharDriverFeature feature);
|
||||||
void qemu_chr_set_feature(Chardev *chr,
|
void qemu_chr_set_feature(Chardev *chr,
|
||||||
CharDriverFeature feature);
|
CharDriverFeature feature);
|
||||||
QemuOpts *qemu_chr_parse_compat(const char *label, const char *filename);
|
QemuOpts *qemu_chr_parse_compat(const char *label, const char *filename);
|
||||||
|
|
||||||
|
#define TYPE_CHARDEV "chardev"
|
||||||
|
#define CHARDEV(obj) OBJECT_CHECK(Chardev, (obj), TYPE_CHARDEV)
|
||||||
|
#define CHARDEV_CLASS(klass) \
|
||||||
|
OBJECT_CLASS_CHECK(ChardevClass, (klass), TYPE_CHARDEV)
|
||||||
|
#define CHARDEV_GET_CLASS(obj) \
|
||||||
|
OBJECT_GET_CLASS(ChardevClass, (obj), TYPE_CHARDEV)
|
||||||
|
|
||||||
|
#define TYPE_CHARDEV_NULL "chardev-null"
|
||||||
|
#define TYPE_CHARDEV_MUX "chardev-mux"
|
||||||
|
#define TYPE_CHARDEV_RINGBUF "chardev-ringbuf"
|
||||||
|
#define TYPE_CHARDEV_PTY "chardev-pty"
|
||||||
|
#define TYPE_CHARDEV_CONSOLE "chardev-console"
|
||||||
|
#define TYPE_CHARDEV_STDIO "chardev-stdio"
|
||||||
|
#define TYPE_CHARDEV_PIPE "chardev-pipe"
|
||||||
|
#define TYPE_CHARDEV_MEMORY "chardev-memory"
|
||||||
|
#define TYPE_CHARDEV_PARALLEL "chardev-parallel"
|
||||||
|
#define TYPE_CHARDEV_FILE "chardev-file"
|
||||||
|
#define TYPE_CHARDEV_SERIAL "chardev-serial"
|
||||||
|
#define TYPE_CHARDEV_SOCKET "chardev-socket"
|
||||||
|
#define TYPE_CHARDEV_UDP "chardev-udp"
|
||||||
|
|
||||||
|
#define CHARDEV_IS_MUX(chr) \
|
||||||
|
object_dynamic_cast(OBJECT(chr), TYPE_CHARDEV_MUX)
|
||||||
|
#define CHARDEV_IS_RINGBUF(chr) \
|
||||||
|
object_dynamic_cast(OBJECT(chr), TYPE_CHARDEV_RINGBUF)
|
||||||
|
#define CHARDEV_IS_PTY(chr) \
|
||||||
|
object_dynamic_cast(OBJECT(chr), TYPE_CHARDEV_PTY)
|
||||||
|
|
||||||
|
typedef struct ChardevClass {
|
||||||
|
ObjectClass parent_class;
|
||||||
|
|
||||||
|
bool internal; /* TODO: eventually use TYPE_USER_CREATABLE */
|
||||||
|
|
||||||
|
void (*open)(Chardev *chr, ChardevBackend *backend,
|
||||||
|
bool *be_opened, Error **errp);
|
||||||
|
|
||||||
|
int (*chr_write)(Chardev *s, const uint8_t *buf, int len);
|
||||||
|
int (*chr_sync_read)(Chardev *s, const uint8_t *buf, int len);
|
||||||
|
GSource *(*chr_add_watch)(Chardev *s, GIOCondition cond);
|
||||||
|
void (*chr_update_read_handler)(Chardev *s, GMainContext *context);
|
||||||
|
int (*chr_ioctl)(Chardev *s, int cmd, void *arg);
|
||||||
|
int (*get_msgfds)(Chardev *s, int* fds, int num);
|
||||||
|
int (*set_msgfds)(Chardev *s, int *fds, int num);
|
||||||
|
int (*chr_add_client)(Chardev *chr, int fd);
|
||||||
|
int (*chr_wait_connected)(Chardev *chr, Error **errp);
|
||||||
|
void (*chr_free)(Chardev *chr);
|
||||||
|
void (*chr_disconnect)(Chardev *chr);
|
||||||
|
void (*chr_accept_input)(Chardev *chr);
|
||||||
|
void (*chr_set_echo)(Chardev *chr, bool echo);
|
||||||
|
void (*chr_set_fe_open)(Chardev *chr, int fe_open);
|
||||||
|
} ChardevClass;
|
||||||
|
|
||||||
struct CharDriver {
|
struct CharDriver {
|
||||||
ChardevBackendKind kind;
|
ChardevBackendKind kind;
|
||||||
const char *alias;
|
const char *alias;
|
||||||
void (*parse)(QemuOpts *opts, ChardevBackend *backend, Error **errp);
|
void (*parse)(QemuOpts *opts, ChardevBackend *backend, Error **errp);
|
||||||
Chardev *(*create)(const CharDriver *driver,
|
|
||||||
const char *id,
|
|
||||||
ChardevBackend *backend,
|
|
||||||
ChardevReturn *ret, bool *be_opened,
|
|
||||||
Error **errp);
|
|
||||||
size_t instance_size;
|
|
||||||
|
|
||||||
int (*chr_write)(struct Chardev *s, const uint8_t *buf, int len);
|
|
||||||
int (*chr_sync_read)(struct Chardev *s,
|
|
||||||
const uint8_t *buf, int len);
|
|
||||||
GSource *(*chr_add_watch)(struct Chardev *s, GIOCondition cond);
|
|
||||||
void (*chr_update_read_handler)(struct Chardev *s,
|
|
||||||
GMainContext *context);
|
|
||||||
int (*chr_ioctl)(struct Chardev *s, int cmd, void *arg);
|
|
||||||
int (*get_msgfds)(struct Chardev *s, int* fds, int num);
|
|
||||||
int (*set_msgfds)(struct Chardev *s, int *fds, int num);
|
|
||||||
int (*chr_add_client)(struct Chardev *chr, int fd);
|
|
||||||
int (*chr_wait_connected)(struct Chardev *chr, Error **errp);
|
|
||||||
void (*chr_free)(struct Chardev *chr);
|
|
||||||
void (*chr_disconnect)(struct Chardev *chr);
|
|
||||||
void (*chr_accept_input)(struct Chardev *chr);
|
|
||||||
void (*chr_set_echo)(struct Chardev *chr, bool echo);
|
|
||||||
void (*chr_set_fe_open)(struct Chardev *chr, int fe_open);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
Chardev *qemu_chardev_new(const char *id, const char *typename,
|
||||||
|
ChardevBackend *backend, Error **errp);
|
||||||
|
|
||||||
void register_char_driver(const CharDriver *driver);
|
void register_char_driver(const CharDriver *driver);
|
||||||
|
|
||||||
extern int term_escape_char;
|
extern int term_escape_char;
|
||||||
|
@ -383,6 +383,8 @@ void graphic_hw_invalidate(QemuConsole *con);
|
|||||||
void graphic_hw_text_update(QemuConsole *con, console_ch_t *chardata);
|
void graphic_hw_text_update(QemuConsole *con, console_ch_t *chardata);
|
||||||
void graphic_hw_gl_block(QemuConsole *con, bool block);
|
void graphic_hw_gl_block(QemuConsole *con, bool block);
|
||||||
|
|
||||||
|
void qemu_console_early_init(void);
|
||||||
|
|
||||||
QemuConsole *qemu_console_lookup_by_index(unsigned int index);
|
QemuConsole *qemu_console_lookup_by_index(unsigned int index);
|
||||||
QemuConsole *qemu_console_lookup_by_device(DeviceState *dev, uint32_t head);
|
QemuConsole *qemu_console_lookup_by_device(DeviceState *dev, uint32_t head);
|
||||||
QemuConsole *qemu_console_lookup_by_device_name(const char *device_id,
|
QemuConsole *qemu_console_lookup_by_device_name(const char *device_id,
|
||||||
|
@ -3196,7 +3196,7 @@ static void ringbuf_completion(ReadLineState *rs, const char *str)
|
|||||||
|
|
||||||
if (!strncmp(chr_info->label, str, len)) {
|
if (!strncmp(chr_info->label, str, len)) {
|
||||||
Chardev *chr = qemu_chr_find(chr_info->label);
|
Chardev *chr = qemu_chr_find(chr_info->label);
|
||||||
if (chr && qemu_chr_is_ringbuf(chr)) {
|
if (chr && CHARDEV_IS_RINGBUF(chr)) {
|
||||||
readline_add_completion(rs, chr_info->label);
|
readline_add_completion(rs, chr_info->label);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
1227
qemu-char.c
1227
qemu-char.c
File diff suppressed because it is too large
Load Diff
@ -18,6 +18,12 @@ typedef struct SpiceChardev {
|
|||||||
QLIST_ENTRY(SpiceChardev) next;
|
QLIST_ENTRY(SpiceChardev) next;
|
||||||
} SpiceChardev;
|
} SpiceChardev;
|
||||||
|
|
||||||
|
#define TYPE_CHARDEV_SPICE "chardev-spice"
|
||||||
|
#define TYPE_CHARDEV_SPICEVMC "chardev-spicevmc"
|
||||||
|
#define TYPE_CHARDEV_SPICEPORT "chardev-spiceport"
|
||||||
|
|
||||||
|
#define SPICE_CHARDEV(obj) OBJECT_CHECK(SpiceChardev, (obj), TYPE_CHARDEV_SPICE)
|
||||||
|
|
||||||
typedef struct SpiceCharSource {
|
typedef struct SpiceCharSource {
|
||||||
GSource source;
|
GSource source;
|
||||||
SpiceChardev *scd;
|
SpiceChardev *scd;
|
||||||
@ -29,7 +35,7 @@ static QLIST_HEAD(, SpiceChardev) spice_chars =
|
|||||||
static int vmc_write(SpiceCharDeviceInstance *sin, const uint8_t *buf, int len)
|
static int vmc_write(SpiceCharDeviceInstance *sin, const uint8_t *buf, int len)
|
||||||
{
|
{
|
||||||
SpiceChardev *scd = container_of(sin, SpiceChardev, sin);
|
SpiceChardev *scd = container_of(sin, SpiceChardev, sin);
|
||||||
Chardev *chr = (Chardev *)scd;
|
Chardev *chr = CHARDEV(scd);
|
||||||
ssize_t out = 0;
|
ssize_t out = 0;
|
||||||
ssize_t last_out;
|
ssize_t last_out;
|
||||||
uint8_t* p = (uint8_t*)buf;
|
uint8_t* p = (uint8_t*)buf;
|
||||||
@ -73,7 +79,7 @@ static int vmc_read(SpiceCharDeviceInstance *sin, uint8_t *buf, int len)
|
|||||||
static void vmc_event(SpiceCharDeviceInstance *sin, uint8_t event)
|
static void vmc_event(SpiceCharDeviceInstance *sin, uint8_t event)
|
||||||
{
|
{
|
||||||
SpiceChardev *scd = container_of(sin, SpiceChardev, sin);
|
SpiceChardev *scd = container_of(sin, SpiceChardev, sin);
|
||||||
Chardev *chr = (Chardev *)scd;
|
Chardev *chr = CHARDEV(scd);
|
||||||
int chr_event;
|
int chr_event;
|
||||||
|
|
||||||
switch (event) {
|
switch (event) {
|
||||||
@ -92,7 +98,7 @@ static void vmc_event(SpiceCharDeviceInstance *sin, uint8_t event)
|
|||||||
static void vmc_state(SpiceCharDeviceInstance *sin, int connected)
|
static void vmc_state(SpiceCharDeviceInstance *sin, int connected)
|
||||||
{
|
{
|
||||||
SpiceChardev *scd = container_of(sin, SpiceChardev, sin);
|
SpiceChardev *scd = container_of(sin, SpiceChardev, sin);
|
||||||
Chardev *chr = (Chardev *)scd;
|
Chardev *chr = CHARDEV(scd);
|
||||||
|
|
||||||
if ((chr->be_open && connected) ||
|
if ((chr->be_open && connected) ||
|
||||||
(!chr->be_open && !connected)) {
|
(!chr->be_open && !connected)) {
|
||||||
@ -173,7 +179,7 @@ static GSourceFuncs SpiceCharSourceFuncs = {
|
|||||||
|
|
||||||
static GSource *spice_chr_add_watch(Chardev *chr, GIOCondition cond)
|
static GSource *spice_chr_add_watch(Chardev *chr, GIOCondition cond)
|
||||||
{
|
{
|
||||||
SpiceChardev *scd = (SpiceChardev *)chr;
|
SpiceChardev *scd = SPICE_CHARDEV(chr);
|
||||||
SpiceCharSource *src;
|
SpiceCharSource *src;
|
||||||
|
|
||||||
assert(cond & G_IO_OUT);
|
assert(cond & G_IO_OUT);
|
||||||
@ -187,7 +193,7 @@ static GSource *spice_chr_add_watch(Chardev *chr, GIOCondition cond)
|
|||||||
|
|
||||||
static int spice_chr_write(Chardev *chr, const uint8_t *buf, int len)
|
static int spice_chr_write(Chardev *chr, const uint8_t *buf, int len)
|
||||||
{
|
{
|
||||||
SpiceChardev *s = (SpiceChardev *)chr;
|
SpiceChardev *s = SPICE_CHARDEV(chr);
|
||||||
int read_bytes;
|
int read_bytes;
|
||||||
|
|
||||||
assert(s->datalen == 0);
|
assert(s->datalen == 0);
|
||||||
@ -206,7 +212,7 @@ static int spice_chr_write(Chardev *chr, const uint8_t *buf, int len)
|
|||||||
|
|
||||||
static void spice_chr_free(struct Chardev *chr)
|
static void spice_chr_free(struct Chardev *chr)
|
||||||
{
|
{
|
||||||
SpiceChardev *s = (SpiceChardev *)chr;
|
SpiceChardev *s = SPICE_CHARDEV(chr);
|
||||||
|
|
||||||
vmc_unregister_interface(s);
|
vmc_unregister_interface(s);
|
||||||
QLIST_REMOVE(s, next);
|
QLIST_REMOVE(s, next);
|
||||||
@ -219,7 +225,7 @@ static void spice_chr_free(struct Chardev *chr)
|
|||||||
|
|
||||||
static void spice_vmc_set_fe_open(struct Chardev *chr, int fe_open)
|
static void spice_vmc_set_fe_open(struct Chardev *chr, int fe_open)
|
||||||
{
|
{
|
||||||
SpiceChardev *s = (SpiceChardev *)chr;
|
SpiceChardev *s = SPICE_CHARDEV(chr);
|
||||||
if (fe_open) {
|
if (fe_open) {
|
||||||
vmc_register_interface(s);
|
vmc_register_interface(s);
|
||||||
} else {
|
} else {
|
||||||
@ -230,7 +236,7 @@ static void spice_vmc_set_fe_open(struct Chardev *chr, int fe_open)
|
|||||||
static void spice_port_set_fe_open(struct Chardev *chr, int fe_open)
|
static void spice_port_set_fe_open(struct Chardev *chr, int fe_open)
|
||||||
{
|
{
|
||||||
#if SPICE_SERVER_VERSION >= 0x000c02
|
#if SPICE_SERVER_VERSION >= 0x000c02
|
||||||
SpiceChardev *s = (SpiceChardev *)chr;
|
SpiceChardev *s = SPICE_CHARDEV(chr);
|
||||||
|
|
||||||
if (fe_open) {
|
if (fe_open) {
|
||||||
spice_server_port_event(&s->sin, SPICE_PORT_EVENT_OPENED);
|
spice_server_port_event(&s->sin, SPICE_PORT_EVENT_OPENED);
|
||||||
@ -242,43 +248,29 @@ static void spice_port_set_fe_open(struct Chardev *chr, int fe_open)
|
|||||||
|
|
||||||
static void spice_chr_accept_input(struct Chardev *chr)
|
static void spice_chr_accept_input(struct Chardev *chr)
|
||||||
{
|
{
|
||||||
SpiceChardev *s = (SpiceChardev *)chr;
|
SpiceChardev *s = SPICE_CHARDEV(chr);
|
||||||
|
|
||||||
spice_server_char_device_wakeup(&s->sin);
|
spice_server_char_device_wakeup(&s->sin);
|
||||||
}
|
}
|
||||||
|
|
||||||
static Chardev *chr_open(const CharDriver *driver,
|
static void chr_open(Chardev *chr, const char *subtype)
|
||||||
const char *subtype,
|
|
||||||
ChardevCommon *backend,
|
|
||||||
Error **errp)
|
|
||||||
{
|
{
|
||||||
Chardev *chr;
|
SpiceChardev *s = SPICE_CHARDEV(chr);
|
||||||
SpiceChardev *s;
|
|
||||||
|
|
||||||
chr = qemu_chr_alloc(driver, backend, errp);
|
|
||||||
if (!chr) {
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
s = (SpiceChardev *)chr;
|
|
||||||
s->active = false;
|
s->active = false;
|
||||||
s->sin.subtype = g_strdup(subtype);
|
s->sin.subtype = g_strdup(subtype);
|
||||||
|
|
||||||
QLIST_INSERT_HEAD(&spice_chars, s, next);
|
QLIST_INSERT_HEAD(&spice_chars, s, next);
|
||||||
|
|
||||||
return chr;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static Chardev *qemu_chr_open_spice_vmc(const CharDriver *driver,
|
static void qemu_chr_open_spice_vmc(Chardev *chr,
|
||||||
const char *id,
|
|
||||||
ChardevBackend *backend,
|
ChardevBackend *backend,
|
||||||
ChardevReturn *ret,
|
|
||||||
bool *be_opened,
|
bool *be_opened,
|
||||||
Error **errp)
|
Error **errp)
|
||||||
{
|
{
|
||||||
ChardevSpiceChannel *spicevmc = backend->u.spicevmc.data;
|
ChardevSpiceChannel *spicevmc = backend->u.spicevmc.data;
|
||||||
const char *type = spicevmc->type;
|
const char *type = spicevmc->type;
|
||||||
const char **psubtype = spice_server_char_device_recognized_subtypes();
|
const char **psubtype = spice_server_char_device_recognized_subtypes();
|
||||||
ChardevCommon *common = qapi_ChardevSpiceChannel_base(spicevmc);
|
|
||||||
|
|
||||||
for (; *psubtype != NULL; ++psubtype) {
|
for (; *psubtype != NULL; ++psubtype) {
|
||||||
if (strcmp(type, *psubtype) == 0) {
|
if (strcmp(type, *psubtype) == 0) {
|
||||||
@ -294,41 +286,33 @@ static Chardev *qemu_chr_open_spice_vmc(const CharDriver *driver,
|
|||||||
subtypes);
|
subtypes);
|
||||||
|
|
||||||
g_free(subtypes);
|
g_free(subtypes);
|
||||||
return NULL;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
*be_opened = false;
|
*be_opened = false;
|
||||||
return chr_open(driver, type, common, errp);
|
chr_open(chr, type);
|
||||||
}
|
}
|
||||||
|
|
||||||
#if SPICE_SERVER_VERSION >= 0x000c02
|
#if SPICE_SERVER_VERSION >= 0x000c02
|
||||||
static Chardev *qemu_chr_open_spice_port(const CharDriver *driver,
|
static void qemu_chr_open_spice_port(Chardev *chr,
|
||||||
const char *id,
|
|
||||||
ChardevBackend *backend,
|
ChardevBackend *backend,
|
||||||
ChardevReturn *ret,
|
|
||||||
bool *be_opened,
|
bool *be_opened,
|
||||||
Error **errp)
|
Error **errp)
|
||||||
{
|
{
|
||||||
ChardevSpicePort *spiceport = backend->u.spiceport.data;
|
ChardevSpicePort *spiceport = backend->u.spiceport.data;
|
||||||
const char *name = spiceport->fqdn;
|
const char *name = spiceport->fqdn;
|
||||||
ChardevCommon *common = qapi_ChardevSpicePort_base(spiceport);
|
|
||||||
Chardev *chr;
|
|
||||||
SpiceChardev *s;
|
SpiceChardev *s;
|
||||||
|
|
||||||
if (name == NULL) {
|
if (name == NULL) {
|
||||||
error_setg(errp, "missing name parameter");
|
error_setg(errp, "missing name parameter");
|
||||||
return NULL;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
chr = chr_open(driver, "port", common, errp);
|
chr_open(chr, "port");
|
||||||
if (!chr) {
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
*be_opened = false;
|
*be_opened = false;
|
||||||
s = (SpiceChardev *)chr;
|
s = SPICE_CHARDEV(chr);
|
||||||
s->sin.portname = g_strdup(name);
|
s->sin.portname = g_strdup(name);
|
||||||
|
|
||||||
return chr;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void qemu_spice_register_ports(void)
|
void qemu_spice_register_ports(void)
|
||||||
@ -374,32 +358,68 @@ static void qemu_chr_parse_spice_port(QemuOpts *opts, ChardevBackend *backend,
|
|||||||
spiceport->fqdn = g_strdup(name);
|
spiceport->fqdn = g_strdup(name);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void char_spice_class_init(ObjectClass *oc, void *data)
|
||||||
|
{
|
||||||
|
ChardevClass *cc = CHARDEV_CLASS(oc);
|
||||||
|
|
||||||
|
cc->chr_write = spice_chr_write;
|
||||||
|
cc->chr_add_watch = spice_chr_add_watch;
|
||||||
|
cc->chr_accept_input = spice_chr_accept_input;
|
||||||
|
cc->chr_free = spice_chr_free;
|
||||||
|
}
|
||||||
|
|
||||||
|
static const TypeInfo char_spice_type_info = {
|
||||||
|
.name = TYPE_CHARDEV_SPICE,
|
||||||
|
.parent = TYPE_CHARDEV,
|
||||||
|
.instance_size = sizeof(SpiceChardev),
|
||||||
|
.class_init = char_spice_class_init,
|
||||||
|
.abstract = true,
|
||||||
|
};
|
||||||
|
|
||||||
|
static void char_spicevmc_class_init(ObjectClass *oc, void *data)
|
||||||
|
{
|
||||||
|
ChardevClass *cc = CHARDEV_CLASS(oc);
|
||||||
|
|
||||||
|
cc->open = qemu_chr_open_spice_vmc;
|
||||||
|
cc->chr_set_fe_open = spice_vmc_set_fe_open;
|
||||||
|
}
|
||||||
|
|
||||||
|
static const TypeInfo char_spicevmc_type_info = {
|
||||||
|
.name = TYPE_CHARDEV_SPICEVMC,
|
||||||
|
.parent = TYPE_CHARDEV_SPICE,
|
||||||
|
.class_init = char_spicevmc_class_init,
|
||||||
|
};
|
||||||
|
|
||||||
|
static void char_spiceport_class_init(ObjectClass *oc, void *data)
|
||||||
|
{
|
||||||
|
ChardevClass *cc = CHARDEV_CLASS(oc);
|
||||||
|
|
||||||
|
cc->open = qemu_chr_open_spice_port;
|
||||||
|
cc->chr_set_fe_open = spice_port_set_fe_open;
|
||||||
|
}
|
||||||
|
|
||||||
|
static const TypeInfo char_spiceport_type_info = {
|
||||||
|
.name = TYPE_CHARDEV_SPICEPORT,
|
||||||
|
.parent = TYPE_CHARDEV_SPICE,
|
||||||
|
.class_init = char_spiceport_class_init,
|
||||||
|
};
|
||||||
|
|
||||||
static void register_types(void)
|
static void register_types(void)
|
||||||
{
|
{
|
||||||
static const CharDriver vmc_driver = {
|
static const CharDriver vmc_driver = {
|
||||||
.instance_size = sizeof(SpiceChardev),
|
|
||||||
.kind = CHARDEV_BACKEND_KIND_SPICEVMC,
|
.kind = CHARDEV_BACKEND_KIND_SPICEVMC,
|
||||||
.parse = qemu_chr_parse_spice_vmc,
|
.parse = qemu_chr_parse_spice_vmc,
|
||||||
.create = qemu_chr_open_spice_vmc,
|
|
||||||
.chr_write = spice_chr_write,
|
|
||||||
.chr_add_watch = spice_chr_add_watch,
|
|
||||||
.chr_set_fe_open = spice_vmc_set_fe_open,
|
|
||||||
.chr_accept_input = spice_chr_accept_input,
|
|
||||||
.chr_free = spice_chr_free,
|
|
||||||
};
|
};
|
||||||
static const CharDriver port_driver = {
|
static const CharDriver port_driver = {
|
||||||
.instance_size = sizeof(SpiceChardev),
|
|
||||||
.kind = CHARDEV_BACKEND_KIND_SPICEPORT,
|
.kind = CHARDEV_BACKEND_KIND_SPICEPORT,
|
||||||
.parse = qemu_chr_parse_spice_port,
|
.parse = qemu_chr_parse_spice_port,
|
||||||
.create = qemu_chr_open_spice_port,
|
|
||||||
.chr_write = spice_chr_write,
|
|
||||||
.chr_add_watch = spice_chr_add_watch,
|
|
||||||
.chr_set_fe_open = spice_port_set_fe_open,
|
|
||||||
.chr_accept_input = spice_chr_accept_input,
|
|
||||||
.chr_free = spice_chr_free,
|
|
||||||
};
|
};
|
||||||
register_char_driver(&vmc_driver);
|
register_char_driver(&vmc_driver);
|
||||||
register_char_driver(&port_driver);
|
register_char_driver(&port_driver);
|
||||||
|
|
||||||
|
type_register_static(&char_spice_type_info);
|
||||||
|
type_register_static(&char_spicevmc_type_info);
|
||||||
|
type_register_static(&char_spiceport_type_info);
|
||||||
}
|
}
|
||||||
|
|
||||||
type_init(register_types);
|
type_init(register_types);
|
||||||
|
60
ui/console.c
60
ui/console.c
@ -1051,9 +1051,12 @@ typedef struct VCChardev {
|
|||||||
QemuConsole *console;
|
QemuConsole *console;
|
||||||
} VCChardev;
|
} VCChardev;
|
||||||
|
|
||||||
|
#define TYPE_CHARDEV_VC "chardev-vc"
|
||||||
|
#define VC_CHARDEV(obj) OBJECT_CHECK(VCChardev, (obj), TYPE_CHARDEV_VC)
|
||||||
|
|
||||||
static int vc_chr_write(Chardev *chr, const uint8_t *buf, int len)
|
static int vc_chr_write(Chardev *chr, const uint8_t *buf, int len)
|
||||||
{
|
{
|
||||||
VCChardev *drv = (VCChardev *)chr;
|
VCChardev *drv = VC_CHARDEV(chr);
|
||||||
QemuConsole *s = drv->console;
|
QemuConsole *s = drv->console;
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
@ -1964,7 +1967,7 @@ int qemu_console_get_height(QemuConsole *con, int fallback)
|
|||||||
|
|
||||||
static void vc_chr_set_echo(Chardev *chr, bool echo)
|
static void vc_chr_set_echo(Chardev *chr, bool echo)
|
||||||
{
|
{
|
||||||
VCChardev *drv = (VCChardev *)chr;
|
VCChardev *drv = VC_CHARDEV(chr);
|
||||||
QemuConsole *s = drv->console;
|
QemuConsole *s = drv->console;
|
||||||
|
|
||||||
s->echo = echo;
|
s->echo = echo;
|
||||||
@ -2005,7 +2008,7 @@ static const GraphicHwOps text_console_ops = {
|
|||||||
|
|
||||||
static void text_console_do_init(Chardev *chr, DisplayState *ds)
|
static void text_console_do_init(Chardev *chr, DisplayState *ds)
|
||||||
{
|
{
|
||||||
VCChardev *drv = (VCChardev *)chr;
|
VCChardev *drv = VC_CHARDEV(chr);
|
||||||
QemuConsole *s = drv->console;
|
QemuConsole *s = drv->console;
|
||||||
int g_width = 80 * FONT_WIDTH;
|
int g_width = 80 * FONT_WIDTH;
|
||||||
int g_height = 24 * FONT_HEIGHT;
|
int g_height = 24 * FONT_HEIGHT;
|
||||||
@ -2058,24 +2061,17 @@ static void text_console_do_init(Chardev *chr, DisplayState *ds)
|
|||||||
|
|
||||||
static const CharDriver vc_driver;
|
static const CharDriver vc_driver;
|
||||||
|
|
||||||
static Chardev *vc_chr_init(const CharDriver *driver,
|
static void vc_chr_open(Chardev *chr,
|
||||||
const char *id, ChardevBackend *backend,
|
ChardevBackend *backend,
|
||||||
ChardevReturn *ret, bool *be_opened,
|
bool *be_opened,
|
||||||
Error **errp)
|
Error **errp)
|
||||||
{
|
{
|
||||||
ChardevVC *vc = backend->u.vc.data;
|
ChardevVC *vc = backend->u.vc.data;
|
||||||
ChardevCommon *common = qapi_ChardevVC_base(vc);
|
VCChardev *drv = VC_CHARDEV(chr);
|
||||||
Chardev *chr;
|
|
||||||
VCChardev *drv;
|
|
||||||
QemuConsole *s;
|
QemuConsole *s;
|
||||||
unsigned width = 0;
|
unsigned width = 0;
|
||||||
unsigned height = 0;
|
unsigned height = 0;
|
||||||
|
|
||||||
chr = qemu_chr_alloc(&vc_driver, common, errp);
|
|
||||||
if (!chr) {
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (vc->has_width) {
|
if (vc->has_width) {
|
||||||
width = vc->width;
|
width = vc->width;
|
||||||
} else if (vc->has_cols) {
|
} else if (vc->has_cols) {
|
||||||
@ -2097,13 +2093,11 @@ static Chardev *vc_chr_init(const CharDriver *driver,
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (!s) {
|
if (!s) {
|
||||||
g_free(chr);
|
|
||||||
error_setg(errp, "cannot create text console");
|
error_setg(errp, "cannot create text console");
|
||||||
return NULL;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
s->chr = chr;
|
s->chr = chr;
|
||||||
drv = (VCChardev *)chr;
|
|
||||||
drv->console = s;
|
drv->console = s;
|
||||||
|
|
||||||
if (display_state) {
|
if (display_state) {
|
||||||
@ -2114,8 +2108,6 @@ static Chardev *vc_chr_init(const CharDriver *driver,
|
|||||||
* stage, so defer OPENED events until they are fully initialized
|
* stage, so defer OPENED events until they are fully initialized
|
||||||
*/
|
*/
|
||||||
*be_opened = false;
|
*be_opened = false;
|
||||||
|
|
||||||
return chr;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void qemu_console_resize(QemuConsole *s, int width, int height)
|
void qemu_console_resize(QemuConsole *s, int width, int height)
|
||||||
@ -2193,19 +2185,39 @@ static const TypeInfo qemu_console_info = {
|
|||||||
.class_size = sizeof(QemuConsoleClass),
|
.class_size = sizeof(QemuConsoleClass),
|
||||||
};
|
};
|
||||||
|
|
||||||
static const CharDriver vc_driver = {
|
static void char_vc_class_init(ObjectClass *oc, void *data)
|
||||||
|
{
|
||||||
|
ChardevClass *cc = CHARDEV_CLASS(oc);
|
||||||
|
|
||||||
|
cc->open = vc_chr_open;
|
||||||
|
cc->chr_write = vc_chr_write;
|
||||||
|
cc->chr_set_echo = vc_chr_set_echo;
|
||||||
|
}
|
||||||
|
|
||||||
|
static const TypeInfo char_vc_type_info = {
|
||||||
|
.name = TYPE_CHARDEV_VC,
|
||||||
|
.parent = TYPE_CHARDEV,
|
||||||
.instance_size = sizeof(VCChardev),
|
.instance_size = sizeof(VCChardev),
|
||||||
|
.class_init = char_vc_class_init,
|
||||||
|
};
|
||||||
|
|
||||||
|
void qemu_console_early_init(void)
|
||||||
|
{
|
||||||
|
/* set the default vc driver */
|
||||||
|
if (!object_class_by_name(TYPE_CHARDEV_VC)) {
|
||||||
|
type_register(&char_vc_type_info);
|
||||||
|
register_char_driver(&vc_driver);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static const CharDriver vc_driver = {
|
||||||
.kind = CHARDEV_BACKEND_KIND_VC,
|
.kind = CHARDEV_BACKEND_KIND_VC,
|
||||||
.parse = qemu_chr_parse_vc,
|
.parse = qemu_chr_parse_vc,
|
||||||
.create = vc_chr_init,
|
|
||||||
.chr_write = vc_chr_write,
|
|
||||||
.chr_set_echo = vc_chr_set_echo,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
static void register_types(void)
|
static void register_types(void)
|
||||||
{
|
{
|
||||||
type_register_static(&qemu_console_info);
|
type_register_static(&qemu_console_info);
|
||||||
register_char_driver(&vc_driver);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
type_init(register_types);
|
type_init(register_types);
|
||||||
|
51
ui/gtk.c
51
ui/gtk.c
@ -187,6 +187,9 @@ typedef struct VCChardev {
|
|||||||
bool echo;
|
bool echo;
|
||||||
} VCChardev;
|
} VCChardev;
|
||||||
|
|
||||||
|
#define TYPE_CHARDEV_VC "chardev-vc"
|
||||||
|
#define VC_CHARDEV(obj) OBJECT_CHECK(VCChardev, (obj), TYPE_CHARDEV_VC)
|
||||||
|
|
||||||
static void gd_grab_pointer(VirtualConsole *vc, const char *reason);
|
static void gd_grab_pointer(VirtualConsole *vc, const char *reason);
|
||||||
static void gd_ungrab_pointer(GtkDisplayState *s);
|
static void gd_ungrab_pointer(GtkDisplayState *s);
|
||||||
static void gd_grab_keyboard(VirtualConsole *vc, const char *reason);
|
static void gd_grab_keyboard(VirtualConsole *vc, const char *reason);
|
||||||
@ -1691,7 +1694,7 @@ static void gd_vc_adjustment_changed(GtkAdjustment *adjustment, void *opaque)
|
|||||||
|
|
||||||
static int gd_vc_chr_write(Chardev *chr, const uint8_t *buf, int len)
|
static int gd_vc_chr_write(Chardev *chr, const uint8_t *buf, int len)
|
||||||
{
|
{
|
||||||
VCChardev *vcd = (VCChardev *)chr;
|
VCChardev *vcd = VC_CHARDEV(chr);
|
||||||
VirtualConsole *vc = vcd->console;
|
VirtualConsole *vc = vcd->console;
|
||||||
|
|
||||||
vte_terminal_feed(VTE_TERMINAL(vc->vte.terminal), (const char *)buf, len);
|
vte_terminal_feed(VTE_TERMINAL(vc->vte.terminal), (const char *)buf, len);
|
||||||
@ -1700,7 +1703,7 @@ static int gd_vc_chr_write(Chardev *chr, const uint8_t *buf, int len)
|
|||||||
|
|
||||||
static void gd_vc_chr_set_echo(Chardev *chr, bool echo)
|
static void gd_vc_chr_set_echo(Chardev *chr, bool echo)
|
||||||
{
|
{
|
||||||
VCChardev *vcd = (VCChardev *)chr;
|
VCChardev *vcd = VC_CHARDEV(chr);
|
||||||
VirtualConsole *vc = vcd->console;
|
VirtualConsole *vc = vcd->console;
|
||||||
|
|
||||||
if (vc) {
|
if (vc) {
|
||||||
@ -1714,23 +1717,14 @@ static int nb_vcs;
|
|||||||
static Chardev *vcs[MAX_VCS];
|
static Chardev *vcs[MAX_VCS];
|
||||||
static const CharDriver gd_vc_driver;
|
static const CharDriver gd_vc_driver;
|
||||||
|
|
||||||
static Chardev *vc_init(const CharDriver *driver,
|
static void gd_vc_open(Chardev *chr,
|
||||||
const char *id, ChardevBackend *backend,
|
ChardevBackend *backend,
|
||||||
ChardevReturn *ret, bool *be_opened,
|
bool *be_opened,
|
||||||
Error **errp)
|
Error **errp)
|
||||||
{
|
{
|
||||||
ChardevVC *vc = backend->u.vc.data;
|
|
||||||
ChardevCommon *common = qapi_ChardevVC_base(vc);
|
|
||||||
Chardev *chr;
|
|
||||||
|
|
||||||
if (nb_vcs == MAX_VCS) {
|
if (nb_vcs == MAX_VCS) {
|
||||||
error_setg(errp, "Maximum number of consoles reached");
|
error_setg(errp, "Maximum number of consoles reached");
|
||||||
return NULL;
|
return;
|
||||||
}
|
|
||||||
|
|
||||||
chr = qemu_chr_alloc(&gd_vc_driver, common, errp);
|
|
||||||
if (!chr) {
|
|
||||||
return NULL;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
vcs[nb_vcs++] = chr;
|
vcs[nb_vcs++] = chr;
|
||||||
@ -1739,16 +1733,27 @@ static Chardev *vc_init(const CharDriver *driver,
|
|||||||
* stage, so defer OPENED events until they are fully initialized
|
* stage, so defer OPENED events until they are fully initialized
|
||||||
*/
|
*/
|
||||||
*be_opened = false;
|
*be_opened = false;
|
||||||
|
|
||||||
return chr;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static const CharDriver gd_vc_driver = {
|
static void char_gd_vc_class_init(ObjectClass *oc, void *data)
|
||||||
|
{
|
||||||
|
ChardevClass *cc = CHARDEV_CLASS(oc);
|
||||||
|
|
||||||
|
cc->open = gd_vc_open;
|
||||||
|
cc->chr_write = gd_vc_chr_write;
|
||||||
|
cc->chr_set_echo = gd_vc_chr_set_echo;
|
||||||
|
}
|
||||||
|
|
||||||
|
static const TypeInfo char_gd_vc_type_info = {
|
||||||
|
.name = TYPE_CHARDEV_VC,
|
||||||
|
.parent = TYPE_CHARDEV,
|
||||||
.instance_size = sizeof(VCChardev),
|
.instance_size = sizeof(VCChardev),
|
||||||
|
.class_init = char_gd_vc_class_init,
|
||||||
|
};
|
||||||
|
|
||||||
|
static const CharDriver gd_vc_driver = {
|
||||||
.kind = CHARDEV_BACKEND_KIND_VC,
|
.kind = CHARDEV_BACKEND_KIND_VC,
|
||||||
.parse = qemu_chr_parse_vc, .create = vc_init,
|
.parse = qemu_chr_parse_vc,
|
||||||
.chr_write = gd_vc_chr_write,
|
|
||||||
.chr_set_echo = gd_vc_chr_set_echo,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
static gboolean gd_vc_in(VteTerminal *terminal, gchar *text, guint size,
|
static gboolean gd_vc_in(VteTerminal *terminal, gchar *text, guint size,
|
||||||
@ -1786,7 +1791,7 @@ static GSList *gd_vc_vte_init(GtkDisplayState *s, VirtualConsole *vc,
|
|||||||
GtkWidget *box;
|
GtkWidget *box;
|
||||||
GtkWidget *scrollbar;
|
GtkWidget *scrollbar;
|
||||||
GtkAdjustment *vadjustment;
|
GtkAdjustment *vadjustment;
|
||||||
VCChardev *vcd = (VCChardev *)chr;
|
VCChardev *vcd = VC_CHARDEV(chr);
|
||||||
|
|
||||||
vc->s = s;
|
vc->s = s;
|
||||||
vc->vte.echo = vcd->echo;
|
vc->vte.echo = vcd->echo;
|
||||||
@ -2347,7 +2352,7 @@ void early_gtk_display_init(int opengl)
|
|||||||
}
|
}
|
||||||
|
|
||||||
#if defined(CONFIG_VTE)
|
#if defined(CONFIG_VTE)
|
||||||
/* overwrite the console.c vc driver */
|
type_register(&char_gd_vc_type_info);
|
||||||
register_char_driver(&gd_vc_driver);
|
register_char_driver(&gd_vc_driver);
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
2
vl.c
2
vl.c
@ -4252,6 +4252,8 @@ int main(int argc, char **argv, char **envp)
|
|||||||
sdl_display_early_init(request_opengl);
|
sdl_display_early_init(request_opengl);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
qemu_console_early_init();
|
||||||
|
|
||||||
if (request_opengl == 1 && display_opengl == 0) {
|
if (request_opengl == 1 && display_opengl == 0) {
|
||||||
#if defined(CONFIG_OPENGL)
|
#if defined(CONFIG_OPENGL)
|
||||||
error_report("OpenGL is not supported by the display");
|
error_report("OpenGL is not supported by the display");
|
||||||
|
Loading…
Reference in New Issue
Block a user