Commit 2e4d9fb126beba5177d9b58a6ecf2f2bfdb560ae

Authored by aurel32
1 parent 88cb0a02

Braille device support

(Samuel Thibault)


git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@4173 c046a42c-6fe2-441c-8c8c-71466251a162
Makefile
@@ -57,6 +57,11 @@ OBJS+=scsi-generic.o @@ -57,6 +57,11 @@ OBJS+=scsi-generic.o
57 OBJS+=usb.o usb-hub.o usb-linux.o usb-hid.o usb-msd.o usb-wacom.o usb-serial.o 57 OBJS+=usb.o usb-hub.o usb-linux.o usb-hid.o usb-msd.o usb-wacom.o usb-serial.o
58 OBJS+=sd.o ssi-sd.o 58 OBJS+=sd.o ssi-sd.o
59 59
  60 +ifdef CONFIG_BRLAPI
  61 +OBJS+= baum.o
  62 +LIBS+=-lbrlapi
  63 +endif
  64 +
60 ifdef CONFIG_WIN32 65 ifdef CONFIG_WIN32
61 OBJS+=tap-win32.o 66 OBJS+=tap-win32.o
62 endif 67 endif
Makefile.target
@@ -658,7 +658,7 @@ main.o: CFLAGS+=-p @@ -658,7 +658,7 @@ main.o: CFLAGS+=-p
658 endif 658 endif
659 659
660 $(QEMU_PROG): $(OBJS) ../libqemu_common.a libqemu.a 660 $(QEMU_PROG): $(OBJS) ../libqemu_common.a libqemu.a
661 - $(CC) $(LDFLAGS) -o $@ $^ $(LIBS) $(SDL_LIBS) $(COCOA_LIBS) $(CURSES_LIBS) 661 + $(CC) $(LDFLAGS) -o $@ $^ $(LIBS) $(SDL_LIBS) $(COCOA_LIBS) $(CURSES_LIBS) $(BRLAPI_LIBS)
662 662
663 endif # !CONFIG_USER_ONLY 663 endif # !CONFIG_USER_ONLY
664 664
configure
@@ -286,6 +286,8 @@ for opt do @@ -286,6 +286,8 @@ for opt do
286 ;; 286 ;;
287 --disable-kqemu) kqemu="no" 287 --disable-kqemu) kqemu="no"
288 ;; 288 ;;
  289 + --disable-brlapi) brlapi="no"
  290 + ;;
289 --enable-profiler) profiler="yes" 291 --enable-profiler) profiler="yes"
290 ;; 292 ;;
291 --enable-cocoa) cocoa="yes" ; coreaudio="yes" ; sdl="no" 293 --enable-cocoa) cocoa="yes" ; coreaudio="yes" ; sdl="no"
@@ -416,6 +418,7 @@ echo " --enable-alsa enable ALSA audio driver" @@ -416,6 +418,7 @@ echo " --enable-alsa enable ALSA audio driver"
416 echo " --enable-esd enable EsoundD audio driver" 418 echo " --enable-esd enable EsoundD audio driver"
417 echo " --enable-fmod enable FMOD audio driver" 419 echo " --enable-fmod enable FMOD audio driver"
418 echo " --enable-dsound enable DirectSound audio driver" 420 echo " --enable-dsound enable DirectSound audio driver"
  421 +echo " --disable-brlapi disable BrlAPI"
419 echo " --disable-vnc-tls disable TLS encryption for VNC server" 422 echo " --disable-vnc-tls disable TLS encryption for VNC server"
420 echo " --disable-curses disable curses output" 423 echo " --disable-curses disable curses output"
421 echo " --enable-system enable all system emulation targets" 424 echo " --enable-system enable all system emulation targets"
@@ -674,6 +677,20 @@ EOF @@ -674,6 +677,20 @@ EOF
674 fi 677 fi
675 678
676 ########################################## 679 ##########################################
  680 +# BrlAPI probe
  681 +
  682 +if test -z "$brlapi" ; then
  683 + brlapi=no
  684 +cat > $TMPC << EOF
  685 +#include <brlapi.h>
  686 +int main( void ) { return brlapi__openConnection (NULL, NULL, NULL); }
  687 +EOF
  688 + if $cc -o $TMPE ${OS_CFLAGS} $TMPC -lbrlapi 2> /tmp/qemu-$$-brlapi.log ; then
  689 + brlapi=yes
  690 + fi # brlapi compile test
  691 +fi # -z $brlapi
  692 +
  693 +##########################################
677 # curses probe 694 # curses probe
678 695
679 if test "$curses" = "yes" ; then 696 if test "$curses" = "yes" ; then
@@ -770,6 +787,7 @@ if test -n &quot;$sparc_cpu&quot;; then @@ -770,6 +787,7 @@ if test -n &quot;$sparc_cpu&quot;; then
770 echo "Target Sparc Arch $sparc_cpu" 787 echo "Target Sparc Arch $sparc_cpu"
771 fi 788 fi
772 echo "kqemu support $kqemu" 789 echo "kqemu support $kqemu"
  790 +echo "brlapi support $brlapi"
