diff options
Diffstat (limited to 'chardev')
-rw-r--r-- | chardev/char.c | 4 | ||||
-rw-r--r-- | chardev/msmouse.c | 152 | ||||
-rw-r--r-- | chardev/wctablet.c | 4 |
3 files changed, 131 insertions, 29 deletions
diff --git a/chardev/char.c b/chardev/char.c index 0169d8dde4..b005df3ccf 100644 --- a/chardev/char.c +++ b/chardev/char.c @@ -193,7 +193,7 @@ int qemu_chr_be_can_write(Chardev *s) return be->chr_can_read(be->opaque); } -void qemu_chr_be_write_impl(Chardev *s, uint8_t *buf, int len) +void qemu_chr_be_write_impl(Chardev *s, const uint8_t *buf, int len) { CharBackend *be = s->be; @@ -202,7 +202,7 @@ void qemu_chr_be_write_impl(Chardev *s, uint8_t *buf, int len) } } -void qemu_chr_be_write(Chardev *s, uint8_t *buf, int len) +void qemu_chr_be_write(Chardev *s, const uint8_t *buf, int len) { if (qemu_chr_replay(s)) { if (replay_mode == REPLAY_MODE_PLAY) { diff --git a/chardev/msmouse.c b/chardev/msmouse.c index eb9231dcdb..ab8fe981d6 100644 --- a/chardev/msmouse.c +++ b/chardev/msmouse.c @@ -24,23 +24,45 @@ #include "qemu/osdep.h" #include "qemu/module.h" +#include "qemu/fifo8.h" #include "chardev/char.h" +#include "chardev/char-serial.h" #include "ui/console.h" #include "ui/input.h" #include "qom/object.h" -#define MSMOUSE_LO6(n) ((n) & 0x3f) -#define MSMOUSE_HI2(n) (((n) & 0xc0) >> 6) +#define MSMOUSE_LO6(n) ((n) & 0x3f) +#define MSMOUSE_HI2(n) (((n) & 0xc0) >> 6) +#define MSMOUSE_PWR(cm) (cm & (CHR_TIOCM_RTS | CHR_TIOCM_DTR)) + +/* Serial PnP for 6 bit devices/mice sends all ASCII chars - 0x20 */ +#define M(c) (c - 0x20) +/* Serial fifo size. */ +#define MSMOUSE_BUF_SZ 64 + +/* Mouse ID: Send "M3" cause we behave like a 3 button logitech mouse. */ +const uint8_t mouse_id[] = {'M', '3'}; +/* + * PnP start "(", PnP version (1.0), vendor ID, product ID, '\\', + * serial ID (omitted), '\\', MS class name, '\\', driver ID (omitted), '\\', + * product description, checksum, ")" + * Missing parts are inserted later. + */ +const uint8_t pnp_data[] = {M('('), 1, '$', M('Q'), M('M'), M('U'), + M('0'), M('0'), M('0'), M('1'), + M('\\'), M('\\'), + M('M'), M('O'), M('U'), M('S'), M('E'), + M('\\'), M('\\')}; struct MouseChardev { Chardev parent; QemuInputHandlerState *hs; + int tiocm; int axis[INPUT_AXIS__MAX]; bool btns[INPUT_BUTTON__MAX]; bool btnc[INPUT_BUTTON__MAX]; - uint8_t outbuf[32]; - int outlen; + Fifo8 outbuf; }; typedef struct MouseChardev MouseChardev; @@ -51,20 +73,18 @@ DECLARE_INSTANCE_CHECKER(MouseChardev, MOUSE_CHARDEV, static void msmouse_chr_accept_input(Chardev *chr) { MouseChardev *mouse = MOUSE_CHARDEV(chr); - int len; + uint32_t len, avail; len = qemu_chr_be_can_write(chr); - if (len > mouse->outlen) { - len = mouse->outlen; - } - if (!len) { - return; - } + avail = fifo8_num_used(&mouse->outbuf); + while (len > 0 && avail > 0) { + const uint8_t *buf; + uint32_t size; - qemu_chr_be_write(chr, mouse->outbuf, len); - mouse->outlen -= len; - if (mouse->outlen) { - memmove(mouse->outbuf, mouse->outbuf + len, mouse->outlen); + buf = fifo8_pop_buf(&mouse->outbuf, MIN(len, avail), &size); + qemu_chr_be_write(chr, buf, size); + len = qemu_chr_be_can_write(chr); + avail -= size; } } @@ -91,12 +111,11 @@ static void msmouse_queue_event(MouseChardev *mouse) mouse->btnc[INPUT_BUTTON_MIDDLE]) { bytes[3] |= (mouse->btns[INPUT_BUTTON_MIDDLE] ? 0x20 : 0x00); mouse->btnc[INPUT_BUTTON_MIDDLE] = false; - count = 4; + count++; } - if (mouse->outlen <= sizeof(mouse->outbuf) - count) { - memcpy(mouse->outbuf + mouse->outlen, bytes, count); - mouse->outlen += count; + if (fifo8_num_free(&mouse->outbuf) >= count) { + fifo8_push_all(&mouse->outbuf, bytes, count); } else { /* queue full -> drop event */ } @@ -109,6 +128,11 @@ static void msmouse_input_event(DeviceState *dev, QemuConsole *src, InputMoveEvent *move; InputBtnEvent *btn; + /* Ignore events if serial mouse powered down. */ + if (!MSMOUSE_PWR(mouse->tiocm)) { + return; + } + switch (evt->type) { case INPUT_EVENT_KIND_REL: move = evt->u.rel.data; @@ -132,6 +156,11 @@ static void msmouse_input_sync(DeviceState *dev) MouseChardev *mouse = MOUSE_CHARDEV(dev); Chardev *chr = CHARDEV(dev); + /* Ignore events if serial mouse powered down. */ + if (!MSMOUSE_PWR(mouse->tiocm)) { + return; + } + msmouse_queue_event(mouse); msmouse_chr_accept_input(chr); } @@ -142,13 +171,6 @@ static int msmouse_chr_write(struct Chardev *s, const uint8_t *buf, int len) return len; } -static void char_msmouse_finalize(Object *obj) -{ - MouseChardev *mouse = MOUSE_CHARDEV(obj); - - qemu_input_handler_unregister(mouse->hs); -} - static QemuInputHandler msmouse_handler = { .name = "QEMU Microsoft Mouse", .mask = INPUT_EVENT_MASK_BTN | INPUT_EVENT_MASK_REL, @@ -156,6 +178,81 @@ static QemuInputHandler msmouse_handler = { .sync = msmouse_input_sync, }; +static int msmouse_ioctl(Chardev *chr, int cmd, void *arg) +{ + MouseChardev *mouse = MOUSE_CHARDEV(chr); + int c, i, j; + uint8_t bytes[MSMOUSE_BUF_SZ / 2]; + int *targ = (int *)arg; + const uint8_t hexchr[16] = {M('0'), M('1'), M('2'), M('3'), M('4'), M('5'), + M('6'), M('7'), M('8'), M('9'), M('A'), M('B'), + M('C'), M('D'), M('E'), M('F')}; + + switch (cmd) { + case CHR_IOCTL_SERIAL_SET_TIOCM: + c = mouse->tiocm; + mouse->tiocm = *(int *)arg; + if (MSMOUSE_PWR(mouse->tiocm)) { + if (!MSMOUSE_PWR(c)) { + /* + * Power on after reset: Send ID and PnP data + * No need to check fifo space as it is empty at this point. + */ + fifo8_push_all(&mouse->outbuf, mouse_id, sizeof(mouse_id)); + /* Add PnP data: */ + fifo8_push_all(&mouse->outbuf, pnp_data, sizeof(pnp_data)); + /* + * Add device description from qemu handler name. + * Make sure this all fits into the queue beforehand! + */ + c = M(')'); + for (i = 0; msmouse_handler.name[i]; i++) { + bytes[i] = M(msmouse_handler.name[i]); + c += bytes[i]; + } + /* Calc more of checksum */ + for (j = 0; j < sizeof(pnp_data); j++) { + c += pnp_data[j]; + } + c &= 0xff; + bytes[i++] = hexchr[c >> 4]; + bytes[i++] = hexchr[c & 0x0f]; + bytes[i++] = M(')'); + fifo8_push_all(&mouse->outbuf, bytes, i); + /* Start sending data to serial. */ + msmouse_chr_accept_input(chr); + } + break; + } + /* + * Reset mouse buffers on power down. + * Mouse won't send anything without power. + */ + fifo8_reset(&mouse->outbuf); + memset(mouse->axis, 0, sizeof(mouse->axis)); + memset(mouse->btns, false, sizeof(mouse->btns)); + memset(mouse->btnc, false, sizeof(mouse->btns)); + break; + case CHR_IOCTL_SERIAL_GET_TIOCM: + /* Remember line control status. */ + *targ = mouse->tiocm; + break; + default: + return -ENOTSUP; + } + return 0; +} + +static void char_msmouse_finalize(Object *obj) +{ + MouseChardev *mouse = MOUSE_CHARDEV(obj); + + if (mouse->hs) { + qemu_input_handler_unregister(mouse->hs); + } + fifo8_destroy(&mouse->outbuf); +} + static void msmouse_chr_open(Chardev *chr, ChardevBackend *backend, bool *be_opened, @@ -166,6 +263,8 @@ static void msmouse_chr_open(Chardev *chr, *be_opened = false; mouse->hs = qemu_input_handler_register((DeviceState *)mouse, &msmouse_handler); + mouse->tiocm = 0; + fifo8_create(&mouse->outbuf, MSMOUSE_BUF_SZ); } static void char_msmouse_class_init(ObjectClass *oc, void *data) @@ -175,6 +274,7 @@ static void char_msmouse_class_init(ObjectClass *oc, void *data) cc->open = msmouse_chr_open; cc->chr_write = msmouse_chr_write; cc->chr_accept_input = msmouse_chr_accept_input; + cc->chr_ioctl = msmouse_ioctl; } static const TypeInfo char_msmouse_type_info = { diff --git a/chardev/wctablet.c b/chardev/wctablet.c index e8b292c43c..43bdf6b608 100644 --- a/chardev/wctablet.c +++ b/chardev/wctablet.c @@ -319,7 +319,9 @@ static void wctablet_chr_finalize(Object *obj) { TabletChardev *tablet = WCTABLET_CHARDEV(obj); - qemu_input_handler_unregister(tablet->hs); + if (tablet->hs) { + qemu_input_handler_unregister(tablet->hs); + } } static void wctablet_chr_open(Chardev *chr, |