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