773 echo "Documentation $build_docs" 791 echo "Documentation $build_docs"
774 [ ! -z "$uname_release" ] && \ 792 [ ! -z "$uname_release" ] && \
775 echo "uname -r $uname_release" 793 echo "uname -r $uname_release"
@@ -1001,6 +1019,11 @@ if test &quot;$curses&quot; = &quot;yes&quot; ; then @@ -1001,6 +1019,11 @@ if test &quot;$curses&quot; = &quot;yes&quot; ; then
1001 echo "CONFIG_CURSES=yes" >> $config_mak 1019 echo "CONFIG_CURSES=yes" >> $config_mak
1002 echo "CURSES_LIBS=-lcurses" >> $config_mak 1020 echo "CURSES_LIBS=-lcurses" >> $config_mak
1003 fi 1021 fi
  1022 +if test "$brlapi" = "yes" ; then
  1023 + echo "CONFIG_BRLAPI=yes" >> $config_mak
  1024 + echo "#define CONFIG_BRLAPI 1" >> $config_h
  1025 + echo "BRLAPI_LIBS=-lbrlapi" >> $config_mak
  1026 +fi
1004 1027
1005 # XXX: suppress that 1028 # XXX: suppress that
1006 if [ "$bsd" = "yes" ] ; then 1029 if [ "$bsd" = "yes" ] ; then
hw/baum.c 0 โ†’ 100644
  1 +/*
  2 + * QEMU Baum Braille Device
  3 + *
  4 + * Copyright (c) 2008 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-common.h"
  25 +#include "qemu-char.h"
  26 +#include "qemu-timer.h"
  27 +#include "usb.h"
  28 +#include <assert.h>
  29 +#include <brlapi.h>
  30 +#include <brlapi_constants.h>
  31 +#include <brlapi_keycodes.h>
  32 +#ifdef CONFIG_SDL
  33 +#include <SDL/SDL_syswm.h>
  34 +#endif
  35 +
  36 +#if 0
  37 +#define DPRINTF(fmt, ...) \
  38 + printf(fmt, ## __VA_ARGS__)
  39 +#else
  40 +#define DPRINTF(fmt, ...)
  41 +#endif
  42 +
  43 +#define ESC 0x1B
  44 +
  45 +#define BAUM_REQ_DisplayData 0x01
  46 +#define BAUM_REQ_GetVersionNumber 0x05
  47 +#define BAUM_REQ_GetKeys 0x08
  48 +#define BAUM_REQ_SetMode 0x12
  49 +#define BAUM_REQ_SetProtocol 0x15
  50 +#define BAUM_REQ_GetDeviceIdentity 0x84
  51 +#define BAUM_REQ_GetSerialNumber 0x8A
  52 +
  53 +#define BAUM_RSP_CellCount 0x01
  54 +#define BAUM_RSP_VersionNumber 0x05
  55 +#define BAUM_RSP_ModeSetting 0x11
  56 +#define BAUM_RSP_CommunicationChannel 0x16
  57 +#define BAUM_RSP_PowerdownSignal 0x17
  58 +#define BAUM_RSP_HorizontalSensors 0x20
  59 +#define BAUM_RSP_VerticalSensors 0x21
  60 +#define BAUM_RSP_RoutingKeys 0x22
  61 +#define BAUM_RSP_Switches 0x23
  62 +#define BAUM_RSP_TopKeys 0x24
  63 +#define BAUM_RSP_HorizontalSensor 0x25
  64 +#define BAUM_RSP_VerticalSensor 0x26
  65 +#define BAUM_RSP_RoutingKey 0x27
  66 +#define BAUM_RSP_FrontKeys6 0x28
  67 +#define BAUM_RSP_BackKeys6 0x29
  68 +#define BAUM_RSP_CommandKeys 0x2B
  69 +#define BAUM_RSP_FrontKeys10 0x2C
  70 +#define BAUM_RSP_BackKeys10 0x2D
  71 +#define BAUM_RSP_EntryKeys 0x33
  72 +#define BAUM_RSP_JoyStick 0x34
  73 +#define BAUM_RSP_ErrorCode 0x40
  74 +#define BAUM_RSP_InfoBlock 0x42
  75 +#define BAUM_RSP_DeviceIdentity 0x84
  76 +#define BAUM_RSP_SerialNumber 0x8A
  77 +#define BAUM_RSP_BluetoothName 0x8C
  78 +
  79 +#define BAUM_TL1 0x01
  80 +#define BAUM_TL2 0x02
  81 +#define BAUM_TL3 0x04
  82 +#define BAUM_TR1 0x08
  83 +#define BAUM_TR2 0x10
  84 +#define BAUM_TR3 0x20
  85 +
  86 +#define BUF_SIZE 256
  87 +
  88 +typedef struct {
  89 + CharDriverState *chr;
  90 +
  91 + brlapi_handle_t *brlapi;
  92 + int brlapi_fd;
  93 + int x, y;
  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 +} BaumDriverState;
  102 +
  103 +/* Let's assume NABCC by default */
  104 +static const uint8_t nabcc_translation[256] = {
  105 + [0] = ' ',
  106 +#ifndef BRLAPI_DOTS
  107 +#define BRLAPI_DOTS(d1,d2,d3,d4,d5,d6,d7,d8) \
  108 + ((d1?BRLAPI_DOT1:0)|\
  109 + (d2?BRLAPI_DOT2:0)|\
  110 + (d3?BRLAPI_DOT3:0)|\
  111 + (d4?BRLAPI_DOT4:0)|\
  112 + (d5?BRLAPI_DOT5:0)|\
  113 + (d6?BRLAPI_DOT6:0)|\
  114 + (d7?BRLAPI_DOT7:0)|\
  115 + (d8?BRLAPI_DOT8:0))
  116 +#endif
  117 + [BRLAPI_DOTS(1,0,0,0,0,0,0,0)] = 'a',
  118 + [BRLAPI_DOTS(1,1,0,0,0,0,0,0)] = 'b',
  119 + [BRLAPI_DOTS(1,0,0,1,0,0,0,0)] = 'c',
  120 + [BRLAPI_DOTS(1,0,0,1,1,0,0,0)] = 'd',
  121 + [BRLAPI_DOTS(1,0,0,0,1,0,0,0)] = 'e',
  122 + [BRLAPI_DOTS(1,1,0,1,0,0,0,0)] = 'f',
  123 + [BRLAPI_DOTS(1,1,0,1,1,0,0,0)] = 'g',
  124 + [BRLAPI_DOTS(1,1,0,0,1,0,0,0)] = 'h',
  125 + [BRLAPI_DOTS(0,1,0,1,0,0,0,0)] = 'i',
  126 + [BRLAPI_DOTS(0,1,0,1,1,0,0,0)] = 'j',
  127 + [BRLAPI_DOTS(1,0,1,0,0,0,0,0)] = 'k',
  128 + [BRLAPI_DOTS(1,1,1,0,0,0,0,0)] = 'l',
  129 + [BRLAPI_DOTS(1,0,1,1,0,0,0,0)] = 'm',
  130 + [BRLAPI_DOTS(1,0,1,1,1,0,0,0)] = 'n',
  131 + [BRLAPI_DOTS(1,0,1,0,1,0,0,0)] = 'o',
  132 + [BRLAPI_DOTS(1,1,1,1,0,0,0,0)] = 'p',
  133 + [BRLAPI_DOTS(1,1,1,1,1,0,0,0)] = 'q',
  134 + [BRLAPI_DOTS(1,1,1,0,1,0,0,0)] = 'r',
  135 + [BRLAPI_DOTS(0,1,1,1,0,0,0,0)] = 's',
  136 + [BRLAPI_DOTS(0,1,1,1,1,0,0,0)] = 't',
  137 + [BRLAPI_DOTS(1,0,1,0,0,1,0,0)] = 'u',
  138 + [BRLAPI_DOTS(1,1,1,0,0,1,0,0)] = 'v',
  139 + [BRLAPI_DOTS(0,1,0,1,1,1,0,0)] = 'w',
  140 + [BRLAPI_DOTS(1,0,1,1,0,1,0,0)] = 'x',
  141 + [BRLAPI_DOTS(1,0,1,1,1,1,0,0)] = 'y',
  142 + [BRLAPI_DOTS(1,0,1,0,1,1,0,0)] = 'z',
  143 +
  144 + [BRLAPI_DOTS(1,0,0,0,0,0,1,0)] = 'A',
  145 + [BRLAPI_DOTS(1,1,0,0,0,0,1,0)] = 'B',
  146 + [BRLAPI_DOTS(1,0,0,1,0,0,1,0)] = 'C',
  147 + [BRLAPI_DOTS(1,0,0,1,1,0,1,0)] = 'D',
  148 + [BRLAPI_DOTS(1,0,0,0,1,0,1,0)] = 'E',
  149 + [BRLAPI_DOTS(1,1,0,1,0,0,1,0)] = 'F',
  150 + [BRLAPI_DOTS(1,1,0,1,1,0,1,0)] = 'G',
  151 + [BRLAPI_DOTS(1,1,0,0,1,0,1,0)] = 'H',
  152 + [BRLAPI_DOTS(0,1,0,1,0,0,1,0)] = 'I',
  153 + [BRLAPI_DOTS(0,1,0,1,1,0,1,0)] = 'J',
  154 + [BRLAPI_DOTS(1,0,1,0,0,0,1,0)] = 'K',
  155 + [BRLAPI_DOTS(1,1,1,0,0,0,1,0)] = 'L',
  156 + [BRLAPI_DOTS(1,0,1,1,0,0,1,0)] = 'M',
  157 + [BRLAPI_DOTS(1,0,1,1,1,0,1,0)] = 'N',
  158 + [BRLAPI_DOTS(1,0,1,0,1,0,1,0)] = 'O',
  159 + [BRLAPI_DOTS(1,1,1,1,0,0,1,0)] = 'P',
  160 + [BRLAPI_DOTS(1,1,1,1,1,0,1,0)] = 'Q',
  161 + [BRLAPI_DOTS(1,1,1,0,1,0,1,0)] = 'R',
  162 + [BRLAPI_DOTS(0,1,1,1,0,0,1,0)] = 'S',
  163 + [BRLAPI_DOTS(0,1,1,1,1,0,1,0)] = 'T',
  164 + [BRLAPI_DOTS(1,0,1,0,0,1,1,0)] = 'U',
  165 + [BRLAPI_DOTS(1,1,1,0,0,1,1,0)] = 'V',
  166 + [BRLAPI_DOTS(0,1,0,1,1,1,1,0)] = 'W',
  167 + [BRLAPI_DOTS(1,0,1,1,0,1,1,0)] = 'X',
  168 + [BRLAPI_DOTS(1,0,1,1,1,1,1,0)] = 'Y',
  169 + [BRLAPI_DOTS(1,0,1,0,1,1,1,0)] = 'Z',
  170 +
  171 + [BRLAPI_DOTS(0,0,1,0,1,1,0,0)] = '0',
  172 + [BRLAPI_DOTS(0,1,0,0,0,0,0,0)] = '1',
  173 + [BRLAPI_DOTS(0,1,1,0,0,0,0,0)] = '2',
  174 + [BRLAPI_DOTS(0,1,0,0,1,0,0,0)] = '3',
  175 + [BRLAPI_DOTS(0,1,0,0,1,1,0,0)] = '4',
  176 + [BRLAPI_DOTS(0,1,0,0,0,1,0,0)] = '5',
  177 + [BRLAPI_DOTS(0,1,1,0,1,0,0,0)] = '6',
  178 + [BRLAPI_DOTS(0,1,1,0,1,1,0,0)] = '7',
  179 + [BRLAPI_DOTS(0,1,1,0,0,1,0,0)] = '8',
  180 + [BRLAPI_DOTS(0,0,1,0,1,0,0,0)] = '9',
  181 +
  182 + [BRLAPI_DOTS(0,0,0,1,0,1,0,0)] = '.',
  183 + [BRLAPI_DOTS(0,0,1,1,0,1,0,0)] = '+',
  184 + [BRLAPI_DOTS(0,0,1,0,0,1,0,0)] = '-',
  185 + [BRLAPI_DOTS(1,0,0,0,0,1,0,0)] = '*',
  186 + [BRLAPI_DOTS(0,0,1,1,0,0,0,0)] = '/',
  187 + [BRLAPI_DOTS(1,1,1,0,1,1,0,0)] = '(',
  188 + [BRLAPI_DOTS(0,1,1,1,1,1,0,0)] = ')',
  189 +
  190 + [BRLAPI_DOTS(1,1,1,1,0,1,0,0)] = '&',
  191 + [BRLAPI_DOTS(0,0,1,1,1,1,0,0)] = '#',
  192 +
  193 + [BRLAPI_DOTS(0,0,0,0,0,1,0,0)] = ',',
  194 + [BRLAPI_DOTS(0,0,0,0,1,1,0,0)] = ';',
  195 + [BRLAPI_DOTS(1,0,0,0,1,1,0,0)] = ':',
  196 + [BRLAPI_DOTS(0,1,1,1,0,1,0,0)] = '!',
  197 + [BRLAPI_DOTS(1,0,0,1,1,1,0,0)] = '?',
  198 + [BRLAPI_DOTS(0,0,0,0,1,0,0,0)] = '"',
  199 + [BRLAPI_DOTS(0,0,1,0,0,0,0,0)] ='\'',
  200 + [BRLAPI_DOTS(0,0,0,1,0,0,0,0)] = '`',
  201 + [BRLAPI_DOTS(0,0,0,1,1,0,1,0)] = '^',
  202 + [BRLAPI_DOTS(0,0,0,1,1,0,0,0)] = '~',
  203 + [BRLAPI_DOTS(0,1,0,1,0,1,1,0)] = '[',
  204 + [BRLAPI_DOTS(1,1,0,1,1,1,1,0)] = ']',
  205 + [BRLAPI_DOTS(0,1,0,1,0,1,0,0)] = '{',
  206 + [BRLAPI_DOTS(1,1,0,1,1,1,0,0)] = '}',
  207 + [BRLAPI_DOTS(1,1,1,1,1,1,0,0)] = '=',
  208 + [BRLAPI_DOTS(1,1,0,0,0,1,0,0)] = '<',
  209 + [BRLAPI_DOTS(0,0,1,1,1,0,0,0)] = '>',
  210 + [BRLAPI_DOTS(1,1,0,1,0,1,0,0)] = '$',
  211 + [BRLAPI_DOTS(1,0,0,1,0,1,0,0)] = '%',
  212 + [BRLAPI_DOTS(0,0,0,1,0,0,1,0)] = '@',
  213 + [BRLAPI_DOTS(1,1,0,0,1,1,0,0)] = '|',
  214 + [BRLAPI_DOTS(1,1,0,0,1,1,1,0)] ='\\',
  215 + [BRLAPI_DOTS(0,0,0,1,1,1,0,0)] = '_',
  216 +};
  217 +
  218 +/* The serial port can receive more of our data */
  219 +static void baum_accept_input(struct CharDriverState *chr)
  220 +{
  221 + BaumDriverState *baum = chr->opaque;
  222 + int room, first;
  223 +
  224 + if (!baum->out_buf_used)
  225 + return;
  226 + room = qemu_chr_can_read(chr);
  227 + if (!room)
  228 + return;
  229 + if (room > baum->out_buf_used)
  230 + room = baum->out_buf_used;
  231 +
  232 + first = BUF_SIZE - baum->out_buf_ptr;
  233 + if (room > first) {
  234 + qemu_chr_read(chr, baum->out_buf + baum->out_buf_ptr, first);
  235 + baum->out_buf_ptr = 0;
  236 + baum->out_buf_used -= first;
  237 + room -= first;
  238 + }
  239 + qemu_chr_read(chr, baum->out_buf + baum->out_buf_ptr, room);
  240 + baum->out_buf_ptr += room;
  241 + baum->out_buf_used -= room;
  242 +}
  243 +
  244 +/* We want to send a packet */
  245 +static void baum_write_packet(BaumDriverState *baum, const uint8_t *buf, int len)
  246 +{
  247 + uint8_t io_buf[1 + 2 * len], *cur = io_buf;
  248 + int room;
  249 + *cur++ = ESC;
  250 + while (len--)
  251 + if ((*cur++ = *buf++) == ESC)
  252 + *cur++ = ESC;
  253 + room = qemu_chr_can_read(baum->chr);
  254 + len = cur - io_buf;
  255 + if (len <= room) {
  256 + /* Fits */
  257 + qemu_chr_read(baum->chr, io_buf, len);
  258 + } else {
  259 + int first;
  260 + uint8_t out;
  261 + /* Can't fit all, send what can be, and store the rest. */
  262 + qemu_chr_read(baum->chr, io_buf, room);
  263 + len -= room;
  264 + cur = io_buf + room;
  265 + if (len > BUF_SIZE - baum->out_buf_used) {
  266 + /* Can't even store it, drop the previous data... */
  267 + assert(len <= BUF_SIZE);
  268 + baum->out_buf_used = 0;
  269 + baum->out_buf_ptr = 0;
  270 + }
  271 + out = baum->out_buf_ptr;
  272 + baum->out_buf_used += len;
  273 + first = BUF_SIZE - baum->out_buf_ptr;
  274 + if (len > first) {
  275 + memcpy(baum->out_buf + out, cur, first);
  276 + out = 0;
  277 + len -= first;
  278 + cur += first;
  279 + }
  280 + memcpy(baum->out_buf + out, cur, len);
  281 + }
  282 +}
  283 +
  284 +/* Called when the other end seems to have a wrong idea of our display size */
  285 +static void baum_cellCount_timer_cb(void *opaque)
  286 +{
  287 + BaumDriverState *baum = opaque;
  288 + uint8_t cell_count[] = { BAUM_RSP_CellCount, baum->x * baum->y };
  289 + DPRINTF("Timeout waiting for DisplayData, sending cell count\n");
  290 + baum_write_packet(baum, cell_count, sizeof(cell_count));
  291 +}
  292 +
  293 +/* Try to interpret a whole incoming packet */
  294 +static int baum_eat_packet(BaumDriverState *baum, const uint8_t *buf, int len)
  295 +{
  296 + const uint8_t *cur = buf;
  297 + uint8_t req = 0;
  298 +
  299 + if (!len--)
  300 + return 0;
  301 + if (*cur++ != ESC) {
  302 + while (*cur != ESC) {
  303 + if (!len--)
  304 + return 0;
  305 + cur++;
  306 + }
  307 + DPRINTF("Dropped %d bytes!\n", cur - buf);
  308 + }
  309 +
  310 +#define EAT(c) do {\
  311 + if (!len--) \
  312 + return 0; \
  313 + if ((c = *cur++) == ESC) { \
  314 + if (!len--) \
  315 + return 0; \
  316 + if (*cur++ != ESC) { \
  317 + DPRINTF("Broken packet %#2x, tossing\n", req); \
  318 + if (qemu_timer_pending(baum->cellCount_timer)) { \
  319 + qemu_del_timer(baum->cellCount_timer); \
  320 + baum_cellCount_timer_cb(baum); \
  321 + } \
  322 + return (cur - 2 - buf); \
  323 + } \
  324 + } \
  325 +} while (0)
  326 +
  327 + EAT(req);
  328 + switch (req) {
  329 + case BAUM_REQ_DisplayData:
  330 + {
  331 + uint8_t cells[baum->x * baum->y], c;
  332 + uint8_t text[baum->x * baum->y];
  333 + uint8_t zero[baum->x * baum->y];
  334 + int cursor = BRLAPI_CURSOR_OFF;
  335 + int i;
  336 +
  337 + /* Allow 100ms to complete the DisplayData packet */
  338 + qemu_mod_timer(baum->cellCount_timer, qemu_get_clock(vm_clock) + ticks_per_sec / 10);
  339 + for (i = 0; i < baum->x * baum->y ; i++) {
  340 + EAT(c);
  341 + cells[i] = c;
  342 + if ((c & (BRLAPI_DOT7|BRLAPI_DOT8))
  343 + == (BRLAPI_DOT7|BRLAPI_DOT8)) {
  344 + cursor = i + 1;
  345 + c &= ~(BRLAPI_DOT7|BRLAPI_DOT8);
  346 + }
  347 + if (!(c = nabcc_translation[c]))
  348 + c = '?';
  349 + text[i] = c;
  350 + }
  351 + qemu_del_timer(baum->cellCount_timer);
  352 +
  353 + memset(zero, 0, sizeof(zero));
  354 +
  355 + brlapi_writeArguments_t wa = {
  356 + .displayNumber = BRLAPI_DISPLAY_DEFAULT,
  357 + .regionBegin = 1,
  358 + .regionSize = baum->x * baum->y,
  359 + .text = text,
  360 + .textSize = baum->x * baum->y,
  361 + .andMask = zero,
  362 + .orMask = cells,
  363 + .cursor = cursor,
  364 + .charset = "ISO-8859-1",
  365 + };
  366 +
  367 + if (brlapi__write(baum->brlapi, &wa) == -1)
  368 + brlapi_perror("baum brlapi_write");
  369 + break;
  370 + }
  371 + case BAUM_REQ_SetMode:
  372 + {
  373 + uint8_t mode, setting;
  374 + DPRINTF("SetMode\n");
  375 + EAT(mode);
  376 + EAT(setting);
  377 + /* ignore */
  378 + break;
  379 + }
  380 + case BAUM_REQ_SetProtocol:
  381 + {
  382 + uint8_t protocol;
  383 + DPRINTF("SetProtocol\n");
  384 + EAT(protocol);
  385 + /* ignore */
  386 + break;
  387 + }
  388 + case BAUM_REQ_GetDeviceIdentity:
  389 + {
  390 + uint8_t identity[17] = { BAUM_RSP_DeviceIdentity,
  391 + 'B','a','u','m',' ','V','a','r','i','o' };
  392 + DPRINTF("GetDeviceIdentity\n");
  393 + identity[11] = '0' + baum->x / 10;
  394 + identity[12] = '0' + baum->x % 10;
  395 + baum_write_packet(baum, identity, sizeof(identity));
  396 + break;
  397 + }
  398 + case BAUM_REQ_GetVersionNumber:
  399 + {
  400 + uint8_t version[] = { BAUM_RSP_VersionNumber, 1 }; /* ? */
  401 + DPRINTF("GetVersionNumber\n");
  402 + baum_write_packet(baum, version, sizeof(version));
  403 + break;
  404 + }
  405 + case BAUM_REQ_GetSerialNumber:
  406 + {
  407 + uint8_t serial[] = { BAUM_RSP_SerialNumber,
  408 + '0','0','0','0','0','0','0','0' };
  409 + DPRINTF("GetSerialNumber\n");
  410 + baum_write_packet(baum, serial, sizeof(serial));
  411 + break;
  412 + }
  413 + case BAUM_REQ_GetKeys:
  414 + {
  415 + DPRINTF("Get%0#2x\n", req);
  416 + /* ignore */
  417 + break;
  418 + }
  419 + default:
  420 + DPRINTF("unrecognized request %0#2x\n", req);
  421 + do
  422 + if (!len--)
  423 + return 0;
  424 + while (*cur++ != ESC);
  425 + cur--;
  426 + break;
  427 + }
  428 + return cur - buf;
  429 +}
  430 +
  431 +/* The other end is writing some data. Store it and try to interpret */
  432 +static int baum_write(CharDriverState *chr, const uint8_t *buf, int len)
  433 +{
  434 + BaumDriverState *baum = chr->opaque;
  435 + int tocopy, cur, eaten, orig_len = len;
  436 +
  437 + if (!len)
  438 + return 0;
  439 + if (!baum->brlapi)
  440 + return len;
  441 +
  442 + while (len) {
  443 + /* Complete our buffer as much as possible */
  444 + tocopy = len;
  445 + if (tocopy > BUF_SIZE - baum->in_buf_used)
  446 + tocopy = BUF_SIZE - baum->in_buf_used;
  447 +
  448 + memcpy(baum->in_buf + baum->in_buf_used, buf, tocopy);
  449 + baum->in_buf_used += tocopy;
  450 + buf += tocopy;
  451 + len -= tocopy;
  452 +
  453 + /* Interpret it as much as possible */
  454 + cur = 0;
  455 + while (cur < baum->in_buf_used &&
  456 + (eaten = baum_eat_packet(baum, baum->in_buf + cur, baum->in_buf_used - cur)))
  457 + cur += eaten;
  458 +
  459 + /* Shift the remainder */
  460 + if (cur) {
  461 + memmove(baum->in_buf, baum->in_buf + cur, baum->in_buf_used - cur);
  462 + baum->in_buf_used -= cur;
  463 + }
  464 +
  465 + /* And continue if any data left */
  466 + }
  467 + return orig_len;
  468 +}
  469 +
  470 +/* The other end sent us some event */
  471 +static void baum_send_event(CharDriverState *chr, int event)
  472 +{
  473 + BaumDriverState *baum = chr->opaque;
  474 + switch (event) {
  475 + case CHR_EVENT_BREAK:
  476 + break;
  477 + case CHR_EVENT_RESET:
  478 + /* Reset state */
  479 + baum->in_buf_used = 0;
  480 + break;
  481 + }
  482 +}
  483 +
  484 +/* Send the key code to the other end */
  485 +static void baum_send_key(BaumDriverState *baum, uint8_t type, uint8_t value) {
  486 + uint8_t packet[] = { type, value };
  487 + DPRINTF("writing key %x %x\n", type, value);
  488 + baum_write_packet(baum, packet, sizeof(packet));
  489 +}
  490 +
  491 +/* We got some data on the BrlAPI socket */
  492 +static void baum_chr_read(void *opaque)
  493 +{
  494 + BaumDriverState *baum = opaque;
  495 + brlapi_keyCode_t code;
  496 + int ret;
  497 + if (!baum->brlapi)
  498 + return;
  499 + while ((ret = brlapi__readKey(baum->brlapi, 0, &code)) == 1) {
  500 + DPRINTF("got key %"BRLAPI_PRIxKEYCODE"\n", code);
  501 + /* Emulate */
  502 + switch (code & BRLAPI_KEY_TYPE_MASK) {
  503 + case BRLAPI_KEY_TYPE_CMD:
  504 + switch (code & BRLAPI_KEY_CMD_BLK_MASK) {
  505 + case BRLAPI_KEY_CMD_ROUTE:
  506 + baum_send_key(baum, BAUM_RSP_RoutingKey, (code & BRLAPI_KEY_CMD_ARG_MASK)+1);
  507 + baum_send_key(baum, BAUM_RSP_RoutingKey, 0);
  508 + break;
  509 + case 0:
  510 + switch (code & BRLAPI_KEY_CMD_ARG_MASK) {
  511 + case BRLAPI_KEY_CMD_FWINLT:
  512 + baum_send_key(baum, BAUM_RSP_TopKeys, BAUM_TL2);
  513 + baum_send_key(baum, BAUM_RSP_TopKeys, 0);
  514 + break;
  515 + case BRLAPI_KEY_CMD_FWINRT:
  516 + baum_send_key(baum, BAUM_RSP_TopKeys, BAUM_TR2);
  517 + baum_send_key(baum, BAUM_RSP_TopKeys, 0);
  518 + break;
  519 + case BRLAPI_KEY_CMD_LNUP:
  520 + baum_send_key(baum, BAUM_RSP_TopKeys, BAUM_TR1);
  521 + baum_send_key(baum, BAUM_RSP_TopKeys, 0);
  522 + break;
  523 + case BRLAPI_KEY_CMD_LNDN:
  524 + baum_send_key(baum, BAUM_RSP_TopKeys, BAUM_TR3);
  525 + baum_send_key(baum, BAUM_RSP_TopKeys, 0);
  526 + break;
  527 + case BRLAPI_KEY_CMD_TOP:
  528 + baum_send_key(baum, BAUM_RSP_TopKeys, BAUM_TL1|BAUM_TR1);
  529 + baum_send_key(baum, BAUM_RSP_TopKeys, 0);
  530 + break;
  531 + case BRLAPI_KEY_CMD_BOT:
  532 + baum_send_key(baum, BAUM_RSP_TopKeys, BAUM_TL3|BAUM_TR3);
  533 + baum_send_key(baum, BAUM_RSP_TopKeys, 0);
  534 + break;
  535 + case BRLAPI_KEY_CMD_TOP_LEFT:
  536 + baum_send_key(baum, BAUM_RSP_TopKeys, BAUM_TL2|BAUM_TR1);
  537 + baum_send_key(baum, BAUM_RSP_TopKeys, 0);
  538 + break;
  539 + case BRLAPI_KEY_CMD_BOT_LEFT:
  540 + baum_send_key(baum, BAUM_RSP_TopKeys, BAUM_TL2|BAUM_TR3);
  541 + baum_send_key(baum, BAUM_RSP_TopKeys, 0);
  542 + break;
  543 + case BRLAPI_KEY_CMD_HOME:
  544 + baum_send_key(baum, BAUM_RSP_TopKeys, BAUM_TL2|BAUM_TR1|BAUM_TR3);
  545 + baum_send_key(baum, BAUM_RSP_TopKeys, 0);
  546 + break;
  547 + case BRLAPI_KEY_CMD_PREFMENU:
  548 + baum_send_key(baum, BAUM_RSP_TopKeys, BAUM_TL1|BAUM_TL3|BAUM_TR1);
  549 + baum_send_key(baum, BAUM_RSP_TopKeys, 0);
  550 + break;
  551 + }
  552 + }
  553 + break;
  554 + case BRLAPI_KEY_TYPE_SYM:
  555 + break;
  556 + }
  557 + }
  558 + if (ret == -1 && (brlapi_errno != BRLAPI_ERROR_LIBCERR || errno != EINTR)) {
  559 + brlapi_perror("baum: brlapi_readKey");
  560 + brlapi__closeConnection(baum->brlapi);
  561 + free(baum->brlapi);
  562 + baum->brlapi = NULL;
  563 + }
  564 +}
  565 +
  566 +CharDriverState *chr_baum_init(void)
  567 +{
  568 + BaumDriverState *baum;
  569 + CharDriverState *chr;
  570 + brlapi_handle_t *handle;
  571 +#ifdef CONFIG_SDL
  572 + SDL_SysWMinfo info;
  573 +#endif
  574 + int tty;
  575 +
  576 + baum = qemu_mallocz(sizeof(BaumDriverState));
  577 + if (!baum)
  578 + return NULL;
  579 +
  580 + baum->chr = chr = qemu_mallocz(sizeof(CharDriverState));
  581 + if (!chr)
  582 + goto fail_baum;
  583 +
  584 + chr->opaque = baum;
  585 + chr->chr_write = baum_write;
  586 + chr->chr_send_event = baum_send_event;
  587 + chr->chr_accept_input = baum_accept_input;
  588 +
  589 + handle = qemu_mallocz(brlapi_getHandleSize());
  590 + if (!handle)
  591 + goto fail_chr;
  592 + baum->brlapi = handle;
  593 +
  594 + baum->brlapi_fd = brlapi__openConnection(handle, NULL, NULL);
  595 + if (baum->brlapi_fd == -1) {
  596 + brlapi_perror("baum_init: brlapi_openConnection");
  597 + goto fail_handle;
  598 + }
  599 +
  600 + baum->cellCount_timer = qemu_new_timer(vm_clock, baum_cellCount_timer_cb, baum);
  601 +
  602 + if (brlapi__getDisplaySize(handle, &baum->x, &baum->y) == -1) {
  603 + brlapi_perror("baum_init: brlapi_getDisplaySize");
  604 + goto fail;
  605 + }
  606 +
  607 +#ifdef CONFIG_SDL
  608 + memset(&info, 0, sizeof(info));
  609 + SDL_VERSION(&info.version);
  610 + if (SDL_GetWMInfo(&info))
  611 + tty = info.info.x11.wmwindow;
  612 + else
  613 +#endif
  614 + tty = BRLAPI_TTY_DEFAULT;
  615 +
  616 + if (brlapi__enterTtyMode(handle, tty, NULL) == -1) {
  617 + brlapi_perror("baum_init: brlapi_enterTtyMode");
  618 + goto fail;
  619 + }
  620 +
  621 + qemu_set_fd_handler(baum->brlapi_fd, baum_chr_read, NULL, baum);
  622 +
  623 + qemu_chr_reset(chr);
  624 +
  625 + return chr;
  626 +
  627 +fail:
  628 + qemu_free_timer(baum->cellCount_timer);
  629 + brlapi__closeConnection(handle);
  630 +fail_handle:
  631 + free(handle);
  632 +fail_chr:
  633 + free(chr);
  634 +fail_baum:
  635 + free(baum);
  636 + return NULL;
  637 +}
  638 +
  639 +USBDevice *usb_baum_init(void)
  640 +{
  641 + /* USB Product ID of Super Vario 40 */
  642 + return usb_serial_init("productid=FE72:braille");
  643 +}
