xref: /qemu/chardev/wctablet.c (revision 7566c6efe75572c63a8841fc09d0a8935b188c2f)
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 #include <stdlib.h>
29378af961SAnatoli Huseu1 #include <string.h>
30378af961SAnatoli Huseu1 #include <sys/time.h>
31378af961SAnatoli Huseu1 #include <time.h>
32378af961SAnatoli Huseu1 
33378af961SAnatoli Huseu1 #include "qemu/osdep.h"
34378af961SAnatoli Huseu1 #include "qemu-common.h"
35*7566c6efSMarc-André Lureau #include "chardev/char-serial.h"
36378af961SAnatoli Huseu1 #include "ui/console.h"
37378af961SAnatoli Huseu1 #include "ui/input.h"
38378af961SAnatoli Huseu1 #include "trace.h"
39378af961SAnatoli Huseu1 
40378af961SAnatoli Huseu1 
41378af961SAnatoli Huseu1 #define WC_OUTPUT_BUF_MAX_LEN 512
42378af961SAnatoli Huseu1 #define WC_COMMAND_MAX_LEN 60
43378af961SAnatoli Huseu1 
44378af961SAnatoli Huseu1 #define WC_L7(n) ((n) & 127)
45378af961SAnatoli Huseu1 #define WC_M7(n) (((n) >> 7) & 127)
46378af961SAnatoli Huseu1 #define WC_H2(n) ((n) >> 14)
47378af961SAnatoli Huseu1 
48378af961SAnatoli Huseu1 #define WC_L4(n) ((n) & 15)
49378af961SAnatoli Huseu1 #define WC_H4(n) (((n) >> 4) & 15)
50378af961SAnatoli Huseu1 
51378af961SAnatoli Huseu1 /* Model string and config string */
52378af961SAnatoli Huseu1 #define WC_MODEL_STRING_LENGTH 18
53378af961SAnatoli Huseu1 uint8_t WC_MODEL_STRING[WC_MODEL_STRING_LENGTH + 1] = "~#CT-0045R,V1.3-5,";
54378af961SAnatoli Huseu1 
55378af961SAnatoli Huseu1 #define WC_CONFIG_STRING_LENGTH 8
56378af961SAnatoli Huseu1 uint8_t WC_CONFIG_STRING[WC_CONFIG_STRING_LENGTH + 1] = "96,N,8,0";
57378af961SAnatoli Huseu1 
58378af961SAnatoli Huseu1 #define WC_FULL_CONFIG_STRING_LENGTH 61
59378af961SAnatoli Huseu1 uint8_t WC_FULL_CONFIG_STRING[WC_FULL_CONFIG_STRING_LENGTH + 1] = {
60378af961SAnatoli Huseu1     0x5c, 0x39, 0x36, 0x2c, 0x4e, 0x2c, 0x38, 0x2c,
61378af961SAnatoli Huseu1     0x31, 0x28, 0x01, 0x24, 0x57, 0x41, 0x43, 0x30,
62378af961SAnatoli Huseu1     0x30, 0x34, 0x35, 0x5c, 0x5c, 0x50, 0x45, 0x4e, 0x5c,
63378af961SAnatoli Huseu1     0x57, 0x41, 0x43, 0x30, 0x30, 0x30, 0x30, 0x5c,
64378af961SAnatoli Huseu1     0x54, 0x61, 0x62, 0x6c, 0x65, 0x74, 0x0d, 0x0a,
65378af961SAnatoli Huseu1     0x43, 0x54, 0x2d, 0x30, 0x30, 0x34, 0x35, 0x52,
66378af961SAnatoli Huseu1     0x2c, 0x56, 0x31, 0x2e, 0x33, 0x2d, 0x35, 0x0d,
67378af961SAnatoli Huseu1     0x0a, 0x45, 0x37, 0x29
68378af961SAnatoli Huseu1 };
69378af961SAnatoli Huseu1 
70378af961SAnatoli Huseu1 /* This structure is used to save private info for Wacom Tablet. */
71378af961SAnatoli Huseu1 typedef struct {
72378af961SAnatoli Huseu1     Chardev parent;
73378af961SAnatoli Huseu1     QemuInputHandlerState *hs;
74378af961SAnatoli Huseu1 
75378af961SAnatoli Huseu1     /* Query string from serial */
76378af961SAnatoli Huseu1     uint8_t query[100];
77378af961SAnatoli Huseu1     int query_index;
78378af961SAnatoli Huseu1 
79378af961SAnatoli Huseu1     /* Command to be sent to serial port */
80378af961SAnatoli Huseu1     uint8_t outbuf[WC_OUTPUT_BUF_MAX_LEN];
81378af961SAnatoli Huseu1     int outlen;
82378af961SAnatoli Huseu1 
83378af961SAnatoli Huseu1     int line_speed;
84378af961SAnatoli Huseu1     bool send_events;
85378af961SAnatoli Huseu1     int axis[INPUT_AXIS__MAX];
86378af961SAnatoli Huseu1     bool btns[INPUT_BUTTON__MAX];
87378af961SAnatoli Huseu1 
88378af961SAnatoli Huseu1 } TabletChardev;
89378af961SAnatoli Huseu1 
90378af961SAnatoli Huseu1 #define TYPE_CHARDEV_WCTABLET "chardev-wctablet"
91378af961SAnatoli Huseu1 #define WCTABLET_CHARDEV(obj)                                      \
92378af961SAnatoli Huseu1     OBJECT_CHECK(TabletChardev, (obj), TYPE_CHARDEV_WCTABLET)
93378af961SAnatoli Huseu1 
94378af961SAnatoli Huseu1 
95378af961SAnatoli Huseu1 static void wctablet_chr_accept_input(Chardev *chr);
96378af961SAnatoli Huseu1 
97378af961SAnatoli Huseu1 static void wctablet_shift_input(TabletChardev *tablet, int count)
98378af961SAnatoli Huseu1 {
99378af961SAnatoli Huseu1     tablet->query_index -= count;
100378af961SAnatoli Huseu1     memmove(tablet->query, tablet->query + count, tablet->query_index);
101378af961SAnatoli Huseu1     tablet->query[tablet->query_index] = 0;
102378af961SAnatoli Huseu1 }
103378af961SAnatoli Huseu1 
104378af961SAnatoli Huseu1 static void wctablet_queue_output(TabletChardev *tablet, uint8_t *buf, int count)
105378af961SAnatoli Huseu1 {
106378af961SAnatoli Huseu1     if (tablet->outlen + count > sizeof(tablet->outbuf)) {
107378af961SAnatoli Huseu1         return;
108378af961SAnatoli Huseu1     }
109378af961SAnatoli Huseu1 
110378af961SAnatoli Huseu1     memcpy(tablet->outbuf + tablet->outlen, buf, count);
111378af961SAnatoli Huseu1     tablet->outlen += count;
112378af961SAnatoli Huseu1     wctablet_chr_accept_input(CHARDEV(tablet));
113378af961SAnatoli Huseu1 }
114378af961SAnatoli Huseu1 
115378af961SAnatoli Huseu1 static void wctablet_reset(TabletChardev *tablet)
116378af961SAnatoli Huseu1 {
117378af961SAnatoli Huseu1     /* clear buffers */
118378af961SAnatoli Huseu1     tablet->query_index = 0;
119378af961SAnatoli Huseu1     tablet->outlen = 0;
120378af961SAnatoli Huseu1     /* reset state */
121378af961SAnatoli Huseu1     tablet->send_events = false;
122378af961SAnatoli Huseu1 }
123378af961SAnatoli Huseu1 
124378af961SAnatoli Huseu1 static void wctablet_queue_event(TabletChardev *tablet)
125378af961SAnatoli Huseu1 {
126378af961SAnatoli Huseu1     uint8_t codes[8] = { 0xe0, 0, 0, 0, 0, 0, 0 };
127378af961SAnatoli Huseu1 
128378af961SAnatoli Huseu1     if (tablet->line_speed != 9600) {
129378af961SAnatoli Huseu1         return;
130378af961SAnatoli Huseu1     }
131378af961SAnatoli Huseu1 
132378af961SAnatoli Huseu1     int newX = tablet->axis[INPUT_AXIS_X] * 0.1537;
133378af961SAnatoli Huseu1     int nexY = tablet->axis[INPUT_AXIS_Y] * 0.1152;
134378af961SAnatoli Huseu1 
135378af961SAnatoli Huseu1     codes[0] = codes[0] | WC_H2(newX);
136378af961SAnatoli Huseu1     codes[1] = codes[1] | WC_M7(newX);
137378af961SAnatoli Huseu1     codes[2] = codes[2] | WC_L7(newX);
138378af961SAnatoli Huseu1 
139378af961SAnatoli Huseu1     codes[3] = codes[3] | WC_H2(nexY);
140378af961SAnatoli Huseu1     codes[4] = codes[4] | WC_M7(nexY);
141378af961SAnatoli Huseu1     codes[5] = codes[5] | WC_L7(nexY);
142378af961SAnatoli Huseu1 
143378af961SAnatoli Huseu1     if (tablet->btns[INPUT_BUTTON_LEFT]) {
144378af961SAnatoli Huseu1         codes[0] = 0xa0;
145378af961SAnatoli Huseu1     }
146378af961SAnatoli Huseu1 
147378af961SAnatoli Huseu1     wctablet_queue_output(tablet, codes, 7);
148378af961SAnatoli Huseu1 }
149378af961SAnatoli Huseu1 
150378af961SAnatoli Huseu1 static void wctablet_input_event(DeviceState *dev, QemuConsole *src,
151378af961SAnatoli Huseu1                                 InputEvent *evt)
152378af961SAnatoli Huseu1 {
153378af961SAnatoli Huseu1     TabletChardev *tablet = (TabletChardev *)dev;
154378af961SAnatoli Huseu1     InputMoveEvent *move;
155378af961SAnatoli Huseu1     InputBtnEvent *btn;
156378af961SAnatoli Huseu1 
157378af961SAnatoli Huseu1     switch (evt->type) {
158378af961SAnatoli Huseu1     case INPUT_EVENT_KIND_ABS:
159378af961SAnatoli Huseu1         move = evt->u.abs.data;
160378af961SAnatoli Huseu1         tablet->axis[move->axis] = move->value;
161378af961SAnatoli Huseu1         break;
162378af961SAnatoli Huseu1 
163378af961SAnatoli Huseu1     case INPUT_EVENT_KIND_BTN:
164378af961SAnatoli Huseu1         btn = evt->u.btn.data;
165378af961SAnatoli Huseu1         tablet->btns[btn->button] = btn->down;
166378af961SAnatoli Huseu1         break;
167378af961SAnatoli Huseu1 
168378af961SAnatoli Huseu1     default:
169378af961SAnatoli Huseu1         /* keep gcc happy */
170378af961SAnatoli Huseu1         break;
171378af961SAnatoli Huseu1     }
172378af961SAnatoli Huseu1 }
173378af961SAnatoli Huseu1 
174378af961SAnatoli Huseu1 static void wctablet_input_sync(DeviceState *dev)
175378af961SAnatoli Huseu1 {
176378af961SAnatoli Huseu1     TabletChardev *tablet = (TabletChardev *)dev;
177378af961SAnatoli Huseu1 
178378af961SAnatoli Huseu1     if (tablet->send_events) {
179378af961SAnatoli Huseu1         wctablet_queue_event(tablet);
180378af961SAnatoli Huseu1     }
181378af961SAnatoli Huseu1 }
182378af961SAnatoli Huseu1 
183378af961SAnatoli Huseu1 static QemuInputHandler wctablet_handler = {
184378af961SAnatoli Huseu1     .name  = "QEMU Wacome Pen Tablet",
185378af961SAnatoli Huseu1     .mask  = INPUT_EVENT_MASK_BTN | INPUT_EVENT_MASK_ABS,
186378af961SAnatoli Huseu1     .event = wctablet_input_event,
187378af961SAnatoli Huseu1     .sync  = wctablet_input_sync,
188378af961SAnatoli Huseu1 };
189378af961SAnatoli Huseu1 
190378af961SAnatoli Huseu1 static void wctablet_chr_accept_input(Chardev *chr)
191378af961SAnatoli Huseu1 {
192378af961SAnatoli Huseu1     TabletChardev *tablet = WCTABLET_CHARDEV(chr);
193378af961SAnatoli Huseu1     int len, canWrite;
194378af961SAnatoli Huseu1 
195378af961SAnatoli Huseu1     canWrite = qemu_chr_be_can_write(chr);
196378af961SAnatoli Huseu1     len = canWrite;
197378af961SAnatoli Huseu1     if (len > tablet->outlen) {
198378af961SAnatoli Huseu1         len = tablet->outlen;
199378af961SAnatoli Huseu1     }
200378af961SAnatoli Huseu1 
201378af961SAnatoli Huseu1     if (len) {
202378af961SAnatoli Huseu1         qemu_chr_be_write(chr, tablet->outbuf, len);
203378af961SAnatoli Huseu1         tablet->outlen -= len;
204378af961SAnatoli Huseu1         if (tablet->outlen) {
205378af961SAnatoli Huseu1             memmove(tablet->outbuf, tablet->outbuf + len, tablet->outlen);
206378af961SAnatoli Huseu1         }
207378af961SAnatoli Huseu1     }
208378af961SAnatoli Huseu1 }
209378af961SAnatoli Huseu1 
210378af961SAnatoli Huseu1 static int wctablet_chr_write(struct Chardev *chr,
211378af961SAnatoli Huseu1                               const uint8_t *buf, int len)
212378af961SAnatoli Huseu1 {
213378af961SAnatoli Huseu1     TabletChardev *tablet = WCTABLET_CHARDEV(chr);
214378af961SAnatoli Huseu1     unsigned int i, clen;
215378af961SAnatoli Huseu1     char *pos;
216378af961SAnatoli Huseu1 
217378af961SAnatoli Huseu1     if (tablet->line_speed != 9600) {
218378af961SAnatoli Huseu1         return len;
219378af961SAnatoli Huseu1     }
220378af961SAnatoli Huseu1     for (i = 0; i < len && tablet->query_index < sizeof(tablet->query) - 1; i++) {
221378af961SAnatoli Huseu1         tablet->query[tablet->query_index++] = buf[i];
222378af961SAnatoli Huseu1     }
223378af961SAnatoli Huseu1     tablet->query[tablet->query_index] = 0;
224378af961SAnatoli Huseu1 
225378af961SAnatoli Huseu1     while (tablet->query_index > 0 && (tablet->query[0] == '@'  ||
226378af961SAnatoli Huseu1                                        tablet->query[0] == '\r' ||
227378af961SAnatoli Huseu1                                        tablet->query[0] == '\n')) {
228378af961SAnatoli Huseu1         wctablet_shift_input(tablet, 1);
229378af961SAnatoli Huseu1     }
230378af961SAnatoli Huseu1     if (!tablet->query_index) {
231378af961SAnatoli Huseu1         return len;
232378af961SAnatoli Huseu1     }
233378af961SAnatoli Huseu1 
234378af961SAnatoli Huseu1     if (strncmp((char *)tablet->query, "~#", 2) == 0) {
235378af961SAnatoli Huseu1         /* init / detect sequence */
236378af961SAnatoli Huseu1         trace_wct_init();
237378af961SAnatoli Huseu1         wctablet_shift_input(tablet, 2);
238378af961SAnatoli Huseu1         wctablet_queue_output(tablet, WC_MODEL_STRING,
239378af961SAnatoli Huseu1                               WC_MODEL_STRING_LENGTH);
240378af961SAnatoli Huseu1         return len;
241378af961SAnatoli Huseu1     }
242378af961SAnatoli Huseu1 
243378af961SAnatoli Huseu1     /* detect line */
244378af961SAnatoli Huseu1     pos = strchr((char *)tablet->query, '\r');
245378af961SAnatoli Huseu1     if (!pos) {
246378af961SAnatoli Huseu1         pos = strchr((char *)tablet->query, '\n');
247378af961SAnatoli Huseu1     }
248378af961SAnatoli Huseu1     if (!pos) {
249378af961SAnatoli Huseu1         return len;
250378af961SAnatoli Huseu1     }
251378af961SAnatoli Huseu1     clen = pos - (char *)tablet->query;
252378af961SAnatoli Huseu1 
253378af961SAnatoli Huseu1     /* process commands */
254378af961SAnatoli Huseu1     if (strncmp((char *)tablet->query, "RE", 2) == 0 &&
255378af961SAnatoli Huseu1         clen == 2) {
256378af961SAnatoli Huseu1         trace_wct_cmd_re();
257378af961SAnatoli Huseu1         wctablet_shift_input(tablet, 3);
258378af961SAnatoli Huseu1         wctablet_queue_output(tablet, WC_CONFIG_STRING,
259378af961SAnatoli Huseu1                               WC_CONFIG_STRING_LENGTH);
260378af961SAnatoli Huseu1 
261378af961SAnatoli Huseu1     } else if (strncmp((char *)tablet->query, "ST", 2) == 0 &&
262378af961SAnatoli Huseu1                clen == 2) {
263378af961SAnatoli Huseu1         trace_wct_cmd_st();
264378af961SAnatoli Huseu1         wctablet_shift_input(tablet, 3);
265378af961SAnatoli Huseu1         tablet->send_events = true;
266378af961SAnatoli Huseu1         wctablet_queue_event(tablet);
267378af961SAnatoli Huseu1 
268378af961SAnatoli Huseu1     } else if (strncmp((char *)tablet->query, "SP", 2) == 0 &&
269378af961SAnatoli Huseu1                clen == 2) {
270378af961SAnatoli Huseu1         trace_wct_cmd_sp();
271378af961SAnatoli Huseu1         wctablet_shift_input(tablet, 3);
272378af961SAnatoli Huseu1         tablet->send_events = false;
273378af961SAnatoli Huseu1 
274378af961SAnatoli Huseu1     } else if (strncmp((char *)tablet->query, "TS", 2) == 0 &&
275378af961SAnatoli Huseu1                clen == 3) {
276378af961SAnatoli Huseu1         unsigned int input = tablet->query[2];
277378af961SAnatoli Huseu1         uint8_t codes[7] = {
278378af961SAnatoli Huseu1             0xa3,
279378af961SAnatoli Huseu1             ((input & 0x80) == 0) ? 0x7e : 0x7f,
280378af961SAnatoli Huseu1             (((WC_H4(input) & 0x7) ^ 0x5) << 4) | (WC_L4(input) ^ 0x7),
281378af961SAnatoli Huseu1             0x03,
282378af961SAnatoli Huseu1             0x7f,
283378af961SAnatoli Huseu1             0x7f,
284378af961SAnatoli Huseu1             0x00,
285378af961SAnatoli Huseu1         };
286378af961SAnatoli Huseu1         trace_wct_cmd_ts(input);
287378af961SAnatoli Huseu1         wctablet_shift_input(tablet, 4);
288378af961SAnatoli Huseu1         wctablet_queue_output(tablet, codes, 7);
289378af961SAnatoli Huseu1 
290378af961SAnatoli Huseu1     } else {
291378af961SAnatoli Huseu1         tablet->query[clen] = 0; /* terminate line for printing */
292378af961SAnatoli Huseu1         trace_wct_cmd_other((char *)tablet->query);
293378af961SAnatoli Huseu1         wctablet_shift_input(tablet, clen + 1);
294378af961SAnatoli Huseu1 
295378af961SAnatoli Huseu1     }
296378af961SAnatoli Huseu1 
297378af961SAnatoli Huseu1     return len;
298378af961SAnatoli Huseu1 }
299378af961SAnatoli Huseu1 
300378af961SAnatoli Huseu1 static int wctablet_chr_ioctl(Chardev *chr, int cmd, void *arg)
301378af961SAnatoli Huseu1 {
302378af961SAnatoli Huseu1     TabletChardev *tablet = WCTABLET_CHARDEV(chr);
303378af961SAnatoli Huseu1     QEMUSerialSetParams *ssp;
304378af961SAnatoli Huseu1 
305378af961SAnatoli Huseu1     switch (cmd) {
306378af961SAnatoli Huseu1     case CHR_IOCTL_SERIAL_SET_PARAMS:
307378af961SAnatoli Huseu1         ssp = arg;
308378af961SAnatoli Huseu1         if (tablet->line_speed != ssp->speed) {
309378af961SAnatoli Huseu1             trace_wct_speed(ssp->speed);
310378af961SAnatoli Huseu1             wctablet_reset(tablet);
311378af961SAnatoli Huseu1             tablet->line_speed = ssp->speed;
312378af961SAnatoli Huseu1         }
313378af961SAnatoli Huseu1         break;
314378af961SAnatoli Huseu1     default:
315378af961SAnatoli Huseu1         return -ENOTSUP;
316378af961SAnatoli Huseu1     }
317378af961SAnatoli Huseu1     return 0;
318378af961SAnatoli Huseu1 }
319378af961SAnatoli Huseu1 
320378af961SAnatoli Huseu1 static void wctablet_chr_finalize(Object *obj)
321378af961SAnatoli Huseu1 {
322378af961SAnatoli Huseu1     TabletChardev *tablet = WCTABLET_CHARDEV(obj);
323378af961SAnatoli Huseu1 
324378af961SAnatoli Huseu1     qemu_input_handler_unregister(tablet->hs);
325378af961SAnatoli Huseu1     g_free(tablet);
326378af961SAnatoli Huseu1 }
327378af961SAnatoli Huseu1 
328378af961SAnatoli Huseu1 static void wctablet_chr_open(Chardev *chr,
329378af961SAnatoli Huseu1                               ChardevBackend *backend,
330378af961SAnatoli Huseu1                               bool *be_opened,
331378af961SAnatoli Huseu1                               Error **errp)
332378af961SAnatoli Huseu1 {
333378af961SAnatoli Huseu1     TabletChardev *tablet = WCTABLET_CHARDEV(chr);
334378af961SAnatoli Huseu1 
335378af961SAnatoli Huseu1     *be_opened = true;
336378af961SAnatoli Huseu1 
337378af961SAnatoli Huseu1     /* init state machine */
338378af961SAnatoli Huseu1     memcpy(tablet->outbuf, WC_FULL_CONFIG_STRING, WC_FULL_CONFIG_STRING_LENGTH);
339378af961SAnatoli Huseu1     tablet->outlen = WC_FULL_CONFIG_STRING_LENGTH;
340378af961SAnatoli Huseu1     tablet->query_index = 0;
341378af961SAnatoli Huseu1 
342378af961SAnatoli Huseu1     tablet->hs = qemu_input_handler_register((DeviceState *)tablet,
343378af961SAnatoli Huseu1                                              &wctablet_handler);
344378af961SAnatoli Huseu1 }
345378af961SAnatoli Huseu1 
346378af961SAnatoli Huseu1 static void wctablet_chr_class_init(ObjectClass *oc, void *data)
347378af961SAnatoli Huseu1 {
348378af961SAnatoli Huseu1     ChardevClass *cc = CHARDEV_CLASS(oc);
349378af961SAnatoli Huseu1 
350378af961SAnatoli Huseu1     cc->open = wctablet_chr_open;
351378af961SAnatoli Huseu1     cc->chr_write = wctablet_chr_write;
352378af961SAnatoli Huseu1     cc->chr_ioctl = wctablet_chr_ioctl;
353378af961SAnatoli Huseu1     cc->chr_accept_input = wctablet_chr_accept_input;
354378af961SAnatoli Huseu1 }
355378af961SAnatoli Huseu1 
356378af961SAnatoli Huseu1 static const TypeInfo wctablet_type_info = {
357378af961SAnatoli Huseu1     .name = TYPE_CHARDEV_WCTABLET,
358378af961SAnatoli Huseu1     .parent = TYPE_CHARDEV,
359378af961SAnatoli Huseu1     .instance_size = sizeof(TabletChardev),
360378af961SAnatoli Huseu1     .instance_finalize = wctablet_chr_finalize,
361378af961SAnatoli Huseu1     .class_init = wctablet_chr_class_init,
362378af961SAnatoli Huseu1 };
363378af961SAnatoli Huseu1 
364378af961SAnatoli Huseu1 static void register_types(void)
365378af961SAnatoli Huseu1 {
366378af961SAnatoli Huseu1      type_register_static(&wctablet_type_info);
367378af961SAnatoli Huseu1 }
368378af961SAnatoli Huseu1 
369378af961SAnatoli Huseu1 type_init(register_types);
370