1 /* 2 * QEMU Baum Braille Device 3 * 4 * Copyright (c) 2008, 2010-2011, 2016 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 243 con = qemu_console_lookup_by_index(0); 244 if (con && qemu_console_is_graphic(con)) { 245 tty = qemu_console_get_window_id(con); 246 if (tty == -1) 247 tty = BRLAPI_TTY_DEFAULT; 248 } 249 250 if (brlapi__enterTtyMode(baum->brlapi, tty, NULL) == -1) { 251 brlapi_perror("baum: brlapi__enterTtyMode"); 252 return 0; 253 } 254 baum->deferred_init = 1; 255 return 1; 256 } 257 258 /* The serial port can receive more of our data */ 259 static void baum_chr_accept_input(struct Chardev *chr) 260 { 261 BaumChardev *baum = BAUM_CHARDEV(chr); 262 int room, first; 263 264 if (!baum->out_buf_used) 265 return; 266 room = qemu_chr_be_can_write(chr); 267 if (!room) 268 return; 269 if (room > baum->out_buf_used) 270 room = baum->out_buf_used; 271 272 first = BUF_SIZE - baum->out_buf_ptr; 273 if (room > first) { 274 qemu_chr_be_write(chr, baum->out_buf + baum->out_buf_ptr, first); 275 baum->out_buf_ptr = 0; 276 baum->out_buf_used -= first; 277 room -= first; 278 } 279 qemu_chr_be_write(chr, baum->out_buf + baum->out_buf_ptr, room); 280 baum->out_buf_ptr += room; 281 baum->out_buf_used -= room; 282 } 283 284 /* We want to send a packet */ 285 static void baum_write_packet(BaumChardev *baum, const uint8_t *buf, int len) 286 { 287 Chardev *chr = CHARDEV(baum); 288 uint8_t io_buf[1 + 2 * len], *cur = io_buf; 289 int room; 290 *cur++ = ESC; 291 while (len--) 292 if ((*cur++ = *buf++) == ESC) 293 *cur++ = ESC; 294 room = qemu_chr_be_can_write(chr); 295 len = cur - io_buf; 296 if (len <= room) { 297 /* Fits */ 298 qemu_chr_be_write(chr, io_buf, len); 299 } else { 300 int first; 301 uint8_t out; 302 /* Can't fit all, send what can be, and store the rest. */ 303 qemu_chr_be_write(chr, io_buf, room); 304 len -= room; 305 cur = io_buf + room; 306 if (len > BUF_SIZE - baum->out_buf_used) { 307 /* Can't even store it, drop the previous data... */ 308 assert(len <= BUF_SIZE); 309 baum->out_buf_used = 0; 310 baum->out_buf_ptr = 0; 311 } 312 out = baum->out_buf_ptr; 313 baum->out_buf_used += len; 314 first = BUF_SIZE - baum->out_buf_ptr; 315 if (len > first) { 316 memcpy(baum->out_buf + out, cur, first); 317 out = 0; 318 len -= first; 319 cur += first; 320 } 321 memcpy(baum->out_buf + out, cur, len); 322 } 323 } 324 325 /* Called when the other end seems to have a wrong idea of our display size */ 326 static void baum_cellCount_timer_cb(void *opaque) 327 { 328 BaumChardev *baum = BAUM_CHARDEV(opaque); 329 uint8_t cell_count[] = { BAUM_RSP_CellCount, baum->x * baum->y }; 330 DPRINTF("Timeout waiting for DisplayData, sending cell count\n"); 331 baum_write_packet(baum, cell_count, sizeof(cell_count)); 332 } 333 334 /* Try to interpret a whole incoming packet */ 335 static int baum_eat_packet(BaumChardev *baum, const uint8_t *buf, int len) 336 { 337 const uint8_t *cur = buf; 338 uint8_t req = 0; 339 340 if (!len--) 341 return 0; 342 if (*cur++ != ESC) { 343 while (*cur != ESC) { 344 if (!len--) 345 return 0; 346 cur++; 347 } 348 DPRINTF("Dropped %td bytes!\n", cur - buf); 349 } 350 351 #define EAT(c) do {\ 352 if (!len--) \ 353 return 0; \ 354 if ((c = *cur++) == ESC) { \ 355 if (!len--) \ 356 return 0; \ 357 if (*cur++ != ESC) { \ 358 DPRINTF("Broken packet %#2x, tossing\n", req); \ 359 if (timer_pending(baum->cellCount_timer)) { \ 360 timer_del(baum->cellCount_timer); \ 361 baum_cellCount_timer_cb(baum); \ 362 } \ 363 return (cur - 2 - buf); \ 364 } \ 365 } \ 366 } while (0) 367 368 EAT(req); 369 switch (req) { 370 case BAUM_REQ_DisplayData: 371 { 372 uint8_t cells[baum->x * baum->y], c; 373 uint8_t text[baum->x * baum->y]; 374 uint8_t zero[baum->x * baum->y]; 375 int cursor = BRLAPI_CURSOR_OFF; 376 int i; 377 378 /* Allow 100ms to complete the DisplayData packet */ 379 timer_mod(baum->cellCount_timer, qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) + 380 NANOSECONDS_PER_SECOND / 10); 381 for (i = 0; i < baum->x * baum->y ; i++) { 382 EAT(c); 383 cells[i] = c; 384 if ((c & (BRLAPI_DOT7|BRLAPI_DOT8)) 385 == (BRLAPI_DOT7|BRLAPI_DOT8)) { 386 cursor = i + 1; 387 c &= ~(BRLAPI_DOT7|BRLAPI_DOT8); 388 } 389 c = nabcc_translation[DOTS2ASCII][c]; 390 if (!c) { 391 c = '?'; 392 } 393 text[i] = c; 394 } 395 timer_del(baum->cellCount_timer); 396 397 memset(zero, 0, sizeof(zero)); 398 399 brlapi_writeArguments_t wa = { 400 .displayNumber = BRLAPI_DISPLAY_DEFAULT, 401 .regionBegin = 1, 402 .regionSize = baum->x * baum->y, 403 .text = (char *)text, 404 .textSize = baum->x * baum->y, 405 .andMask = zero, 406 .orMask = cells, 407 .cursor = cursor, 408 .charset = (char *)"ISO-8859-1", 409 }; 410 411 if (brlapi__write(baum->brlapi, &wa) == -1) 412 brlapi_perror("baum brlapi_write"); 413 break; 414 } 415 case BAUM_REQ_SetMode: 416 { 417 uint8_t mode, setting; 418 DPRINTF("SetMode\n"); 419 EAT(mode); 420 EAT(setting); 421 /* ignore */ 422 break; 423 } 424 case BAUM_REQ_SetProtocol: 425 { 426 uint8_t protocol; 427 DPRINTF("SetProtocol\n"); 428 EAT(protocol); 429 /* ignore */ 430 break; 431 } 432 case BAUM_REQ_GetDeviceIdentity: 433 { 434 uint8_t identity[17] = { BAUM_RSP_DeviceIdentity, 435 'B','a','u','m',' ','V','a','r','i','o' }; 436 DPRINTF("GetDeviceIdentity\n"); 437 identity[11] = '0' + baum->x / 10; 438 identity[12] = '0' + baum->x % 10; 439 baum_write_packet(baum, identity, sizeof(identity)); 440 break; 441 } 442 case BAUM_REQ_GetVersionNumber: 443 { 444 uint8_t version[] = { BAUM_RSP_VersionNumber, 1 }; /* ? */ 445 DPRINTF("GetVersionNumber\n"); 446 baum_write_packet(baum, version, sizeof(version)); 447 break; 448 } 449 case BAUM_REQ_GetSerialNumber: 450 { 451 uint8_t serial[] = { BAUM_RSP_SerialNumber, 452 '0','0','0','0','0','0','0','0' }; 453 DPRINTF("GetSerialNumber\n"); 454 baum_write_packet(baum, serial, sizeof(serial)); 455 break; 456 } 457 case BAUM_REQ_GetKeys: 458 { 459 DPRINTF("Get%0#2x\n", req); 460 /* ignore */ 461 break; 462 } 463 default: 464 DPRINTF("unrecognized request %0#2x\n", req); 465 do 466 if (!len--) 467 return 0; 468 while (*cur++ != ESC); 469 cur--; 470 break; 471 } 472 return cur - buf; 473 } 474 475 /* The other end is writing some data. Store it and try to interpret */ 476 static int baum_chr_write(Chardev *chr, const uint8_t *buf, int len) 477 { 478 BaumChardev *baum = BAUM_CHARDEV(chr); 479 int tocopy, cur, eaten, orig_len = len; 480 481 if (!len) 482 return 0; 483 if (!baum->brlapi) 484 return len; 485 if (!baum_deferred_init(baum)) 486 return len; 487 488 while (len) { 489 /* Complete our buffer as much as possible */ 490 tocopy = len; 491 if (tocopy > BUF_SIZE - baum->in_buf_used) 492 tocopy = BUF_SIZE - baum->in_buf_used; 493 494 memcpy(baum->in_buf + baum->in_buf_used, buf, tocopy); 495 baum->in_buf_used += tocopy; 496 buf += tocopy; 497 len -= tocopy; 498 499 /* Interpret it as much as possible */ 500 cur = 0; 501 while (cur < baum->in_buf_used && 502 (eaten = baum_eat_packet(baum, baum->in_buf + cur, baum->in_buf_used - cur))) 503 cur += eaten; 504 505 /* Shift the remainder */ 506 if (cur) { 507 memmove(baum->in_buf, baum->in_buf + cur, baum->in_buf_used - cur); 508 baum->in_buf_used -= cur; 509 } 510 511 /* And continue if any data left */ 512 } 513 return orig_len; 514 } 515 516 /* Send the key code to the other end */ 517 static void baum_send_key(BaumChardev *baum, uint8_t type, uint8_t value) 518 { 519 uint8_t packet[] = { type, value }; 520 DPRINTF("writing key %x %x\n", type, value); 521 baum_write_packet(baum, packet, sizeof(packet)); 522 } 523 524 static void baum_send_key2(BaumChardev *baum, uint8_t type, uint8_t value, 525 uint8_t value2) 526 { 527 uint8_t packet[] = { type, value, value2 }; 528 DPRINTF("writing key %x %x\n", type, value); 529 baum_write_packet(baum, packet, sizeof(packet)); 530 } 531 532 /* We got some data on the BrlAPI socket */ 533 static void baum_chr_read(void *opaque) 534 { 535 BaumChardev *baum = BAUM_CHARDEV(opaque); 536 brlapi_keyCode_t code; 537 int ret; 538 if (!baum->brlapi) 539 return; 540 if (!baum_deferred_init(baum)) 541 return; 542 while ((ret = brlapi__readKey(baum->brlapi, 0, &code)) == 1) { 543 DPRINTF("got key %"BRLAPI_PRIxKEYCODE"\n", code); 544 /* Emulate */ 545 switch (code & BRLAPI_KEY_TYPE_MASK) { 546 case BRLAPI_KEY_TYPE_CMD: 547 switch (code & BRLAPI_KEY_CMD_BLK_MASK) { 548 case BRLAPI_KEY_CMD_ROUTE: 549 baum_send_key(baum, BAUM_RSP_RoutingKey, (code & BRLAPI_KEY_CMD_ARG_MASK)+1); 550 baum_send_key(baum, BAUM_RSP_RoutingKey, 0); 551 break; 552 case 0: 553 switch (code & BRLAPI_KEY_CMD_ARG_MASK) { 554 case BRLAPI_KEY_CMD_FWINLT: 555 baum_send_key(baum, BAUM_RSP_TopKeys, BAUM_TL2); 556 baum_send_key(baum, BAUM_RSP_TopKeys, 0); 557 break; 558 case BRLAPI_KEY_CMD_FWINRT: 559 baum_send_key(baum, BAUM_RSP_TopKeys, BAUM_TR2); 560 baum_send_key(baum, BAUM_RSP_TopKeys, 0); 561 break; 562 case BRLAPI_KEY_CMD_LNUP: 563 baum_send_key(baum, BAUM_RSP_TopKeys, BAUM_TR1); 564 baum_send_key(baum, BAUM_RSP_TopKeys, 0); 565 break; 566 case BRLAPI_KEY_CMD_LNDN: 567 baum_send_key(baum, BAUM_RSP_TopKeys, BAUM_TR3); 568 baum_send_key(baum, BAUM_RSP_TopKeys, 0); 569 break; 570 case BRLAPI_KEY_CMD_TOP: 571 baum_send_key(baum, BAUM_RSP_TopKeys, BAUM_TL1|BAUM_TR1); 572 baum_send_key(baum, BAUM_RSP_TopKeys, 0); 573 break; 574 case BRLAPI_KEY_CMD_BOT: 575 baum_send_key(baum, BAUM_RSP_TopKeys, BAUM_TL3|BAUM_TR3); 576 baum_send_key(baum, BAUM_RSP_TopKeys, 0); 577 break; 578 case BRLAPI_KEY_CMD_TOP_LEFT: 579 baum_send_key(baum, BAUM_RSP_TopKeys, BAUM_TL2|BAUM_TR1); 580 baum_send_key(baum, BAUM_RSP_TopKeys, 0); 581 break; 582 case BRLAPI_KEY_CMD_BOT_LEFT: 583 baum_send_key(baum, BAUM_RSP_TopKeys, BAUM_TL2|BAUM_TR3); 584 baum_send_key(baum, BAUM_RSP_TopKeys, 0); 585 break; 586 case BRLAPI_KEY_CMD_HOME: 587 baum_send_key(baum, BAUM_RSP_TopKeys, BAUM_TL2|BAUM_TR1|BAUM_TR3); 588 baum_send_key(baum, BAUM_RSP_TopKeys, 0); 589 break; 590 case BRLAPI_KEY_CMD_PREFMENU: 591 baum_send_key(baum, BAUM_RSP_TopKeys, BAUM_TL1|BAUM_TL3|BAUM_TR1); 592 baum_send_key(baum, BAUM_RSP_TopKeys, 0); 593 break; 594 } 595 } 596 break; 597 case BRLAPI_KEY_TYPE_SYM: 598 { 599 brlapi_keyCode_t keysym = code & BRLAPI_KEY_CODE_MASK; 600 if (keysym < 0x100) { 601 uint8_t dots = nabcc_translation[ASCII2DOTS][keysym]; 602 if (dots) { 603 baum_send_key2(baum, BAUM_RSP_EntryKeys, 0, dots); 604 baum_send_key2(baum, BAUM_RSP_EntryKeys, 0, 0); 605 } 606 } 607 break; 608 } 609 } 610 } 611 if (ret == -1 && (brlapi_errno != BRLAPI_ERROR_LIBCERR || errno != EINTR)) { 612 brlapi_perror("baum: brlapi_readKey"); 613 brlapi__closeConnection(baum->brlapi); 614 g_free(baum->brlapi); 615 baum->brlapi = NULL; 616 } 617 } 618 619 static void char_braille_finalize(Object *obj) 620 { 621 BaumChardev *baum = BAUM_CHARDEV(obj); 622 623 timer_free(baum->cellCount_timer); 624 if (baum->brlapi) { 625 brlapi__closeConnection(baum->brlapi); 626 g_free(baum->brlapi); 627 } 628 } 629 630 static void baum_chr_open(Chardev *chr, 631 ChardevBackend *backend, 632 bool *be_opened, 633 Error **errp) 634 { 635 BaumChardev *baum = BAUM_CHARDEV(chr); 636 brlapi_handle_t *handle; 637 638 handle = g_malloc0(brlapi_getHandleSize()); 639 baum->brlapi = handle; 640 641 baum->brlapi_fd = brlapi__openConnection(handle, NULL, NULL); 642 if (baum->brlapi_fd == -1) { 643 error_setg(errp, "brlapi__openConnection: %s", 644 brlapi_strerror(brlapi_error_location())); 645 g_free(handle); 646 return; 647 } 648 baum->deferred_init = 0; 649 650 baum->cellCount_timer = timer_new_ns(QEMU_CLOCK_VIRTUAL, baum_cellCount_timer_cb, baum); 651 652 qemu_set_fd_handler(baum->brlapi_fd, baum_chr_read, NULL, baum); 653 } 654 655 static void char_braille_class_init(ObjectClass *oc, void *data) 656 { 657 ChardevClass *cc = CHARDEV_CLASS(oc); 658 659 cc->open = baum_chr_open; 660 cc->chr_write = baum_chr_write; 661 cc->chr_accept_input = baum_chr_accept_input; 662 } 663 664 static const TypeInfo char_braille_type_info = { 665 .name = TYPE_CHARDEV_BRAILLE, 666 .parent = TYPE_CHARDEV, 667 .instance_size = sizeof(BaumChardev), 668 .instance_finalize = char_braille_finalize, 669 .class_init = char_braille_class_init, 670 }; 671 672 static void register_types(void) 673 { 674 type_register_static(&char_braille_type_info); 675 } 676 677 type_init(register_types); 678