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 struct BaumChardev { 91 Chardev parent; 92 93 brlapi_handle_t *brlapi; 94 int brlapi_fd; 95 unsigned int x, y; 96 bool deferred_init; 97 98 uint8_t in_buf[BUF_SIZE]; 99 uint8_t in_buf_used; 100 uint8_t out_buf[BUF_SIZE]; 101 uint8_t out_buf_used, out_buf_ptr; 102 103 QEMUTimer *cellCount_timer; 104 }; 105 typedef struct BaumChardev BaumChardev; 106 107 #define TYPE_CHARDEV_BRAILLE "chardev-braille" 108 #define BAUM_CHARDEV(obj) OBJECT_CHECK(BaumChardev, (obj), TYPE_CHARDEV_BRAILLE) 109 110 /* Let's assume NABCC by default */ 111 enum way { 112 DOTS2ASCII, 113 ASCII2DOTS 114 }; 115 static const uint8_t nabcc_translation[2][256] = { 116 #ifndef BRLAPI_DOTS 117 #define BRLAPI_DOTS(d1,d2,d3,d4,d5,d6,d7,d8) \ 118 ((d1?BRLAPI_DOT1:0)|\ 119 (d2?BRLAPI_DOT2:0)|\ 120 (d3?BRLAPI_DOT3:0)|\ 121 (d4?BRLAPI_DOT4:0)|\ 122 (d5?BRLAPI_DOT5:0)|\ 123 (d6?BRLAPI_DOT6:0)|\ 124 (d7?BRLAPI_DOT7:0)|\ 125 (d8?BRLAPI_DOT8:0)) 126 #endif 127 #define DO(dots, ascii) \ 128 [DOTS2ASCII][dots] = ascii, \ 129 [ASCII2DOTS][ascii] = dots 130 DO(0, ' '), 131 DO(BRLAPI_DOTS(1, 0, 0, 0, 0, 0, 0, 0), 'a'), 132 DO(BRLAPI_DOTS(1, 1, 0, 0, 0, 0, 0, 0), 'b'), 133 DO(BRLAPI_DOTS(1, 0, 0, 1, 0, 0, 0, 0), 'c'), 134 DO(BRLAPI_DOTS(1, 0, 0, 1, 1, 0, 0, 0), 'd'), 135 DO(BRLAPI_DOTS(1, 0, 0, 0, 1, 0, 0, 0), 'e'), 136 DO(BRLAPI_DOTS(1, 1, 0, 1, 0, 0, 0, 0), 'f'), 137 DO(BRLAPI_DOTS(1, 1, 0, 1, 1, 0, 0, 0), 'g'), 138 DO(BRLAPI_DOTS(1, 1, 0, 0, 1, 0, 0, 0), 'h'), 139 DO(BRLAPI_DOTS(0, 1, 0, 1, 0, 0, 0, 0), 'i'), 140 DO(BRLAPI_DOTS(0, 1, 0, 1, 1, 0, 0, 0), 'j'), 141 DO(BRLAPI_DOTS(1, 0, 1, 0, 0, 0, 0, 0), 'k'), 142 DO(BRLAPI_DOTS(1, 1, 1, 0, 0, 0, 0, 0), 'l'), 143 DO(BRLAPI_DOTS(1, 0, 1, 1, 0, 0, 0, 0), 'm'), 144 DO(BRLAPI_DOTS(1, 0, 1, 1, 1, 0, 0, 0), 'n'), 145 DO(BRLAPI_DOTS(1, 0, 1, 0, 1, 0, 0, 0), 'o'), 146 DO(BRLAPI_DOTS(1, 1, 1, 1, 0, 0, 0, 0), 'p'), 147 DO(BRLAPI_DOTS(1, 1, 1, 1, 1, 0, 0, 0), 'q'), 148 DO(BRLAPI_DOTS(1, 1, 1, 0, 1, 0, 0, 0), 'r'), 149 DO(BRLAPI_DOTS(0, 1, 1, 1, 0, 0, 0, 0), 's'), 150 DO(BRLAPI_DOTS(0, 1, 1, 1, 1, 0, 0, 0), 't'), 151 DO(BRLAPI_DOTS(1, 0, 1, 0, 0, 1, 0, 0), 'u'), 152 DO(BRLAPI_DOTS(1, 1, 1, 0, 0, 1, 0, 0), 'v'), 153 DO(BRLAPI_DOTS(0, 1, 0, 1, 1, 1, 0, 0), 'w'), 154 DO(BRLAPI_DOTS(1, 0, 1, 1, 0, 1, 0, 0), 'x'), 155 DO(BRLAPI_DOTS(1, 0, 1, 1, 1, 1, 0, 0), 'y'), 156 DO(BRLAPI_DOTS(1, 0, 1, 0, 1, 1, 0, 0), 'z'), 157 158 DO(BRLAPI_DOTS(1, 0, 0, 0, 0, 0, 1, 0), 'A'), 159 DO(BRLAPI_DOTS(1, 1, 0, 0, 0, 0, 1, 0), 'B'), 160 DO(BRLAPI_DOTS(1, 0, 0, 1, 0, 0, 1, 0), 'C'), 161 DO(BRLAPI_DOTS(1, 0, 0, 1, 1, 0, 1, 0), 'D'), 162 DO(BRLAPI_DOTS(1, 0, 0, 0, 1, 0, 1, 0), 'E'), 163 DO(BRLAPI_DOTS(1, 1, 0, 1, 0, 0, 1, 0), 'F'), 164 DO(BRLAPI_DOTS(1, 1, 0, 1, 1, 0, 1, 0), 'G'), 165 DO(BRLAPI_DOTS(1, 1, 0, 0, 1, 0, 1, 0), 'H'), 166 DO(BRLAPI_DOTS(0, 1, 0, 1, 0, 0, 1, 0), 'I'), 167 DO(BRLAPI_DOTS(0, 1, 0, 1, 1, 0, 1, 0), 'J'), 168 DO(BRLAPI_DOTS(1, 0, 1, 0, 0, 0, 1, 0), 'K'), 169 DO(BRLAPI_DOTS(1, 1, 1, 0, 0, 0, 1, 0), 'L'), 170 DO(BRLAPI_DOTS(1, 0, 1, 1, 0, 0, 1, 0), 'M'), 171 DO(BRLAPI_DOTS(1, 0, 1, 1, 1, 0, 1, 0), 'N'), 172 DO(BRLAPI_DOTS(1, 0, 1, 0, 1, 0, 1, 0), 'O'), 173 DO(BRLAPI_DOTS(1, 1, 1, 1, 0, 0, 1, 0), 'P'), 174 DO(BRLAPI_DOTS(1, 1, 1, 1, 1, 0, 1, 0), 'Q'), 175 DO(BRLAPI_DOTS(1, 1, 1, 0, 1, 0, 1, 0), 'R'), 176 DO(BRLAPI_DOTS(0, 1, 1, 1, 0, 0, 1, 0), 'S'), 177 DO(BRLAPI_DOTS(0, 1, 1, 1, 1, 0, 1, 0), 'T'), 178 DO(BRLAPI_DOTS(1, 0, 1, 0, 0, 1, 1, 0), 'U'), 179 DO(BRLAPI_DOTS(1, 1, 1, 0, 0, 1, 1, 0), 'V'), 180 DO(BRLAPI_DOTS(0, 1, 0, 1, 1, 1, 1, 0), 'W'), 181 DO(BRLAPI_DOTS(1, 0, 1, 1, 0, 1, 1, 0), 'X'), 182 DO(BRLAPI_DOTS(1, 0, 1, 1, 1, 1, 1, 0), 'Y'), 183 DO(BRLAPI_DOTS(1, 0, 1, 0, 1, 1, 1, 0), 'Z'), 184 185 DO(BRLAPI_DOTS(0, 0, 1, 0, 1, 1, 0, 0), '0'), 186 DO(BRLAPI_DOTS(0, 1, 0, 0, 0, 0, 0, 0), '1'), 187 DO(BRLAPI_DOTS(0, 1, 1, 0, 0, 0, 0, 0), '2'), 188 DO(BRLAPI_DOTS(0, 1, 0, 0, 1, 0, 0, 0), '3'), 189 DO(BRLAPI_DOTS(0, 1, 0, 0, 1, 1, 0, 0), '4'), 190 DO(BRLAPI_DOTS(0, 1, 0, 0, 0, 1, 0, 0), '5'), 191 DO(BRLAPI_DOTS(0, 1, 1, 0, 1, 0, 0, 0), '6'), 192 DO(BRLAPI_DOTS(0, 1, 1, 0, 1, 1, 0, 0), '7'), 193 DO(BRLAPI_DOTS(0, 1, 1, 0, 0, 1, 0, 0), '8'), 194 DO(BRLAPI_DOTS(0, 0, 1, 0, 1, 0, 0, 0), '9'), 195 196 DO(BRLAPI_DOTS(0, 0, 0, 1, 0, 1, 0, 0), '.'), 197 DO(BRLAPI_DOTS(0, 0, 1, 1, 0, 1, 0, 0), '+'), 198 DO(BRLAPI_DOTS(0, 0, 1, 0, 0, 1, 0, 0), '-'), 199 DO(BRLAPI_DOTS(1, 0, 0, 0, 0, 1, 0, 0), '*'), 200 DO(BRLAPI_DOTS(0, 0, 1, 1, 0, 0, 0, 0), '/'), 201 DO(BRLAPI_DOTS(1, 1, 1, 0, 1, 1, 0, 0), '('), 202 DO(BRLAPI_DOTS(0, 1, 1, 1, 1, 1, 0, 0), ')'), 203 204 DO(BRLAPI_DOTS(1, 1, 1, 1, 0, 1, 0, 0), '&'), 205 DO(BRLAPI_DOTS(0, 0, 1, 1, 1, 1, 0, 0), '#'), 206 207 DO(BRLAPI_DOTS(0, 0, 0, 0, 0, 1, 0, 0), ','), 208 DO(BRLAPI_DOTS(0, 0, 0, 0, 1, 1, 0, 0), ';'), 209 DO(BRLAPI_DOTS(1, 0, 0, 0, 1, 1, 0, 0), ':'), 210 DO(BRLAPI_DOTS(0, 1, 1, 1, 0, 1, 0, 0), '!'), 211 DO(BRLAPI_DOTS(1, 0, 0, 1, 1, 1, 0, 0), '?'), 212 DO(BRLAPI_DOTS(0, 0, 0, 0, 1, 0, 0, 0), '"'), 213 DO(BRLAPI_DOTS(0, 0, 1, 0, 0, 0, 0, 0), '\''), 214 DO(BRLAPI_DOTS(0, 0, 0, 1, 0, 0, 0, 0), '`'), 215 DO(BRLAPI_DOTS(0, 0, 0, 1, 1, 0, 1, 0), '^'), 216 DO(BRLAPI_DOTS(0, 0, 0, 1, 1, 0, 0, 0), '~'), 217 DO(BRLAPI_DOTS(0, 1, 0, 1, 0, 1, 1, 0), '['), 218 DO(BRLAPI_DOTS(1, 1, 0, 1, 1, 1, 1, 0), ']'), 219 DO(BRLAPI_DOTS(0, 1, 0, 1, 0, 1, 0, 0), '{'), 220 DO(BRLAPI_DOTS(1, 1, 0, 1, 1, 1, 0, 0), '}'), 221 DO(BRLAPI_DOTS(1, 1, 1, 1, 1, 1, 0, 0), '='), 222 DO(BRLAPI_DOTS(1, 1, 0, 0, 0, 1, 0, 0), '<'), 223 DO(BRLAPI_DOTS(0, 0, 1, 1, 1, 0, 0, 0), '>'), 224 DO(BRLAPI_DOTS(1, 1, 0, 1, 0, 1, 0, 0), '$'), 225 DO(BRLAPI_DOTS(1, 0, 0, 1, 0, 1, 0, 0), '%'), 226 DO(BRLAPI_DOTS(0, 0, 0, 1, 0, 0, 1, 0), '@'), 227 DO(BRLAPI_DOTS(1, 1, 0, 0, 1, 1, 0, 0), '|'), 228 DO(BRLAPI_DOTS(1, 1, 0, 0, 1, 1, 1, 0), '\\'), 229 DO(BRLAPI_DOTS(0, 0, 0, 1, 1, 1, 0, 0), '_'), 230 }; 231 232 /* The guest OS has started discussing with us, finish initializing BrlAPI */ 233 static int baum_deferred_init(BaumChardev *baum) 234 { 235 int tty = BRLAPI_TTY_DEFAULT; 236 QemuConsole *con; 237 238 if (baum->deferred_init) { 239 return 1; 240 } 241 242 if (brlapi__getDisplaySize(baum->brlapi, &baum->x, &baum->y) == -1) { 243 brlapi_perror("baum: brlapi__getDisplaySize"); 244 return 0; 245 } 246 if (baum->y > 1) { 247 baum->y = 1; 248 } 249 if (baum->x > 84) { 250 baum->x = 84; 251 } 252 253 con = qemu_console_lookup_by_index(0); 254 if (con && qemu_console_is_graphic(con)) { 255 tty = qemu_console_get_window_id(con); 256 if (tty == -1) 257 tty = BRLAPI_TTY_DEFAULT; 258 } 259 260 if (brlapi__enterTtyMode(baum->brlapi, tty, NULL) == -1) { 261 brlapi_perror("baum: brlapi__enterTtyMode"); 262 return 0; 263 } 264 baum->deferred_init = 1; 265 return 1; 266 } 267 268 /* The serial port can receive more of our data */ 269 static void baum_chr_accept_input(struct Chardev *chr) 270 { 271 BaumChardev *baum = BAUM_CHARDEV(chr); 272 int room, first; 273 274 if (!baum->out_buf_used) 275 return; 276 room = qemu_chr_be_can_write(chr); 277 if (!room) 278 return; 279 if (room > baum->out_buf_used) 280 room = baum->out_buf_used; 281 282 first = BUF_SIZE - baum->out_buf_ptr; 283 if (room > first) { 284 qemu_chr_be_write(chr, baum->out_buf + baum->out_buf_ptr, first); 285 baum->out_buf_ptr = 0; 286 baum->out_buf_used -= first; 287 room -= first; 288 } 289 qemu_chr_be_write(chr, baum->out_buf + baum->out_buf_ptr, room); 290 baum->out_buf_ptr += room; 291 baum->out_buf_used -= room; 292 } 293 294 /* We want to send a packet */ 295 static void baum_write_packet(BaumChardev *baum, const uint8_t *buf, int len) 296 { 297 Chardev *chr = CHARDEV(baum); 298 uint8_t io_buf[1 + 2 * len], *cur = io_buf; 299 int room; 300 *cur++ = ESC; 301 while (len--) 302 if ((*cur++ = *buf++) == ESC) 303 *cur++ = ESC; 304 room = qemu_chr_be_can_write(chr); 305 len = cur - io_buf; 306 if (len <= room) { 307 /* Fits */ 308 qemu_chr_be_write(chr, io_buf, len); 309 } else { 310 int first; 311 uint8_t out; 312 /* Can't fit all, send what can be, and store the rest. */ 313 qemu_chr_be_write(chr, io_buf, room); 314 len -= room; 315 cur = io_buf + room; 316 if (len > BUF_SIZE - baum->out_buf_used) { 317 /* Can't even store it, drop the previous data... */ 318 assert(len <= BUF_SIZE); 319 baum->out_buf_used = 0; 320 baum->out_buf_ptr = 0; 321 } 322 out = baum->out_buf_ptr; 323 baum->out_buf_used += len; 324 first = BUF_SIZE - baum->out_buf_ptr; 325 if (len > first) { 326 memcpy(baum->out_buf + out, cur, first); 327 out = 0; 328 len -= first; 329 cur += first; 330 } 331 memcpy(baum->out_buf + out, cur, len); 332 } 333 } 334 335 /* Called when the other end seems to have a wrong idea of our display size */ 336 static void baum_cellCount_timer_cb(void *opaque) 337 { 338 BaumChardev *baum = BAUM_CHARDEV(opaque); 339 uint8_t cell_count[] = { BAUM_RSP_CellCount, baum->x * baum->y }; 340 DPRINTF("Timeout waiting for DisplayData, sending cell count\n"); 341 baum_write_packet(baum, cell_count, sizeof(cell_count)); 342 } 343 344 /* Try to interpret a whole incoming packet */ 345 static int baum_eat_packet(BaumChardev *baum, const uint8_t *buf, int len) 346 { 347 const uint8_t *cur = buf; 348 uint8_t req = 0; 349 350 if (!len--) 351 return 0; 352 if (*cur++ != ESC) { 353 while (*cur != ESC) { 354 if (!len--) 355 return 0; 356 cur++; 357 } 358 DPRINTF("Dropped %td bytes!\n", cur - buf); 359 } 360 361 #define EAT(c) do {\ 362 if (!len--) \ 363 return 0; \ 364 if ((c = *cur++) == ESC) { \ 365 if (!len--) \ 366 return 0; \ 367 if (*cur++ != ESC) { \ 368 DPRINTF("Broken packet %#2x, tossing\n", req); \ 369 if (timer_pending(baum->cellCount_timer)) { \ 370 timer_del(baum->cellCount_timer); \ 371 baum_cellCount_timer_cb(baum); \ 372 } \ 373 return (cur - 2 - buf); \ 374 } \ 375 } \ 376 } while (0) 377 378 EAT(req); 379 switch (req) { 380 case BAUM_REQ_DisplayData: 381 { 382 uint8_t cells[baum->x * baum->y], c; 383 uint8_t text[baum->x * baum->y]; 384 uint8_t zero[baum->x * baum->y]; 385 int cursor = BRLAPI_CURSOR_OFF; 386 int i; 387 388 /* Allow 100ms to complete the DisplayData packet */ 389 timer_mod(baum->cellCount_timer, qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) + 390 NANOSECONDS_PER_SECOND / 10); 391 for (i = 0; i < baum->x * baum->y ; i++) { 392 EAT(c); 393 cells[i] = c; 394 if ((c & (BRLAPI_DOT7|BRLAPI_DOT8)) 395 == (BRLAPI_DOT7|BRLAPI_DOT8)) { 396 cursor = i + 1; 397 c &= ~(BRLAPI_DOT7|BRLAPI_DOT8); 398 } 399 c = nabcc_translation[DOTS2ASCII][c]; 400 if (!c) { 401 c = '?'; 402 } 403 text[i] = c; 404 } 405 timer_del(baum->cellCount_timer); 406 407 memset(zero, 0, sizeof(zero)); 408 409 brlapi_writeArguments_t wa = { 410 .displayNumber = BRLAPI_DISPLAY_DEFAULT, 411 .regionBegin = 1, 412 .regionSize = baum->x * baum->y, 413 .text = (char *)text, 414 .textSize = baum->x * baum->y, 415 .andMask = zero, 416 .orMask = cells, 417 .cursor = cursor, 418 .charset = (char *)"ISO-8859-1", 419 }; 420 421 if (brlapi__write(baum->brlapi, &wa) == -1) 422 brlapi_perror("baum brlapi_write"); 423 break; 424 } 425 case BAUM_REQ_SetMode: 426 { 427 uint8_t mode, setting; 428 DPRINTF("SetMode\n"); 429 EAT(mode); 430 EAT(setting); 431 /* ignore */ 432 break; 433 } 434 case BAUM_REQ_SetProtocol: 435 { 436 uint8_t protocol; 437 DPRINTF("SetProtocol\n"); 438 EAT(protocol); 439 /* ignore */ 440 break; 441 } 442 case BAUM_REQ_GetDeviceIdentity: 443 { 444 uint8_t identity[17] = { BAUM_RSP_DeviceIdentity, 445 'B','a','u','m',' ','V','a','r','i','o' }; 446 DPRINTF("GetDeviceIdentity\n"); 447 identity[11] = '0' + baum->x / 10; 448 identity[12] = '0' + baum->x % 10; 449 baum_write_packet(baum, identity, sizeof(identity)); 450 break; 451 } 452 case BAUM_REQ_GetVersionNumber: 453 { 454 uint8_t version[] = { BAUM_RSP_VersionNumber, 1 }; /* ? */ 455 DPRINTF("GetVersionNumber\n"); 456 baum_write_packet(baum, version, sizeof(version)); 457 break; 458 } 459 case BAUM_REQ_GetSerialNumber: 460 { 461 uint8_t serial[] = { BAUM_RSP_SerialNumber, 462 '0','0','0','0','0','0','0','0' }; 463 DPRINTF("GetSerialNumber\n"); 464 baum_write_packet(baum, serial, sizeof(serial)); 465 break; 466 } 467 case BAUM_REQ_GetKeys: 468 { 469 DPRINTF("Get%0#2x\n", req); 470 /* ignore */ 471 break; 472 } 473 default: 474 DPRINTF("unrecognized request %0#2x\n", req); 475 do 476 if (!len--) 477 return 0; 478 while (*cur++ != ESC); 479 cur--; 480 break; 481 } 482 return cur - buf; 483 } 484 485 /* The other end is writing some data. Store it and try to interpret */ 486 static int baum_chr_write(Chardev *chr, const uint8_t *buf, int len) 487 { 488 BaumChardev *baum = BAUM_CHARDEV(chr); 489 int tocopy, cur, eaten, orig_len = len; 490 491 if (!len) 492 return 0; 493 if (!baum->brlapi) 494 return len; 495 if (!baum_deferred_init(baum)) 496 return len; 497 498 while (len) { 499 /* Complete our buffer as much as possible */ 500 tocopy = len; 501 if (tocopy > BUF_SIZE - baum->in_buf_used) 502 tocopy = BUF_SIZE - baum->in_buf_used; 503 504 memcpy(baum->in_buf + baum->in_buf_used, buf, tocopy); 505 baum->in_buf_used += tocopy; 506 buf += tocopy; 507 len -= tocopy; 508 509 /* Interpret it as much as possible */ 510 cur = 0; 511 while (cur < baum->in_buf_used && 512 (eaten = baum_eat_packet(baum, baum->in_buf + cur, baum->in_buf_used - cur))) 513 cur += eaten; 514 515 /* Shift the remainder */ 516 if (cur) { 517 memmove(baum->in_buf, baum->in_buf + cur, baum->in_buf_used - cur); 518 baum->in_buf_used -= cur; 519 } 520 521 /* And continue if any data left */ 522 } 523 return orig_len; 524 } 525 526 /* Send the key code to the other end */ 527 static void baum_send_key(BaumChardev *baum, uint8_t type, uint8_t value) 528 { 529 uint8_t packet[] = { type, value }; 530 DPRINTF("writing key %x %x\n", type, value); 531 baum_write_packet(baum, packet, sizeof(packet)); 532 } 533 534 static void baum_send_key2(BaumChardev *baum, uint8_t type, uint8_t value, 535 uint8_t value2) 536 { 537 uint8_t packet[] = { type, value, value2 }; 538 DPRINTF("writing key %x %x\n", type, value); 539 baum_write_packet(baum, packet, sizeof(packet)); 540 } 541 542 /* We got some data on the BrlAPI socket */ 543 static void baum_chr_read(void *opaque) 544 { 545 BaumChardev *baum = BAUM_CHARDEV(opaque); 546 brlapi_keyCode_t code; 547 int ret; 548 if (!baum->brlapi) 549 return; 550 if (!baum_deferred_init(baum)) 551 return; 552 while ((ret = brlapi__readKey(baum->brlapi, 0, &code)) == 1) { 553 DPRINTF("got key %"BRLAPI_PRIxKEYCODE"\n", code); 554 /* Emulate */ 555 switch (code & BRLAPI_KEY_TYPE_MASK) { 556 case BRLAPI_KEY_TYPE_CMD: 557 switch (code & BRLAPI_KEY_CMD_BLK_MASK) { 558 case BRLAPI_KEY_CMD_ROUTE: 559 baum_send_key(baum, BAUM_RSP_RoutingKey, (code & BRLAPI_KEY_CMD_ARG_MASK)+1); 560 baum_send_key(baum, BAUM_RSP_RoutingKey, 0); 561 break; 562 case 0: 563 switch (code & BRLAPI_KEY_CMD_ARG_MASK) { 564 case BRLAPI_KEY_CMD_FWINLT: 565 baum_send_key(baum, BAUM_RSP_TopKeys, BAUM_TL2); 566 baum_send_key(baum, BAUM_RSP_TopKeys, 0); 567 break; 568 case BRLAPI_KEY_CMD_FWINRT: 569 baum_send_key(baum, BAUM_RSP_TopKeys, BAUM_TR2); 570 baum_send_key(baum, BAUM_RSP_TopKeys, 0); 571 break; 572 case BRLAPI_KEY_CMD_LNUP: 573 baum_send_key(baum, BAUM_RSP_TopKeys, BAUM_TR1); 574 baum_send_key(baum, BAUM_RSP_TopKeys, 0); 575 break; 576 case BRLAPI_KEY_CMD_LNDN: 577 baum_send_key(baum, BAUM_RSP_TopKeys, BAUM_TR3); 578 baum_send_key(baum, BAUM_RSP_TopKeys, 0); 579 break; 580 case BRLAPI_KEY_CMD_TOP: 581 baum_send_key(baum, BAUM_RSP_TopKeys, BAUM_TL1|BAUM_TR1); 582 baum_send_key(baum, BAUM_RSP_TopKeys, 0); 583 break; 584 case BRLAPI_KEY_CMD_BOT: 585 baum_send_key(baum, BAUM_RSP_TopKeys, BAUM_TL3|BAUM_TR3); 586 baum_send_key(baum, BAUM_RSP_TopKeys, 0); 587 break; 588 case BRLAPI_KEY_CMD_TOP_LEFT: 589 baum_send_key(baum, BAUM_RSP_TopKeys, BAUM_TL2|BAUM_TR1); 590 baum_send_key(baum, BAUM_RSP_TopKeys, 0); 591 break; 592 case BRLAPI_KEY_CMD_BOT_LEFT: 593 baum_send_key(baum, BAUM_RSP_TopKeys, BAUM_TL2|BAUM_TR3); 594 baum_send_key(baum, BAUM_RSP_TopKeys, 0); 595 break; 596 case BRLAPI_KEY_CMD_HOME: 597 baum_send_key(baum, BAUM_RSP_TopKeys, BAUM_TL2|BAUM_TR1|BAUM_TR3); 598 baum_send_key(baum, BAUM_RSP_TopKeys, 0); 599 break; 600 case BRLAPI_KEY_CMD_PREFMENU: 601 baum_send_key(baum, BAUM_RSP_TopKeys, BAUM_TL1|BAUM_TL3|BAUM_TR1); 602 baum_send_key(baum, BAUM_RSP_TopKeys, 0); 603 break; 604 } 605 } 606 break; 607 case BRLAPI_KEY_TYPE_SYM: 608 { 609 brlapi_keyCode_t keysym = code & BRLAPI_KEY_CODE_MASK; 610 if (keysym < 0x100) { 611 uint8_t dots = nabcc_translation[ASCII2DOTS][keysym]; 612 if (dots) { 613 baum_send_key2(baum, BAUM_RSP_EntryKeys, 0, dots); 614 baum_send_key2(baum, BAUM_RSP_EntryKeys, 0, 0); 615 } 616 } 617 break; 618 } 619 } 620 } 621 if (ret == -1 && (brlapi_errno != BRLAPI_ERROR_LIBCERR || errno != EINTR)) { 622 brlapi_perror("baum: brlapi_readKey"); 623 brlapi__closeConnection(baum->brlapi); 624 g_free(baum->brlapi); 625 baum->brlapi = NULL; 626 } 627 } 628 629 static void char_braille_finalize(Object *obj) 630 { 631 BaumChardev *baum = BAUM_CHARDEV(obj); 632 633 timer_free(baum->cellCount_timer); 634 if (baum->brlapi) { 635 brlapi__closeConnection(baum->brlapi); 636 g_free(baum->brlapi); 637 } 638 } 639 640 static void baum_chr_open(Chardev *chr, 641 ChardevBackend *backend, 642 bool *be_opened, 643 Error **errp) 644 { 645 BaumChardev *baum = BAUM_CHARDEV(chr); 646 brlapi_handle_t *handle; 647 648 handle = g_malloc0(brlapi_getHandleSize()); 649 baum->brlapi = handle; 650 651 baum->brlapi_fd = brlapi__openConnection(handle, NULL, NULL); 652 if (baum->brlapi_fd == -1) { 653 error_setg(errp, "brlapi__openConnection: %s", 654 brlapi_strerror(brlapi_error_location())); 655 g_free(handle); 656 baum->brlapi = NULL; 657 return; 658 } 659 baum->deferred_init = 0; 660 661 baum->cellCount_timer = timer_new_ns(QEMU_CLOCK_VIRTUAL, baum_cellCount_timer_cb, baum); 662 663 qemu_set_fd_handler(baum->brlapi_fd, baum_chr_read, NULL, baum); 664 } 665 666 static void char_braille_class_init(ObjectClass *oc, void *data) 667 { 668 ChardevClass *cc = CHARDEV_CLASS(oc); 669 670 cc->open = baum_chr_open; 671 cc->chr_write = baum_chr_write; 672 cc->chr_accept_input = baum_chr_accept_input; 673 } 674 675 static const TypeInfo char_braille_type_info = { 676 .name = TYPE_CHARDEV_BRAILLE, 677 .parent = TYPE_CHARDEV, 678 .instance_size = sizeof(BaumChardev), 679 .instance_finalize = char_braille_finalize, 680 .class_init = char_braille_class_init, 681 }; 682 683 static void register_types(void) 684 { 685 type_register_static(&char_braille_type_info); 686 } 687 688 type_init(register_types); 689