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