xref: /qemu/chardev/baum.c (revision 48805df9)
16b10e573SMarc-André Lureau /*
26b10e573SMarc-André Lureau  * QEMU Baum Braille Device
36b10e573SMarc-André Lureau  *
41ef7c96eSSamuel Thibault  * Copyright (c) 2008, 2010-2011, 2016-2017 Samuel Thibault
56b10e573SMarc-André Lureau  *
66b10e573SMarc-André Lureau  * Permission is hereby granted, free of charge, to any person obtaining a copy
76b10e573SMarc-André Lureau  * of this software and associated documentation files (the "Software"), to deal
86b10e573SMarc-André Lureau  * in the Software without restriction, including without limitation the rights
96b10e573SMarc-André Lureau  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
106b10e573SMarc-André Lureau  * copies of the Software, and to permit persons to whom the Software is
116b10e573SMarc-André Lureau  * furnished to do so, subject to the following conditions:
126b10e573SMarc-André Lureau  *
136b10e573SMarc-André Lureau  * The above copyright notice and this permission notice shall be included in
146b10e573SMarc-André Lureau  * all copies or substantial portions of the Software.
156b10e573SMarc-André Lureau  *
166b10e573SMarc-André Lureau  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
176b10e573SMarc-André Lureau  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
186b10e573SMarc-André Lureau  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
196b10e573SMarc-André Lureau  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
206b10e573SMarc-André Lureau  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
216b10e573SMarc-André Lureau  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
226b10e573SMarc-André Lureau  * THE SOFTWARE.
236b10e573SMarc-André Lureau  */
240b8fa32fSMarkus Armbruster 
256b10e573SMarc-André Lureau #include "qemu/osdep.h"
266b10e573SMarc-André Lureau #include "qapi/error.h"
276b10e573SMarc-André Lureau #include "chardev/char.h"
28db725815SMarkus Armbruster #include "qemu/main-loop.h"
290b8fa32fSMarkus Armbruster #include "qemu/module.h"
306b10e573SMarc-André Lureau #include "qemu/timer.h"
316b10e573SMarc-André Lureau #include "hw/usb.h"
326b10e573SMarc-André Lureau #include "ui/console.h"
336b10e573SMarc-André Lureau #include <brlapi.h>
346b10e573SMarc-André Lureau #include <brlapi_constants.h>
356b10e573SMarc-André Lureau #include <brlapi_keycodes.h>
36db1015e9SEduardo Habkost #include "qom/object.h"
376b10e573SMarc-André Lureau 
386b10e573SMarc-André Lureau #if 0
396b10e573SMarc-André Lureau #define DPRINTF(fmt, ...) \
406b10e573SMarc-André Lureau         printf(fmt, ## __VA_ARGS__)
416b10e573SMarc-André Lureau #else
426b10e573SMarc-André Lureau #define DPRINTF(fmt, ...)
436b10e573SMarc-André Lureau #endif
446b10e573SMarc-André Lureau 
456b10e573SMarc-André Lureau #define ESC 0x1B
466b10e573SMarc-André Lureau 
476b10e573SMarc-André Lureau #define BAUM_REQ_DisplayData            0x01
486b10e573SMarc-André Lureau #define BAUM_REQ_GetVersionNumber       0x05
496b10e573SMarc-André Lureau #define BAUM_REQ_GetKeys                0x08
506b10e573SMarc-André Lureau #define BAUM_REQ_SetMode                0x12
516b10e573SMarc-André Lureau #define BAUM_REQ_SetProtocol            0x15
526b10e573SMarc-André Lureau #define BAUM_REQ_GetDeviceIdentity      0x84
536b10e573SMarc-André Lureau #define BAUM_REQ_GetSerialNumber        0x8A
546b10e573SMarc-André Lureau 
556b10e573SMarc-André Lureau #define BAUM_RSP_CellCount              0x01
566b10e573SMarc-André Lureau #define BAUM_RSP_VersionNumber          0x05
576b10e573SMarc-André Lureau #define BAUM_RSP_ModeSetting            0x11
586b10e573SMarc-André Lureau #define BAUM_RSP_CommunicationChannel   0x16
596b10e573SMarc-André Lureau #define BAUM_RSP_PowerdownSignal        0x17
606b10e573SMarc-André Lureau #define BAUM_RSP_HorizontalSensors      0x20
616b10e573SMarc-André Lureau #define BAUM_RSP_VerticalSensors        0x21
626b10e573SMarc-André Lureau #define BAUM_RSP_RoutingKeys            0x22
636b10e573SMarc-André Lureau #define BAUM_RSP_Switches               0x23
646b10e573SMarc-André Lureau #define BAUM_RSP_TopKeys                0x24
656b10e573SMarc-André Lureau #define BAUM_RSP_HorizontalSensor       0x25
666b10e573SMarc-André Lureau #define BAUM_RSP_VerticalSensor         0x26
676b10e573SMarc-André Lureau #define BAUM_RSP_RoutingKey             0x27
686b10e573SMarc-André Lureau #define BAUM_RSP_FrontKeys6             0x28
696b10e573SMarc-André Lureau #define BAUM_RSP_BackKeys6              0x29
706b10e573SMarc-André Lureau #define BAUM_RSP_CommandKeys            0x2B
716b10e573SMarc-André Lureau #define BAUM_RSP_FrontKeys10            0x2C
726b10e573SMarc-André Lureau #define BAUM_RSP_BackKeys10             0x2D
736b10e573SMarc-André Lureau #define BAUM_RSP_EntryKeys              0x33
746b10e573SMarc-André Lureau #define BAUM_RSP_JoyStick               0x34
756b10e573SMarc-André Lureau #define BAUM_RSP_ErrorCode              0x40
766b10e573SMarc-André Lureau #define BAUM_RSP_InfoBlock              0x42
776b10e573SMarc-André Lureau #define BAUM_RSP_DeviceIdentity         0x84
786b10e573SMarc-André Lureau #define BAUM_RSP_SerialNumber           0x8A
796b10e573SMarc-André Lureau #define BAUM_RSP_BluetoothName          0x8C
806b10e573SMarc-André Lureau 
816b10e573SMarc-André Lureau #define BAUM_TL1 0x01
826b10e573SMarc-André Lureau #define BAUM_TL2 0x02
836b10e573SMarc-André Lureau #define BAUM_TL3 0x04
846b10e573SMarc-André Lureau #define BAUM_TR1 0x08
856b10e573SMarc-André Lureau #define BAUM_TR2 0x10
866b10e573SMarc-André Lureau #define BAUM_TR3 0x20
876b10e573SMarc-André Lureau 
886b10e573SMarc-André Lureau #define BUF_SIZE 256
896b10e573SMarc-André Lureau 
90f63a6e38SPhilippe Mathieu-Daudé #define X_MAX   84
91f63a6e38SPhilippe Mathieu-Daudé #define Y_MAX   1
92f63a6e38SPhilippe Mathieu-Daudé 
93db1015e9SEduardo Habkost struct BaumChardev {
946b10e573SMarc-André Lureau     Chardev parent;
956b10e573SMarc-André Lureau 
966b10e573SMarc-André Lureau     brlapi_handle_t *brlapi;
976b10e573SMarc-André Lureau     int brlapi_fd;
986b10e573SMarc-André Lureau     unsigned int x, y;
996b10e573SMarc-André Lureau     bool deferred_init;
1006b10e573SMarc-André Lureau 
1016b10e573SMarc-André Lureau     uint8_t in_buf[BUF_SIZE];
1026b10e573SMarc-André Lureau     uint8_t in_buf_used;
1036b10e573SMarc-André Lureau     uint8_t out_buf[BUF_SIZE];
1046b10e573SMarc-André Lureau     uint8_t out_buf_used, out_buf_ptr;
1056b10e573SMarc-André Lureau 
1066b10e573SMarc-André Lureau     QEMUTimer *cellCount_timer;
107db1015e9SEduardo Habkost };
108db1015e9SEduardo Habkost typedef struct BaumChardev BaumChardev;
1096b10e573SMarc-André Lureau 
1106b10e573SMarc-André Lureau #define TYPE_CHARDEV_BRAILLE "chardev-braille"
1118110fa1dSEduardo Habkost DECLARE_INSTANCE_CHECKER(BaumChardev, BAUM_CHARDEV,
1128110fa1dSEduardo Habkost                          TYPE_CHARDEV_BRAILLE)
1136b10e573SMarc-André Lureau 
1146b10e573SMarc-André Lureau /* Let's assume NABCC by default */
1156b10e573SMarc-André Lureau enum way {
1166b10e573SMarc-André Lureau     DOTS2ASCII,
1176b10e573SMarc-André Lureau     ASCII2DOTS
1186b10e573SMarc-André Lureau };
1196b10e573SMarc-André Lureau static const uint8_t nabcc_translation[2][256] = {
1206b10e573SMarc-André Lureau #ifndef BRLAPI_DOTS
1216b10e573SMarc-André Lureau #define BRLAPI_DOTS(d1,d2,d3,d4,d5,d6,d7,d8) \
1226b10e573SMarc-André Lureau     ((d1?BRLAPI_DOT1:0)|\
1236b10e573SMarc-André Lureau      (d2?BRLAPI_DOT2:0)|\
1246b10e573SMarc-André Lureau      (d3?BRLAPI_DOT3:0)|\
1256b10e573SMarc-André Lureau      (d4?BRLAPI_DOT4:0)|\
1266b10e573SMarc-André Lureau      (d5?BRLAPI_DOT5:0)|\
1276b10e573SMarc-André Lureau      (d6?BRLAPI_DOT6:0)|\
1286b10e573SMarc-André Lureau      (d7?BRLAPI_DOT7:0)|\
1296b10e573SMarc-André Lureau      (d8?BRLAPI_DOT8:0))
1306b10e573SMarc-André Lureau #endif
1316b10e573SMarc-André Lureau #define DO(dots, ascii) \
1326b10e573SMarc-André Lureau     [DOTS2ASCII][dots] = ascii, \
1336b10e573SMarc-André Lureau     [ASCII2DOTS][ascii] = dots
1346b10e573SMarc-André Lureau     DO(0, ' '),
1356b10e573SMarc-André Lureau     DO(BRLAPI_DOTS(1, 0, 0, 0, 0, 0, 0, 0), 'a'),
1366b10e573SMarc-André Lureau     DO(BRLAPI_DOTS(1, 1, 0, 0, 0, 0, 0, 0), 'b'),
1376b10e573SMarc-André Lureau     DO(BRLAPI_DOTS(1, 0, 0, 1, 0, 0, 0, 0), 'c'),
1386b10e573SMarc-André Lureau     DO(BRLAPI_DOTS(1, 0, 0, 1, 1, 0, 0, 0), 'd'),
1396b10e573SMarc-André Lureau     DO(BRLAPI_DOTS(1, 0, 0, 0, 1, 0, 0, 0), 'e'),
1406b10e573SMarc-André Lureau     DO(BRLAPI_DOTS(1, 1, 0, 1, 0, 0, 0, 0), 'f'),
1416b10e573SMarc-André Lureau     DO(BRLAPI_DOTS(1, 1, 0, 1, 1, 0, 0, 0), 'g'),
1426b10e573SMarc-André Lureau     DO(BRLAPI_DOTS(1, 1, 0, 0, 1, 0, 0, 0), 'h'),
1436b10e573SMarc-André Lureau     DO(BRLAPI_DOTS(0, 1, 0, 1, 0, 0, 0, 0), 'i'),
1446b10e573SMarc-André Lureau     DO(BRLAPI_DOTS(0, 1, 0, 1, 1, 0, 0, 0), 'j'),
1456b10e573SMarc-André Lureau     DO(BRLAPI_DOTS(1, 0, 1, 0, 0, 0, 0, 0), 'k'),
1466b10e573SMarc-André Lureau     DO(BRLAPI_DOTS(1, 1, 1, 0, 0, 0, 0, 0), 'l'),
1476b10e573SMarc-André Lureau     DO(BRLAPI_DOTS(1, 0, 1, 1, 0, 0, 0, 0), 'm'),
1486b10e573SMarc-André Lureau     DO(BRLAPI_DOTS(1, 0, 1, 1, 1, 0, 0, 0), 'n'),
1496b10e573SMarc-André Lureau     DO(BRLAPI_DOTS(1, 0, 1, 0, 1, 0, 0, 0), 'o'),
1506b10e573SMarc-André Lureau     DO(BRLAPI_DOTS(1, 1, 1, 1, 0, 0, 0, 0), 'p'),
1516b10e573SMarc-André Lureau     DO(BRLAPI_DOTS(1, 1, 1, 1, 1, 0, 0, 0), 'q'),
1526b10e573SMarc-André Lureau     DO(BRLAPI_DOTS(1, 1, 1, 0, 1, 0, 0, 0), 'r'),
1536b10e573SMarc-André Lureau     DO(BRLAPI_DOTS(0, 1, 1, 1, 0, 0, 0, 0), 's'),
1546b10e573SMarc-André Lureau     DO(BRLAPI_DOTS(0, 1, 1, 1, 1, 0, 0, 0), 't'),
1556b10e573SMarc-André Lureau     DO(BRLAPI_DOTS(1, 0, 1, 0, 0, 1, 0, 0), 'u'),
1566b10e573SMarc-André Lureau     DO(BRLAPI_DOTS(1, 1, 1, 0, 0, 1, 0, 0), 'v'),
1576b10e573SMarc-André Lureau     DO(BRLAPI_DOTS(0, 1, 0, 1, 1, 1, 0, 0), 'w'),
1586b10e573SMarc-André Lureau     DO(BRLAPI_DOTS(1, 0, 1, 1, 0, 1, 0, 0), 'x'),
1596b10e573SMarc-André Lureau     DO(BRLAPI_DOTS(1, 0, 1, 1, 1, 1, 0, 0), 'y'),
1606b10e573SMarc-André Lureau     DO(BRLAPI_DOTS(1, 0, 1, 0, 1, 1, 0, 0), 'z'),
1616b10e573SMarc-André Lureau 
1626b10e573SMarc-André Lureau     DO(BRLAPI_DOTS(1, 0, 0, 0, 0, 0, 1, 0), 'A'),
1636b10e573SMarc-André Lureau     DO(BRLAPI_DOTS(1, 1, 0, 0, 0, 0, 1, 0), 'B'),
1646b10e573SMarc-André Lureau     DO(BRLAPI_DOTS(1, 0, 0, 1, 0, 0, 1, 0), 'C'),
1656b10e573SMarc-André Lureau     DO(BRLAPI_DOTS(1, 0, 0, 1, 1, 0, 1, 0), 'D'),
1666b10e573SMarc-André Lureau     DO(BRLAPI_DOTS(1, 0, 0, 0, 1, 0, 1, 0), 'E'),
1676b10e573SMarc-André Lureau     DO(BRLAPI_DOTS(1, 1, 0, 1, 0, 0, 1, 0), 'F'),
1686b10e573SMarc-André Lureau     DO(BRLAPI_DOTS(1, 1, 0, 1, 1, 0, 1, 0), 'G'),
1696b10e573SMarc-André Lureau     DO(BRLAPI_DOTS(1, 1, 0, 0, 1, 0, 1, 0), 'H'),
1706b10e573SMarc-André Lureau     DO(BRLAPI_DOTS(0, 1, 0, 1, 0, 0, 1, 0), 'I'),
1716b10e573SMarc-André Lureau     DO(BRLAPI_DOTS(0, 1, 0, 1, 1, 0, 1, 0), 'J'),
1726b10e573SMarc-André Lureau     DO(BRLAPI_DOTS(1, 0, 1, 0, 0, 0, 1, 0), 'K'),
1736b10e573SMarc-André Lureau     DO(BRLAPI_DOTS(1, 1, 1, 0, 0, 0, 1, 0), 'L'),
1746b10e573SMarc-André Lureau     DO(BRLAPI_DOTS(1, 0, 1, 1, 0, 0, 1, 0), 'M'),
1756b10e573SMarc-André Lureau     DO(BRLAPI_DOTS(1, 0, 1, 1, 1, 0, 1, 0), 'N'),
1766b10e573SMarc-André Lureau     DO(BRLAPI_DOTS(1, 0, 1, 0, 1, 0, 1, 0), 'O'),
1776b10e573SMarc-André Lureau     DO(BRLAPI_DOTS(1, 1, 1, 1, 0, 0, 1, 0), 'P'),
1786b10e573SMarc-André Lureau     DO(BRLAPI_DOTS(1, 1, 1, 1, 1, 0, 1, 0), 'Q'),
1796b10e573SMarc-André Lureau     DO(BRLAPI_DOTS(1, 1, 1, 0, 1, 0, 1, 0), 'R'),
1806b10e573SMarc-André Lureau     DO(BRLAPI_DOTS(0, 1, 1, 1, 0, 0, 1, 0), 'S'),
1816b10e573SMarc-André Lureau     DO(BRLAPI_DOTS(0, 1, 1, 1, 1, 0, 1, 0), 'T'),
1826b10e573SMarc-André Lureau     DO(BRLAPI_DOTS(1, 0, 1, 0, 0, 1, 1, 0), 'U'),
1836b10e573SMarc-André Lureau     DO(BRLAPI_DOTS(1, 1, 1, 0, 0, 1, 1, 0), 'V'),
1846b10e573SMarc-André Lureau     DO(BRLAPI_DOTS(0, 1, 0, 1, 1, 1, 1, 0), 'W'),
1856b10e573SMarc-André Lureau     DO(BRLAPI_DOTS(1, 0, 1, 1, 0, 1, 1, 0), 'X'),
1866b10e573SMarc-André Lureau     DO(BRLAPI_DOTS(1, 0, 1, 1, 1, 1, 1, 0), 'Y'),
1876b10e573SMarc-André Lureau     DO(BRLAPI_DOTS(1, 0, 1, 0, 1, 1, 1, 0), 'Z'),
1886b10e573SMarc-André Lureau 
1896b10e573SMarc-André Lureau     DO(BRLAPI_DOTS(0, 0, 1, 0, 1, 1, 0, 0), '0'),
1906b10e573SMarc-André Lureau     DO(BRLAPI_DOTS(0, 1, 0, 0, 0, 0, 0, 0), '1'),
1916b10e573SMarc-André Lureau     DO(BRLAPI_DOTS(0, 1, 1, 0, 0, 0, 0, 0), '2'),
1926b10e573SMarc-André Lureau     DO(BRLAPI_DOTS(0, 1, 0, 0, 1, 0, 0, 0), '3'),
1936b10e573SMarc-André Lureau     DO(BRLAPI_DOTS(0, 1, 0, 0, 1, 1, 0, 0), '4'),
1946b10e573SMarc-André Lureau     DO(BRLAPI_DOTS(0, 1, 0, 0, 0, 1, 0, 0), '5'),
1956b10e573SMarc-André Lureau     DO(BRLAPI_DOTS(0, 1, 1, 0, 1, 0, 0, 0), '6'),
1966b10e573SMarc-André Lureau     DO(BRLAPI_DOTS(0, 1, 1, 0, 1, 1, 0, 0), '7'),
1976b10e573SMarc-André Lureau     DO(BRLAPI_DOTS(0, 1, 1, 0, 0, 1, 0, 0), '8'),
1986b10e573SMarc-André Lureau     DO(BRLAPI_DOTS(0, 0, 1, 0, 1, 0, 0, 0), '9'),
1996b10e573SMarc-André Lureau 
2006b10e573SMarc-André Lureau     DO(BRLAPI_DOTS(0, 0, 0, 1, 0, 1, 0, 0), '.'),
2016b10e573SMarc-André Lureau     DO(BRLAPI_DOTS(0, 0, 1, 1, 0, 1, 0, 0), '+'),
2026b10e573SMarc-André Lureau     DO(BRLAPI_DOTS(0, 0, 1, 0, 0, 1, 0, 0), '-'),
2036b10e573SMarc-André Lureau     DO(BRLAPI_DOTS(1, 0, 0, 0, 0, 1, 0, 0), '*'),
2046b10e573SMarc-André Lureau     DO(BRLAPI_DOTS(0, 0, 1, 1, 0, 0, 0, 0), '/'),
2056b10e573SMarc-André Lureau     DO(BRLAPI_DOTS(1, 1, 1, 0, 1, 1, 0, 0), '('),
2066b10e573SMarc-André Lureau     DO(BRLAPI_DOTS(0, 1, 1, 1, 1, 1, 0, 0), ')'),
2076b10e573SMarc-André Lureau 
2086b10e573SMarc-André Lureau     DO(BRLAPI_DOTS(1, 1, 1, 1, 0, 1, 0, 0), '&'),
2096b10e573SMarc-André Lureau     DO(BRLAPI_DOTS(0, 0, 1, 1, 1, 1, 0, 0), '#'),
2106b10e573SMarc-André Lureau 
2116b10e573SMarc-André Lureau     DO(BRLAPI_DOTS(0, 0, 0, 0, 0, 1, 0, 0), ','),
2126b10e573SMarc-André Lureau     DO(BRLAPI_DOTS(0, 0, 0, 0, 1, 1, 0, 0), ';'),
2136b10e573SMarc-André Lureau     DO(BRLAPI_DOTS(1, 0, 0, 0, 1, 1, 0, 0), ':'),
2146b10e573SMarc-André Lureau     DO(BRLAPI_DOTS(0, 1, 1, 1, 0, 1, 0, 0), '!'),
2156b10e573SMarc-André Lureau     DO(BRLAPI_DOTS(1, 0, 0, 1, 1, 1, 0, 0), '?'),
2166b10e573SMarc-André Lureau     DO(BRLAPI_DOTS(0, 0, 0, 0, 1, 0, 0, 0), '"'),
2176b10e573SMarc-André Lureau     DO(BRLAPI_DOTS(0, 0, 1, 0, 0, 0, 0, 0), '\''),
2186b10e573SMarc-André Lureau     DO(BRLAPI_DOTS(0, 0, 0, 1, 0, 0, 0, 0), '`'),
2196b10e573SMarc-André Lureau     DO(BRLAPI_DOTS(0, 0, 0, 1, 1, 0, 1, 0), '^'),
2206b10e573SMarc-André Lureau     DO(BRLAPI_DOTS(0, 0, 0, 1, 1, 0, 0, 0), '~'),
2216b10e573SMarc-André Lureau     DO(BRLAPI_DOTS(0, 1, 0, 1, 0, 1, 1, 0), '['),
2226b10e573SMarc-André Lureau     DO(BRLAPI_DOTS(1, 1, 0, 1, 1, 1, 1, 0), ']'),
2236b10e573SMarc-André Lureau     DO(BRLAPI_DOTS(0, 1, 0, 1, 0, 1, 0, 0), '{'),
2246b10e573SMarc-André Lureau     DO(BRLAPI_DOTS(1, 1, 0, 1, 1, 1, 0, 0), '}'),
2256b10e573SMarc-André Lureau     DO(BRLAPI_DOTS(1, 1, 1, 1, 1, 1, 0, 0), '='),
2266b10e573SMarc-André Lureau     DO(BRLAPI_DOTS(1, 1, 0, 0, 0, 1, 0, 0), '<'),
2276b10e573SMarc-André Lureau     DO(BRLAPI_DOTS(0, 0, 1, 1, 1, 0, 0, 0), '>'),
2286b10e573SMarc-André Lureau     DO(BRLAPI_DOTS(1, 1, 0, 1, 0, 1, 0, 0), '$'),
2296b10e573SMarc-André Lureau     DO(BRLAPI_DOTS(1, 0, 0, 1, 0, 1, 0, 0), '%'),
2306b10e573SMarc-André Lureau     DO(BRLAPI_DOTS(0, 0, 0, 1, 0, 0, 1, 0), '@'),
2316b10e573SMarc-André Lureau     DO(BRLAPI_DOTS(1, 1, 0, 0, 1, 1, 0, 0), '|'),
2326b10e573SMarc-André Lureau     DO(BRLAPI_DOTS(1, 1, 0, 0, 1, 1, 1, 0), '\\'),
2336b10e573SMarc-André Lureau     DO(BRLAPI_DOTS(0, 0, 0, 1, 1, 1, 0, 0), '_'),
2346b10e573SMarc-André Lureau };
2356b10e573SMarc-André Lureau 
2366b10e573SMarc-André Lureau /* The guest OS has started discussing with us, finish initializing BrlAPI */
baum_deferred_init(BaumChardev * baum)2376b10e573SMarc-André Lureau static int baum_deferred_init(BaumChardev *baum)
2386b10e573SMarc-André Lureau {
2396b10e573SMarc-André Lureau     int tty = BRLAPI_TTY_DEFAULT;
2406b10e573SMarc-André Lureau     QemuConsole *con;
2416b10e573SMarc-André Lureau 
2426b10e573SMarc-André Lureau     if (baum->deferred_init) {
2436b10e573SMarc-André Lureau         return 1;
2446b10e573SMarc-André Lureau     }
2456b10e573SMarc-André Lureau 
2466b10e573SMarc-André Lureau     if (brlapi__getDisplaySize(baum->brlapi, &baum->x, &baum->y) == -1) {
2476b10e573SMarc-André Lureau         brlapi_perror("baum: brlapi__getDisplaySize");
2486b10e573SMarc-André Lureau         return 0;
2496b10e573SMarc-André Lureau     }
250f63a6e38SPhilippe Mathieu-Daudé     if (baum->y > Y_MAX) {
251f63a6e38SPhilippe Mathieu-Daudé         baum->y = Y_MAX;
2521ef7c96eSSamuel Thibault     }
253f63a6e38SPhilippe Mathieu-Daudé     if (baum->x > X_MAX) {
254f63a6e38SPhilippe Mathieu-Daudé         baum->x = X_MAX;
2551ef7c96eSSamuel Thibault     }
2566b10e573SMarc-André Lureau 
2576b10e573SMarc-André Lureau     con = qemu_console_lookup_by_index(0);
2586b10e573SMarc-André Lureau     if (con && qemu_console_is_graphic(con)) {
2596b10e573SMarc-André Lureau         tty = qemu_console_get_window_id(con);
2606b10e573SMarc-André Lureau         if (tty == -1)
2616b10e573SMarc-André Lureau             tty = BRLAPI_TTY_DEFAULT;
2626b10e573SMarc-André Lureau     }
2636b10e573SMarc-André Lureau 
2646b10e573SMarc-André Lureau     if (brlapi__enterTtyMode(baum->brlapi, tty, NULL) == -1) {
2656b10e573SMarc-André Lureau         brlapi_perror("baum: brlapi__enterTtyMode");
2666b10e573SMarc-André Lureau         return 0;
2676b10e573SMarc-André Lureau     }
2686b10e573SMarc-André Lureau     baum->deferred_init = 1;
2696b10e573SMarc-André Lureau     return 1;
2706b10e573SMarc-André Lureau }
2716b10e573SMarc-André Lureau 
2726b10e573SMarc-André Lureau /* The serial port can receive more of our data */
baum_chr_accept_input(struct Chardev * chr)2736b10e573SMarc-André Lureau static void baum_chr_accept_input(struct Chardev *chr)
2746b10e573SMarc-André Lureau {
2756b10e573SMarc-André Lureau     BaumChardev *baum = BAUM_CHARDEV(chr);
2766b10e573SMarc-André Lureau     int room, first;
2776b10e573SMarc-André Lureau 
2786b10e573SMarc-André Lureau     if (!baum->out_buf_used)
2796b10e573SMarc-André Lureau         return;
2806b10e573SMarc-André Lureau     room = qemu_chr_be_can_write(chr);
2816b10e573SMarc-André Lureau     if (!room)
2826b10e573SMarc-André Lureau         return;
2836b10e573SMarc-André Lureau     if (room > baum->out_buf_used)
2846b10e573SMarc-André Lureau         room = baum->out_buf_used;
2856b10e573SMarc-André Lureau 
2866b10e573SMarc-André Lureau     first = BUF_SIZE - baum->out_buf_ptr;
2876b10e573SMarc-André Lureau     if (room > first) {
2886b10e573SMarc-André Lureau         qemu_chr_be_write(chr, baum->out_buf + baum->out_buf_ptr, first);
2896b10e573SMarc-André Lureau         baum->out_buf_ptr = 0;
2906b10e573SMarc-André Lureau         baum->out_buf_used -= first;
2916b10e573SMarc-André Lureau         room -= first;
2926b10e573SMarc-André Lureau     }
2936b10e573SMarc-André Lureau     qemu_chr_be_write(chr, baum->out_buf + baum->out_buf_ptr, room);
2946b10e573SMarc-André Lureau     baum->out_buf_ptr += room;
2956b10e573SMarc-André Lureau     baum->out_buf_used -= room;
2966b10e573SMarc-André Lureau }
2976b10e573SMarc-André Lureau 
2986b10e573SMarc-André Lureau /* We want to send a packet */
baum_write_packet(BaumChardev * baum,const uint8_t * buf,int len)2996b10e573SMarc-André Lureau static void baum_write_packet(BaumChardev *baum, const uint8_t *buf, int len)
3006b10e573SMarc-André Lureau {
3016b10e573SMarc-André Lureau     Chardev *chr = CHARDEV(baum);
302d34977d6SPhilippe Mathieu-Daudé     g_autofree uint8_t *io_buf = g_malloc(1 + 2 * len);
303d34977d6SPhilippe Mathieu-Daudé     uint8_t *cur = io_buf;
3046b10e573SMarc-André Lureau     int room;
3056b10e573SMarc-André Lureau     *cur++ = ESC;
3066b10e573SMarc-André Lureau     while (len--)
3076b10e573SMarc-André Lureau         if ((*cur++ = *buf++) == ESC)
3086b10e573SMarc-André Lureau             *cur++ = ESC;
3096b10e573SMarc-André Lureau     room = qemu_chr_be_can_write(chr);
3106b10e573SMarc-André Lureau     len = cur - io_buf;
3116b10e573SMarc-André Lureau     if (len <= room) {
3126b10e573SMarc-André Lureau         /* Fits */
3136b10e573SMarc-André Lureau         qemu_chr_be_write(chr, io_buf, len);
3146b10e573SMarc-André Lureau     } else {
3156b10e573SMarc-André Lureau         int first;
3166b10e573SMarc-André Lureau         uint8_t out;
3176b10e573SMarc-André Lureau         /* Can't fit all, send what can be, and store the rest. */
3186b10e573SMarc-André Lureau         qemu_chr_be_write(chr, io_buf, room);
3196b10e573SMarc-André Lureau         len -= room;
3206b10e573SMarc-André Lureau         cur = io_buf + room;
3216b10e573SMarc-André Lureau         if (len > BUF_SIZE - baum->out_buf_used) {
3226b10e573SMarc-André Lureau             /* Can't even store it, drop the previous data... */
3236b10e573SMarc-André Lureau             assert(len <= BUF_SIZE);
3246b10e573SMarc-André Lureau             baum->out_buf_used = 0;
3256b10e573SMarc-André Lureau             baum->out_buf_ptr = 0;
3266b10e573SMarc-André Lureau         }
3276b10e573SMarc-André Lureau         out = baum->out_buf_ptr;
3286b10e573SMarc-André Lureau         baum->out_buf_used += len;
3296b10e573SMarc-André Lureau         first = BUF_SIZE - baum->out_buf_ptr;
3306b10e573SMarc-André Lureau         if (len > first) {
3316b10e573SMarc-André Lureau             memcpy(baum->out_buf + out, cur, first);
3326b10e573SMarc-André Lureau             out = 0;
3336b10e573SMarc-André Lureau             len -= first;
3346b10e573SMarc-André Lureau             cur += first;
3356b10e573SMarc-André Lureau         }
3366b10e573SMarc-André Lureau         memcpy(baum->out_buf + out, cur, len);
3376b10e573SMarc-André Lureau     }
3386b10e573SMarc-André Lureau }
3396b10e573SMarc-André Lureau 
3406b10e573SMarc-André Lureau /* Called when the other end seems to have a wrong idea of our display size */
baum_cellCount_timer_cb(void * opaque)3416b10e573SMarc-André Lureau static void baum_cellCount_timer_cb(void *opaque)
3426b10e573SMarc-André Lureau {
3436b10e573SMarc-André Lureau     BaumChardev *baum = BAUM_CHARDEV(opaque);
3446b10e573SMarc-André Lureau     uint8_t cell_count[] = { BAUM_RSP_CellCount, baum->x * baum->y };
3456b10e573SMarc-André Lureau     DPRINTF("Timeout waiting for DisplayData, sending cell count\n");
3466b10e573SMarc-André Lureau     baum_write_packet(baum, cell_count, sizeof(cell_count));
3476b10e573SMarc-André Lureau }
3486b10e573SMarc-André Lureau 
3496b10e573SMarc-André Lureau /* Try to interpret a whole incoming packet */
baum_eat_packet(BaumChardev * baum,const uint8_t * buf,int len)3506b10e573SMarc-André Lureau static int baum_eat_packet(BaumChardev *baum, const uint8_t *buf, int len)
3516b10e573SMarc-André Lureau {
3526b10e573SMarc-André Lureau     const uint8_t *cur = buf;
3536b10e573SMarc-André Lureau     uint8_t req = 0;
3546b10e573SMarc-André Lureau 
3556b10e573SMarc-André Lureau     if (!len--)
3566b10e573SMarc-André Lureau         return 0;
3576b10e573SMarc-André Lureau     if (*cur++ != ESC) {
3586b10e573SMarc-André Lureau         while (*cur != ESC) {
3596b10e573SMarc-André Lureau             if (!len--)
3606b10e573SMarc-André Lureau                 return 0;
3616b10e573SMarc-André Lureau             cur++;
3626b10e573SMarc-André Lureau         }
3636b10e573SMarc-André Lureau         DPRINTF("Dropped %td bytes!\n", cur - buf);
3646b10e573SMarc-André Lureau     }
3656b10e573SMarc-André Lureau 
3666b10e573SMarc-André Lureau #define EAT(c) do {\
3676b10e573SMarc-André Lureau     if (!len--) \
3686b10e573SMarc-André Lureau         return 0; \
3696b10e573SMarc-André Lureau     if ((c = *cur++) == ESC) { \
3706b10e573SMarc-André Lureau         if (!len--) \
3716b10e573SMarc-André Lureau             return 0; \
3726b10e573SMarc-André Lureau         if (*cur++ != ESC) { \
3736b10e573SMarc-André Lureau             DPRINTF("Broken packet %#2x, tossing\n", req); \
3746b10e573SMarc-André Lureau             if (timer_pending(baum->cellCount_timer)) {    \
3756b10e573SMarc-André Lureau                 timer_del(baum->cellCount_timer);     \
3766b10e573SMarc-André Lureau                 baum_cellCount_timer_cb(baum);             \
3776b10e573SMarc-André Lureau             } \
3786b10e573SMarc-André Lureau             return (cur - 2 - buf); \
3796b10e573SMarc-André Lureau         } \
3806b10e573SMarc-André Lureau     } \
3816b10e573SMarc-André Lureau } while (0)
3826b10e573SMarc-André Lureau 
3836b10e573SMarc-André Lureau     EAT(req);
3846b10e573SMarc-André Lureau     switch (req) {
3856b10e573SMarc-André Lureau     case BAUM_REQ_DisplayData:
3866b10e573SMarc-André Lureau     {
3871e3acd33SPhilippe Mathieu-Daudé         uint8_t cells[X_MAX * Y_MAX], c;
3881e3acd33SPhilippe Mathieu-Daudé         uint8_t text[X_MAX * Y_MAX];
3891e3acd33SPhilippe Mathieu-Daudé         uint8_t zero[X_MAX * Y_MAX];
3906b10e573SMarc-André Lureau         int cursor = BRLAPI_CURSOR_OFF;
3916b10e573SMarc-André Lureau         int i;
3926b10e573SMarc-André Lureau 
3936b10e573SMarc-André Lureau         /* Allow 100ms to complete the DisplayData packet */
3946b10e573SMarc-André Lureau         timer_mod(baum->cellCount_timer, qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) +
3956b10e573SMarc-André Lureau                        NANOSECONDS_PER_SECOND / 10);
3966b10e573SMarc-André Lureau         for (i = 0; i < baum->x * baum->y ; i++) {
3976b10e573SMarc-André Lureau             EAT(c);
3986b10e573SMarc-André Lureau             cells[i] = c;
3996b10e573SMarc-André Lureau             if ((c & (BRLAPI_DOT7|BRLAPI_DOT8))
4006b10e573SMarc-André Lureau                     == (BRLAPI_DOT7|BRLAPI_DOT8)) {
4016b10e573SMarc-André Lureau                 cursor = i + 1;
4026b10e573SMarc-André Lureau                 c &= ~(BRLAPI_DOT7|BRLAPI_DOT8);
4036b10e573SMarc-André Lureau             }
4046b10e573SMarc-André Lureau             c = nabcc_translation[DOTS2ASCII][c];
4056b10e573SMarc-André Lureau             if (!c) {
4066b10e573SMarc-André Lureau                 c = '?';
4076b10e573SMarc-André Lureau             }
4086b10e573SMarc-André Lureau             text[i] = c;
4096b10e573SMarc-André Lureau         }
4106b10e573SMarc-André Lureau         timer_del(baum->cellCount_timer);
4116b10e573SMarc-André Lureau 
4121e3acd33SPhilippe Mathieu-Daudé         memset(zero, 0, baum->x * baum->y);
4136b10e573SMarc-André Lureau 
4146b10e573SMarc-André Lureau         brlapi_writeArguments_t wa = {
4156b10e573SMarc-André Lureau             .displayNumber = BRLAPI_DISPLAY_DEFAULT,
4166b10e573SMarc-André Lureau             .regionBegin = 1,
4176b10e573SMarc-André Lureau             .regionSize = baum->x * baum->y,
4186b10e573SMarc-André Lureau             .text = (char *)text,
4196b10e573SMarc-André Lureau             .textSize = baum->x * baum->y,
4206b10e573SMarc-André Lureau             .andMask = zero,
4216b10e573SMarc-André Lureau             .orMask = cells,
4226b10e573SMarc-André Lureau             .cursor = cursor,
4236b10e573SMarc-André Lureau             .charset = (char *)"ISO-8859-1",
4246b10e573SMarc-André Lureau         };
4256b10e573SMarc-André Lureau 
4266b10e573SMarc-André Lureau         if (brlapi__write(baum->brlapi, &wa) == -1)
4276b10e573SMarc-André Lureau             brlapi_perror("baum brlapi_write");
4286b10e573SMarc-André Lureau         break;
4296b10e573SMarc-André Lureau     }
4306b10e573SMarc-André Lureau     case BAUM_REQ_SetMode:
4316b10e573SMarc-André Lureau     {
4326b10e573SMarc-André Lureau         uint8_t mode, setting;
4336b10e573SMarc-André Lureau         DPRINTF("SetMode\n");
4346b10e573SMarc-André Lureau         EAT(mode);
4356b10e573SMarc-André Lureau         EAT(setting);
4366b10e573SMarc-André Lureau         /* ignore */
4376b10e573SMarc-André Lureau         break;
4386b10e573SMarc-André Lureau     }
4396b10e573SMarc-André Lureau     case BAUM_REQ_SetProtocol:
4406b10e573SMarc-André Lureau     {
4416b10e573SMarc-André Lureau         uint8_t protocol;
4426b10e573SMarc-André Lureau         DPRINTF("SetProtocol\n");
4436b10e573SMarc-André Lureau         EAT(protocol);
4446b10e573SMarc-André Lureau         /* ignore */
4456b10e573SMarc-André Lureau         break;
4466b10e573SMarc-André Lureau     }
4476b10e573SMarc-André Lureau     case BAUM_REQ_GetDeviceIdentity:
4486b10e573SMarc-André Lureau     {
4496b10e573SMarc-André Lureau         uint8_t identity[17] = { BAUM_RSP_DeviceIdentity,
4506b10e573SMarc-André Lureau             'B','a','u','m',' ','V','a','r','i','o' };
4516b10e573SMarc-André Lureau         DPRINTF("GetDeviceIdentity\n");
4526b10e573SMarc-André Lureau         identity[11] = '0' + baum->x / 10;
4536b10e573SMarc-André Lureau         identity[12] = '0' + baum->x % 10;
4546b10e573SMarc-André Lureau         baum_write_packet(baum, identity, sizeof(identity));
4556b10e573SMarc-André Lureau         break;
4566b10e573SMarc-André Lureau     }
4576b10e573SMarc-André Lureau     case BAUM_REQ_GetVersionNumber:
4586b10e573SMarc-André Lureau     {
4596b10e573SMarc-André Lureau         uint8_t version[] = { BAUM_RSP_VersionNumber, 1 }; /* ? */
4606b10e573SMarc-André Lureau         DPRINTF("GetVersionNumber\n");
4616b10e573SMarc-André Lureau         baum_write_packet(baum, version, sizeof(version));
4626b10e573SMarc-André Lureau         break;
4636b10e573SMarc-André Lureau     }
4646b10e573SMarc-André Lureau     case BAUM_REQ_GetSerialNumber:
4656b10e573SMarc-André Lureau     {
4666b10e573SMarc-André Lureau         uint8_t serial[] = { BAUM_RSP_SerialNumber,
4676b10e573SMarc-André Lureau             '0','0','0','0','0','0','0','0' };
4686b10e573SMarc-André Lureau         DPRINTF("GetSerialNumber\n");
4696b10e573SMarc-André Lureau         baum_write_packet(baum, serial, sizeof(serial));
4706b10e573SMarc-André Lureau         break;
4716b10e573SMarc-André Lureau     }
4726b10e573SMarc-André Lureau     case BAUM_REQ_GetKeys:
4736b10e573SMarc-André Lureau     {
4746b10e573SMarc-André Lureau         DPRINTF("Get%0#2x\n", req);
4756b10e573SMarc-André Lureau         /* ignore */
4766b10e573SMarc-André Lureau         break;
4776b10e573SMarc-André Lureau     }
4786b10e573SMarc-André Lureau     default:
4796b10e573SMarc-André Lureau         DPRINTF("unrecognized request %0#2x\n", req);
4806b10e573SMarc-André Lureau         do
4816b10e573SMarc-André Lureau             if (!len--)
4826b10e573SMarc-André Lureau                 return 0;
4836b10e573SMarc-André Lureau         while (*cur++ != ESC);
4846b10e573SMarc-André Lureau         cur--;
4856b10e573SMarc-André Lureau         break;
4866b10e573SMarc-André Lureau     }
4876b10e573SMarc-André Lureau     return cur - buf;
4886b10e573SMarc-André Lureau }
4896b10e573SMarc-André Lureau 
4906b10e573SMarc-André Lureau /* The other end is writing some data.  Store it and try to interpret */
baum_chr_write(Chardev * chr,const uint8_t * buf,int len)4916b10e573SMarc-André Lureau static int baum_chr_write(Chardev *chr, const uint8_t *buf, int len)
4926b10e573SMarc-André Lureau {
4936b10e573SMarc-André Lureau     BaumChardev *baum = BAUM_CHARDEV(chr);
4946b10e573SMarc-André Lureau     int tocopy, cur, eaten, orig_len = len;
4956b10e573SMarc-André Lureau 
4966b10e573SMarc-André Lureau     if (!len)
4976b10e573SMarc-André Lureau         return 0;
4986b10e573SMarc-André Lureau     if (!baum->brlapi)
4996b10e573SMarc-André Lureau         return len;
5006b10e573SMarc-André Lureau     if (!baum_deferred_init(baum))
5016b10e573SMarc-André Lureau         return len;
5026b10e573SMarc-André Lureau 
5036b10e573SMarc-André Lureau     while (len) {
5046b10e573SMarc-André Lureau         /* Complete our buffer as much as possible */
5056b10e573SMarc-André Lureau         tocopy = len;
5066b10e573SMarc-André Lureau         if (tocopy > BUF_SIZE - baum->in_buf_used)
5076b10e573SMarc-André Lureau             tocopy = BUF_SIZE - baum->in_buf_used;
5086b10e573SMarc-André Lureau 
5096b10e573SMarc-André Lureau         memcpy(baum->in_buf + baum->in_buf_used, buf, tocopy);
5106b10e573SMarc-André Lureau         baum->in_buf_used += tocopy;
5116b10e573SMarc-André Lureau         buf += tocopy;
5126b10e573SMarc-André Lureau         len -= tocopy;
5136b10e573SMarc-André Lureau 
5146b10e573SMarc-André Lureau         /* Interpret it as much as possible */
5156b10e573SMarc-André Lureau         cur = 0;
5166b10e573SMarc-André Lureau         while (cur < baum->in_buf_used &&
5176b10e573SMarc-André Lureau                 (eaten = baum_eat_packet(baum, baum->in_buf + cur, baum->in_buf_used - cur)))
5186b10e573SMarc-André Lureau             cur += eaten;
5196b10e573SMarc-André Lureau 
5206b10e573SMarc-André Lureau         /* Shift the remainder */
5216b10e573SMarc-André Lureau         if (cur) {
5226b10e573SMarc-André Lureau             memmove(baum->in_buf, baum->in_buf + cur, baum->in_buf_used - cur);
5236b10e573SMarc-André Lureau             baum->in_buf_used -= cur;
5246b10e573SMarc-André Lureau         }
5256b10e573SMarc-André Lureau 
5266b10e573SMarc-André Lureau         /* And continue if any data left */
5276b10e573SMarc-André Lureau     }
5286b10e573SMarc-André Lureau     return orig_len;
5296b10e573SMarc-André Lureau }
5306b10e573SMarc-André Lureau 
5316b10e573SMarc-André Lureau /* Send the key code to the other end */
baum_send_key(BaumChardev * baum,uint8_t type,uint8_t value)5326b10e573SMarc-André Lureau static void baum_send_key(BaumChardev *baum, uint8_t type, uint8_t value)
5336b10e573SMarc-André Lureau {
5346b10e573SMarc-André Lureau     uint8_t packet[] = { type, value };
5356b10e573SMarc-André Lureau     DPRINTF("writing key %x %x\n", type, value);
5366b10e573SMarc-André Lureau     baum_write_packet(baum, packet, sizeof(packet));
5376b10e573SMarc-André Lureau }
5386b10e573SMarc-André Lureau 
baum_send_key2(BaumChardev * baum,uint8_t type,uint8_t value,uint8_t value2)5396b10e573SMarc-André Lureau static void baum_send_key2(BaumChardev *baum, uint8_t type, uint8_t value,
5406b10e573SMarc-André Lureau                            uint8_t value2)
5416b10e573SMarc-André Lureau {
5426b10e573SMarc-André Lureau     uint8_t packet[] = { type, value, value2 };
5436b10e573SMarc-André Lureau     DPRINTF("writing key %x %x\n", type, value);
5446b10e573SMarc-André Lureau     baum_write_packet(baum, packet, sizeof(packet));
5456b10e573SMarc-André Lureau }
5466b10e573SMarc-André Lureau 
5476b10e573SMarc-André Lureau /* We got some data on the BrlAPI socket */
baum_chr_read(void * opaque)5486b10e573SMarc-André Lureau static void baum_chr_read(void *opaque)
5496b10e573SMarc-André Lureau {
5506b10e573SMarc-André Lureau     BaumChardev *baum = BAUM_CHARDEV(opaque);
5516b10e573SMarc-André Lureau     brlapi_keyCode_t code;
5526b10e573SMarc-André Lureau     int ret;
5536b10e573SMarc-André Lureau     if (!baum->brlapi)
5546b10e573SMarc-André Lureau         return;
5556b10e573SMarc-André Lureau     if (!baum_deferred_init(baum))
5566b10e573SMarc-André Lureau         return;
5576b10e573SMarc-André Lureau     while ((ret = brlapi__readKey(baum->brlapi, 0, &code)) == 1) {
5586b10e573SMarc-André Lureau         DPRINTF("got key %"BRLAPI_PRIxKEYCODE"\n", code);
5596b10e573SMarc-André Lureau         /* Emulate */
5606b10e573SMarc-André Lureau         switch (code & BRLAPI_KEY_TYPE_MASK) {
5616b10e573SMarc-André Lureau         case BRLAPI_KEY_TYPE_CMD:
5626b10e573SMarc-André Lureau             switch (code & BRLAPI_KEY_CMD_BLK_MASK) {
5636b10e573SMarc-André Lureau             case BRLAPI_KEY_CMD_ROUTE:
5646b10e573SMarc-André Lureau                 baum_send_key(baum, BAUM_RSP_RoutingKey, (code & BRLAPI_KEY_CMD_ARG_MASK)+1);
5656b10e573SMarc-André Lureau                 baum_send_key(baum, BAUM_RSP_RoutingKey, 0);
5666b10e573SMarc-André Lureau                 break;
5676b10e573SMarc-André Lureau             case 0:
5686b10e573SMarc-André Lureau                 switch (code & BRLAPI_KEY_CMD_ARG_MASK) {
5696b10e573SMarc-André Lureau                 case BRLAPI_KEY_CMD_FWINLT:
5706b10e573SMarc-André Lureau                     baum_send_key(baum, BAUM_RSP_TopKeys, BAUM_TL2);
5716b10e573SMarc-André Lureau                     baum_send_key(baum, BAUM_RSP_TopKeys, 0);
5726b10e573SMarc-André Lureau                     break;
5736b10e573SMarc-André Lureau                 case BRLAPI_KEY_CMD_FWINRT:
5746b10e573SMarc-André Lureau                     baum_send_key(baum, BAUM_RSP_TopKeys, BAUM_TR2);
5756b10e573SMarc-André Lureau                     baum_send_key(baum, BAUM_RSP_TopKeys, 0);
5766b10e573SMarc-André Lureau                     break;
5776b10e573SMarc-André Lureau                 case BRLAPI_KEY_CMD_LNUP:
5786b10e573SMarc-André Lureau                     baum_send_key(baum, BAUM_RSP_TopKeys, BAUM_TR1);
5796b10e573SMarc-André Lureau                     baum_send_key(baum, BAUM_RSP_TopKeys, 0);
5806b10e573SMarc-André Lureau                     break;
5816b10e573SMarc-André Lureau                 case BRLAPI_KEY_CMD_LNDN:
5826b10e573SMarc-André Lureau                     baum_send_key(baum, BAUM_RSP_TopKeys, BAUM_TR3);
5836b10e573SMarc-André Lureau                     baum_send_key(baum, BAUM_RSP_TopKeys, 0);
5846b10e573SMarc-André Lureau                     break;
5856b10e573SMarc-André Lureau                 case BRLAPI_KEY_CMD_TOP:
5866b10e573SMarc-André Lureau                     baum_send_key(baum, BAUM_RSP_TopKeys, BAUM_TL1|BAUM_TR1);
5876b10e573SMarc-André Lureau                     baum_send_key(baum, BAUM_RSP_TopKeys, 0);
5886b10e573SMarc-André Lureau                     break;
5896b10e573SMarc-André Lureau                 case BRLAPI_KEY_CMD_BOT:
5906b10e573SMarc-André Lureau                     baum_send_key(baum, BAUM_RSP_TopKeys, BAUM_TL3|BAUM_TR3);
5916b10e573SMarc-André Lureau                     baum_send_key(baum, BAUM_RSP_TopKeys, 0);
5926b10e573SMarc-André Lureau                     break;
5936b10e573SMarc-André Lureau                 case BRLAPI_KEY_CMD_TOP_LEFT:
5946b10e573SMarc-André Lureau                     baum_send_key(baum, BAUM_RSP_TopKeys, BAUM_TL2|BAUM_TR1);
5956b10e573SMarc-André Lureau                     baum_send_key(baum, BAUM_RSP_TopKeys, 0);
5966b10e573SMarc-André Lureau                     break;
5976b10e573SMarc-André Lureau                 case BRLAPI_KEY_CMD_BOT_LEFT:
5986b10e573SMarc-André Lureau                     baum_send_key(baum, BAUM_RSP_TopKeys, BAUM_TL2|BAUM_TR3);
5996b10e573SMarc-André Lureau                     baum_send_key(baum, BAUM_RSP_TopKeys, 0);
6006b10e573SMarc-André Lureau                     break;
6016b10e573SMarc-André Lureau                 case BRLAPI_KEY_CMD_HOME:
6026b10e573SMarc-André Lureau                     baum_send_key(baum, BAUM_RSP_TopKeys, BAUM_TL2|BAUM_TR1|BAUM_TR3);
6036b10e573SMarc-André Lureau                     baum_send_key(baum, BAUM_RSP_TopKeys, 0);
6046b10e573SMarc-André Lureau                     break;
6056b10e573SMarc-André Lureau                 case BRLAPI_KEY_CMD_PREFMENU:
6066b10e573SMarc-André Lureau                     baum_send_key(baum, BAUM_RSP_TopKeys, BAUM_TL1|BAUM_TL3|BAUM_TR1);
6076b10e573SMarc-André Lureau                     baum_send_key(baum, BAUM_RSP_TopKeys, 0);
6086b10e573SMarc-André Lureau                     break;
6096b10e573SMarc-André Lureau                 }
6106b10e573SMarc-André Lureau             }
6116b10e573SMarc-André Lureau             break;
6126b10e573SMarc-André Lureau         case BRLAPI_KEY_TYPE_SYM:
6136b10e573SMarc-André Lureau             {
6146b10e573SMarc-André Lureau                 brlapi_keyCode_t keysym = code & BRLAPI_KEY_CODE_MASK;
6156b10e573SMarc-André Lureau                 if (keysym < 0x100) {
6166b10e573SMarc-André Lureau                     uint8_t dots = nabcc_translation[ASCII2DOTS][keysym];
6176b10e573SMarc-André Lureau                     if (dots) {
6186b10e573SMarc-André Lureau                         baum_send_key2(baum, BAUM_RSP_EntryKeys, 0, dots);
6196b10e573SMarc-André Lureau                         baum_send_key2(baum, BAUM_RSP_EntryKeys, 0, 0);
6206b10e573SMarc-André Lureau                     }
6216b10e573SMarc-André Lureau                 }
6226b10e573SMarc-André Lureau                 break;
6236b10e573SMarc-André Lureau             }
6246b10e573SMarc-André Lureau         }
6256b10e573SMarc-André Lureau     }
6266b10e573SMarc-André Lureau     if (ret == -1 && (brlapi_errno != BRLAPI_ERROR_LIBCERR || errno != EINTR)) {
6276b10e573SMarc-André Lureau         brlapi_perror("baum: brlapi_readKey");
6286b10e573SMarc-André Lureau         brlapi__closeConnection(baum->brlapi);
6296b10e573SMarc-André Lureau         g_free(baum->brlapi);
6306b10e573SMarc-André Lureau         baum->brlapi = NULL;
6316b10e573SMarc-André Lureau     }
6326b10e573SMarc-André Lureau }
6336b10e573SMarc-André Lureau 
char_braille_finalize(Object * obj)6346b10e573SMarc-André Lureau static void char_braille_finalize(Object *obj)
6356b10e573SMarc-André Lureau {
6366b10e573SMarc-André Lureau     BaumChardev *baum = BAUM_CHARDEV(obj);
6376b10e573SMarc-André Lureau 
6386b10e573SMarc-André Lureau     timer_free(baum->cellCount_timer);
6396b10e573SMarc-André Lureau     if (baum->brlapi) {
6406b10e573SMarc-André Lureau         brlapi__closeConnection(baum->brlapi);
6416b10e573SMarc-André Lureau         g_free(baum->brlapi);
6426b10e573SMarc-André Lureau     }
6436b10e573SMarc-André Lureau }
6446b10e573SMarc-André Lureau 
baum_chr_open(Chardev * chr,ChardevBackend * backend,bool * be_opened,Error ** errp)6456b10e573SMarc-André Lureau static void baum_chr_open(Chardev *chr,
6466b10e573SMarc-André Lureau                           ChardevBackend *backend,
6476b10e573SMarc-André Lureau                           bool *be_opened,
6486b10e573SMarc-André Lureau                           Error **errp)
6496b10e573SMarc-André Lureau {
6506b10e573SMarc-André Lureau     BaumChardev *baum = BAUM_CHARDEV(chr);
6516b10e573SMarc-André Lureau     brlapi_handle_t *handle;
6526b10e573SMarc-André Lureau 
6536b10e573SMarc-André Lureau     handle = g_malloc0(brlapi_getHandleSize());
6546b10e573SMarc-André Lureau     baum->brlapi = handle;
6556b10e573SMarc-André Lureau 
6566b10e573SMarc-André Lureau     baum->brlapi_fd = brlapi__openConnection(handle, NULL, NULL);
6576b10e573SMarc-André Lureau     if (baum->brlapi_fd == -1) {
6586b10e573SMarc-André Lureau         error_setg(errp, "brlapi__openConnection: %s",
6596b10e573SMarc-André Lureau                    brlapi_strerror(brlapi_error_location()));
6606b10e573SMarc-André Lureau         g_free(handle);
66198e87903SLiang Yan         baum->brlapi = NULL;
6626b10e573SMarc-André Lureau         return;
6636b10e573SMarc-André Lureau     }
6646b10e573SMarc-André Lureau     baum->deferred_init = 0;
6656b10e573SMarc-André Lureau 
6666b10e573SMarc-André Lureau     baum->cellCount_timer = timer_new_ns(QEMU_CLOCK_VIRTUAL, baum_cellCount_timer_cb, baum);
6676b10e573SMarc-André Lureau 
6686b10e573SMarc-André Lureau     qemu_set_fd_handler(baum->brlapi_fd, baum_chr_read, NULL, baum);
6696b10e573SMarc-André Lureau }
6706b10e573SMarc-André Lureau 
char_braille_class_init(ObjectClass * oc,void * data)6716b10e573SMarc-André Lureau static void char_braille_class_init(ObjectClass *oc, void *data)
6726b10e573SMarc-André Lureau {
6736b10e573SMarc-André Lureau     ChardevClass *cc = CHARDEV_CLASS(oc);
6746b10e573SMarc-André Lureau 
6756b10e573SMarc-André Lureau     cc->open = baum_chr_open;
6766b10e573SMarc-André Lureau     cc->chr_write = baum_chr_write;
6776b10e573SMarc-André Lureau     cc->chr_accept_input = baum_chr_accept_input;
6786b10e573SMarc-André Lureau }
6796b10e573SMarc-André Lureau 
6806b10e573SMarc-André Lureau static const TypeInfo char_braille_type_info = {
6816b10e573SMarc-André Lureau     .name = TYPE_CHARDEV_BRAILLE,
6826b10e573SMarc-André Lureau     .parent = TYPE_CHARDEV,
6836b10e573SMarc-André Lureau     .instance_size = sizeof(BaumChardev),
6846b10e573SMarc-André Lureau     .instance_finalize = char_braille_finalize,
6856b10e573SMarc-André Lureau     .class_init = char_braille_class_init,
6866b10e573SMarc-André Lureau };
687882273d9SGerd Hoffmann module_obj(TYPE_CHARDEV_BRAILLE);
6886b10e573SMarc-André Lureau 
register_types(void)6896b10e573SMarc-André Lureau static void register_types(void)
6906b10e573SMarc-André Lureau {
6916b10e573SMarc-André Lureau     type_register_static(&char_braille_type_info);
6926b10e573SMarc-André Lureau }
6936b10e573SMarc-André Lureau 
6946b10e573SMarc-André Lureau type_init(register_types);
695