hw/baum.h 0 โ†’ 100644
  1 +/*
  2 + * QEMU Baum
  3 + *
  4 + * Copyright (c) 2008 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 +/* usb device */
  26 +USBDevice *usb_baum_init(void);
  27 +
  28 +/* char device */
  29 +CharDriverState *chr_baum_init(void);
qemu-doc.texi
@@ -546,6 +546,10 @@ Pass through the host device identified by vendor_id:product_id (Linux only). @@ -546,6 +546,10 @@ Pass through the host device identified by vendor_id:product_id (Linux only).
546 Serial converter to host character device @var{dev}, see @code{-serial} for the 546 Serial converter to host character device @var{dev}, see @code{-serial} for the
547 available devices. 547 available devices.
548 548
  549 +@item braille
  550 +Braille device. This will use BrlAPI to display the braille output on a real
  551 +or fake device.
  552 +
549 @end table 553 @end table
550 554
551 @end table 555 @end table
@@ -859,6 +863,10 @@ listening on port 4444 would be: @@ -859,6 +863,10 @@ listening on port 4444 would be:
859 @item -serial mon:telnet::4444,server,nowait 863 @item -serial mon:telnet::4444,server,nowait
860 @end table 864 @end table
861 865
  866 +@item braille
  867 +Braille device. This will use BrlAPI to display the braille output on a real
  868 +or fake device.
  869 +
