2
* Minimalistic braille device kernel support.
4
* By default, shows console messages on the braille device.
5
* Pressing Insert switches to VC browsing.
7
* Copyright (C) Samuel Thibault <samuel.thibault@ens-lyon.org>
9
* This program is free software ; you can redistribute it and/or modify
10
* it under the terms of the GNU General Public License as published by
11
* the Free Software Foundation ; either version 2 of the License, or
12
* (at your option) any later version.
14
* This program is distributed in the hope that it will be useful,
15
* but WITHOUT ANY WARRANTY ; without even the implied warranty of
16
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17
* GNU General Public License for more details.
19
* You should have received a copy of the GNU General Public License
20
* along with the program ; if not, write to the Free Software
21
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
24
#include <linux/kernel.h>
25
#include <linux/module.h>
26
#include <linux/moduleparam.h>
27
#include <linux/console.h>
28
#include <linux/notifier.h>
30
#include <linux/selection.h>
31
#include <linux/vt_kern.h>
32
#include <linux/consolemap.h>
34
#include <linux/keyboard.h>
35
#include <linux/kbd_kern.h>
36
#include <linux/input.h>
38
MODULE_AUTHOR("samuel.thibault@ens-lyon.org");
39
MODULE_DESCRIPTION("braille device");
40
MODULE_LICENSE("GPL");
43
* Braille device support part.
46
/* Emit various sounds */
48
module_param(sound, bool, 0);
49
MODULE_PARM_DESC(sound, "emit sounds");
51
static void beep(unsigned int freq)
54
kd_mksound(freq, HZ/10);
59
#define BRAILLE_KEY KEY_INSERT
60
static u16 console_buf[WIDTH];
61
static int console_cursor;
64
static int vc_x, vc_y, lastvc_x, lastvc_y;
66
/* show console ? (or show VC) */
67
static int console_show = 1;
68
/* pending newline ? */
69
static int console_newline = 1;
70
static int lastVC = -1;
72
static struct console *braille_co;
74
/* Very VisioBraille-specific */
75
static void braille_write(u16 *buf)
77
static u16 lastwrite[WIDTH];
78
unsigned char data[1 + 1 + 2*WIDTH + 2 + 1], csum = 0, *c;
85
if (!memcmp(lastwrite, buf, WIDTH * sizeof(*buf)))
87
memcpy(lastwrite, buf, WIDTH * sizeof(*buf));
98
for (i = 0; i < WIDTH; i++) {
102
else if (out == 0x00)
119
braille_co->write(braille_co, data, c - data);
122
/* Follow the VC cursor*/
123
static void vc_follow_cursor(struct vc_data *vc)
125
vc_x = vc->vc_x - (vc->vc_x % WIDTH);
131
/* Maybe the VC cursor moved, if so follow it */
132
static void vc_maybe_cursor_moved(struct vc_data *vc)
134
if (vc->vc_x != lastvc_x || vc->vc_y != lastvc_y)
135
vc_follow_cursor(vc);
138
/* Show portion of VC at vc_x, vc_y */
139
static void vc_refresh(struct vc_data *vc)
144
for (i = 0; i < WIDTH; i++) {
145
u16 glyph = screen_glyph(vc,
146
2 * (vc_x + i) + vc_y * vc->vc_size_row);
147
buf[i] = inverse_translate(vc, glyph, 1);
156
static int keyboard_notifier_call(struct notifier_block *blk,
157
unsigned long code, void *_param)
159
struct keyboard_notifier_param *param = _param;
160
struct vc_data *vc = param->vc;
169
if (param->value == BRAILLE_KEY) {
172
vc_maybe_cursor_moved(vc);
178
switch (param->value) {
183
braille_write(console_buf);
190
} else if (vc_y >= 1) {
193
vc_x = vc->vc_cols-WIDTH;
198
if (vc_x + WIDTH < vc->vc_cols) {
200
} else if (vc_y + 1 < vc->vc_rows) {
208
if (vc_y + 1 < vc->vc_rows)
220
vc_follow_cursor(vc);
228
vc_y = vc->vc_rows-1;
234
if (ret == NOTIFY_STOP)
238
case KBD_POST_KEYSYM:
240
unsigned char type = KTYP(param->value) - 0xf0;
241
if (type == KT_SPEC) {
242
unsigned char val = KVAL(param->value);
247
on_off = vc_kbd_led(kbd_table + fg_console,
251
on_off = vc_kbd_led(kbd_table + fg_console,
255
on_off = vc_kbd_led(kbd_table + fg_console,
261
else if (on_off == 0)
265
case KBD_UNBOUND_KEYCODE:
274
static struct notifier_block keyboard_notifier_block = {
275
.notifier_call = keyboard_notifier_call,
278
static int vt_notifier_call(struct notifier_block *blk,
279
unsigned long code, void *_param)
281
struct vt_notifier_param *param = _param;
282
struct vc_data *vc = param->vc;
290
unsigned char c = param->c;
291
if (vc->vc_num != fg_console)
296
if (console_cursor > 0) {
298
console_buf[console_cursor] = ' ';
312
/* Ignore other control sequences */
314
if (console_newline) {
315
memset(console_buf, 0, sizeof(console_buf));
319
if (console_cursor == WIDTH)
320
memmove(console_buf, &console_buf[1],
321
(WIDTH-1) * sizeof(*console_buf));
324
console_buf[console_cursor-1] = c;
328
braille_write(console_buf);
330
vc_maybe_cursor_moved(vc);
336
/* Maybe a VT switch, flush */
338
if (vc->vc_num != lastVC) {
340
memset(console_buf, 0, sizeof(console_buf));
342
braille_write(console_buf);
345
vc_maybe_cursor_moved(vc);
353
static struct notifier_block vt_notifier_block = {
354
.notifier_call = vt_notifier_call,
358
* Called from printk.c when console=brl is given
361
int braille_register_console(struct console *console, int index,
362
char *console_options, char *braille_options)
365
if (!console_options)
366
/* Only support VisioBraille for now */
367
console_options = "57600o8";
370
if (console->setup) {
371
ret = console->setup(console, console_options);
375
console->flags |= CON_ENABLED;
376
console->index = index;
377
braille_co = console;
378
register_keyboard_notifier(&keyboard_notifier_block);
379
register_vt_notifier(&vt_notifier_block);
383
int braille_unregister_console(struct console *console)
385
if (braille_co != console)
387
unregister_keyboard_notifier(&keyboard_notifier_block);
388
unregister_vt_notifier(&vt_notifier_block);