1 /* 2 * QEMU Baum Braille Device 3 * 4 * Copyright (c) 2008, 2010-2011, 2016-2017 Samuel Thibault 5 * 6 * Permission is hereby granted, free of charge, to any person obtaining a copy 7 * of this software and associated documentation files (the "Software"), to deal 8 * in the Software without restriction, including without limitation the rights 9 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 * copies of the Software, and to permit persons to whom the Software is 11 * furnished to do so, subject to the following conditions: 12 * 13 * The above copyright notice and this permission notice shall be included in 14 * all copies or substantial portions of the Software. 15 * 16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 19 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 22 * THE SOFTWARE. 23 */ 24 25 #include "qemu/osdep.h" 26 #include "qapi/error.h" 27 #include "chardev/char.h" 28 #include "qemu/main-loop.h" 29 #include "qemu/module.h" 30 #include "qemu/timer.h" 31 #include "hw/usb.h" 32 #include "ui/console.h" 33 #include <brlapi.h> 34 #include <brlapi_constants.h> 35 #include <brlapi_keycodes.h> 36 #include "qom/object.h" 37 38 #if 0 39 #define DPRINTF(fmt, ...) \ 40 printf(fmt, ## __VA_ARGS__) 41 #else 42 #define DPRINTF(fmt, ...) 43 #endif 44 45 #define ESC 0x1B 46 47 #define BAUM_REQ_DisplayData 0x01 48 #define BAUM_REQ_GetVersionNumber 0x05 49 #define BAUM_REQ_GetKeys 0x08 50 #define BAUM_REQ_SetMode 0x12 51 #define BAUM_REQ_SetProtocol 0x15 52 #define BAUM_REQ_GetDeviceIdentity 0x84 53 #define BAUM_REQ_GetSerialNumber 0x8A 54 55 #define BAUM_RSP_CellCount 0x01 56 #define BAUM_RSP_VersionNumber 0x05 57 #define BAUM_RSP_ModeSetting 0x11 58 #define BAUM_RSP_CommunicationChannel 0x16 59 #define BAUM_RSP_PowerdownSignal 0x17 60 #define BAUM_RSP_HorizontalSensors 0x20 61 #define BAUM_RSP_VerticalSensors 0x21 62 #define BAUM_RSP_RoutingKeys 0x22 63 #define BAUM_RSP_Switches 0x23 64 #define BAUM_RSP_TopKeys 0x24 65 #define BAUM_RSP_HorizontalSensor 0x25 66 #define BAUM_RSP_VerticalSensor 0x26 67 #define BAUM_RSP_RoutingKey 0x27 68 #define BAUM_RSP_FrontKeys6 0x28 69 #define BAUM_RSP_BackKeys6 0x29 70 #define BAUM_RSP_CommandKeys 0x2B 71 #define BAUM_RSP_FrontKeys10 0x2C 72 #define BAUM_RSP_BackKeys10 0x2D 73 #define BAUM_RSP_EntryKeys 0x33 74 #define BAUM_RSP_JoyStick 0x34 75 #define BAUM_RSP_ErrorCode 0x40 76 #define BAUM_RSP_InfoBlock 0x42 77 #define BAUM_RSP_DeviceIdentity 0x84 78 #define BAUM_RSP_SerialNumber 0x8A 79 #define BAUM_RSP_BluetoothName 0x8C 80 81 #define BAUM_TL1 0x01 82 #define BAUM_TL2 0x02 83 #define BAUM_TL3 0x04 84 #define BAUM_TR1 0x08 85 #define BAUM_TR2 0x10 86 #define BAUM_TR3 0x20 87 88 #define BUF_SIZE 256 89 90 #define X_MAX 84 91 #define Y_MAX 1 92 93 struct BaumChardev { 94 Chardev parent; 95 96 brlapi_handle_t *brlapi; 97 int brlapi_fd; 98 unsigned int x, y; 99 bool deferred_init; 100 101 uint8_t in_buf[BUF_SIZE]; 102 uint8_t in_buf_used; 103 uint8_t out_buf[BUF_SIZE]; 104 uint8_t out_buf_used, out_buf_ptr; 105 106 QEMUTimer *cellCount_timer; 107 }; 108 typedef struct BaumChardev BaumChardev; 109 110 #define TYPE_CHARDEV_BRAILLE "chardev-braille" 111 DECLARE_INSTANCE_CHECKER(BaumChardev, BAUM_CHARDEV, 112 TYPE_CHARDEV_BRAILLE) 113 114 /* Let's assume NABCC by default */ 115 enum way { 116 DOTS2ASCII, 117 ASCII2DOTS 118 }; 119 static const uint8_t nabcc_translation[2][256] = { 120 #ifndef BRLAPI_DOTS 121 #define BRLAPI_DOTS(d1,d2,d3,d4,d5,d6,d7,d8) \ 122 ((d1?BRLAPI_DOT1:0)|\ 123 (d2?BRLAPI_DOT2:0)|\ 124 (d3?BRLAPI_DOT3:0)|\ 125 (d4?BRLAPI_DOT4:0)|\ 126 (d5?BRLAPI_DOT5:0)|\ 127 (d6?BRLAPI_DOT6:0)|\ 128 (d7?BRLAPI_DOT7:0)|\ 129 (d8?BRLAPI_DOT8:0)) 130 #endif 131 #define DO(dots, ascii) \ 132 [DOTS2ASCII][dots] = ascii, \ 133 [ASCII2DOTS][ascii] = dots 134 DO(0, ' '), 135 DO(BRLAPI_DOTS(1, 0, 0, 0, 0, 0, 0, 0), 'a'), 136 DO(BRLAPI_DOTS(1, 1, 0, 0, 0, 0, 0, 0), 'b'), 137 DO(BRLAPI_DOTS(1, 0, 0, 1, 0, 0, 0, 0), 'c'), 138 DO(BRLAPI_DOTS(1, 0, 0, 1, 1, 0, 0, 0), 'd'), 139 DO(BRLAPI_DOTS(1, 0, 0, 0, 1, 0, 0, 0), 'e'), 140 DO(BRLAPI_DOTS(1, 1, 0, 1, 0, 0, 0, 0), 'f'), 141 DO(BRLAPI_DOTS(1, 1, 0, 1, 1, 0, 0, 0), 'g'), 142 DO(BRLAPI_DOTS(1, 1, 0, 0, 1, 0, 0, 0), 'h'), 143 DO(BRLAPI_DOTS(0, 1, 0, 1, 0, 0, 0, 0), 'i'), 144 DO(BRLAPI_DOTS(0, 1, 0, 1, 1, 0, 0, 0), 'j'), 145 DO(BRLAPI_DOTS(1, 0, 1, 0, 0, 0, 0, 0), 'k'), 146 DO(BRLAPI_DOTS(1, 1, 1, 0, 0, 0, 0, 0), 'l'), 147 DO(BRLAPI_DOTS(1, 0, 1, 1, 0, 0, 0, 0), 'm'), 148 DO(BRLAPI_DOTS(1, 0, 1, 1, 1, 0, 0, 0), 'n'), 149 DO(BRLAPI_DOTS(1, 0, 1, 0, 1, 0, 0, 0), 'o'), 150 DO(BRLAPI_DOTS(1, 1, 1, 1, 0, 0, 0, 0), 'p'), 151 DO(BRLAPI_DOTS(1, 1, 1, 1, 1, 0, 0, 0), 'q'), 152 DO(BRLAPI_DOTS(1, 1, 1, 0, 1, 0, 0, 0), 'r'), 153 DO(BRLAPI_DOTS(0, 1, 1, 1, 0, 0, 0, 0), 's'), 154 DO(BRLAPI_DOTS(0, 1, 1, 1, 1, 0, 0, 0), 't'), 155 DO(BRLAPI_DOTS(1, 0, 1, 0, 0, 1, 0, 0), 'u'), 156 DO(BRLAPI_DOTS(1, 1, 1, 0, 0, 1, 0, 0), 'v'), 157 DO(BRLAPI_DOTS(0, 1, 0, 1, 1, 1, 0, 0), 'w'), 158 DO(BRLAPI_DOTS(1, 0, 1, 1, 0, 1, 0, 0), 'x'), 159 DO(BRLAPI_DOTS(1, 0, 1, 1, 1, 1, 0, 0), 'y'), 160 DO(BRLAPI_DOTS(1, 0, 1, 0, 1, 1, 0, 0), 'z'), 161 162 DO(BRLAPI_DOTS(1, 0, 0, 0, 0, 0, 1, 0), 'A'), 163 DO(BRLAPI_DOTS(1, 1, 0, 0, 0, 0, 1, 0), 'B'), 164 DO(BRLAPI_DOTS(1, 0, 0, 1, 0, 0, 1, 0), 'C'), 165 DO(BRLAPI_DOTS(1, 0, 0, 1, 1, 0, 1, 0), 'D'), 166 DO(BRLAPI_DOTS(1, 0, 0, 0, 1, 0, 1, 0), 'E'), 167 DO(BRLAPI_DOTS(1, 1, 0, 1, 0, 0, 1, 0), 'F'), 168 DO(BRLAPI_DOTS(1, 1, 0, 1, 1, 0, 1, 0), 'G'), 169 DO(BRLAPI_DOTS(1, 1, 0, 0, 1, 0, 1, 0), 'H'), 170 DO(BRLAPI_DOTS(0, 1, 0, 1, 0, 0, 1, 0), 'I'), 171 DO(BRLAPI_DOTS(0, 1, 0, 1, 1, 0, 1, 0), 'J'), 172 DO(BRLAPI_DOTS(1, 0, 1, 0, 0, 0, 1, 0), 'K'), 173 DO(BRLAPI_DOTS(1, 1, 1, 0, 0, 0, 1, 0), 'L'), 174 DO(BRLAPI_DOTS(1, 0, 1, 1, 0, 0, 1, 0), 'M'), 175 DO(BRLAPI_DOTS(1, 0, 1, 1, 1, 0, 1, 0), 'N'), 176 DO(BRLAPI_DOTS(1, 0, 1, 0, 1, 0, 1, 0), 'O'), 177 DO(BRLAPI_DOTS(1, 1, 1, 1, 0, 0, 1, 0), 'P'), 178 DO(BRLAPI_DOTS(1, 1, 1, 1, 1, 0, 1, 0), 'Q'), 179 DO(BRLAPI_DOTS(1, 1, 1, 0, 1, 0, 1, 0), 'R'), 180 DO(BRLAPI_DOTS(0, 1, 1, 1, 0, 0, 1, 0), 'S'), 181 DO(BRLAPI_DOTS(0, 1, 1, 1, 1, 0, 1, 0), 'T'), 182 DO(BRLAPI_DOTS(1, 0, 1, 0, 0, 1, 1, 0), 'U'), 183 DO(BRLAPI_DOTS(1, 1, 1, 0, 0, 1, 1, 0), 'V'), 184 DO(BRLAPI_DOTS(0, 1, 0, 1, 1, 1, 1, 0), 'W'), 185 DO(BRLAPI_DOTS(1, 0, 1, 1, 0, 1, 1, 0), 'X'), 186 DO(BRLAPI_DOTS(1, 0, 1, 1, 1, 1, 1, 0), 'Y'), 187 DO(BRLAPI_DOTS(1, 0, 1, 0, 1, 1, 1, 0), 'Z'), 188 189 DO(BRLAPI_DOTS(0, 0, 1, 0, 1, 1, 0, 0), '0'), 190 DO(BRLAPI_DOTS(0, 1, 0, 0, 0, 0, 0, 0), '1'), 191 DO(BRLAPI_DOTS(0, 1, 1, 0, 0, 0, 0, 0), '2'), 192 DO(BRLAPI_DOTS(0, 1, 0, 0, 1, 0, 0, 0), '3'), 193 DO(BRLAPI_DOTS(0, 1, 0, 0, 1, 1, 0, 0), '4'), 194 DO(BRLAPI_DOTS(0, 1, 0, 0, 0, 1, 0, 0), '5'), 195 DO(BRLAPI_DOTS(0, 1, 1, 0, 1, 0, 0, 0), '6'), 196 DO(BRLAPI_DOTS(0, 1, 1, 0, 1, 1, 0, 0), '7'), 197 DO(BRLAPI_DOTS(0, 1, 1, 0, 0, 1, 0, 0), '8'), 198 DO(BRLAPI_DOTS(0, 0, 1, 0, 1, 0, 0, 0), '9'), 199 200 DO(BRLAPI_DOTS(0, 0, 0, 1, 0, 1, 0, 0), '.'), 201 DO(BRLAPI_DOTS(0, 0, 1, 1, 0, 1, 0, 0), '+'), 202 DO(BRLAPI_DOTS(0, 0, 1, 0, 0, 1, 0, 0), '-'), 203 DO(BRLAPI_DOTS(1, 0, 0, 0, 0, 1, 0, 0), '*'), 204 DO(BRLAPI_DOTS(0, 0, 1, 1, 0, 0, 0, 0), '/'), 205 DO(BRLAPI_DOTS(1, 1, 1, 0, 1, 1, 0, 0), '('), 206 DO(BRLAPI_DOTS(0, 1, 1, 1, 1, 1, 0, 0), ')'), 207 208 DO(BRLAPI_DOTS(1, 1, 1, 1, 0, 1, 0, 0), '&'), 209 DO(BRLAPI_DOTS(0, 0, 1, 1, 1, 1, 0, 0), '#'), 210 211 DO(BRLAPI_DOTS(0, 0, 0, 0, 0, 1, 0, 0), ','), 212 DO(BRLAPI_DOTS(0, 0, 0, 0, 1, 1, 0, 0), ';'), 213 DO(BRLAPI_DOTS(1, 0, 0, 0, 1, 1, 0, 0), ':'), 214 DO(BRLAPI_DOTS(0, 1, 1, 1, 0, 1, 0, 0), '!'), 215 DO(BRLAPI_DOTS(1, 0, 0, 1, 1, 1, 0, 0), '?'), 216 DO(BRLAPI_DOTS(0, 0, 0, 0, 1, 0, 0, 0), '"'), 217 DO(BRLAPI_DOTS(0, 0, 1, 0, 0, 0, 0, 0), '\''), 218 DO(BRLAPI_DOTS(0, 0, 0, 1, 0, 0, 0, 0), '`'), 219 DO(BRLAPI_DOTS(0, 0, 0, 1, 1, 0, 1, 0), '^'), 220 DO(BRLAPI_DOTS(0, 0, 0, 1, 1, 0, 0, 0), '~'), 221 DO(BRLAPI_DOTS(0, 1, 0, 1, 0, 1, 1, 0), '['), 222 DO(BRLAPI_DOTS(1, 1, 0, 1, 1, 1, 1, 0), ']'), 223 DO(BRLAPI_DOTS(0, 1, 0, 1, 0, 1, 0, 0), '{'), 224 DO(BRLAPI_DOTS(1, 1, 0, 1, 1, 1, 0, 0), '}'), 225 DO(BRLAPI_DOTS(1, 1, 1, 1, 1, 1, 0, 0), '='), 226 DO(BRLAPI_DOTS(1, 1, 0, 0, 0, 1, 0, 0), '<'), 227 DO(BRLAPI_DOTS(0, 0, 1, 1, 1, 0, 0, 0), '>'), 228 DO(BRLAPI_DOTS(1, 1, 0, 1, 0, 1, 0, 0), '$'), 229 DO(BRLAPI_DOTS(1, 0, 0, 1, 0, 1, 0, 0), '%'), 230 DO(BRLAPI_DOTS(0, 0, 0, 1, 0, 0, 1, 0), '@'), 231 DO(BRLAPI_DOTS(1, 1, 0, 0, 1, 1, 0, 0), '|'), 232 DO(BRLAPI_DOTS(1, 1, 0, 0, 1, 1, 1, 0), '\\'), 233 DO(BRLAPI_DOTS(0, 0, 0, 1, 1, 1, 0, 0), '_'), 234 }; 235 236 /* The guest OS has started discussing with us, finish initializing BrlAPI */ 237 static int baum_deferred_init(BaumChardev *baum) 238 { 239 int tty = BRLAPI_TTY_DEFAULT; 240 QemuConsole *con; 241 242 if (baum->deferred_init) { 243 return 1; 244 } 245 246 if (brlapi__getDisplaySize(baum->brlapi, &baum->x, &baum->y) == -1) { 247 brlapi_perror("baum: brlapi__getDisplaySize"); 248 return 0; 249 } 250 if (baum->y > Y_MAX) { 251 baum->y = Y_MAX; 252 } 253 if (baum->x > X_MAX) { 254 baum->x = X_MAX; 255 } 256 257 con = qemu_console_lookup_by_index(0); 258 if (con && qemu_console_is_graphic(con)) { 259 tty = qemu_console_get_window_id(con); 260 if (tty == -1) 261 tty = BRLAPI_TTY_DEFAULT; 262 } 263 264 if (brlapi__enterTtyMode(baum->brlapi, tty, NULL) == -1) { 265 brlapi_perror("baum: brlapi__enterTtyMode"); 266 return 0; 267 } 268 baum->deferred_init = 1; 269 return 1; 270 } 271 272 /* The serial port can receive more of our data */ 273 static void baum_chr_accept_input(struct Chardev *chr) 274 { 275 BaumChardev *baum = BAUM_CHARDEV(chr); 276 int room, first; 277 278 if (!baum->out_buf_used) 279 return; 280 room = qemu_chr_be_can_write(chr); 281 if (!room) 282 return; 283 if (room > baum->out_buf_used) 284 room = baum->out_buf_used; 285 286 first = BUF_SIZE - baum->out_buf_ptr; 287 if (room > first) { 288 qemu_chr_be_write(chr, baum->out_buf + baum->out_buf_ptr, first); 289 baum->out_buf_ptr = 0; 290 baum->out_buf_used -= first; 291 room -= first; 292 } 293 qemu_chr_be_write(chr, baum->out_buf + baum->out_buf_ptr, room); 294 baum->out_buf_ptr += room; 295 baum->out_buf_used -= room; 296 } 297 298 /* We want to send a packet */ 299 static void baum_write_packet(BaumChardev *baum, const uint8_t *buf, int len) 300 { 301 Chardev *chr = CHARDEV(baum); 302 g_autofree uint8_t *io_buf = g_malloc(1 + 2 * len); 303 uint8_t *cur = io_buf; 304 int room; 305 *cur++ = ESC; 306 while (len--) 307 if ((*cur++ = *buf++) == ESC) 308 *cur++ = ESC; 309 room = qemu_chr_be_can_write(chr); 310 len = cur - io_buf; 311 if (len <= room) { 312 /* Fits */ 313 qemu_chr_be_write(chr, io_buf, len); 314 } else { 315 int first; 316 uint8_t out; 317 /* Can't fit all, send what can be, and store the rest. */ 318 qemu_chr_be_write(chr, io_buf, room); 319 len -= room; 320 cur = io_buf + room; 321 if (len > BUF_SIZE - baum->out_buf_used) { 322 /* Can't even store it, drop the previous data... */ 323 assert(len <= BUF_SIZE); 324 baum->out_buf_used = 0; 325 baum->out_buf_ptr = 0; 326 } 327 out = baum->out_buf_ptr; 328 baum->out_buf_used += len; 329 first = BUF_SIZE - baum->out_buf_ptr; 330 if (len > first) { 331 memcpy(baum->out_buf + out, cur, first); 332 out = 0; 333 len -= first; 334 cur += first; 335 } 336 memcpy(baum->out_buf + out, cur, len); 337 } 338 } 339 340 /* Called when the other end seems to have a wrong idea of our display size */ 341 static void baum_cellCount_timer_cb(void *opaque) 342 { 343 BaumChardev *baum = BAUM_CHARDEV(opaque); 344 uint8_t cell_count[] = { BAUM_RSP_CellCount, baum->x * baum->y }; 345 DPRINTF("Timeout waiting for DisplayData, sending cell count\n"); 346 baum_write_packet(baum, cell_count, sizeof(cell_count)); 347 } 348 349 /* Try to interpret a whole incoming packet */ 350 static int baum_eat_packet(BaumChardev *baum, const uint8_t *buf, int len) 351 { 352 const uint8_t *cur = buf; 353 uint8_t req = 0; 354 355 if (!len--) 356 return 0; 357 if (*cur++ != ESC) { 358 while (*cur != ESC) { 359 if (!len--) 360 return 0; 361 cur++; 362 } 363 DPRINTF("Dropped %td bytes!\n", cur - buf); 364 } 365 366 #define EAT(c) do {\ 367 if (!len--) \ 368 return 0; \ 369 if ((c = *cur++) == ESC) { \ 370 if (!len--) \ 371 return 0; \ 372 if (*cur++ != ESC) { \ 373 DPRINTF("Broken packet %#2x, tossing\n", req); \ 374 if (timer_pending(baum->cellCount_timer)) { \ 375 timer_del(baum->cellCount_timer); \ 376 baum_cellCount_timer_cb(baum); \ 377 } \ 378 return (cur - 2 - buf); \ 379 } \ 380 } \ 381 } while (0) 382 383 EAT(req); 384 switch (req) { 385 case BAUM_REQ_DisplayData: 386 { 387 uint8_t cells[X_MAX * Y_MAX], c; 388 uint8_t text[X_MAX * Y_MAX]; 389 uint8_t zero[X_MAX * Y_MAX]; 390 int cursor = BRLAPI_CURSOR_OFF; 391 int i; 392 393 /* Allow 100ms to complete the DisplayData packet */ 394 timer_mod(baum->cellCount_timer, qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) + 395 NANOSECONDS_PER_SECOND / 10); 396 for (i = 0; i < baum->x * baum->y ; i++) { 397 EAT(c); 398 cells[i] = c; 399 if ((c & (BRLAPI_DOT7|BRLAPI_DOT8)) 400 == (BRLAPI_DOT7|BRLAPI_DOT8)) { 401 cursor = i + 1; 402 c &= ~(BRLAPI_DOT7|BRLAPI_DOT8); 403 } 404 c = nabcc_translation[DOTS2ASCII][c]; 405 if (!c) { 406 c = '?'; 407 } 408 text[i] = c; 409 } 410 timer_del(baum->cellCount_timer); 411 412 memset(zero, 0, baum->x * baum->y); 413 414 brlapi_writeArguments_t wa = { 415 .displayNumber = BRLAPI_DISPLAY_DEFAULT, 416 .regionBegin = 1, 417 .regionSize = baum->x * baum->y, 418 .text = (char *)text, 419 .textSize = baum->x * baum->y, 420 .andMask = zero, 421 .orMask = cells, 422 .cursor = cursor, 423 .charset = (char *)"ISO-8859-1", 424 }; 425 426 if (brlapi__write(baum->brlapi, &wa) == -1) 427 brlapi_perror("baum brlapi_write"); 428 break; 429 } 430 case BAUM_REQ_SetMode: 431 { 432 uint8_t mode, setting; 433 DPRINTF("SetMode\n"); 434 EAT(mode); 435 EAT(setting); 436 /* ignore */ 437 break; 438 } 439 case BAUM_REQ_SetProtocol: 440 { 441 uint8_t protocol; 442 DPRINTF("SetProtocol\n"); 443 EAT(protocol); 444 /* ignore */ 445 break; 446 } 447 case BAUM_REQ_GetDeviceIdentity: 448 { 449 uint8_t identity[17] = { BAUM_RSP_DeviceIdentity, 450 'B','a','u','m',' ','V','a','r','i','o' }; 451 DPRINTF("GetDeviceIdentity\n"); 452 identity[11] = '0' + baum->x / 10; 453 identity[12] = '0' + baum->x % 10; 454 baum_write_packet(baum, identity, sizeof(identity)); 455 break; 456 } 457 case BAUM_REQ_GetVersionNumber: 458 { 459 uint8_t version[] = { BAUM_RSP_VersionNumber, 1 }; /* ? */ 460 DPRINTF("GetVersionNumber\n"); 461 baum_write_packet(baum, version, sizeof(version)); 462 break; 463 } 464 case BAUM_REQ_GetSerialNumber: 465 { 466 uint8_t serial[] = { BAUM_RSP_SerialNumber, 467 '0','0','0','0','0','0','0','0' }; 468 DPRINTF("GetSerialNumber\n"); 469 baum_write_packet(baum, serial, sizeof(serial)); 470 break; 471 } 472 case BAUM_REQ_GetKeys: 473 { 474 DPRINTF("Get%0#2x\n", req); 475 /* ignore */ 476 break; 477 } 478 default: 479 DPRINTF("unrecognized request %0#2x\n", req); 480 do 481 if (!len--) 482 return 0; 483 while (*cur++ != ESC); 484 cur--; 485 break; 486 } 487 return cur - buf; 488 } 489 490 /* The other end is writing some data. Store it and try to interpret */ 491 static int baum_chr_write(Chardev *chr, const uint8_t *buf, int len) 492 { 493 BaumChardev *baum = BAUM_CHARDEV(chr); 494 int tocopy, cur, eaten, orig_len = len; 495 496 if (!len) 497 return 0; 498 if (!baum->brlapi) 499 return len; 500 if (!baum_deferred_init(baum)) 501 return len; 502 503 while (len) { 504 /* Complete our buffer as much as possible */ 505 tocopy = len; 506 if (tocopy > BUF_SIZE - baum->in_buf_used) 507 tocopy = BUF_SIZE - baum->in_buf_used; 508 509 memcpy(baum->in_buf + baum->in_buf_used, buf, tocopy); 510 baum->in_buf_used += tocopy; 511 buf += tocopy; 512 len -= tocopy; 513 514 /* Interpret it as much as possible */ 515 cur = 0; 516 while (cur < baum->in_buf_used && 517 (eaten = baum_eat_packet(baum, baum->in_buf + cur, baum->in_buf_used - cur))) 518 cur += eaten; 519 520 /* Shift the remainder */ 521 if (cur) { 522 memmove(baum->in_buf, baum->in_buf + cur, baum->in_buf_used - cur); 523 baum->in_buf_used -= cur; 524 } 525 526 /* And continue if any data left */ 527 } 528 return orig_len; 529 } 530 531 /* Send the key code to the other end */ 532 static void baum_send_key(BaumChardev *baum, uint8_t type, uint8_t value) 533 { 534 uint8_t packet[] = { type, value }; 535 DPRINTF("writing key %x %x\n", type, value); 536 baum_write_packet(baum, packet, sizeof(packet)); 537 } 538 539 static void baum_send_key2(BaumChardev *baum, uint8_t type, uint8_t value, 540 uint8_t value2) 541 { 542 uint8_t packet[] = { type, value, value2 }; 543 DPRINTF("writing key %x %x\n", type, value); 544 baum_write_packet(baum, packet, sizeof(packet)); 545 } 546 547 /* We got some data on the BrlAPI socket */ 548 static void baum_chr_read(void *opaque) 549 { 550 BaumChardev *baum = BAUM_CHARDEV(opaque); 551 brlapi_keyCode_t code; 552 int ret; 553 if (!baum->brlapi) 554 return; 555 if (!baum_deferred_init(baum)) 556 return; 557 while ((ret = brlapi__readKey(baum->brlapi, 0, &code)) == 1) { 558 DPRINTF("got key %"BRLAPI_PRIxKEYCODE"\n", code); 559 /* Emulate */ 560 switch (code & BRLAPI_KEY_TYPE_MASK) { 561 case BRLAPI_KEY_TYPE_CMD: 562 switch (code & BRLAPI_KEY_CMD_BLK_MASK) { 563 case BRLAPI_KEY_CMD_ROUTE: 564 baum_send_key(baum, BAUM_RSP_RoutingKey, (code & BRLAPI_KEY_CMD_ARG_MASK)+1); 565 baum_send_key(baum, BAUM_RSP_RoutingKey, 0); 566 break; 567 case 0: 568 switch (code & BRLAPI_KEY_CMD_ARG_MASK) { 569 case BRLAPI_KEY_CMD_FWINLT: 570 baum_send_key(baum, BAUM_RSP_TopKeys, BAUM_TL2); 571 baum_send_key(baum, BAUM_RSP_TopKeys, 0); 572 break; 573 case BRLAPI_KEY_CMD_FWINRT: 574 baum_send_key(baum, BAUM_RSP_TopKeys, BAUM_TR2); 575 baum_send_key(baum, BAUM_RSP_TopKeys, 0); 576 break; 577 case BRLAPI_KEY_CMD_LNUP: 578 baum_send_key(baum, BAUM_RSP_TopKeys, BAUM_TR1); 579 baum_send_key(baum, BAUM_RSP_TopKeys, 0); 580 break; 581 case BRLAPI_KEY_CMD_LNDN: 582 baum_send_key(baum, BAUM_RSP_TopKeys, BAUM_TR3); 583 baum_send_key(baum, BAUM_RSP_TopKeys, 0); 584 break; 585 case BRLAPI_KEY_CMD_TOP: 586 baum_send_key(baum, BAUM_RSP_TopKeys, BAUM_TL1|BAUM_TR1); 587 baum_send_key(baum, BAUM_RSP_TopKeys, 0); 588 break; 589 case BRLAPI_KEY_CMD_BOT: 590 baum_send_key(baum, BAUM_RSP_TopKeys, BAUM_TL3|BAUM_TR3); 591 baum_send_key(baum, BAUM_RSP_TopKeys, 0); 592 break; 593 case BRLAPI_KEY_CMD_TOP_LEFT: 594 baum_send_key(baum, BAUM_RSP_TopKeys, BAUM_TL2|BAUM_TR1); 595 baum_send_key(baum, BAUM_RSP_TopKeys, 0); 596 break; 597 case BRLAPI_KEY_CMD_BOT_LEFT: 598 baum_send_key(baum, BAUM_RSP_TopKeys, BAUM_TL2|BAUM_TR3); 599 baum_send_key(baum, BAUM_RSP_TopKeys, 0); 600 break; 601 case BRLAPI_KEY_CMD_HOME: 602 baum_send_key(baum, BAUM_RSP_TopKeys, BAUM_TL2|BAUM_TR1|BAUM_TR3); 603 baum_send_key(baum, BAUM_RSP_TopKeys, 0); 604 break; 605 case BRLAPI_KEY_CMD_PREFMENU: 606 baum_send_key(baum, BAUM_RSP_TopKeys, BAUM_TL1|BAUM_TL3|BAUM_TR1); 607 baum_send_key(baum, BAUM_RSP_TopKeys, 0); 608 break; 609 } 610 } 611 break; 612 case BRLAPI_KEY_TYPE_SYM: 613 { 614 brlapi_keyCode_t keysym = code & BRLAPI_KEY_CODE_MASK; 615 if (keysym < 0x100) { 616 uint8_t dots = nabcc_translation[ASCII2DOTS][keysym]; 617 if (dots) { 618 baum_send_key2(baum, BAUM_RSP_EntryKeys, 0, dots); 619 baum_send_key2(baum, BAUM_RSP_EntryKeys, 0, 0); 620 } 621 } 622 break; 623 } 624 } 625 } 626 if (ret == -1 && (brlapi_errno != BRLAPI_ERROR_LIBCERR || errno != EINTR)) { 627 brlapi_perror("baum: brlapi_readKey"); 628 brlapi__closeConnection(baum->brlapi); 629 g_free(baum->brlapi); 630 baum->brlapi = NULL; 631 } 632 } 633 634 static void char_braille_finalize(Object *obj) 635 { 636 BaumChardev *baum = BAUM_CHARDEV(obj); 637 638 timer_free(baum->cellCount_timer); 639 if (baum->brlapi) { 640 brlapi__closeConnection(baum->brlapi); 641 g_free(baum->brlapi); 642 } 643 } 644 645 static void baum_chr_open(Chardev *chr, 646 ChardevBackend *backend, 647 bool *be_opened, 648 Error **errp) 649 { 650 BaumChardev *baum = BAUM_CHARDEV(chr); 651 brlapi_handle_t *handle; 652 653 handle = g_malloc0(brlapi_getHandleSize()); 654 baum->brlapi = handle; 655 656 baum->brlapi_fd = brlapi__openConnection(handle, NULL, NULL); 657 if (baum->brlapi_fd == -1) { 658 error_setg(errp, "brlapi__openConnection: %s", 659 brlapi_strerror(brlapi_error_location())); 660 g_free(handle); 661 baum->brlapi = NULL; 662 return; 663 } 664 baum->deferred_init = 0; 665 666 baum->cellCount_timer = timer_new_ns(QEMU_CLOCK_VIRTUAL, baum_cellCount_timer_cb, baum); 667 668 qemu_set_fd_handler(baum->brlapi_fd, baum_chr_read, NULL, baum); 669 } 670 671 static void char_braille_class_init(ObjectClass *oc, void *data) 672 { 673 ChardevClass *cc = CHARDEV_CLASS(oc); 674 675 cc->open = baum_chr_open; 676 cc->chr_write = baum_chr_write; 677 cc->chr_accept_input = baum_chr_accept_input; 678 } 679 680 static const TypeInfo char_braille_type_info = { 681 .name = TYPE_CHARDEV_BRAILLE, 682 .parent = TYPE_CHARDEV, 683 .instance_size = sizeof(BaumChardev), 684 .instance_finalize = char_braille_finalize, 685 .class_init = char_braille_class_init, 686 }; 687 module_obj(TYPE_CHARDEV_BRAILLE); 688 689 static void register_types(void) 690 { 691 type_register_static(&char_braille_type_info); 692 } 693 694 type_init(register_types); 695