xref: /openbmc/qemu/chardev/wctablet.c (revision 46919512fcfec1e677733a16bc178898c524854f)
16b10e573SMarc-André Lureau /*
26b10e573SMarc-André Lureau  * QEMU Wacom Penpartner serial tablet emulation
36b10e573SMarc-André Lureau  *
46b10e573SMarc-André Lureau  * some protocol details:
56b10e573SMarc-André Lureau  *   http://linuxwacom.sourceforge.net/wiki/index.php/Serial_Protocol_IV
66b10e573SMarc-André Lureau  *
76b10e573SMarc-André Lureau  * Copyright (c) 2016 Anatoli Huseu1
86b10e573SMarc-André Lureau  * Copyright (c) 2016,17 Gerd Hoffmann
96b10e573SMarc-André Lureau  *
106b10e573SMarc-André Lureau  * Permission is hereby granted, free of charge, to any person obtaining a copy
116b10e573SMarc-André Lureau  * of this software and associated documentation files (the "Software"), to
126b10e573SMarc-André Lureau  * deal in the Software without restriction, including without limitation
136b10e573SMarc-André Lureau  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
146b10e573SMarc-André Lureau  * and/or sell copies of the Software, and to permit persons to whom the
156b10e573SMarc-André Lureau  * Software is furnished to do so, subject to the following conditions:
166b10e573SMarc-André Lureau  *
176b10e573SMarc-André Lureau  * The above copyright notice and this permission notice shall be included in
186b10e573SMarc-André Lureau  * all copies or substantial portions of the Software.
196b10e573SMarc-André Lureau  *
206b10e573SMarc-André Lureau  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
216b10e573SMarc-André Lureau  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
226b10e573SMarc-André Lureau  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
236b10e573SMarc-André Lureau  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
246b10e573SMarc-André Lureau  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM
256b10e573SMarc-André Lureau  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
266b10e573SMarc-André Lureau  * THE SOFTWARE.
276b10e573SMarc-André Lureau  */
286b10e573SMarc-André Lureau 
296b10e573SMarc-André Lureau #include "qemu/osdep.h"
300b8fa32fSMarkus Armbruster #include "qemu/module.h"
316b10e573SMarc-André Lureau #include "chardev/char-serial.h"
326b10e573SMarc-André Lureau #include "ui/console.h"
336b10e573SMarc-André Lureau #include "ui/input.h"
346b10e573SMarc-André Lureau #include "trace.h"
35db1015e9SEduardo Habkost #include "qom/object.h"
366b10e573SMarc-André Lureau 
376b10e573SMarc-André Lureau 
386b10e573SMarc-André Lureau #define WC_OUTPUT_BUF_MAX_LEN 512
396b10e573SMarc-André Lureau #define WC_COMMAND_MAX_LEN 60
406b10e573SMarc-André Lureau 
416b10e573SMarc-André Lureau #define WC_L7(n) ((n) & 127)
426b10e573SMarc-André Lureau #define WC_M7(n) (((n) >> 7) & 127)
436b10e573SMarc-André Lureau #define WC_H2(n) ((n) >> 14)
446b10e573SMarc-André Lureau 
456b10e573SMarc-André Lureau #define WC_L4(n) ((n) & 15)
466b10e573SMarc-André Lureau #define WC_H4(n) (((n) >> 4) & 15)
476b10e573SMarc-André Lureau 
486b10e573SMarc-André Lureau /* Model string and config string */
496b10e573SMarc-André Lureau #define WC_MODEL_STRING_LENGTH 18
506b10e573SMarc-André Lureau uint8_t WC_MODEL_STRING[WC_MODEL_STRING_LENGTH + 1] = "~#CT-0045R,V1.3-5,";
516b10e573SMarc-André Lureau 
526b10e573SMarc-André Lureau #define WC_CONFIG_STRING_LENGTH 8
536b10e573SMarc-André Lureau uint8_t WC_CONFIG_STRING[WC_CONFIG_STRING_LENGTH + 1] = "96,N,8,0";
546b10e573SMarc-André Lureau 
556b10e573SMarc-André Lureau #define WC_FULL_CONFIG_STRING_LENGTH 61
566b10e573SMarc-André Lureau uint8_t WC_FULL_CONFIG_STRING[WC_FULL_CONFIG_STRING_LENGTH + 1] = {
576b10e573SMarc-André Lureau     0x5c, 0x39, 0x36, 0x2c, 0x4e, 0x2c, 0x38, 0x2c,
586b10e573SMarc-André Lureau     0x31, 0x28, 0x01, 0x24, 0x57, 0x41, 0x43, 0x30,
596b10e573SMarc-André Lureau     0x30, 0x34, 0x35, 0x5c, 0x5c, 0x50, 0x45, 0x4e, 0x5c,
606b10e573SMarc-André Lureau     0x57, 0x41, 0x43, 0x30, 0x30, 0x30, 0x30, 0x5c,
616b10e573SMarc-André Lureau     0x54, 0x61, 0x62, 0x6c, 0x65, 0x74, 0x0d, 0x0a,
626b10e573SMarc-André Lureau     0x43, 0x54, 0x2d, 0x30, 0x30, 0x34, 0x35, 0x52,
636b10e573SMarc-André Lureau     0x2c, 0x56, 0x31, 0x2e, 0x33, 0x2d, 0x35, 0x0d,
646b10e573SMarc-André Lureau     0x0a, 0x45, 0x37, 0x29
656b10e573SMarc-André Lureau };
666b10e573SMarc-André Lureau 
676b10e573SMarc-André Lureau /* This structure is used to save private info for Wacom Tablet. */
68db1015e9SEduardo Habkost struct TabletChardev {
696b10e573SMarc-André Lureau     Chardev parent;
706b10e573SMarc-André Lureau     QemuInputHandlerState *hs;
716b10e573SMarc-André Lureau 
726b10e573SMarc-André Lureau     /* Query string from serial */
736b10e573SMarc-André Lureau     uint8_t query[100];
746b10e573SMarc-André Lureau     int query_index;
756b10e573SMarc-André Lureau 
766b10e573SMarc-André Lureau     /* Command to be sent to serial port */
776b10e573SMarc-André Lureau     uint8_t outbuf[WC_OUTPUT_BUF_MAX_LEN];
786b10e573SMarc-André Lureau     int outlen;
796b10e573SMarc-André Lureau 
806b10e573SMarc-André Lureau     int line_speed;
816b10e573SMarc-André Lureau     bool send_events;
826b10e573SMarc-André Lureau     int axis[INPUT_AXIS__MAX];
836b10e573SMarc-André Lureau     bool btns[INPUT_BUTTON__MAX];
846b10e573SMarc-André Lureau 
85db1015e9SEduardo Habkost };
86db1015e9SEduardo Habkost typedef struct TabletChardev TabletChardev;
876b10e573SMarc-André Lureau 
886b10e573SMarc-André Lureau #define TYPE_CHARDEV_WCTABLET "chardev-wctablet"
898110fa1dSEduardo Habkost DECLARE_INSTANCE_CHECKER(TabletChardev, WCTABLET_CHARDEV,
908110fa1dSEduardo Habkost                          TYPE_CHARDEV_WCTABLET)
916b10e573SMarc-André Lureau 
926b10e573SMarc-André Lureau 
936b10e573SMarc-André Lureau static void wctablet_chr_accept_input(Chardev *chr);
946b10e573SMarc-André Lureau 
wctablet_shift_input(TabletChardev * tablet,int count)956b10e573SMarc-André Lureau static void wctablet_shift_input(TabletChardev *tablet, int count)
966b10e573SMarc-André Lureau {
976b10e573SMarc-André Lureau     tablet->query_index -= count;
986b10e573SMarc-André Lureau     memmove(tablet->query, tablet->query + count, tablet->query_index);
996b10e573SMarc-André Lureau     tablet->query[tablet->query_index] = 0;
1006b10e573SMarc-André Lureau }
1016b10e573SMarc-André Lureau 
wctablet_queue_output(TabletChardev * tablet,uint8_t * buf,int count)1026b10e573SMarc-André Lureau static void wctablet_queue_output(TabletChardev *tablet, uint8_t *buf, int count)
1036b10e573SMarc-André Lureau {
1046b10e573SMarc-André Lureau     if (tablet->outlen + count > sizeof(tablet->outbuf)) {
1056b10e573SMarc-André Lureau         return;
1066b10e573SMarc-André Lureau     }
1076b10e573SMarc-André Lureau 
1086b10e573SMarc-André Lureau     memcpy(tablet->outbuf + tablet->outlen, buf, count);
1096b10e573SMarc-André Lureau     tablet->outlen += count;
1106b10e573SMarc-André Lureau     wctablet_chr_accept_input(CHARDEV(tablet));
1116b10e573SMarc-André Lureau }
1126b10e573SMarc-André Lureau 
wctablet_reset(TabletChardev * tablet)1136b10e573SMarc-André Lureau static void wctablet_reset(TabletChardev *tablet)
1146b10e573SMarc-André Lureau {
1156b10e573SMarc-André Lureau     /* clear buffers */
1166b10e573SMarc-André Lureau     tablet->query_index = 0;
1176b10e573SMarc-André Lureau     tablet->outlen = 0;
1186b10e573SMarc-André Lureau     /* reset state */
1196b10e573SMarc-André Lureau     tablet->send_events = false;
1206b10e573SMarc-André Lureau }
1216b10e573SMarc-André Lureau 
wctablet_queue_event(TabletChardev * tablet)1226b10e573SMarc-André Lureau static void wctablet_queue_event(TabletChardev *tablet)
1236b10e573SMarc-André Lureau {
1246b10e573SMarc-André Lureau     uint8_t codes[8] = { 0xe0, 0, 0, 0, 0, 0, 0 };
1256b10e573SMarc-André Lureau 
1266b10e573SMarc-André Lureau     if (tablet->line_speed != 9600) {
1276b10e573SMarc-André Lureau         return;
1286b10e573SMarc-André Lureau     }
1296b10e573SMarc-André Lureau 
1306b10e573SMarc-André Lureau     int newX = tablet->axis[INPUT_AXIS_X] * 0.1537;
1316b10e573SMarc-André Lureau     int nexY = tablet->axis[INPUT_AXIS_Y] * 0.1152;
1326b10e573SMarc-André Lureau 
1336b10e573SMarc-André Lureau     codes[0] = codes[0] | WC_H2(newX);
1346b10e573SMarc-André Lureau     codes[1] = codes[1] | WC_M7(newX);
1356b10e573SMarc-André Lureau     codes[2] = codes[2] | WC_L7(newX);
1366b10e573SMarc-André Lureau 
1376b10e573SMarc-André Lureau     codes[3] = codes[3] | WC_H2(nexY);
1386b10e573SMarc-André Lureau     codes[4] = codes[4] | WC_M7(nexY);
1396b10e573SMarc-André Lureau     codes[5] = codes[5] | WC_L7(nexY);
1406b10e573SMarc-André Lureau 
1416b10e573SMarc-André Lureau     if (tablet->btns[INPUT_BUTTON_LEFT]) {
1426b10e573SMarc-André Lureau         codes[0] = 0xa0;
1436b10e573SMarc-André Lureau     }
1446b10e573SMarc-André Lureau 
1456b10e573SMarc-André Lureau     wctablet_queue_output(tablet, codes, 7);
1466b10e573SMarc-André Lureau }
1476b10e573SMarc-André Lureau 
wctablet_input_event(DeviceState * dev,QemuConsole * src,InputEvent * evt)1486b10e573SMarc-André Lureau static void wctablet_input_event(DeviceState *dev, QemuConsole *src,
1496b10e573SMarc-André Lureau                                 InputEvent *evt)
1506b10e573SMarc-André Lureau {
1516b10e573SMarc-André Lureau     TabletChardev *tablet = (TabletChardev *)dev;
1526b10e573SMarc-André Lureau     InputMoveEvent *move;
1536b10e573SMarc-André Lureau     InputBtnEvent *btn;
1546b10e573SMarc-André Lureau 
1556b10e573SMarc-André Lureau     switch (evt->type) {
1566b10e573SMarc-André Lureau     case INPUT_EVENT_KIND_ABS:
1576b10e573SMarc-André Lureau         move = evt->u.abs.data;
1586b10e573SMarc-André Lureau         tablet->axis[move->axis] = move->value;
1596b10e573SMarc-André Lureau         break;
1606b10e573SMarc-André Lureau 
1616b10e573SMarc-André Lureau     case INPUT_EVENT_KIND_BTN:
1626b10e573SMarc-André Lureau         btn = evt->u.btn.data;
1636b10e573SMarc-André Lureau         tablet->btns[btn->button] = btn->down;
1646b10e573SMarc-André Lureau         break;
1656b10e573SMarc-André Lureau 
1666b10e573SMarc-André Lureau     default:
1676b10e573SMarc-André Lureau         /* keep gcc happy */
1686b10e573SMarc-André Lureau         break;
1696b10e573SMarc-André Lureau     }
1706b10e573SMarc-André Lureau }
1716b10e573SMarc-André Lureau 
wctablet_input_sync(DeviceState * dev)1726b10e573SMarc-André Lureau static void wctablet_input_sync(DeviceState *dev)
1736b10e573SMarc-André Lureau {
1746b10e573SMarc-André Lureau     TabletChardev *tablet = (TabletChardev *)dev;
1756b10e573SMarc-André Lureau 
1766b10e573SMarc-André Lureau     if (tablet->send_events) {
1776b10e573SMarc-André Lureau         wctablet_queue_event(tablet);
1786b10e573SMarc-André Lureau     }
1796b10e573SMarc-André Lureau }
1806b10e573SMarc-André Lureau 
181*b1be65f6SPhilippe Mathieu-Daudé static const QemuInputHandler wctablet_handler = {
182129263c6SPhilippe Mathieu-Daudé     .name  = "QEMU Wacom Pen Tablet",
1836b10e573SMarc-André Lureau     .mask  = INPUT_EVENT_MASK_BTN | INPUT_EVENT_MASK_ABS,
1846b10e573SMarc-André Lureau     .event = wctablet_input_event,
1856b10e573SMarc-André Lureau     .sync  = wctablet_input_sync,
1866b10e573SMarc-André Lureau };
1876b10e573SMarc-André Lureau 
wctablet_chr_accept_input(Chardev * chr)1886b10e573SMarc-André Lureau static void wctablet_chr_accept_input(Chardev *chr)
1896b10e573SMarc-André Lureau {
1906b10e573SMarc-André Lureau     TabletChardev *tablet = WCTABLET_CHARDEV(chr);
1916b10e573SMarc-André Lureau     int len, canWrite;
1926b10e573SMarc-André Lureau 
1936b10e573SMarc-André Lureau     canWrite = qemu_chr_be_can_write(chr);
1946b10e573SMarc-André Lureau     len = canWrite;
1956b10e573SMarc-André Lureau     if (len > tablet->outlen) {
1966b10e573SMarc-André Lureau         len = tablet->outlen;
1976b10e573SMarc-André Lureau     }
1986b10e573SMarc-André Lureau 
1996b10e573SMarc-André Lureau     if (len) {
2006b10e573SMarc-André Lureau         qemu_chr_be_write(chr, tablet->outbuf, len);
2016b10e573SMarc-André Lureau         tablet->outlen -= len;
2026b10e573SMarc-André Lureau         if (tablet->outlen) {
2036b10e573SMarc-André Lureau             memmove(tablet->outbuf, tablet->outbuf + len, tablet->outlen);
2046b10e573SMarc-André Lureau         }
2056b10e573SMarc-André Lureau     }
2066b10e573SMarc-André Lureau }
2076b10e573SMarc-André Lureau 
wctablet_chr_write(struct Chardev * chr,const uint8_t * buf,int len)2086b10e573SMarc-André Lureau static int wctablet_chr_write(struct Chardev *chr,
2096b10e573SMarc-André Lureau                               const uint8_t *buf, int len)
2106b10e573SMarc-André Lureau {
2116b10e573SMarc-André Lureau     TabletChardev *tablet = WCTABLET_CHARDEV(chr);
2126b10e573SMarc-André Lureau     unsigned int i, clen;
2136b10e573SMarc-André Lureau     char *pos;
2146b10e573SMarc-André Lureau 
2156b10e573SMarc-André Lureau     if (tablet->line_speed != 9600) {
2166b10e573SMarc-André Lureau         return len;
2176b10e573SMarc-André Lureau     }
2186b10e573SMarc-André Lureau     for (i = 0; i < len && tablet->query_index < sizeof(tablet->query) - 1; i++) {
2196b10e573SMarc-André Lureau         tablet->query[tablet->query_index++] = buf[i];
2206b10e573SMarc-André Lureau     }
2216b10e573SMarc-André Lureau     tablet->query[tablet->query_index] = 0;
2226b10e573SMarc-André Lureau 
2236b10e573SMarc-André Lureau     while (tablet->query_index > 0 && (tablet->query[0] == '@'  ||
2246b10e573SMarc-André Lureau                                        tablet->query[0] == '\r' ||
2256b10e573SMarc-André Lureau                                        tablet->query[0] == '\n')) {
2266b10e573SMarc-André Lureau         wctablet_shift_input(tablet, 1);
2276b10e573SMarc-André Lureau     }
2286b10e573SMarc-André Lureau     if (!tablet->query_index) {
2296b10e573SMarc-André Lureau         return len;
2306b10e573SMarc-André Lureau     }
2316b10e573SMarc-André Lureau 
2326b10e573SMarc-André Lureau     if (strncmp((char *)tablet->query, "~#", 2) == 0) {
2336b10e573SMarc-André Lureau         /* init / detect sequence */
2346b10e573SMarc-André Lureau         trace_wct_init();
2356b10e573SMarc-André Lureau         wctablet_shift_input(tablet, 2);
2366b10e573SMarc-André Lureau         wctablet_queue_output(tablet, WC_MODEL_STRING,
2376b10e573SMarc-André Lureau                               WC_MODEL_STRING_LENGTH);
2386b10e573SMarc-André Lureau         return len;
2396b10e573SMarc-André Lureau     }
2406b10e573SMarc-André Lureau 
2416b10e573SMarc-André Lureau     /* detect line */
2426b10e573SMarc-André Lureau     pos = strchr((char *)tablet->query, '\r');
2436b10e573SMarc-André Lureau     if (!pos) {
2446b10e573SMarc-André Lureau         pos = strchr((char *)tablet->query, '\n');
2456b10e573SMarc-André Lureau     }
2466b10e573SMarc-André Lureau     if (!pos) {
2476b10e573SMarc-André Lureau         return len;
2486b10e573SMarc-André Lureau     }
2496b10e573SMarc-André Lureau     clen = pos - (char *)tablet->query;
2506b10e573SMarc-André Lureau 
2516b10e573SMarc-André Lureau     /* process commands */
2526b10e573SMarc-André Lureau     if (strncmp((char *)tablet->query, "RE", 2) == 0 &&
2536b10e573SMarc-André Lureau         clen == 2) {
2546b10e573SMarc-André Lureau         trace_wct_cmd_re();
2556b10e573SMarc-André Lureau         wctablet_shift_input(tablet, 3);
2566b10e573SMarc-André Lureau         wctablet_queue_output(tablet, WC_CONFIG_STRING,
2576b10e573SMarc-André Lureau                               WC_CONFIG_STRING_LENGTH);
2586b10e573SMarc-André Lureau 
2596b10e573SMarc-André Lureau     } else if (strncmp((char *)tablet->query, "ST", 2) == 0 &&
2606b10e573SMarc-André Lureau                clen == 2) {
2616b10e573SMarc-André Lureau         trace_wct_cmd_st();
2626b10e573SMarc-André Lureau         wctablet_shift_input(tablet, 3);
2636b10e573SMarc-André Lureau         tablet->send_events = true;
2646b10e573SMarc-André Lureau         wctablet_queue_event(tablet);
2656b10e573SMarc-André Lureau 
2666b10e573SMarc-André Lureau     } else if (strncmp((char *)tablet->query, "SP", 2) == 0 &&
2676b10e573SMarc-André Lureau                clen == 2) {
2686b10e573SMarc-André Lureau         trace_wct_cmd_sp();
2696b10e573SMarc-André Lureau         wctablet_shift_input(tablet, 3);
2706b10e573SMarc-André Lureau         tablet->send_events = false;
2716b10e573SMarc-André Lureau 
2726b10e573SMarc-André Lureau     } else if (strncmp((char *)tablet->query, "TS", 2) == 0 &&
2736b10e573SMarc-André Lureau                clen == 3) {
2746b10e573SMarc-André Lureau         unsigned int input = tablet->query[2];
2756b10e573SMarc-André Lureau         uint8_t codes[7] = {
2766b10e573SMarc-André Lureau             0xa3,
2776b10e573SMarc-André Lureau             ((input & 0x80) == 0) ? 0x7e : 0x7f,
2786b10e573SMarc-André Lureau             (((WC_H4(input) & 0x7) ^ 0x5) << 4) | (WC_L4(input) ^ 0x7),
2796b10e573SMarc-André Lureau             0x03,
2806b10e573SMarc-André Lureau             0x7f,
2816b10e573SMarc-André Lureau             0x7f,
2826b10e573SMarc-André Lureau             0x00,
2836b10e573SMarc-André Lureau         };
2846b10e573SMarc-André Lureau         trace_wct_cmd_ts(input);
2856b10e573SMarc-André Lureau         wctablet_shift_input(tablet, 4);
2866b10e573SMarc-André Lureau         wctablet_queue_output(tablet, codes, 7);
2876b10e573SMarc-André Lureau 
2886b10e573SMarc-André Lureau     } else {
2896b10e573SMarc-André Lureau         tablet->query[clen] = 0; /* terminate line for printing */
2906b10e573SMarc-André Lureau         trace_wct_cmd_other((char *)tablet->query);
2916b10e573SMarc-André Lureau         wctablet_shift_input(tablet, clen + 1);
2926b10e573SMarc-André Lureau 
2936b10e573SMarc-André Lureau     }
2946b10e573SMarc-André Lureau 
2956b10e573SMarc-André Lureau     return len;
2966b10e573SMarc-André Lureau }
2976b10e573SMarc-André Lureau 
wctablet_chr_ioctl(Chardev * chr,int cmd,void * arg)2986b10e573SMarc-André Lureau static int wctablet_chr_ioctl(Chardev *chr, int cmd, void *arg)
2996b10e573SMarc-André Lureau {
3006b10e573SMarc-André Lureau     TabletChardev *tablet = WCTABLET_CHARDEV(chr);
3016b10e573SMarc-André Lureau     QEMUSerialSetParams *ssp;
3026b10e573SMarc-André Lureau 
3036b10e573SMarc-André Lureau     switch (cmd) {
3046b10e573SMarc-André Lureau     case CHR_IOCTL_SERIAL_SET_PARAMS:
3056b10e573SMarc-André Lureau         ssp = arg;
3066b10e573SMarc-André Lureau         if (tablet->line_speed != ssp->speed) {
3076b10e573SMarc-André Lureau             trace_wct_speed(ssp->speed);
3086b10e573SMarc-André Lureau             wctablet_reset(tablet);
3096b10e573SMarc-André Lureau             tablet->line_speed = ssp->speed;
3106b10e573SMarc-André Lureau         }
3116b10e573SMarc-André Lureau         break;
3126b10e573SMarc-André Lureau     default:
3136b10e573SMarc-André Lureau         return -ENOTSUP;
3146b10e573SMarc-André Lureau     }
3156b10e573SMarc-André Lureau     return 0;
3166b10e573SMarc-André Lureau }
3176b10e573SMarc-André Lureau 
wctablet_chr_finalize(Object * obj)3186b10e573SMarc-André Lureau static void wctablet_chr_finalize(Object *obj)
3196b10e573SMarc-André Lureau {
3206b10e573SMarc-André Lureau     TabletChardev *tablet = WCTABLET_CHARDEV(obj);
3216b10e573SMarc-André Lureau 
322fc0c1285SMaksim Davydov     if (tablet->hs) {
3236b10e573SMarc-André Lureau         qemu_input_handler_unregister(tablet->hs);
3246b10e573SMarc-André Lureau     }
325fc0c1285SMaksim Davydov }
3266b10e573SMarc-André Lureau 
wctablet_chr_open(Chardev * chr,ChardevBackend * backend,bool * be_opened,Error ** errp)3276b10e573SMarc-André Lureau static void wctablet_chr_open(Chardev *chr,
3286b10e573SMarc-André Lureau                               ChardevBackend *backend,
3296b10e573SMarc-André Lureau                               bool *be_opened,
3306b10e573SMarc-André Lureau                               Error **errp)
3316b10e573SMarc-André Lureau {
3326b10e573SMarc-André Lureau     TabletChardev *tablet = WCTABLET_CHARDEV(chr);
3336b10e573SMarc-André Lureau 
3346b10e573SMarc-André Lureau     *be_opened = true;
3356b10e573SMarc-André Lureau 
3366b10e573SMarc-André Lureau     /* init state machine */
3376b10e573SMarc-André Lureau     memcpy(tablet->outbuf, WC_FULL_CONFIG_STRING, WC_FULL_CONFIG_STRING_LENGTH);
3386b10e573SMarc-André Lureau     tablet->outlen = WC_FULL_CONFIG_STRING_LENGTH;
3396b10e573SMarc-André Lureau     tablet->query_index = 0;
3406b10e573SMarc-André Lureau 
3416b10e573SMarc-André Lureau     tablet->hs = qemu_input_handler_register((DeviceState *)tablet,
3426b10e573SMarc-André Lureau                                              &wctablet_handler);
3436b10e573SMarc-André Lureau }
3446b10e573SMarc-André Lureau 
wctablet_chr_class_init(ObjectClass * oc,void * data)3456b10e573SMarc-André Lureau static void wctablet_chr_class_init(ObjectClass *oc, void *data)
3466b10e573SMarc-André Lureau {
3476b10e573SMarc-André Lureau     ChardevClass *cc = CHARDEV_CLASS(oc);
3486b10e573SMarc-André Lureau 
3496b10e573SMarc-André Lureau     cc->open = wctablet_chr_open;
3506b10e573SMarc-André Lureau     cc->chr_write = wctablet_chr_write;
3516b10e573SMarc-André Lureau     cc->chr_ioctl = wctablet_chr_ioctl;
3526b10e573SMarc-André Lureau     cc->chr_accept_input = wctablet_chr_accept_input;
3536b10e573SMarc-André Lureau }
3546b10e573SMarc-André Lureau 
3556b10e573SMarc-André Lureau static const TypeInfo wctablet_type_info = {
3566b10e573SMarc-André Lureau     .name = TYPE_CHARDEV_WCTABLET,
3576b10e573SMarc-André Lureau     .parent = TYPE_CHARDEV,
3586b10e573SMarc-André Lureau     .instance_size = sizeof(TabletChardev),
3596b10e573SMarc-André Lureau     .instance_finalize = wctablet_chr_finalize,
3606b10e573SMarc-André Lureau     .class_init = wctablet_chr_class_init,
3616b10e573SMarc-André Lureau };
3626b10e573SMarc-André Lureau 
register_types(void)3636b10e573SMarc-André Lureau static void register_types(void)
3646b10e573SMarc-André Lureau {
3656b10e573SMarc-André Lureau      type_register_static(&wctablet_type_info);
3666b10e573SMarc-André Lureau }
3676b10e573SMarc-André Lureau 
3686b10e573SMarc-André Lureau type_init(register_types);
369