862 @end table 870 @end table
863 871
864 @item -parallel @var{dev} 872 @item -parallel @var{dev}
@@ -1614,6 +1622,9 @@ usb_add serial:productid=FA00:tcp:192.168.0.2:4444 @@ -1614,6 +1622,9 @@ usb_add serial:productid=FA00:tcp:192.168.0.2:4444
1614 @end example 1622 @end example
1615 will connect to tcp port 4444 of ip 192.168.0.2, and plug that to the virtual 1623 will connect to tcp port 4444 of ip 192.168.0.2, and plug that to the virtual
1616 serial converter, faking a Matrix Orbital LCD Display (USB ID 0403:FA00). 1624 serial converter, faking a Matrix Orbital LCD Display (USB ID 0403:FA00).
  1625 +@item braille
  1626 +Braille device. This will use BrlAPI to display the braille output on a real
  1627 +or fake device.
1617 @end table 1628 @end table
1618 1629
1619 @node host_usb_devices 1630 @node host_usb_devices
@@ -28,6 +28,7 @@ @@ -28,6 +28,7 @@
28 #include "hw/pc.h" 28 #include "hw/pc.h"
29 #include "hw/audiodev.h" 29 #include "hw/audiodev.h"
30 #include "hw/isa.h" 30 #include "hw/isa.h"
  31 +#include "hw/baum.h"
