xref: /qemu/chardev/wctablet.c (revision db1015e92e04835c9eb50c29625fe566d1202dbd)
1378af961SAnatoli Huseu1 /*
2378af961SAnatoli Huseu1  * QEMU Wacom Penpartner serial tablet emulation
3378af961SAnatoli Huseu1  *
4378af961SAnatoli Huseu1  * some protocol details:
5378af961SAnatoli Huseu1  *   http://linuxwacom.sourceforge.net/wiki/index.php/Serial_Protocol_IV
6378af961SAnatoli Huseu1  *
7378af961SAnatoli Huseu1  * Copyright (c) 2016 Anatoli Huseu1
8378af961SAnatoli Huseu1  * Copyright (c) 2016,17 Gerd Hoffmann
9378af961SAnatoli Huseu1  *
10378af961SAnatoli Huseu1  * Permission is hereby granted, free of charge, to any person obtaining a copy
11378af961SAnatoli Huseu1  * of this software and associated documentation files (the "Software"), to
12378af961SAnatoli Huseu1  * deal in the Software without restriction, including without limitation
13378af961SAnatoli Huseu1  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
14378af961SAnatoli Huseu1  * and/or sell copies of the Software, and to permit persons to whom the
15378af961SAnatoli Huseu1  * Software is furnished to do so, subject to the following conditions:
16378af961SAnatoli Huseu1  *
17378af961SAnatoli Huseu1  * The above copyright notice and this permission notice shall be included in
18378af961SAnatoli Huseu1  * all copies or substantial portions of the Software.
19378af961SAnatoli Huseu1  *
20378af961SAnatoli Huseu1  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
21378af961SAnatoli Huseu1  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
22378af961SAnatoli Huseu1  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
23378af961SAnatoli Huseu1  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
24378af961SAnatoli Huseu1  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM
25378af961SAnatoli Huseu1  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
26378af961SAnatoli Huseu1  * THE SOFTWARE.
27378af961SAnatoli Huseu1  */
28378af961SAnatoli Huseu1 
29378af961SAnatoli Huseu1 #include "qemu/osdep.h"
300b8fa32fSMarkus Armbruster #include "qemu/module.h"
317566c6efSMarc-André Lureau #include "chardev/char-serial.h"
32378af961SAnatoli Huseu1 #include "ui/console.h"
33378af961SAnatoli Huseu1 #include "ui/input.h"
34378af961SAnatoli Huseu1 #include "trace.h"
35*db1015e9SEduardo Habkost #include "qom/object.h"
36378af961SAnatoli Huseu1 
37378af961SAnatoli Huseu1 
38378af961SAnatoli Huseu1 #define WC_OUTPUT_BUF_MAX_LEN 512
39378af961SAnatoli Huseu1 #define WC_COMMAND_MAX_LEN 60
40378af961SAnatoli Huseu1 
41378af961SAnatoli Huseu1 #define WC_L7(n) ((n) & 127)
42378af961SAnatoli Huseu1 #define WC_M7(n) (((n) >> 7) & 127)
43378af961SAnatoli Huseu1 #define WC_H2(n) ((n) >> 14)
44378af961SAnatoli Huseu1 
45378af961SAnatoli Huseu1 #define WC_L4(n) ((n) & 15)
46378af961SAnatoli Huseu1 #define WC_H4(n) (((n) >> 4) & 15)
47378af961SAnatoli Huseu1 
48378af961SAnatoli Huseu1 /* Model string and config string */
49378af961SAnatoli Huseu1 #define WC_MODEL_STRING_LENGTH 18
50378af961SAnatoli Huseu1 uint8_t WC_MODEL_STRING[WC_MODEL_STRING_LENGTH + 1] = "~#CT-0045R,V1.3-5,";
51378af961SAnatoli Huseu1 
52378af961SAnatoli Huseu1 #define WC_CONFIG_STRING_LENGTH 8
53378af961SAnatoli Huseu1 uint8_t WC_CONFIG_STRING[WC_CONFIG_STRING_LENGTH + 1] = "96,N,8,0";
54378af961SAnatoli Huseu1 
55378af961SAnatoli Huseu1 #define WC_FULL_CONFIG_STRING_LENGTH 61
56378af961SAnatoli Huseu1 uint8_t WC_FULL_CONFIG_STRING[WC_FULL_CONFIG_STRING_LENGTH + 1] = {
57378af961SAnatoli Huseu1     0x5c, 0x39, 0x36, 0x2c, 0x4e, 0x2c, 0x38, 0x2c,
58378af961SAnatoli Huseu1     0x31, 0x28, 0x01, 0x24, 0x57, 0x41, 0x43, 0x30,
59378af961SAnatoli Huseu1     0x30, 0x34, 0x35, 0x5c, 0x5c, 0x50, 0x45, 0x4e, 0x5c,
60378af961SAnatoli Huseu1     0x57, 0x41, 0x43, 0x30, 0x30, 0x30, 0x30, 0x5c,
61378af961SAnatoli Huseu1     0x54, 0x61, 0x62, 0x6c, 0x65, 0x74, 0x0d, 0x0a,
62378af961SAnatoli Huseu1     0x43, 0x54, 0x2d, 0x30, 0x30, 0x34, 0x35, 0x52,
63378af961SAnatoli Huseu1     0x2c, 0x56, 0x31, 0x2e, 0x33, 0x2d, 0x35, 0x0d,
64378af961SAnatoli Huseu1     0x0a, 0x45, 0x37, 0x29
65378af961SAnatoli Huseu1 };
66378af961SAnatoli Huseu1 
67378af961SAnatoli Huseu1 /* This structure is used to save private info for Wacom Tablet. */
68*db1015e9SEduardo Habkost struct TabletChardev {
69378af961SAnatoli Huseu1     Chardev parent;
70378af961SAnatoli Huseu1     QemuInputHandlerState *hs;
71378af961SAnatoli Huseu1 
72378af961SAnatoli Huseu1     /* Query string from serial */
73378af961SAnatoli Huseu1     uint8_t query[100];
74378af961SAnatoli Huseu1     int query_index;
75378af961SAnatoli Huseu1 
76378af961SAnatoli Huseu1     /* Command to be sent to serial port */
77378af961SAnatoli Huseu1     uint8_t outbuf[WC_OUTPUT_BUF_MAX_LEN];
78378af961SAnatoli Huseu1     int outlen;
79378af961SAnatoli Huseu1 
80378af961SAnatoli Huseu1     int line_speed;
81378af961SAnatoli Huseu1     bool send_events;
82378af961SAnatoli Huseu1     int axis[INPUT_AXIS__MAX];
83378af961SAnatoli Huseu1     bool btns[INPUT_BUTTON__MAX];
84378af961SAnatoli Huseu1 
85*db1015e9SEduardo Habkost };
86*db1015e9SEduardo Habkost typedef struct TabletChardev TabletChardev;
87378af961SAnatoli Huseu1 
88378af961SAnatoli Huseu1 #define TYPE_CHARDEV_WCTABLET "chardev-wctablet"
89378af961SAnatoli Huseu1 #define WCTABLET_CHARDEV(obj)                                      \
90378af961SAnatoli Huseu1     OBJECT_CHECK(TabletChardev, (obj), TYPE_CHARDEV_WCTABLET)
91378af961SAnatoli Huseu1 
92378af961SAnatoli Huseu1 
93378af961SAnatoli Huseu1 static void wctablet_chr_accept_input(Chardev *chr);
94378af961SAnatoli Huseu1 
95378af961SAnatoli Huseu1 static void wctablet_shift_input(TabletChardev *tablet, int count)
96378af961SAnatoli Huseu1 {
97378af961SAnatoli Huseu1     tablet->query_index -= count;
98378af961SAnatoli Huseu1     memmove(tablet->query, tablet->query + count, tablet->query_index);
99378af961SAnatoli Huseu1     tablet->query[tablet->query_index] = 0;
100378af961SAnatoli Huseu1 }
101378af961SAnatoli Huseu1 
102378af961SAnatoli Huseu1 static void wctablet_queue_output(TabletChardev *tablet, uint8_t *buf, int count)
103378af961SAnatoli Huseu1 {
104378af961SAnatoli Huseu1     if (tablet->outlen + count > sizeof(tablet->outbuf)) {
105378af961SAnatoli Huseu1         return;
106378af961SAnatoli Huseu1     }
107378af961SAnatoli Huseu1 
108378af961SAnatoli Huseu1     memcpy(tablet->outbuf + tablet->outlen, buf, count);
109378af961SAnatoli Huseu1     tablet->outlen += count;
110378af961SAnatoli Huseu1     wctablet_chr_accept_input(CHARDEV(tablet));
111378af961SAnatoli Huseu1 }
112378af961SAnatoli Huseu1 
113378af961SAnatoli Huseu1 static void wctablet_reset(TabletChardev *tablet)
114378af961SAnatoli Huseu1 {
115378af961SAnatoli Huseu1     /* clear buffers */
116378af961SAnatoli Huseu1     tablet->query_index = 0;
117378af961SAnatoli Huseu1     tablet->outlen = 0;
118378af961SAnatoli Huseu1     /* reset state */
119378af961SAnatoli Huseu1     tablet->send_events = false;
120378af961SAnatoli Huseu1 }
121378af961SAnatoli Huseu1 
122378af961SAnatoli Huseu1 static void wctablet_queue_event(TabletChardev *tablet)
123378af961SAnatoli Huseu1 {
124378af961SAnatoli Huseu1     uint8_t codes[8] = { 0xe0, 0, 0, 0, 0, 0, 0 };
125378af961SAnatoli Huseu1 
126378af961SAnatoli Huseu1     if (tablet->line_speed != 9600) {
127378af961SAnatoli Huseu1         return;
128378af961SAnatoli Huseu1     }
129378af961SAnatoli Huseu1 
130378af961SAnatoli Huseu1     int newX = tablet->axis[INPUT_AXIS_X] * 0.1537;
131378af961SAnatoli Huseu1     int nexY = tablet->axis[INPUT_AXIS_Y] * 0.1152;
132378af961SAnatoli Huseu1 
133378af961SAnatoli Huseu1     codes[0] = codes[0] | WC_H2(newX);
134378af961SAnatoli Huseu1     codes[1] = codes[1] | WC_M7(newX);
135378af961SAnatoli Huseu1     codes[2] = codes[2] | WC_L7(newX);
136378af961SAnatoli Huseu1 
137378af961SAnatoli Huseu1     codes[3] = codes[3] | WC_H2(nexY);
138378af961SAnatoli Huseu1     codes[4] = codes[4] | WC_M7(nexY);
139378af961SAnatoli Huseu1     codes[5] = codes[5] | WC_L7(nexY);
140378af961SAnatoli Huseu1 
141378af961SAnatoli Huseu1     if (tablet->btns[INPUT_BUTTON_LEFT]) {
142378af961SAnatoli Huseu1         codes[0] = 0xa0;
143378af961SAnatoli Huseu1     }
144378af961SAnatoli Huseu1 
145378af961SAnatoli Huseu1     wctablet_queue_output(tablet, codes, 7);
146378af961SAnatoli Huseu1 }
147378af961SAnatoli Huseu1 
148378af961SAnatoli Huseu1 static void wctablet_input_event(DeviceState *dev, QemuConsole *src,
149378af961SAnatoli Huseu1                                 InputEvent *evt)
150378af961SAnatoli Huseu1 {
151378af961SAnatoli Huseu1     TabletChardev *tablet = (TabletChardev *)dev;
152378af961SAnatoli Huseu1     InputMoveEvent *move;
153378af961SAnatoli Huseu1     InputBtnEvent *btn;
154378af961SAnatoli Huseu1 
155378af961SAnatoli Huseu1     switch (evt->type) {
156378af961SAnatoli Huseu1     case INPUT_EVENT_KIND_ABS:
157378af961SAnatoli Huseu1         move = evt->u.abs.data;
158378af961SAnatoli Huseu1         tablet->axis[move->axis] = move->value;
159378af961SAnatoli Huseu1         break;
160378af961SAnatoli Huseu1 
161378af961SAnatoli Huseu1     case INPUT_EVENT_KIND_BTN:
162378af961SAnatoli Huseu1         btn = evt->u.btn.data;
163378af961SAnatoli Huseu1         tablet->btns[btn->button] = btn->down;
164378af961SAnatoli Huseu1         break;
165378af961SAnatoli Huseu1 
166378af961SAnatoli Huseu1     default:
167378af961SAnatoli Huseu1         /* keep gcc happy */
168378af961SAnatoli Huseu1         break;
169378af961SAnatoli Huseu1     }
170378af961SAnatoli Huseu1 }
171378af961SAnatoli Huseu1 
172378af961SAnatoli Huseu1 static void wctablet_input_sync(DeviceState *dev)
173378af961SAnatoli Huseu1 {
174378af961SAnatoli Huseu1     TabletChardev *tablet = (TabletChardev *)dev;
175378af961SAnatoli Huseu1 
176378af961SAnatoli Huseu1     if (tablet->send_events) {
177378af961SAnatoli Huseu1         wctablet_queue_event(tablet);
178378af961SAnatoli Huseu1     }
179378af961SAnatoli Huseu1 }
180378af961SAnatoli Huseu1 
181378af961SAnatoli Huseu1 static QemuInputHandler wctablet_handler = {
182129263c6SPhilippe Mathieu-Daudé     .name  = "QEMU Wacom Pen Tablet",
183378af961SAnatoli Huseu1     .mask  = INPUT_EVENT_MASK_BTN | INPUT_EVENT_MASK_ABS,
184378af961SAnatoli Huseu1     .event = wctablet_input_event,
185378af961SAnatoli Huseu1     .sync  = wctablet_input_sync,
186378af961SAnatoli Huseu1 };
187378af961SAnatoli Huseu1 
188378af961SAnatoli Huseu1 static void wctablet_chr_accept_input(Chardev *chr)
189378af961SAnatoli Huseu1 {
190378af961SAnatoli Huseu1     TabletChardev *tablet = WCTABLET_CHARDEV(chr);
191378af961SAnatoli Huseu1     int len, canWrite;
192378af961SAnatoli Huseu1 
193378af961SAnatoli Huseu1     canWrite = qemu_chr_be_can_write(chr);
194378af961SAnatoli Huseu1     len = canWrite;
195378af961SAnatoli Huseu1     if (len > tablet->outlen) {
196378af961SAnatoli Huseu1         len = tablet->outlen;
197378af961SAnatoli Huseu1     }
198378af961SAnatoli Huseu1 
199378af961SAnatoli Huseu1     if (len) {
200378af961SAnatoli Huseu1         qemu_chr_be_write(chr, tablet->outbuf, len);
201378af961SAnatoli Huseu1         tablet->outlen -= len;
202378af961SAnatoli Huseu1         if (tablet->outlen) {
203378af961SAnatoli Huseu1             memmove(tablet->outbuf, tablet->outbuf + len, tablet->outlen);
204378af961SAnatoli Huseu1         }
205378af961SAnatoli Huseu1     }
206378af961SAnatoli Huseu1 }
207378af961SAnatoli Huseu1 
208378af961SAnatoli Huseu1 static int wctablet_chr_write(struct Chardev *chr,
209378af961SAnatoli Huseu1                               const uint8_t *buf, int len)
210378af961SAnatoli Huseu1 {
211378af961SAnatoli Huseu1     TabletChardev *tablet = WCTABLET_CHARDEV(chr);
212378af961SAnatoli Huseu1     unsigned int i, clen;
213378af961SAnatoli Huseu1     char *pos;
214378af961SAnatoli Huseu1 
215378af961SAnatoli Huseu1     if (tablet->line_speed != 9600) {
216378af961SAnatoli Huseu1         return len;
217378af961SAnatoli Huseu1     }
218378af961SAnatoli Huseu1     for (i = 0; i < len && tablet->query_index < sizeof(tablet->query) - 1; i++) {
219378af961SAnatoli Huseu1         tablet->query[tablet->query_index++] = buf[i];
220378af961SAnatoli Huseu1     }
221378af961SAnatoli Huseu1     tablet->query[tablet->query_index] = 0;
222378af961SAnatoli Huseu1 
223378af961SAnatoli Huseu1     while (tablet->query_index > 0 && (tablet->query[0] == '@'  ||
224378af961SAnatoli Huseu1                                        tablet->query[0] == '\r' ||
225378af961SAnatoli Huseu1                                        tablet->query[0] == '\n')) {
226378af961SAnatoli Huseu1         wctablet_shift_input(tablet, 1);
227378af961SAnatoli Huseu1     }
228378af961SAnatoli Huseu1     if (!tablet->query_index) {
229378af961SAnatoli Huseu1         return len;
230378af961SAnatoli Huseu1     }
231378af961SAnatoli Huseu1 
232378af961SAnatoli Huseu1     if (strncmp((char *)tablet->query, "~#", 2) == 0) {
233378af961SAnatoli Huseu1         /* init / detect sequence */
234378af961SAnatoli Huseu1         trace_wct_init();
235378af961SAnatoli Huseu1         wctablet_shift_input(tablet, 2);
236378af961SAnatoli Huseu1         wctablet_queue_output(tablet, WC_MODEL_STRING,
237378af961SAnatoli Huseu1                               WC_MODEL_STRING_LENGTH);
238378af961SAnatoli Huseu1         return len;
239378af961SAnatoli Huseu1     }
240378af961SAnatoli Huseu1 
241378af961SAnatoli Huseu1     /* detect line */
242378af961SAnatoli Huseu1     pos = strchr((char *)tablet->query, '\r');
243378af961SAnatoli Huseu1     if (!pos) {
244378af961SAnatoli Huseu1         pos = strchr((char *)tablet->query, '\n');
245378af961SAnatoli Huseu1     }
246378af961SAnatoli Huseu1     if (!pos) {
247378af961SAnatoli Huseu1         return len;
248378af961SAnatoli Huseu1     }
249378af961SAnatoli Huseu1     clen = pos - (char *)tablet->query;
250378af961SAnatoli Huseu1 
251378af961SAnatoli Huseu1     /* process commands */
252378af961SAnatoli Huseu1     if (strncmp((char *)tablet->query, "RE", 2) == 0 &&
253378af961SAnatoli Huseu1         clen == 2) {
254378af961SAnatoli Huseu1         trace_wct_cmd_re();
255378af961SAnatoli Huseu1         wctablet_shift_input(tablet, 3);
256378af961SAnatoli Huseu1         wctablet_queue_output(tablet, WC_CONFIG_STRING,
257378af961SAnatoli Huseu1                               WC_CONFIG_STRING_LENGTH);
258378af961SAnatoli Huseu1 
259378af961SAnatoli Huseu1     } else if (strncmp((char *)tablet->query, "ST", 2) == 0 &&
260378af961SAnatoli Huseu1                clen == 2) {
261378af961SAnatoli Huseu1         trace_wct_cmd_st();
262378af961SAnatoli Huseu1         wctablet_shift_input(tablet, 3);
263378af961SAnatoli Huseu1         tablet->send_events = true;
264378af961SAnatoli Huseu1         wctablet_queue_event(tablet);
265378af961SAnatoli Huseu1 
266378af961SAnatoli Huseu1     } else if (strncmp((char *)tablet->query, "SP", 2) == 0 &&
267378af961SAnatoli Huseu1                clen == 2) {
268378af961SAnatoli Huseu1         trace_wct_cmd_sp();
269378af961SAnatoli Huseu1         wctablet_shift_input(tablet, 3);
270378af961SAnatoli Huseu1         tablet->send_events = false;
271378af961SAnatoli Huseu1 
272378af961SAnatoli Huseu1     } else if (strncmp((char *)tablet->query, "TS", 2) == 0 &&
273378af961SAnatoli Huseu1                clen == 3) {
274378af961SAnatoli Huseu1         unsigned int input = tablet->query[2];
275378af961SAnatoli Huseu1         uint8_t codes[7] = {
276378af961SAnatoli Huseu1             0xa3,
277378af961SAnatoli Huseu1             ((input & 0x80) == 0) ? 0x7e : 0x7f,
278378af961SAnatoli Huseu1             (((WC_H4(input) & 0x7) ^ 0x5) << 4) | (WC_L4(input) ^ 0x7),
279378af961SAnatoli Huseu1             0x03,
280378af961SAnatoli Huseu1             0x7f,
281378af961SAnatoli Huseu1             0x7f,
282378af961SAnatoli Huseu1             0x00,
283378af961SAnatoli Huseu1         };
284378af961SAnatoli Huseu1         trace_wct_cmd_ts(input);
285378af961SAnatoli Huseu1         wctablet_shift_input(tablet, 4);
286378af961SAnatoli Huseu1         wctablet_queue_output(tablet, codes, 7);
287378af961SAnatoli Huseu1 
288378af961SAnatoli Huseu1     } else {
289378af961SAnatoli Huseu1         tablet->query[clen] = 0; /* terminate line for printing */
290378af961SAnatoli Huseu1         trace_wct_cmd_other((char *)tablet->query);
291378af961SAnatoli Huseu1         wctablet_shift_input(tablet, clen + 1);
292378af961SAnatoli Huseu1 
293378af961SAnatoli Huseu1     }
294378af961SAnatoli Huseu1 
295378af961SAnatoli Huseu1     return len;
296378af961SAnatoli Huseu1 }
297378af961SAnatoli Huseu1 
298378af961SAnatoli Huseu1 static int wctablet_chr_ioctl(Chardev *chr, int cmd, void *arg)
299378af961SAnatoli Huseu1 {
300378af961SAnatoli Huseu1     TabletChardev *tablet = WCTABLET_CHARDEV(chr);
301378af961SAnatoli Huseu1     QEMUSerialSetParams *ssp;
302378af961SAnatoli Huseu1 
303378af961SAnatoli Huseu1     switch (cmd) {
304378af961SAnatoli Huseu1     case CHR_IOCTL_SERIAL_SET_PARAMS:
305378af961SAnatoli Huseu1         ssp = arg;
306378af961SAnatoli Huseu1         if (tablet->line_speed != ssp->speed) {
307378af961SAnatoli Huseu1             trace_wct_speed(ssp->speed);
308378af961SAnatoli Huseu1             wctablet_reset(tablet);
309378af961SAnatoli Huseu1             tablet->line_speed = ssp->speed;
310378af961SAnatoli Huseu1         }
311378af961SAnatoli Huseu1         break;
312378af961SAnatoli Huseu1     default:
313378af961SAnatoli Huseu1         return -ENOTSUP;
314378af961SAnatoli Huseu1     }
315378af961SAnatoli Huseu1     return 0;
316378af961SAnatoli Huseu1 }
317378af961SAnatoli Huseu1 
318378af961SAnatoli Huseu1 static void wctablet_chr_finalize(Object *obj)
319378af961SAnatoli Huseu1 {
320378af961SAnatoli Huseu1     TabletChardev *tablet = WCTABLET_CHARDEV(obj);
321378af961SAnatoli Huseu1 
322378af961SAnatoli Huseu1     qemu_input_handler_unregister(tablet->hs);
323378af961SAnatoli Huseu1     g_free(tablet);
324378af961SAnatoli Huseu1 }
325378af961SAnatoli Huseu1 
326378af961SAnatoli Huseu1 static void wctablet_chr_open(Chardev *chr,
327378af961SAnatoli Huseu1                               ChardevBackend *backend,
328378af961SAnatoli Huseu1                               bool *be_opened,
329378af961SAnatoli Huseu1                               Error **errp)
330378af961SAnatoli Huseu1 {
331378af961SAnatoli Huseu1     TabletChardev *tablet = WCTABLET_CHARDEV(chr);
332378af961SAnatoli Huseu1 
333378af961SAnatoli Huseu1     *be_opened = true;
334378af961SAnatoli Huseu1 
335378af961SAnatoli Huseu1     /* init state machine */
336378af961SAnatoli Huseu1     memcpy(tablet->outbuf, WC_FULL_CONFIG_STRING, WC_FULL_CONFIG_STRING_LENGTH);
337378af961SAnatoli Huseu1     tablet->outlen = WC_FULL_CONFIG_STRING_LENGTH;
338378af961SAnatoli Huseu1     tablet->query_index = 0;
339378af961SAnatoli Huseu1 
340378af961SAnatoli Huseu1     tablet->hs = qemu_input_handler_register((DeviceState *)tablet,
341378af961SAnatoli Huseu1                                              &wctablet_handler);
342378af961SAnatoli Huseu1 }
343378af961SAnatoli Huseu1 
344378af961SAnatoli Huseu1 static void wctablet_chr_class_init(ObjectClass *oc, void *data)
345378af961SAnatoli Huseu1 {
346378af961SAnatoli Huseu1     ChardevClass *cc = CHARDEV_CLASS(oc);
347378af961SAnatoli Huseu1 
348378af961SAnatoli Huseu1     cc->open = wctablet_chr_open;
349378af961SAnatoli Huseu1     cc->chr_write = wctablet_chr_write;
350378af961SAnatoli Huseu1     cc->chr_ioctl = wctablet_chr_ioctl;
351378af961SAnatoli Huseu1     cc->chr_accept_input = wctablet_chr_accept_input;
352378af961SAnatoli Huseu1 }
353378af961SAnatoli Huseu1 
354378af961SAnatoli Huseu1 static const TypeInfo wctablet_type_info = {
355378af961SAnatoli Huseu1     .name = TYPE_CHARDEV_WCTABLET,
356378af961SAnatoli Huseu1     .parent = TYPE_CHARDEV,
357378af961SAnatoli Huseu1     .instance_size = sizeof(TabletChardev),
358378af961SAnatoli Huseu1     .instance_finalize = wctablet_chr_finalize,
359378af961SAnatoli Huseu1     .class_init = wctablet_chr_class_init,
360378af961SAnatoli Huseu1 };
361378af961SAnatoli Huseu1 
362378af961SAnatoli Huseu1 static void register_types(void)
363378af961SAnatoli Huseu1 {
364378af961SAnatoli Huseu1      type_register_static(&wctablet_type_info);
365378af961SAnatoli Huseu1 }
366378af961SAnatoli Huseu1 
367378af961SAnatoli Huseu1 type_init(register_types);
368