chardev related patches
-----BEGIN PGP SIGNATURE----- iQJQBAABCAA6FiEEh6m9kz+HxgbSdvYt2ujhCXWWnOUFAmM1evIcHG1hcmNhbmRy ZS5sdXJlYXVAcmVkaGF0LmNvbQAKCRDa6OEJdZac5evvD/49HQuMxsHaTvXSLPxi Bkv9W8cHSEOuAVsgizrd3Z/AEx8MMsZLprtGttYpQN4041aBbyDG7PR1PirVibe7 s5uuqq2LB85dCkrPyiTkfGosbnndDy+VH9ZH+vS6CMKHYRSwpRjYUoKt5e75JhtP RefwFihkVyr3HbsD6SKjB8lV25yw2tQB6BizTedaNmM6ZSmX/TRtes1JgeK3l5jD 7hQVqqEAJ6YvZnpg070Om43sae7j0yoW7Dg45DVViQNJeRG/0rwBKAbUZuLzs9lH hMjqlUW+It7Q7DvkkoLO6DiBsIceeZneZ3XHnv0/OrXDILS2ZWRnm2+qKJp75fub TXFafZX3RIn8ZL6Lw4uz/tsX5CllzuiT/2EO2/CzFIaGESi8Y5eFL3xku7tDWzq8 EtsAehQeHOvNU/mw8Z1hPEozcPMFUY9eUPF7vPRHPV+g+YI+UlrZCFGcJaZpspeP h3rUXInftMHHocr/LvI9DMEzgHjOZrDqjECSavp1nHrGbRLfBl/1QNPql1cZJ+H/ XDygo1x/QVlEkTaBWqcMFifgqJ7xvHPDQd6rvIbBYwUUWU1B79UKON0i6WOMk7A6 vjsJz7Sk+cJMOMwc76w+qd0mRauWkcfiS08Y4g+4HksymZev5OeGNuuDfI6zwfFt T21TIS/c0zmcNU1sgXB6U2VTiw== =pMT6 -----END PGP SIGNATURE----- Merge tag 'char-pull-request' of https://gitlab.com/marcandre.lureau/qemu into staging chardev related patches # -----BEGIN PGP SIGNATURE----- # # iQJQBAABCAA6FiEEh6m9kz+HxgbSdvYt2ujhCXWWnOUFAmM1evIcHG1hcmNhbmRy # ZS5sdXJlYXVAcmVkaGF0LmNvbQAKCRDa6OEJdZac5evvD/49HQuMxsHaTvXSLPxi # Bkv9W8cHSEOuAVsgizrd3Z/AEx8MMsZLprtGttYpQN4041aBbyDG7PR1PirVibe7 # s5uuqq2LB85dCkrPyiTkfGosbnndDy+VH9ZH+vS6CMKHYRSwpRjYUoKt5e75JhtP # RefwFihkVyr3HbsD6SKjB8lV25yw2tQB6BizTedaNmM6ZSmX/TRtes1JgeK3l5jD # 7hQVqqEAJ6YvZnpg070Om43sae7j0yoW7Dg45DVViQNJeRG/0rwBKAbUZuLzs9lH # hMjqlUW+It7Q7DvkkoLO6DiBsIceeZneZ3XHnv0/OrXDILS2ZWRnm2+qKJp75fub # TXFafZX3RIn8ZL6Lw4uz/tsX5CllzuiT/2EO2/CzFIaGESi8Y5eFL3xku7tDWzq8 # EtsAehQeHOvNU/mw8Z1hPEozcPMFUY9eUPF7vPRHPV+g+YI+UlrZCFGcJaZpspeP # h3rUXInftMHHocr/LvI9DMEzgHjOZrDqjECSavp1nHrGbRLfBl/1QNPql1cZJ+H/ # XDygo1x/QVlEkTaBWqcMFifgqJ7xvHPDQd6rvIbBYwUUWU1B79UKON0i6WOMk7A6 # vjsJz7Sk+cJMOMwc76w+qd0mRauWkcfiS08Y4g+4HksymZev5OeGNuuDfI6zwfFt # T21TIS/c0zmcNU1sgXB6U2VTiw== # =pMT6 # -----END PGP SIGNATURE----- # gpg: Signature made Thu 29 Sep 2022 07:01:06 EDT # gpg: using RSA key 87A9BD933F87C606D276F62DDAE8E10975969CE5 # gpg: issuer "marcandre.lureau@redhat.com" # gpg: Good signature from "Marc-André Lureau <marcandre.lureau@redhat.com>" [full] # gpg: aka "Marc-André Lureau <marcandre.lureau@gmail.com>" [full] # Primary key fingerprint: 87A9 BD93 3F87 C606 D276 F62D DAE8 E109 7596 9CE5 * tag 'char-pull-request' of https://gitlab.com/marcandre.lureau/qemu: vhost-user: Call qemu_socketpair() instead of socketpair() oslib-posix: Introduce qemu_socketpair() chardev: fix segfault in finalize serial: Allow unaligned i/o access msmouse: Add pnp data msmouse: Use fifo8 instead of array chardev: src buffer const for write functions msmouse: Handle mouse reset Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
This commit is contained in:
commit
539cb0876b
@ -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) {
|
||||
|
@ -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 = {
|
||||
|
@ -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,
|
||||
|
@ -961,6 +961,9 @@ void serial_set_frequency(SerialState *s, uint32_t frequency)
|
||||
const MemoryRegionOps serial_io_ops = {
|
||||
.read = serial_ioport_read,
|
||||
.write = serial_ioport_write,
|
||||
.valid = {
|
||||
.unaligned = 1,
|
||||
},
|
||||
.impl = {
|
||||
.min_access_size = 1,
|
||||
.max_access_size = 1,
|
||||
|
@ -11,6 +11,7 @@
|
||||
*/
|
||||
|
||||
#include "qemu/osdep.h"
|
||||
#include "qemu/sockets.h"
|
||||
#include "hw/qdev-properties.h"
|
||||
#include "hw/virtio/virtio-gpu.h"
|
||||
#include "chardev/char-fe.h"
|
||||
@ -375,7 +376,7 @@ vhost_user_gpu_do_set_socket(VhostUserGPU *g, Error **errp)
|
||||
Chardev *chr;
|
||||
int sv[2];
|
||||
|
||||
if (socketpair(PF_UNIX, SOCK_STREAM, 0, sv) == -1) {
|
||||
if (qemu_socketpair(PF_UNIX, SOCK_STREAM, 0, sv) == -1) {
|
||||
error_setg_errno(errp, errno, "socketpair() failed");
|
||||
return false;
|
||||
}
|
||||
|
@ -1726,7 +1726,7 @@ static int vhost_setup_slave_channel(struct vhost_dev *dev)
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (socketpair(PF_UNIX, SOCK_STREAM, 0, sv) == -1) {
|
||||
if (qemu_socketpair(PF_UNIX, SOCK_STREAM, 0, sv) == -1) {
|
||||
int saved_errno = errno;
|
||||
error_report("socketpair() failed");
|
||||
return -saved_errno;
|
||||
|
@ -186,7 +186,7 @@ int qemu_chr_be_can_write(Chardev *s);
|
||||
* the caller should call @qemu_chr_be_can_write to determine how much data
|
||||
* the front end can currently accept.
|
||||
*/
|
||||
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);
|
||||
|
||||
/**
|
||||
* qemu_chr_be_write_impl:
|
||||
@ -195,7 +195,7 @@ void qemu_chr_be_write(Chardev *s, uint8_t *buf, int len);
|
||||
*
|
||||
* Implementation of back end writing. Used by replay module.
|
||||
*/
|
||||
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);
|
||||
|
||||
/**
|
||||
* qemu_chr_be_update_read_handlers:
|
||||
|
@ -14,6 +14,24 @@ int inet_aton(const char *cp, struct in_addr *ia);
|
||||
/* misc helpers */
|
||||
bool fd_is_socket(int fd);
|
||||
int qemu_socket(int domain, int type, int protocol);
|
||||
|
||||
#ifndef WIN32
|
||||
/**
|
||||
* qemu_socketpair:
|
||||
* @domain: specifies a communication domain, such as PF_UNIX
|
||||
* @type: specifies the socket type.
|
||||
* @protocol: specifies a particular protocol to be used with the socket
|
||||
* @sv: an array to store the pair of socket created
|
||||
*
|
||||
* Creates an unnamed pair of connected sockets in the specified domain,
|
||||
* of the specified type, and using the optionally specified protocol.
|
||||
* And automatically set the close-on-exec flags on the returned sockets
|
||||
*
|
||||
* Return 0 on success.
|
||||
*/
|
||||
int qemu_socketpair(int domain, int type, int protocol, int sv[2]);
|
||||
#endif
|
||||
|
||||
int qemu_accept(int s, struct sockaddr *addr, socklen_t *addrlen);
|
||||
int socket_set_cork(int fd, int v);
|
||||
int socket_set_nodelay(int fd);
|
||||
|
@ -198,7 +198,7 @@ uint64_t blkreplay_next_id(void);
|
||||
/*! Registers char driver to save it's events */
|
||||
void replay_register_char_driver(struct Chardev *chr);
|
||||
/*! Saves write to char device event to the log */
|
||||
void replay_chr_be_write(struct Chardev *s, uint8_t *buf, int len);
|
||||
void replay_chr_be_write(struct Chardev *s, const uint8_t *buf, int len);
|
||||
/*! Writes char write return value to the replay log. */
|
||||
void replay_char_write_event_save(int res, int offset);
|
||||
/*! Reads char write return value from the replay log. */
|
||||
|
@ -48,7 +48,7 @@ void replay_register_char_driver(Chardev *chr)
|
||||
char_drivers[drivers_count++] = chr;
|
||||
}
|
||||
|
||||
void replay_chr_be_write(Chardev *s, uint8_t *buf, int len)
|
||||
void replay_chr_be_write(Chardev *s, const uint8_t *buf, int len)
|
||||
{
|
||||
CharEvent *event = g_new0(CharEvent, 1);
|
||||
|
||||
|
@ -53,7 +53,7 @@ void replay_register_char_driver(struct Chardev *chr)
|
||||
{
|
||||
}
|
||||
|
||||
void replay_chr_be_write(struct Chardev *s, uint8_t *buf, int len)
|
||||
void replay_chr_be_write(struct Chardev *s, const uint8_t *buf, int len)
|
||||
{
|
||||
abort();
|
||||
}
|
||||
|
@ -253,6 +253,25 @@ void qemu_set_cloexec(int fd)
|
||||
assert(f != -1);
|
||||
}
|
||||
|
||||
int qemu_socketpair(int domain, int type, int protocol, int sv[2])
|
||||
{
|
||||
int ret;
|
||||
|
||||
#ifdef SOCK_CLOEXEC
|
||||
ret = socketpair(domain, type | SOCK_CLOEXEC, protocol, sv);
|
||||
if (ret != -1 || errno != EINVAL) {
|
||||
return ret;
|
||||
}
|
||||
#endif
|
||||
ret = socketpair(domain, type, protocol, sv);;
|
||||
if (ret == 0) {
|
||||
qemu_set_cloexec(sv[0]);
|
||||
qemu_set_cloexec(sv[1]);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
char *
|
||||
qemu_get_local_state_dir(void)
|
||||
{
|
||||
|
Loading…
Reference in New Issue
Block a user