31 #include "net.h" 32 #include "net.h"
32 #include "console.h" 33 #include "console.h"
33 #include "sysemu.h" 34 #include "sysemu.h"
@@ -3473,7 +3474,12 @@ CharDriverState *qemu_chr_open(const char *filename) @@ -3473,7 +3474,12 @@ CharDriverState *qemu_chr_open(const char *filename)
3473 } else 3474 } else
3474 if (strstart(filename, "file:", &p)) { 3475 if (strstart(filename, "file:", &p)) {
3475 return qemu_chr_open_win_file_out(p); 3476 return qemu_chr_open_win_file_out(p);
3476 - } 3477 + } else
  3478 +#endif
  3479 +#ifdef CONFIG_BRLAPI
  3480 + if (!strcmp(filename, "braille")) {
  3481 + return chr_baum_init();
  3482 + } else
3477 #endif 3483 #endif
3478 { 3484 {
3479 return NULL; 3485 return NULL;
@@ -5281,6 +5287,10 @@ static int usb_device_add(const char *devname) @@ -5281,6 +5287,10 @@ static int usb_device_add(const char *devname)
5281 dev = usb_wacom_init(); 5287 dev = usb_wacom_init();
5282 } else if (strstart(devname, "serial:", &p)) { 5288 } else if (strstart(devname, "serial:", &p)) {
5283 dev = usb_serial_init(p); 5289 dev = usb_serial_init(p);
  5290 +#ifdef CONFIG_BRLAPI
  5291 + } else if (!strcmp(devname, "braille")) {
  5292 + dev = usb_baum_init();
  5293 +#endif
5284 } else { 5294 } else {
5285 return -1; 5295 return -1;
5286 } 5296 }