2008-02-04 03:22:23

by Samuel Thibault

[permalink] [raw]
Subject: [PATCH] Basic braille screen reader support

This adds a minimalistic braille screen reader support.
This is meant to be used by blind people e.g. on boot failures or when /
cannot be mounted etc and thus the userland screen readers can not work.

Signed-off-by: Samuel Thibault <[email protected]

--- linux-2.6.24-orig/drivers/char/consolemap.c 2008-01-25 08:32:05.000000000 +0000
+++ linux-2.6.24-perso/drivers/char/consolemap.c 2008-02-03 21:27:04.000000000 +0000
@@ -277,6 +277,7 @@
return p->inverse_translations[m][glyph];
}
}
+EXPORT_SYMBOL_GPL(inverse_translate);

static void update_user_maps(void)
{
--- linux-2.6.24-orig/drivers/char/vt.c 2008-01-25 08:32:06.000000000 +0000
+++ linux-2.6.24-perso/drivers/char/vt.c 2008-02-03 21:27:04.000000000 +0000
@@ -3982,6 +3982,7 @@
c |= 0x100;
return c;
}
+EXPORT_SYMBOL_GPL(screen_glyph);

/* used by vcs - note the word offset */
unsigned short *screen_pos(struct vc_data *vc, int w_offset, int viewed)
--- linux-2.6.24-orig/drivers/char/keyboard.c 2008-01-25 08:32:06.000000000 +0000
+++ linux-2.6.24-perso/drivers/char/keyboard.c 2008-02-04 02:44:37.000000000 +0000
@@ -110,6 +110,7 @@
const int NR_TYPES = ARRAY_SIZE(max_vals);

struct kbd_struct kbd_table[MAX_NR_CONSOLES];
+EXPORT_SYMBOL_GPL(kbd_table);
static struct kbd_struct *kbd = kbd_table;

struct vt_spawn_console vt_spawn_con = {
@@ -260,6 +261,7 @@
} else
kd_nosound(0);
}
+EXPORT_SYMBOL_GPL(kd_mksound);

/*
* Setting the keyboard rate.
--- linux-2.6.24-orig/drivers/Kconfig 2008-01-25 08:32:04.000000000 +0000
+++ linux-2.6.24-perso/drivers/Kconfig 2008-02-04 01:32:17.000000000 +0000
@@ -95,4 +95,6 @@
source "drivers/uio/Kconfig"

source "drivers/virtio/Kconfig"
+
+source "drivers/a11y/Kconfig"
endmenu
--- linux-2.6.24-orig/drivers/Makefile 2008-01-25 08:32:04.000000000 +0000
+++ linux-2.6.24-perso/drivers/Makefile 2008-02-04 01:33:27.000000000 +0000
@@ -28,6 +28,8 @@
obj-$(CONFIG_FB_INTEL) += video/intelfb/

obj-y += serial/
+# a11y comes after serial because it depends on it
+obj-$(CONFIG_A11Y) += a11y/
obj-$(CONFIG_PARPORT) += parport/
obj-y += base/ block/ misc/ mfd/ net/ media/
obj-$(CONFIG_NUBUS) += nubus/
--- linux-2.6.24-orig/include/linux/serial_8250.h 2007-10-09 21:31:38.000000000 +0100
+++ linux-2.6.24-perso/include/linux/serial_8250.h 2008-02-03 21:28:40.000000000 +0000
@@ -66,4 +66,6 @@
extern int serial8250_find_port_for_earlycon(void);
extern int setup_early_serial8250_console(char *cmdline);

+extern struct console serial8250_console;
+
#endif
--- linux-2.6.24-orig/drivers/serial/8250.c 2007-10-09 21:31:38.000000000 +0100
+++ linux-2.6.24-perso/drivers/serial/8250.c 2008-02-03 21:29:54.000000000 +0000
@@ -2547,7 +2547,7 @@
}

static struct uart_driver serial8250_reg;
-static struct console serial8250_console = {
+struct console serial8250_console = {
.name = "ttyS",
.write = serial8250_console_write,
.device = uart_console_device,
@@ -2557,6 +2557,7 @@
.index = -1,
.data = &serial8250_reg,
};
+EXPORT_SYMBOL_GPL(serial8250_console);

static int __init serial8250_console_init(void)
{
diff -urN linux-2.6.24-orig/drivers/a11y/braille/braille_console.c linux-2.6.24-perso/drivers/a11y/braille/braille_console.c
--- linux-2.6.24-orig/drivers/a11y/braille/braille_console.c 1970-01-01 01:00:00.000000000 +0100
+++ linux-2.6.24-perso/drivers/a11y/braille/braille_console.c 2008-02-04 01:58:16.000000000 +0000
@@ -0,0 +1,390 @@
+/*
+ * Minimalistic braille device kernel support.
+ *
+ * By default, shows console messages on the braille device.
+ * Pressing Insert switches to VC browsing.
+ *
+ * Copyright (C) Samuel Thibault <[email protected]>
+ *
+ * This program is free software ; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation ; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY ; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with the program ; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <linux/autoconf.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/console.h>
+#include <linux/notifier.h>
+
+#include <linux/selection.h>
+#include <linux/vt_kern.h>
+#include <linux/consolemap.h>
+
+#include <linux/keyboard.h>
+#include <linux/kbd_kern.h>
+#include <linux/input.h>
+
+#include <linux/serial_8250.h>
+
+MODULE_AUTHOR("[email protected]");
+MODULE_DESCRIPTION("braille device");
+MODULE_LICENSE("GPL");
+
+/*
+ * Braille device support part.
+ */
+
+/* Emit various sounds */
+static int sound;
+module_param(sound, bool, 0);
+MODULE_PARM_DESC(sound, "emit sounds");
+#define beep(freq) do { if (sound) kd_mksound(freq, HZ/10); } while(0)
+
+/* mini console */
+#define WIDTH 40
+#define BRAILLE_KEY KEY_INSERT
+static u16 console_buf[WIDTH];
+static int console_cursor = 0;
+
+/* mini view of VC */
+static int vc_x, vc_y, lastvc_x, lastvc_y;
+
+/* show console ? (or show VC) */
+static int console_show = 1;
+/* pending newline ? */
+static int console_newline = 1;
+static int lastVC = -1;
+
+static struct console *braille_co;
+
+/* Very VisioBraille-specific */
+static void braille_write(u16 *buf)
+{
+ static u16 lastwrite[WIDTH];
+ unsigned char data[1 + 1 + 2*WIDTH + 2 + 1], csum = 0, *c;
+ u16 out;
+ int i;
+
+ if (!braille_co)
+ return;
+
+ if (!memcmp(lastwrite, buf, WIDTH * sizeof(*buf)))
+ return;
+ memcpy(lastwrite, buf, WIDTH * sizeof(*buf));
+
+#define SOH 1
+#define STX 2
+#define ETX 2
+#define EOT 4
+#define ENQ 5
+ data[0] = STX;
+ data[1] = '>';
+ csum ^= '>';
+ c = &data[2];
+ for (i=0; i<WIDTH; i++) {
+ out = buf[i];
+ if (out >= 0x100)
+ out = '?';
+ else if (out == 0x00)
+ out = ' ';
+ csum ^= out;
+ if (out <= 0x05) {
+ *c++ = SOH;
+ out |= 0x40;
+ }
+ *c++ = out;
+ }
+
+ if (csum <= 0x05) {
+ *c++ = SOH;
+ csum = 0x40;
+ }
+ *c++ = csum;
+ *c++ = ETX;
+
+ serial8250_console.write(braille_co, data, c - data);
+}
+
+/* Follow the VC cursor*/
+static void vc_follow_cursor(struct vc_data *vc)
+{
+ vc_x = vc->vc_x - (vc->vc_x % WIDTH);
+ vc_y = vc->vc_y;
+ lastvc_x = vc->vc_x;
+ lastvc_y = vc->vc_y;
+}
+
+/* Maybe the VC cursor moved, if so follow it */
+static void vc_maybe_cursor_moved(struct vc_data *vc)
+{
+ if (vc->vc_x != lastvc_x || vc->vc_y != lastvc_y)
+ vc_follow_cursor(vc);
+}
+
+/* Show portion of VC at vc_x, vc_y */
+static void vc_refresh(struct vc_data *vc)
+{
+ u16 buf[WIDTH];
+ int i;
+
+ for (i = 0; i<WIDTH; i++) {
+ u16 glyph = screen_glyph(vc, 2 * (vc_x + i) + vc_y * vc->vc_size_row);
+ buf[i] = inverse_translate(vc, glyph, 1);
+ }
+ braille_write(buf);
+}
+
+/*
+ * Link to keyboard
+ */
+
+static int keyboard_notifier_call(struct notifier_block *blk, unsigned long code, void *_param)
+{
+ struct keyboard_notifier_param *param = _param;
+ struct vc_data *vc = param->vc;
+ int ret = NOTIFY_OK;
+
+ if (!param->down)
+ return ret;
+
+ switch (code) {
+ case KBD_KEYCODE:
+ if (console_show) {
+ if (param->value == BRAILLE_KEY) {
+ console_show = 0;
+ beep(880);
+ vc_maybe_cursor_moved(vc);
+ vc_refresh(vc);
+ ret = NOTIFY_STOP;
+ }
+ } else {
+ ret = NOTIFY_STOP;
+ switch (param->value) {
+ case KEY_INSERT:
+ beep(440);
+ console_show = 1;
+ lastVC = -1;
+ braille_write(console_buf);
+ break;
+ case KEY_LEFT:
+ if (vc_x > 0) {
+ vc_x -= WIDTH;
+ if (vc_x < 0)
+ vc_x = 0;
+ } else if (vc_y >= 1) {
+ beep(880);
+ vc_y--;
+ vc_x = vc->vc_cols-WIDTH;
+ } else
+ beep(220);
+ break;
+ case KEY_RIGHT:
+ if (vc_x + WIDTH < vc->vc_cols) {
+ vc_x += WIDTH;
+ } else if (vc_y + 1 < vc->vc_rows) {
+ beep(880);
+ vc_y++;
+ vc_x = 0;
+ } else
+ beep(220);
+ break;
+ case KEY_DOWN:
+ if (vc_y + 1 < vc->vc_rows)
+ vc_y++;
+ else
+ beep(220);
+ break;
+ case KEY_UP:
+ if (vc_y >= 1)
+ vc_y--;
+ else
+ beep(220);
+ break;
+ case KEY_HOME:
+ vc_follow_cursor(vc);
+ break;
+ case KEY_PAGEUP:
+ vc_x = 0;
+ vc_y = 0;
+ break;
+ case KEY_PAGEDOWN:
+ vc_x = 0;
+ vc_y = vc->vc_rows-1;
+ break;
+ default:
+ ret = NOTIFY_OK;
+ break;
+ }
+ if (ret == NOTIFY_STOP)
+ vc_refresh(vc);
+ }
+ break;
+ case KBD_POST_KEYSYM:
+ {
+ unsigned char type = KTYP(param->value) - 0xf0;
+ if (type == KT_SPEC) {
+ unsigned char val = KVAL(param->value);
+ int on_off = -1;
+
+ switch(val) {
+ case KVAL(K_CAPS):
+ on_off = vc_kbd_led(kbd_table + fg_console, VC_CAPSLOCK);
+ break;
+ case KVAL(K_NUM):
+ on_off = vc_kbd_led(kbd_table + fg_console, VC_NUMLOCK);
+ break;
+ case KVAL(K_HOLD):
+ on_off = vc_kbd_led(kbd_table + fg_console, VC_SCROLLOCK);
+ break;
+ }
+ if (on_off == 1)
+ beep(880);
+ else if (on_off == 0)
+ beep(440);
+ }
+ }
+ case KBD_UNBOUND_KEYCODE:
+ case KBD_UNICODE:
+ case KBD_KEYSYM:
+ /* Unused */
+ break;
+ }
+ return ret;
+}
+
+static struct notifier_block keyboard_notifier_block = {
+ .notifier_call = keyboard_notifier_call,
+};
+
+static int vt_notifier_call(struct notifier_block *blk, unsigned long code, void *_param)
+{
+ struct vt_notifier_param *param = _param;
+ struct vc_data *vc = param->vc;
+ switch (code) {
+ case VT_ALLOCATE:
+ break;
+ case VT_DEALLOCATE:
+ break;
+ case VT_WRITE:
+ {
+ unsigned char c = param->c;
+ switch (c) {
+ case '\b':
+ case 127:
+ if (console_cursor > 0) {
+ console_cursor--;
+ console_buf[console_cursor] = ' ';
+ }
+ break;
+ case '\n':
+ case '\v':
+ case '\f':
+ case '\r':
+ console_newline = 1;
+ break;
+ case '\t':
+ c = ' ';
+ /* Fallthrough */
+ default:
+ if (c < 32)
+ /* Ignore other control sequences */
+ break;
+ if (console_newline) {
+ memset(console_buf, 0, sizeof(console_buf));
+ console_cursor = 0;
+ console_newline = 0;
+ }
+ if (console_cursor == WIDTH)
+ memmove(console_buf, &console_buf[1], (WIDTH-1) * sizeof(*console_buf));
+ else
+ console_cursor++;
+ console_buf[console_cursor-1] = c;
+ break;
+ }
+ if (console_show)
+ braille_write(console_buf);
+ else {
+ vc_maybe_cursor_moved(vc);
+ vc_refresh(vc);
+ }
+ break;
+ }
+ case VT_UPDATE:
+ /* Maybe a VT switch, flush */
+ if (console_show) {
+ if (vc->vc_num != lastVC) {
+ lastVC = vc->vc_num;
+ memset(console_buf, 0, sizeof(console_buf));
+ console_cursor = 0;
+ braille_write(console_buf);
+ }
+ } else {
+ vc_maybe_cursor_moved(vc);
+ vc_refresh(vc);
+ }
+ break;
+ }
+ return NOTIFY_OK;
+}
+
+static struct notifier_block vt_notifier_block = {
+ .notifier_call = vt_notifier_call,
+};
+
+/*
+ * Link to serial console
+ */
+
+static int __init braille_console_setup(struct console *co, char *options)
+{
+ int ret = 0;
+ if (co->index == -1)
+ co->index = 0;
+#ifndef MODULE
+ ret = serial8250_console.setup(co, options);
+ if (ret < 0)
+ return ret;
+#endif
+ braille_co = co;
+ return ret;
+}
+
+static struct console braille_console = {
+ .name = "brl",
+ .setup = braille_console_setup,
+ .flags = CON_PRINTBUFFER,
+ .index = -1,
+};
+
+/*
+ * Module access
+ */
+
+static int __init checkinit(void)
+{
+ register_console(&braille_console);
+ register_keyboard_notifier(&keyboard_notifier_block);
+ register_vt_notifier(&vt_notifier_block);
+ return 0;
+}
+static void __exit checkexit(void)
+{
+ unregister_vt_notifier(&vt_notifier_block);
+ unregister_keyboard_notifier(&keyboard_notifier_block);
+ unregister_console(&braille_console);
+}
+
+module_init(checkinit);
+module_exit(checkexit);
diff -urN linux-2.6.24-orig/drivers/a11y/Kconfig linux-2.6.24-perso/drivers/a11y/Kconfig
--- linux-2.6.24-orig/drivers/a11y/Kconfig 1970-01-01 01:00:00.000000000 +0100
+++ linux-2.6.24-perso/drivers/a11y/Kconfig 2008-02-04 01:54:36.000000000 +0000
@@ -0,0 +1,22 @@
+menuconfig A11Y
+ bool "Accessibility support"
+ ---help---
+ Enable a submenu where accessibility items may be enabled.
+
+ If unsure, say N.
+
+if A11Y
+config A11Y_BRAILLE_CONSOLE
+ tristate "Console on braille device"
+ depends on SERIAL_8250_CONSOLE
+ ---help---
+ Enables console output on a braille device connected to a 8250
+ serial port. For now only the VisioBraille device is supported.
+
+ To actually enable it, you need to pass option
+ console=brl0
+ to the kernel. Options are the same as for serial console.
+
+ If unsure, say N.
+
+endif # A11Y
diff -urN linux-2.6.24-orig/drivers/a11y/Makefile linux-2.6.24-perso/drivers/a11y/Makefile
--- linux-2.6.24-orig/drivers/a11y/Makefile 1970-01-01 01:00:00.000000000 +0100
+++ linux-2.6.24-perso/drivers/a11y/Makefile 2008-02-04 01:42:32.000000000 +0000
@@ -0,0 +1 @@
+obj-$(CONFIG_A11Y_BRAILLE_CONSOLE) += braille/braille_console.o


2008-02-04 03:29:38

by Samuel Thibault

[permalink] [raw]
Subject: Re: [PATCH] Basic braille screen reader support

Note: as said in the comments, this is currently only for the
VisioBraille device, but having this in the vanilla kernel will help a
lot to get people testing drivers for other devices, as they will not
have to recompile a patched kernel but just insert test modules
(remember that for blind people it is already not so easy to just _use_
computers...)

Samuel

2008-02-04 17:12:09

by Greg KH

[permalink] [raw]
Subject: Re: [PATCH] Basic braille screen reader support

On Mon, Feb 04, 2008 at 03:18:43AM +0000, Samuel Thibault wrote:
> This adds a minimalistic braille screen reader support.
> This is meant to be used by blind people e.g. on boot failures or when /
> cannot be mounted etc and thus the userland screen readers can not work.

Will this api work with the SpeakUp kernel drivers? Are the hooks
sufficient for what those drivers are expecting?

> Signed-off-by: Samuel Thibault <[email protected]

You forgot a trailing '>' :)

thanks,

greg k-h

2008-02-04 17:25:44

by Samuel Thibault

[permalink] [raw]
Subject: Re: [PATCH] Basic braille screen reader support

Hello,

Greg KH, le Mon 04 Feb 2008 09:10:08 -0800, a ?crit :
> On Mon, Feb 04, 2008 at 03:18:43AM +0000, Samuel Thibault wrote:
> > This adds a minimalistic braille screen reader support.
> > This is meant to be used by blind people e.g. on boot failures or when /
> > cannot be mounted etc and thus the userland screen readers can not work.
>
> Will this api work with the SpeakUp kernel drivers? Are the hooks
> sufficient for what those drivers are expecting?

SpeakUp and this are quite independant (though they will probably both
end up in the drivers/a11y/ directory), at least just because the way
they review the screen is very different. Speech synthesis' matter is
the time to say things, while braille's matter is the space to show
things.

However, they share the same low-level primitives: the recently added
keyboard and vc notifiers, screen_glyph(), inverse_translate(),
kd_mksound, etc.

> > Signed-off-by: Samuel Thibault <[email protected]
>
> You forgot a trailing '>' :)

Ergl :)

Samuel

2008-02-04 18:09:35

by Greg KH

[permalink] [raw]
Subject: Re: [PATCH] Basic braille screen reader support

On Mon, Feb 04, 2008 at 05:24:41PM +0000, Samuel Thibault wrote:
> Hello,
>
> Greg KH, le Mon 04 Feb 2008 09:10:08 -0800, a ?crit :
> > On Mon, Feb 04, 2008 at 03:18:43AM +0000, Samuel Thibault wrote:
> > > This adds a minimalistic braille screen reader support.
> > > This is meant to be used by blind people e.g. on boot failures or when /
> > > cannot be mounted etc and thus the userland screen readers can not work.
> >
> > Will this api work with the SpeakUp kernel drivers? Are the hooks
> > sufficient for what those drivers are expecting?
>
> SpeakUp and this are quite independant (though they will probably both
> end up in the drivers/a11y/ directory), at least just because the way
> they review the screen is very different. Speech synthesis' matter is
> the time to say things, while braille's matter is the space to show
> things.
>
> However, they share the same low-level primitives: the recently added
> keyboard and vc notifiers, screen_glyph(), inverse_translate(),
> kd_mksound, etc.

I guess I'm worried that the hooks that you add here will not be usable
by speakup, and we'll have to add more in places close to this, but not
quite the same.

I know speaking and "showing" are two different things, but they both
require the same data flow going into them in order to achieve their
goals, I just don't want to see this work being done without considering
both needs.

But, if you feel that both will work properly with these limited
exports, I have no objections.

thanks,

greg k-h

2008-02-04 18:16:16

by Samuel Thibault

[permalink] [raw]
Subject: Re: [PATCH] Basic braille screen reader support

Greg KH, le Mon 04 Feb 2008 10:06:17 -0800, a ?crit :
> > However, they share the same low-level primitives: the recently added
> > keyboard and vc notifiers, screen_glyph(), inverse_translate(),
> > kd_mksound, etc.
>
> I guess I'm worried that the hooks that you add here will not be usable
> by speakup, and we'll have to add more in places close to this, but not
> quite the same.

Actually, speakup already just use these and no others.

> I know speaking and "showing" are two different things, but they both
> require the same data flow going into them in order to achieve their
> goals, I just don't want to see this work being done without considering
> both needs.

I _am_ considering both needs. Actually, most of the recent commits to
SpeakUp are mines :)

> But, if you feel that both will work properly with these limited
> exports, I have no objections.

They already both do :)

Samuel

2008-02-04 18:31:28

by Greg KH

[permalink] [raw]
Subject: Re: [PATCH] Basic braille screen reader support

On Mon, Feb 04, 2008 at 06:15:12PM +0000, Samuel Thibault wrote:
> Greg KH, le Mon 04 Feb 2008 10:06:17 -0800, a ?crit :
> > > However, they share the same low-level primitives: the recently added
> > > keyboard and vc notifiers, screen_glyph(), inverse_translate(),
> > > kd_mksound, etc.
> >
> > I guess I'm worried that the hooks that you add here will not be usable
> > by speakup, and we'll have to add more in places close to this, but not
> > quite the same.
>
> Actually, speakup already just use these and no others.

Great. I have no objection to this patch then :)

thanks,

greg k-h

2008-02-05 22:01:21

by Samuel Thibault

[permalink] [raw]
Subject: [PATCH,RESEND] Basic braille screen reader support

This adds a minimalistic braille screen reader support.
This is meant to be used by blind people e.g. on boot failures or when /
cannot be mounted etc and thus the userland screen readers can not work.

Signed-off-by: Samuel Thibault <[email protected]>

---
Greg KH was OK with this patch and there was no other complains, so I
resubmit it, with a fixed signed-off-by.
I think it should fine for mainline, as it is not enable by default and
doesn't change anything else and exporting a few functions that will be
needed for SpeakUp too.

--- linux-2.6.24-orig/drivers/char/consolemap.c 2008-01-25 08:32:05.000000000 +0000
+++ linux-2.6.24-perso/drivers/char/consolemap.c 2008-02-03 21:27:04.000000000 +0000
@@ -277,6 +277,7 @@
return p->inverse_translations[m][glyph];
}
}
+EXPORT_SYMBOL_GPL(inverse_translate);

static void update_user_maps(void)
{
--- linux-2.6.24-orig/drivers/char/vt.c 2008-01-25 08:32:06.000000000 +0000
+++ linux-2.6.24-perso/drivers/char/vt.c 2008-02-03 21:27:04.000000000 +0000
@@ -3982,6 +3982,7 @@
c |= 0x100;
return c;
}
+EXPORT_SYMBOL_GPL(screen_glyph);

/* used by vcs - note the word offset */
unsigned short *screen_pos(struct vc_data *vc, int w_offset, int viewed)
--- linux-2.6.24-orig/drivers/char/keyboard.c 2008-01-25 08:32:06.000000000 +0000
+++ linux-2.6.24-perso/drivers/char/keyboard.c 2008-02-04 02:44:37.000000000 +0000
@@ -110,6 +110,7 @@
const int NR_TYPES = ARRAY_SIZE(max_vals);

struct kbd_struct kbd_table[MAX_NR_CONSOLES];
+EXPORT_SYMBOL_GPL(kbd_table);
static struct kbd_struct *kbd = kbd_table;

struct vt_spawn_console vt_spawn_con = {
@@ -260,6 +261,7 @@
} else
kd_nosound(0);
}
+EXPORT_SYMBOL_GPL(kd_mksound);

/*
* Setting the keyboard rate.
--- linux-2.6.24-orig/drivers/Kconfig 2008-01-25 08:32:04.000000000 +0000
+++ linux-2.6.24-perso/drivers/Kconfig 2008-02-04 01:32:17.000000000 +0000
@@ -95,4 +95,6 @@
source "drivers/uio/Kconfig"

source "drivers/virtio/Kconfig"
+
+source "drivers/a11y/Kconfig"
endmenu
--- linux-2.6.24-orig/drivers/Makefile 2008-01-25 08:32:04.000000000 +0000
+++ linux-2.6.24-perso/drivers/Makefile 2008-02-04 01:33:27.000000000 +0000
@@ -28,6 +28,8 @@
obj-$(CONFIG_FB_INTEL) += video/intelfb/

obj-y += serial/
+# a11y comes after serial because it depends on it
+obj-$(CONFIG_A11Y) += a11y/
obj-$(CONFIG_PARPORT) += parport/
obj-y += base/ block/ misc/ mfd/ net/ media/
obj-$(CONFIG_NUBUS) += nubus/
--- linux-2.6.24-orig/include/linux/serial_8250.h 2007-10-09 21:31:38.000000000 +0100
+++ linux-2.6.24-perso/include/linux/serial_8250.h 2008-02-03 21:28:40.000000000 +0000
@@ -66,4 +66,6 @@
extern int serial8250_find_port_for_earlycon(void);
extern int setup_early_serial8250_console(char *cmdline);

+extern struct console serial8250_console;
+
#endif
--- linux-2.6.24-orig/drivers/serial/8250.c 2007-10-09 21:31:38.000000000 +0100
+++ linux-2.6.24-perso/drivers/serial/8250.c 2008-02-03 21:29:54.000000000 +0000
@@ -2547,7 +2547,7 @@
}

static struct uart_driver serial8250_reg;
-static struct console serial8250_console = {
+struct console serial8250_console = {
.name = "ttyS",
.write = serial8250_console_write,
.device = uart_console_device,
@@ -2557,6 +2557,7 @@
.index = -1,
.data = &serial8250_reg,
};
+EXPORT_SYMBOL_GPL(serial8250_console);

static int __init serial8250_console_init(void)
{
diff -urN linux-2.6.24-orig/drivers/a11y/braille/braille_console.c linux-2.6.24-perso/drivers/a11y/braille/braille_console.c
--- linux-2.6.24-orig/drivers/a11y/braille/braille_console.c 1970-01-01 01:00:00.000000000 +0100
+++ linux-2.6.24-perso/drivers/a11y/braille/braille_console.c 2008-02-04 01:58:16.000000000 +0000
@@ -0,0 +1,390 @@
+/*
+ * Minimalistic braille device kernel support.
+ *
+ * By default, shows console messages on the braille device.
+ * Pressing Insert switches to VC browsing.
+ *
+ * Copyright (C) Samuel Thibault <[email protected]>
+ *
+ * This program is free software ; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation ; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY ; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with the program ; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <linux/autoconf.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/console.h>
+#include <linux/notifier.h>
+
+#include <linux/selection.h>
+#include <linux/vt_kern.h>
+#include <linux/consolemap.h>
+
+#include <linux/keyboard.h>
+#include <linux/kbd_kern.h>
+#include <linux/input.h>
+
+#include <linux/serial_8250.h>
+
+MODULE_AUTHOR("[email protected]");
+MODULE_DESCRIPTION("braille device");
+MODULE_LICENSE("GPL");
+
+/*
+ * Braille device support part.
+ */
+
+/* Emit various sounds */
+static int sound;
+module_param(sound, bool, 0);
+MODULE_PARM_DESC(sound, "emit sounds");
+#define beep(freq) do { if (sound) kd_mksound(freq, HZ/10); } while(0)
+
+/* mini console */
+#define WIDTH 40
+#define BRAILLE_KEY KEY_INSERT
+static u16 console_buf[WIDTH];
+static int console_cursor = 0;
+
+/* mini view of VC */
+static int vc_x, vc_y, lastvc_x, lastvc_y;
+
+/* show console ? (or show VC) */
+static int console_show = 1;
+/* pending newline ? */
+static int console_newline = 1;
+static int lastVC = -1;
+
+static struct console *braille_co;
+
+/* Very VisioBraille-specific */
+static void braille_write(u16 *buf)
+{
+ static u16 lastwrite[WIDTH];
+ unsigned char data[1 + 1 + 2*WIDTH + 2 + 1], csum = 0, *c;
+ u16 out;
+ int i;
+
+ if (!braille_co)
+ return;
+
+ if (!memcmp(lastwrite, buf, WIDTH * sizeof(*buf)))
+ return;
+ memcpy(lastwrite, buf, WIDTH * sizeof(*buf));
+
+#define SOH 1
+#define STX 2
+#define ETX 2
+#define EOT 4
+#define ENQ 5
+ data[0] = STX;
+ data[1] = '>';
+ csum ^= '>';
+ c = &data[2];
+ for (i=0; i<WIDTH; i++) {
+ out = buf[i];
+ if (out >= 0x100)
+ out = '?';
+ else if (out == 0x00)
+ out = ' ';
+ csum ^= out;
+ if (out <= 0x05) {
+ *c++ = SOH;
+ out |= 0x40;
+ }
+ *c++ = out;
+ }
+
+ if (csum <= 0x05) {
+ *c++ = SOH;
+ csum = 0x40;
+ }
+ *c++ = csum;
+ *c++ = ETX;
+
+ serial8250_console.write(braille_co, data, c - data);
+}
+
+/* Follow the VC cursor*/
+static void vc_follow_cursor(struct vc_data *vc)
+{
+ vc_x = vc->vc_x - (vc->vc_x % WIDTH);
+ vc_y = vc->vc_y;
+ lastvc_x = vc->vc_x;
+ lastvc_y = vc->vc_y;
+}
+
+/* Maybe the VC cursor moved, if so follow it */
+static void vc_maybe_cursor_moved(struct vc_data *vc)
+{
+ if (vc->vc_x != lastvc_x || vc->vc_y != lastvc_y)
+ vc_follow_cursor(vc);
+}
+
+/* Show portion of VC at vc_x, vc_y */
+static void vc_refresh(struct vc_data *vc)
+{
+ u16 buf[WIDTH];
+ int i;
+
+ for (i = 0; i<WIDTH; i++) {
+ u16 glyph = screen_glyph(vc, 2 * (vc_x + i) + vc_y * vc->vc_size_row);
+ buf[i] = inverse_translate(vc, glyph, 1);
+ }
+ braille_write(buf);
+}
+
+/*
+ * Link to keyboard
+ */
+
+static int keyboard_notifier_call(struct notifier_block *blk, unsigned long code, void *_param)
+{
+ struct keyboard_notifier_param *param = _param;
+ struct vc_data *vc = param->vc;
+ int ret = NOTIFY_OK;
+
+ if (!param->down)
+ return ret;
+
+ switch (code) {
+ case KBD_KEYCODE:
+ if (console_show) {
+ if (param->value == BRAILLE_KEY) {
+ console_show = 0;
+ beep(880);
+ vc_maybe_cursor_moved(vc);
+ vc_refresh(vc);
+ ret = NOTIFY_STOP;
+ }
+ } else {
+ ret = NOTIFY_STOP;
+ switch (param->value) {
+ case KEY_INSERT:
+ beep(440);
+ console_show = 1;
+ lastVC = -1;
+ braille_write(console_buf);
+ break;
+ case KEY_LEFT:
+ if (vc_x > 0) {
+ vc_x -= WIDTH;
+ if (vc_x < 0)
+ vc_x = 0;
+ } else if (vc_y >= 1) {
+ beep(880);
+ vc_y--;
+ vc_x = vc->vc_cols-WIDTH;
+ } else
+ beep(220);
+ break;
+ case KEY_RIGHT:
+ if (vc_x + WIDTH < vc->vc_cols) {
+ vc_x += WIDTH;
+ } else if (vc_y + 1 < vc->vc_rows) {
+ beep(880);
+ vc_y++;
+ vc_x = 0;
+ } else
+ beep(220);
+ break;
+ case KEY_DOWN:
+ if (vc_y + 1 < vc->vc_rows)
+ vc_y++;
+ else
+ beep(220);
+ break;
+ case KEY_UP:
+ if (vc_y >= 1)
+ vc_y--;
+ else
+ beep(220);
+ break;
+ case KEY_HOME:
+ vc_follow_cursor(vc);
+ break;
+ case KEY_PAGEUP:
+ vc_x = 0;
+ vc_y = 0;
+ break;
+ case KEY_PAGEDOWN:
+ vc_x = 0;
+ vc_y = vc->vc_rows-1;
+ break;
+ default:
+ ret = NOTIFY_OK;
+ break;
+ }
+ if (ret == NOTIFY_STOP)
+ vc_refresh(vc);
+ }
+ break;
+ case KBD_POST_KEYSYM:
+ {
+ unsigned char type = KTYP(param->value) - 0xf0;
+ if (type == KT_SPEC) {
+ unsigned char val = KVAL(param->value);
+ int on_off = -1;
+
+ switch(val) {
+ case KVAL(K_CAPS):
+ on_off = vc_kbd_led(kbd_table + fg_console, VC_CAPSLOCK);
+ break;
+ case KVAL(K_NUM):
+ on_off = vc_kbd_led(kbd_table + fg_console, VC_NUMLOCK);
+ break;
+ case KVAL(K_HOLD):
+ on_off = vc_kbd_led(kbd_table + fg_console, VC_SCROLLOCK);
+ break;
+ }
+ if (on_off == 1)
+ beep(880);
+ else if (on_off == 0)
+ beep(440);
+ }
+ }
+ case KBD_UNBOUND_KEYCODE:
+ case KBD_UNICODE:
+ case KBD_KEYSYM:
+ /* Unused */
+ break;
+ }
+ return ret;
+}
+
+static struct notifier_block keyboard_notifier_block = {
+ .notifier_call = keyboard_notifier_call,
+};
+
+static int vt_notifier_call(struct notifier_block *blk, unsigned long code, void *_param)
+{
+ struct vt_notifier_param *param = _param;
+ struct vc_data *vc = param->vc;
+ switch (code) {
+ case VT_ALLOCATE:
+ break;
+ case VT_DEALLOCATE:
+ break;
+ case VT_WRITE:
+ {
+ unsigned char c = param->c;
+ switch (c) {
+ case '\b':
+ case 127:
+ if (console_cursor > 0) {
+ console_cursor--;
+ console_buf[console_cursor] = ' ';
+ }
+ break;
+ case '\n':
+ case '\v':
+ case '\f':
+ case '\r':
+ console_newline = 1;
+ break;
+ case '\t':
+ c = ' ';
+ /* Fallthrough */
+ default:
+ if (c < 32)
+ /* Ignore other control sequences */
+ break;
+ if (console_newline) {
+ memset(console_buf, 0, sizeof(console_buf));
+ console_cursor = 0;
+ console_newline = 0;
+ }
+ if (console_cursor == WIDTH)
+ memmove(console_buf, &console_buf[1], (WIDTH-1) * sizeof(*console_buf));
+ else
+ console_cursor++;
+ console_buf[console_cursor-1] = c;
+ break;
+ }
+ if (console_show)
+ braille_write(console_buf);
+ else {
+ vc_maybe_cursor_moved(vc);
+ vc_refresh(vc);
+ }
+ break;
+ }
+ case VT_UPDATE:
+ /* Maybe a VT switch, flush */
+ if (console_show) {
+ if (vc->vc_num != lastVC) {
+ lastVC = vc->vc_num;
+ memset(console_buf, 0, sizeof(console_buf));
+ console_cursor = 0;
+ braille_write(console_buf);
+ }
+ } else {
+ vc_maybe_cursor_moved(vc);
+ vc_refresh(vc);
+ }
+ break;
+ }
+ return NOTIFY_OK;
+}
+
+static struct notifier_block vt_notifier_block = {
+ .notifier_call = vt_notifier_call,
+};
+
+/*
+ * Link to serial console
+ */
+
+static int __init braille_console_setup(struct console *co, char *options)
+{
+ int ret = 0;
+ if (co->index == -1)
+ co->index = 0;
+#ifndef MODULE
+ ret = serial8250_console.setup(co, options);
+ if (ret < 0)
+ return ret;
+#endif
+ braille_co = co;
+ return ret;
+}
+
+static struct console braille_console = {
+ .name = "brl",
+ .setup = braille_console_setup,
+ .flags = CON_PRINTBUFFER,
+ .index = -1,
+};
+
+/*
+ * Module access
+ */
+
+static int __init checkinit(void)
+{
+ register_console(&braille_console);
+ register_keyboard_notifier(&keyboard_notifier_block);
+ register_vt_notifier(&vt_notifier_block);
+ return 0;
+}
+static void __exit checkexit(void)
+{
+ unregister_vt_notifier(&vt_notifier_block);
+ unregister_keyboard_notifier(&keyboard_notifier_block);
+ unregister_console(&braille_console);
+}
+
+module_init(checkinit);
+module_exit(checkexit);
diff -urN linux-2.6.24-orig/drivers/a11y/Kconfig linux-2.6.24-perso/drivers/a11y/Kconfig
--- linux-2.6.24-orig/drivers/a11y/Kconfig 1970-01-01 01:00:00.000000000 +0100
+++ linux-2.6.24-perso/drivers/a11y/Kconfig 2008-02-04 01:54:36.000000000 +0000
@@ -0,0 +1,22 @@
+menuconfig A11Y
+ bool "Accessibility support"
+ ---help---
+ Enable a submenu where accessibility items may be enabled.
+
+ If unsure, say N.
+
+if A11Y
+config A11Y_BRAILLE_CONSOLE
+ tristate "Console on braille device"
+ depends on SERIAL_8250_CONSOLE
+ ---help---
+ Enables console output on a braille device connected to a 8250
+ serial port. For now only the VisioBraille device is supported.
+
+ To actually enable it, you need to pass option
+ console=brl0
+ to the kernel. Options are the same as for serial console.
+
+ If unsure, say N.
+
+endif # A11Y
diff -urN linux-2.6.24-orig/drivers/a11y/Makefile linux-2.6.24-perso/drivers/a11y/Makefile
--- linux-2.6.24-orig/drivers/a11y/Makefile 1970-01-01 01:00:00.000000000 +0100
+++ linux-2.6.24-perso/drivers/a11y/Makefile 2008-02-04 01:42:32.000000000 +0000
@@ -0,0 +1 @@
+obj-$(CONFIG_A11Y_BRAILLE_CONSOLE) += braille/braille_console.o

2008-02-06 00:59:25

by Andrew Morton

[permalink] [raw]
Subject: Re: [PATCH,RESEND] Basic braille screen reader support

On Tue, 5 Feb 2008 22:00:54 +0000
Samuel Thibault <[email protected]> wrote:

> This adds a minimalistic braille screen reader support.
> This is meant to be used by blind people e.g. on boot failures or when /
> cannot be mounted etc and thus the userland screen readers can not work.

Could you feed it through scritps/checkpatch.pl please? That finds a lot
of trivial stuff which we'd prefer be fixed.

> +#define beep(freq) do { if (sound) kd_mksound(freq, HZ/10); } while(0)

This can (and hence should!) be impemented in a C function (I think?).

> +
> +/* mini console */
> +#define WIDTH 40
> +#define BRAILLE_KEY KEY_INSERT
> +static u16 console_buf[WIDTH];
> +static int console_cursor = 0;

Unneeded initialisation (checkpatch will tell you about this)

> +/* mini view of VC */
> +static int vc_x, vc_y, lastvc_x, lastvc_y;
> +
> +/* show console ? (or show VC) */
> +static int console_show = 1;
> +/* pending newline ? */
> +static int console_newline = 1;
> +static int lastVC = -1;
> +
> +static struct console *braille_co;
> +
> +/* Very VisioBraille-specific */
> +static void braille_write(u16 *buf)
> +{
> + static u16 lastwrite[WIDTH];
> + unsigned char data[1 + 1 + 2*WIDTH + 2 + 1], csum = 0, *c;
> + u16 out;
> + int i;
> +
> + if (!braille_co)
> + return;
> +
> + if (!memcmp(lastwrite, buf, WIDTH * sizeof(*buf)))
> + return;
> + memcpy(lastwrite, buf, WIDTH * sizeof(*buf));

`lastwrite' is a kernel-wide singleton and hence at least needs some
locking protecting its consistency.

If this is a single-opener-only device then I _guess_ this approach is OK.
If not, `lastwrite' really should be some dynamically-allocated, per-open thing,
presumably accessed by file.private_data.

> +#define SOH 1
> +#define STX 2
> +#define ETX 2
> +#define EOT 4
> +#define ENQ 5
> + data[0] = STX;
> + data[1] = '>';
> + csum ^= '>';
> + c = &data[2];
> + for (i=0; i<WIDTH; i++) {
> + out = buf[i];
> + if (out >= 0x100)
> + out = '?';
> + else if (out == 0x00)
> + out = ' ';
> + csum ^= out;
> + if (out <= 0x05) {
> + *c++ = SOH;
> + out |= 0x40;
> + }
> + *c++ = out;
> + }
> +
> + if (csum <= 0x05) {
> + *c++ = SOH;
> + csum = 0x40;
> + }
> + *c++ = csum;
> + *c++ = ETX;
> +
> + serial8250_console.write(braille_co, data, c - data);
> +}

hm. Is it appropriate that this driver wire itself directly into
serial8250? What if the screen reader is attached to some other sort of
uart, or a terminal server, or...

Maybe this all should be implemented as a line discipline, or something
like that?

> +/*
> + * Link to keyboard
> + */
> +
> +static int keyboard_notifier_call(struct notifier_block *blk, unsigned long code, void *_param)
> +{
> + struct keyboard_notifier_param *param = _param;
> + struct vc_data *vc = param->vc;
> + int ret = NOTIFY_OK;
> +
> + if (!param->down)
> + return ret;
> +
> + switch (code) {
> + case KBD_KEYCODE:

Maybe Dmitry and Jiri would have time to review this code?

> +static struct notifier_block keyboard_notifier_block = {
> + .notifier_call = keyboard_notifier_call,
> +};
> +
> +static int vt_notifier_call(struct notifier_block *blk, unsigned long code, void *_param)
> +{
> + struct vt_notifier_param *param = _param;
> + struct vc_data *vc = param->vc;
> + switch (code) {
> + case VT_ALLOCATE:
> + break;
> + case VT_DEALLOCATE:
> + break;
> + case VT_WRITE:
> + {
> + unsigned char c = param->c;
> + switch (c) {
> + case '\b':
> + case 127:
> + if (console_cursor > 0) {
> + console_cursor--;
> + console_buf[console_cursor] = ' ';
> + }
> + break;
> + case '\n':
> + case '\v':
> + case '\f':
> + case '\r':
> + console_newline = 1;
> + break;
> + case '\t':
> + c = ' ';
> + /* Fallthrough */
> + default:
> + if (c < 32)
> + /* Ignore other control sequences */
> + break;
> + if (console_newline) {
> + memset(console_buf, 0, sizeof(console_buf));
> + console_cursor = 0;
> + console_newline = 0;
> + }
> + if (console_cursor == WIDTH)
> + memmove(console_buf, &console_buf[1], (WIDTH-1) * sizeof(*console_buf));
> + else
> + console_cursor++;
> + console_buf[console_cursor-1] = c;
> + break;
> + }
> + if (console_show)
> + braille_write(console_buf);
> + else {
> + vc_maybe_cursor_moved(vc);
> + vc_refresh(vc);
> + }
> + break;
> + }
> + case VT_UPDATE:
> + /* Maybe a VT switch, flush */
> + if (console_show) {
> + if (vc->vc_num != lastVC) {
> + lastVC = vc->vc_num;
> + memset(console_buf, 0, sizeof(console_buf));
> + console_cursor = 0;
> + braille_write(console_buf);
> + }
> + } else {
> + vc_maybe_cursor_moved(vc);
> + vc_refresh(vc);
> + }
> + break;
> + }
> + return NOTIFY_OK;
> +}
> +
> +static struct notifier_block vt_notifier_block = {
> + .notifier_call = vt_notifier_call,
> +};
> +
> +/*
> + * Link to serial console
> + */
> +
> +static int __init braille_console_setup(struct console *co, char *options)
> +{
> + int ret = 0;
> + if (co->index == -1)
> + co->index = 0;
> +#ifndef MODULE
> + ret = serial8250_console.setup(co, options);
> + if (ret < 0)
> + return ret;
> +#endif

That's pretty ungainly. Again, if we had some clear spearation between the
protocol layer and the device-driver layer and some way of binding them
under userspace control (like a line discipline), all this would get better.

> + braille_co = co;
> + return ret;
> +}
> +
> +static struct console braille_console = {
> + .name = "brl",
> + .setup = braille_console_setup,
> + .flags = CON_PRINTBUFFER,
> + .index = -1,
> +};
> +
>
> ...
>
> diff -urN linux-2.6.24-orig/drivers/a11y/Kconfig linux-2.6.24-perso/drivers/a11y/Kconfig
> --- linux-2.6.24-orig/drivers/a11y/Kconfig 1970-01-01 01:00:00.000000000 +0100
> +++ linux-2.6.24-perso/drivers/a11y/Kconfig 2008-02-04 01:54:36.000000000 +0000
> @@ -0,0 +1,22 @@
> +menuconfig A11Y
> + bool "Accessibility support"

That's cute, but perhaps we should be boring and call it
CONFIG_ACCESSIBILITY. That would be more accessible ;)

> + ---help---
> + Enable a submenu where accessibility items may be enabled.
> +
> + If unsure, say N.
> +
> +if A11Y
> +config A11Y_BRAILLE_CONSOLE

And that would get very lengthy.

> + tristate "Console on braille device"
> + depends on SERIAL_8250_CONSOLE
> + ---help---
> + Enables console output on a braille device connected to a 8250
> + serial port. For now only the VisioBraille device is supported.
> +
> + To actually enable it, you need to pass option
> + console=brl0
> + to the kernel. Options are the same as for serial console.
> +
> + If unsure, say N.
> +
> +endif # A11Y

2008-02-06 02:04:41

by Samuel Thibault

[permalink] [raw]
Subject: Re: [PATCH,RESEND] Basic braille screen reader support

Andrew Morton, le Tue 05 Feb 2008 16:58:53 -0800, a ?crit :
> On Tue, 5 Feb 2008 22:00:54 +0000
> Samuel Thibault <[email protected]> wrote:
>
> > This adds a minimalistic braille screen reader support.
> > This is meant to be used by blind people e.g. on boot failures or when /
> > cannot be mounted etc and thus the userland screen readers can not work.
>
> Could you feed it through scritps/checkpatch.pl please? That finds a lot
> of trivial stuff which we'd prefer be fixed.

Oops, sorry, it's probably been some time since I last read
SubmittingPatches. Actually, this discovered a false positive in
checkpatch.pl for kbd_table :)

> `lastwrite' is a kernel-wide singleton and hence at least needs some
> locking protecting its consistency.
>
> If this is a single-opener-only device then I _guess_ this approach is OK.

It is meant to be yes, though it was lacking protection against this.
Fixed in this new version.

> > + serial8250_console.write(braille_co, data, c - data);
>
> hm. Is it appropriate that this driver wire itself directly into
> serial8250?

We want to have output as early as possible for debugging, just like
early serial consoles.

> What if the screen reader is attached to some other sort of
> uart, or a terminal server, or...

Indeed that's an issue. For now, there is no clean way to attach to the
early serial drivers, that's why I chose 8250, which should be correct
99% of the time for the current users of this. We could add a parameter
to the console=brl option that specifies which early serial console to
use.

> Maybe this all should be implemented as a line discipline, or something
> like that?

For a permanent screen reader, yes (that's what we will probably do for
SpeakUp), but for an boot reader, I don't think it may even work.

> > +#ifndef MODULE
> > + ret = serial8250_console.setup(co, options);
> > + if (ret < 0)
> > + return ret;
> > +#endif
>
> That's pretty ungainly.

The problem is that there is currently no better way to setup the serial
port so early.

> Again, if we had some clear spearation between the
> protocol layer and the device-driver layer and some way of binding them
> under userspace control (like a line discipline), all this would get better.

Again, we need the screen reader working during boot, even before init
exists. A line discipline would indeed be fine if we had userspace
control, but this tool is precisely intended for the case when userspace
can't be booted :)

> > @@ -0,0 +1,22 @@
> > +menuconfig A11Y
> > + bool "Accessibility support"
>
> That's cute,

Well, that's the official name (http://www.a11y.org) :)

> but perhaps we should be boring and call it
> CONFIG_ACCESSIBILITY. That would be more accessible ;)

Why not :)

> > + ---help---
> > + Enable a submenu where accessibility items may be enabled.
> > +
> > + If unsure, say N.
> > +
> > +if A11Y
> > +config A11Y_BRAILLE_CONSOLE
>
> And that would get very lengthy.

Then keep A11Y here?

Here is a revised patch.

Samuel

This adds a minimalistic braille screen reader support.
This is meant to be used by blind people e.g. on boot failures or when /
cannot be mounted etc and thus the userland screen readers can not work.

Signed-off-by: Samuel Thibault <[email protected]>

--- linux-2.6.24-orig/drivers/char/consolemap.c 2008-01-25 08:32:05.000000000 +0000
+++ linux-2.6.24-perso/drivers/char/consolemap.c 2008-02-03 21:27:04.000000000 +0000
@@ -277,6 +277,7 @@
return p->inverse_translations[m][glyph];
}
}
+EXPORT_SYMBOL_GPL(inverse_translate);

static void update_user_maps(void)
{
--- linux-2.6.24-orig/drivers/char/vt.c 2008-01-25 08:32:06.000000000 +0000
+++ linux-2.6.24-perso/drivers/char/vt.c 2008-02-03 21:27:04.000000000 +0000
@@ -3982,6 +3982,7 @@
c |= 0x100;
return c;
}
+EXPORT_SYMBOL_GPL(screen_glyph);

/* used by vcs - note the word offset */
unsigned short *screen_pos(struct vc_data *vc, int w_offset, int viewed)
--- linux-2.6.24-orig/drivers/char/keyboard.c 2008-01-25 08:32:06.000000000 +0000
+++ linux-2.6.24-perso/drivers/char/keyboard.c 2008-02-04 02:44:37.000000000 +0000
@@ -110,6 +110,7 @@
const int NR_TYPES = ARRAY_SIZE(max_vals);

struct kbd_struct kbd_table[MAX_NR_CONSOLES];
+EXPORT_SYMBOL_GPL(kbd_table);
static struct kbd_struct *kbd = kbd_table;

struct vt_spawn_console vt_spawn_con = {
@@ -260,6 +261,7 @@
} else
kd_nosound(0);
}
+EXPORT_SYMBOL_GPL(kd_mksound);

/*
* Setting the keyboard rate.
--- linux-2.6.24-orig/drivers/Kconfig 2008-01-25 08:32:04.000000000 +0000
+++ linux-2.6.24-perso/drivers/Kconfig 2008-02-04 01:32:17.000000000 +0000
@@ -95,4 +95,6 @@
source "drivers/uio/Kconfig"

source "drivers/virtio/Kconfig"
+
+source "drivers/a11y/Kconfig"
endmenu
--- linux-2.6.24-orig/drivers/Makefile 2008-01-25 08:32:04.000000000 +0000
+++ linux-2.6.24-perso/drivers/Makefile 2008-02-04 01:33:27.000000000 +0000
@@ -28,6 +28,8 @@
obj-$(CONFIG_FB_INTEL) += video/intelfb/

obj-y += serial/
+# a11y comes after serial because it depends on it
+obj-$(CONFIG_ACCESSIBILITY) += a11y/
obj-$(CONFIG_PARPORT) += parport/
obj-y += base/ block/ misc/ mfd/ net/ media/
obj-$(CONFIG_NUBUS) += nubus/
--- linux-2.6.24-orig/include/linux/serial_8250.h 2007-10-09 21:31:38.000000000 +0100
+++ linux-2.6.24-perso/include/linux/serial_8250.h 2008-02-03 21:28:40.000000000 +0000
@@ -66,4 +66,6 @@
extern int serial8250_find_port_for_earlycon(void);
extern int setup_early_serial8250_console(char *cmdline);

+extern struct console serial8250_console;
+
#endif
--- linux-2.6.24-orig/drivers/serial/8250.c 2007-10-09 21:31:38.000000000 +0100
+++ linux-2.6.24-perso/drivers/serial/8250.c 2008-02-03 21:29:54.000000000 +0000
@@ -2547,7 +2547,7 @@
}

static struct uart_driver serial8250_reg;
-static struct console serial8250_console = {
+struct console serial8250_console = {
.name = "ttyS",
.write = serial8250_console_write,
.device = uart_console_device,
@@ -2557,6 +2557,7 @@
.index = -1,
.data = &serial8250_reg,
};
+EXPORT_SYMBOL_GPL(serial8250_console);

static int __init serial8250_console_init(void)
{
diff -urN linux-2.6.24-orig/drivers/a11y/braille/braille_console.c linux-2.6.24-perso/drivers/a11y/braille/braille_console.c
--- linux-2.6.24-orig/drivers/a11y/braille/braille_console.c 1970-01-01 01:00:00.000000000 +0100
+++ linux-2.6.24-perso/drivers/a11y/braille/braille_console.c 2008-02-04 01:58:16.000000000 +0000
@@ -0,0 +1,404 @@
+/*
+ * Minimalistic braille device kernel support.
+ *
+ * By default, shows console messages on the braille device.
+ * Pressing Insert switches to VC browsing.
+ *
+ * Copyright (C) Samuel Thibault <[email protected]>
+ *
+ * This program is free software ; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation ; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY ; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with the program ; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <linux/autoconf.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/console.h>
+#include <linux/notifier.h>
+
+#include <linux/selection.h>
+#include <linux/vt_kern.h>
+#include <linux/consolemap.h>
+
+#include <linux/keyboard.h>
+#include <linux/kbd_kern.h>
+#include <linux/input.h>
+
+#include <linux/serial_8250.h>
+
+MODULE_AUTHOR("[email protected]");
+MODULE_DESCRIPTION("braille device");
+MODULE_LICENSE("GPL");
+
+/*
+ * Braille device support part.
+ */
+
+/* Emit various sounds */
+static int sound;
+module_param(sound, bool, 0);
+MODULE_PARM_DESC(sound, "emit sounds");
+
+static void beep(unsigned int freq)
+{
+ if (sound)
+ kd_mksound(freq, HZ/10);
+}
+
+/* mini console */
+#define WIDTH 40
+#define BRAILLE_KEY KEY_INSERT
+static u16 console_buf[WIDTH];
+static int console_cursor;
+
+/* mini view of VC */
+static int vc_x, vc_y, lastvc_x, lastvc_y;
+
+/* show console ? (or show VC) */
+static int console_show = 1;
+/* pending newline ? */
+static int console_newline = 1;
+static int lastVC = -1;
+
+static struct console *braille_co;
+
+/* Very VisioBraille-specific */
+static void braille_write(u16 *buf)
+{
+ static u16 lastwrite[WIDTH];
+ unsigned char data[1 + 1 + 2*WIDTH + 2 + 1], csum = 0, *c;
+ u16 out;
+ int i;
+
+ if (!braille_co)
+ return;
+
+ if (!memcmp(lastwrite, buf, WIDTH * sizeof(*buf)))
+ return;
+ memcpy(lastwrite, buf, WIDTH * sizeof(*buf));
+
+#define SOH 1
+#define STX 2
+#define ETX 2
+#define EOT 4
+#define ENQ 5
+ data[0] = STX;
+ data[1] = '>';
+ csum ^= '>';
+ c = &data[2];
+ for (i = 0; i < WIDTH; i++) {
+ out = buf[i];
+ if (out >= 0x100)
+ out = '?';
+ else if (out == 0x00)
+ out = ' ';
+ csum ^= out;
+ if (out <= 0x05) {
+ *c++ = SOH;
+ out |= 0x40;
+ }
+ *c++ = out;
+ }
+
+ if (csum <= 0x05) {
+ *c++ = SOH;
+ csum = 0x40;
+ }
+ *c++ = csum;
+ *c++ = ETX;
+
+ serial8250_console.write(braille_co, data, c - data);
+}
+
+/* Follow the VC cursor*/
+static void vc_follow_cursor(struct vc_data *vc)
+{
+ vc_x = vc->vc_x - (vc->vc_x % WIDTH);
+ vc_y = vc->vc_y;
+ lastvc_x = vc->vc_x;
+ lastvc_y = vc->vc_y;
+}
+
+/* Maybe the VC cursor moved, if so follow it */
+static void vc_maybe_cursor_moved(struct vc_data *vc)
+{
+ if (vc->vc_x != lastvc_x || vc->vc_y != lastvc_y)
+ vc_follow_cursor(vc);
+}
+
+/* Show portion of VC at vc_x, vc_y */
+static void vc_refresh(struct vc_data *vc)
+{
+ u16 buf[WIDTH];
+ int i;
+
+ for (i = 0; i < WIDTH; i++) {
+ u16 glyph = screen_glyph(vc,
+ 2 * (vc_x + i) + vc_y * vc->vc_size_row);
+ buf[i] = inverse_translate(vc, glyph, 1);
+ }
+ braille_write(buf);
+}
+
+/*
+ * Link to keyboard
+ */
+
+static int keyboard_notifier_call(struct notifier_block *blk,
+ unsigned long code, void *_param)
+{
+ struct keyboard_notifier_param *param = _param;
+ struct vc_data *vc = param->vc;
+ int ret = NOTIFY_OK;
+
+ if (!param->down)
+ return ret;
+
+ switch (code) {
+ case KBD_KEYCODE:
+ if (console_show) {
+ if (param->value == BRAILLE_KEY) {
+ console_show = 0;
+ beep(880);
+ vc_maybe_cursor_moved(vc);
+ vc_refresh(vc);
+ ret = NOTIFY_STOP;
+ }
+ } else {
+ ret = NOTIFY_STOP;
+ switch (param->value) {
+ case KEY_INSERT:
+ beep(440);
+ console_show = 1;
+ lastVC = -1;
+ braille_write(console_buf);
+ break;
+ case KEY_LEFT:
+ if (vc_x > 0) {
+ vc_x -= WIDTH;
+ if (vc_x < 0)
+ vc_x = 0;
+ } else if (vc_y >= 1) {
+ beep(880);
+ vc_y--;
+ vc_x = vc->vc_cols-WIDTH;
+ } else
+ beep(220);
+ break;
+ case KEY_RIGHT:
+ if (vc_x + WIDTH < vc->vc_cols) {
+ vc_x += WIDTH;
+ } else if (vc_y + 1 < vc->vc_rows) {
+ beep(880);
+ vc_y++;
+ vc_x = 0;
+ } else
+ beep(220);
+ break;
+ case KEY_DOWN:
+ if (vc_y + 1 < vc->vc_rows)
+ vc_y++;
+ else
+ beep(220);
+ break;
+ case KEY_UP:
+ if (vc_y >= 1)
+ vc_y--;
+ else
+ beep(220);
+ break;
+ case KEY_HOME:
+ vc_follow_cursor(vc);
+ break;
+ case KEY_PAGEUP:
+ vc_x = 0;
+ vc_y = 0;
+ break;
+ case KEY_PAGEDOWN:
+ vc_x = 0;
+ vc_y = vc->vc_rows-1;
+ break;
+ default:
+ ret = NOTIFY_OK;
+ break;
+ }
+ if (ret == NOTIFY_STOP)
+ vc_refresh(vc);
+ }
+ break;
+ case KBD_POST_KEYSYM:
+ {
+ unsigned char type = KTYP(param->value) - 0xf0;
+ if (type == KT_SPEC) {
+ unsigned char val = KVAL(param->value);
+ int on_off = -1;
+
+ switch (val) {
+ case KVAL(K_CAPS):
+ on_off = vc_kbd_led(kbd_table + fg_console,
+ VC_CAPSLOCK);
+ break;
+ case KVAL(K_NUM):
+ on_off = vc_kbd_led(kbd_table + fg_console,
+ VC_NUMLOCK);
+ break;
+ case KVAL(K_HOLD):
+ on_off = vc_kbd_led(kbd_table + fg_console,
+ VC_SCROLLOCK);
+ break;
+ }
+ if (on_off == 1)
+ beep(880);
+ else if (on_off == 0)
+ beep(440);
+ }
+ }
+ case KBD_UNBOUND_KEYCODE:
+ case KBD_UNICODE:
+ case KBD_KEYSYM:
+ /* Unused */
+ break;
+ }
+ return ret;
+}
+
+static struct notifier_block keyboard_notifier_block = {
+ .notifier_call = keyboard_notifier_call,
+};
+
+static int vt_notifier_call(struct notifier_block *blk,
+ unsigned long code, void *_param)
+{
+ struct vt_notifier_param *param = _param;
+ struct vc_data *vc = param->vc;
+ switch (code) {
+ case VT_ALLOCATE:
+ break;
+ case VT_DEALLOCATE:
+ break;
+ case VT_WRITE:
+ {
+ unsigned char c = param->c;
+ switch (c) {
+ case '\b':
+ case 127:
+ if (console_cursor > 0) {
+ console_cursor--;
+ console_buf[console_cursor] = ' ';
+ }
+ break;
+ case '\n':
+ case '\v':
+ case '\f':
+ case '\r':
+ console_newline = 1;
+ break;
+ case '\t':
+ c = ' ';
+ /* Fallthrough */
+ default:
+ if (c < 32)
+ /* Ignore other control sequences */
+ break;
+ if (console_newline) {
+ memset(console_buf, 0, sizeof(console_buf));
+ console_cursor = 0;
+ console_newline = 0;
+ }
+ if (console_cursor == WIDTH)
+ memmove(console_buf, &console_buf[1],
+ (WIDTH-1) * sizeof(*console_buf));
+ else
+ console_cursor++;
+ console_buf[console_cursor-1] = c;
+ break;
+ }
+ if (console_show)
+ braille_write(console_buf);
+ else {
+ vc_maybe_cursor_moved(vc);
+ vc_refresh(vc);
+ }
+ break;
+ }
+ case VT_UPDATE:
+ /* Maybe a VT switch, flush */
+ if (console_show) {
+ if (vc->vc_num != lastVC) {
+ lastVC = vc->vc_num;
+ memset(console_buf, 0, sizeof(console_buf));
+ console_cursor = 0;
+ braille_write(console_buf);
+ }
+ } else {
+ vc_maybe_cursor_moved(vc);
+ vc_refresh(vc);
+ }
+ break;
+ }
+ return NOTIFY_OK;
+}
+
+static struct notifier_block vt_notifier_block = {
+ .notifier_call = vt_notifier_call,
+};
+
+/*
+ * Link to serial console
+ */
+
+static int __init braille_console_setup(struct console *co, char *options)
+{
+ int ret = 0;
+ if (braille_co)
+ return -ENODEV;
+ if (co->index == -1)
+ co->index = 0;
+#ifndef MODULE
+ ret = serial8250_console.setup(co, options);
+ if (ret < 0)
+ return ret;
+#endif
+ braille_co = co;
+ return ret;
+}
+
+static struct console braille_console = {
+ .name = "brl",
+ .setup = braille_console_setup,
+ .flags = CON_PRINTBUFFER,
+ .index = -1,
+};
+
+/*
+ * Module access
+ */
+
+static int __init checkinit(void)
+{
+ register_console(&braille_console);
+ register_keyboard_notifier(&keyboard_notifier_block);
+ register_vt_notifier(&vt_notifier_block);
+ return 0;
+}
+static void __exit checkexit(void)
+{
+ unregister_vt_notifier(&vt_notifier_block);
+ unregister_keyboard_notifier(&keyboard_notifier_block);
+ unregister_console(&braille_console);
+}
+
+module_init(checkinit);
+module_exit(checkexit);
diff -urN linux-2.6.24-orig/drivers/a11y/Kconfig linux-2.6.24-perso/drivers/a11y/Kconfig
--- linux-2.6.24-orig/drivers/a11y/Kconfig 1970-01-01 01:00:00.000000000 +0100
+++ linux-2.6.24-perso/drivers/a11y/Kconfig 2008-02-04 01:54:36.000000000 +0000
@@ -0,0 +1,22 @@
+menuconfig ACCESSIBILITY
+ bool "Accessibility support"
+ ---help---
+ Enable a submenu where accessibility items may be enabled.
+
+ If unsure, say N.
+
+if ACCESSIBILITY
+config A11Y_BRAILLE_CONSOLE
+ tristate "Console on braille device"
+ depends on SERIAL_8250_CONSOLE
+ ---help---
+ Enables console output on a braille device connected to a 8250
+ serial port. For now only the VisioBraille device is supported.
+
+ To actually enable it, you need to pass option
+ console=brl0
+ to the kernel. Options are the same as for serial console.
+
+ If unsure, say N.
+
+endif # ACCESSIBILITY
diff -urN linux-2.6.24-orig/drivers/a11y/Makefile linux-2.6.24-perso/drivers/a11y/Makefile
--- linux-2.6.24-orig/drivers/a11y/Makefile 1970-01-01 01:00:00.000000000 +0100
+++ linux-2.6.24-perso/drivers/a11y/Makefile 2008-02-04 01:42:32.000000000 +0000
@@ -0,0 +1 @@
+obj-$(CONFIG_A11Y_BRAILLE_CONSOLE) += braille/braille_console.o

2008-02-22 00:29:46

by Samuel Thibault

[permalink] [raw]
Subject: [PATCH2] Basic braille screen reader support

Samuel Thibault, le Wed 06 Feb 2008 02:04:23 +0000, a ?crit :
> Andrew Morton, le Tue 05 Feb 2008 16:58:53 -0800, a ?crit :
> > On Tue, 5 Feb 2008 22:00:54 +0000
> > Samuel Thibault <[email protected]> wrote:
> > > + serial8250_console.write(braille_co, data, c - data);
> >
> > hm. Is it appropriate that this driver wire itself directly into
> > serial8250?
> > What if the screen reader is attached to some other sort of
> > uart, or a terminal server, or...
>
> Indeed that's an issue. For now, there is no clean way to attach to the
> early serial drivers, that's why I chose 8250,

In the patch below, I hook into kernel/printk.c's console= parser, which
now gives me attachment to any kind of console.




This adds a minimalistic braille screen reader support.
This is meant to be used by blind people e.g. on boot failures or when /
cannot be mounted etc and thus the userland screen readers can not work.

Signed-off-by: Samuel Thibault <[email protected]>

diff -ur linux-2.6.24.1-orig/drivers/char/consolemap.c linux-2.6.24.1-perso/drivers/char/consolemap.c
--- linux-2.6.24.1-orig/drivers/char/consolemap.c 2008-01-25 09:32:05.000000000 +0100
+++ linux-2.6.24.1-perso/drivers/char/consolemap.c 2008-02-03 22:27:04.000000000 +0100
@@ -277,6 +277,7 @@
return p->inverse_translations[m][glyph];
}
}
+EXPORT_SYMBOL_GPL(inverse_translate);

static void update_user_maps(void)
{
diff -ur linux-2.6.24.1-orig/drivers/char/keyboard.c linux-2.6.24.1-perso/drivers/char/keyboard.c
--- linux-2.6.24.1-orig/drivers/char/keyboard.c 2008-01-25 09:32:06.000000000 +0100
+++ linux-2.6.24.1-perso/drivers/char/keyboard.c 2008-02-04 03:44:37.000000000 +0100
@@ -110,6 +110,7 @@
const int NR_TYPES = ARRAY_SIZE(max_vals);

struct kbd_struct kbd_table[MAX_NR_CONSOLES];
+EXPORT_SYMBOL_GPL(kbd_table);
static struct kbd_struct *kbd = kbd_table;

struct vt_spawn_console vt_spawn_con = {
@@ -260,6 +261,7 @@
} else
kd_nosound(0);
}
+EXPORT_SYMBOL_GPL(kd_mksound);

/*
* Setting the keyboard rate.
diff -ur linux-2.6.24.1-orig/drivers/char/vt.c linux-2.6.24.1-perso/drivers/char/vt.c
--- linux-2.6.24.1-orig/drivers/char/vt.c 2008-01-25 09:32:06.000000000 +0100
+++ linux-2.6.24.1-perso/drivers/char/vt.c 2008-02-03 22:27:04.000000000 +0100
@@ -3982,6 +3982,7 @@
c |= 0x100;
return c;
}
+EXPORT_SYMBOL_GPL(screen_glyph);

/* used by vcs - note the word offset */
unsigned short *screen_pos(struct vc_data *vc, int w_offset, int viewed)
diff -ur linux-2.6.24.1-orig/drivers/Kconfig linux-2.6.24.1-perso/drivers/Kconfig
--- linux-2.6.24.1-orig/drivers/Kconfig 2008-01-25 09:32:04.000000000 +0100
+++ linux-2.6.24.1-perso/drivers/Kconfig 2008-02-20 21:52:54.000000000 +0100
@@ -95,4 +95,6 @@
source "drivers/uio/Kconfig"

source "drivers/virtio/Kconfig"
+
+source "drivers/accessibility/Kconfig"
endmenu
diff -ur linux-2.6.24.1-orig/drivers/Makefile linux-2.6.24.1-perso/drivers/Makefile
--- linux-2.6.24.1-orig/drivers/Makefile 2008-01-25 09:32:04.000000000 +0100
+++ linux-2.6.24.1-perso/drivers/Makefile 2008-02-20 21:55:38.000000000 +0100
@@ -5,6 +5,7 @@
# Rewritten to use lists instead of if-statements.
#

+obj-$(CONFIG_ACCESSIBILITY) += accessibility/
obj-$(CONFIG_PCI) += pci/
obj-$(CONFIG_PARISC) += parisc/
obj-$(CONFIG_RAPIDIO) += rapidio/
diff -ur linux-2.6.24.1-orig/include/linux/console.h linux-2.6.24.1-perso/include/linux/console.h
--- linux-2.6.24.1-orig/include/linux/console.h 2008-01-25 09:32:44.000000000 +0100
+++ linux-2.6.24.1-perso/include/linux/console.h 2008-02-21 12:11:08.000000000 +0100
@@ -91,6 +91,7 @@
#define CON_ENABLED (4)
#define CON_BOOT (8)
#define CON_ANYTIME (16) /* Safe to call when cpu is offline */
+#define CON_BRL (32) /* Used for a braille device */

struct console {
char name[16];
@@ -121,6 +122,9 @@
extern void console_stop(struct console *);
extern void console_start(struct console *);
extern int is_console_locked(void);
+extern int braille_register_console(struct console *, int index,
+ char *console_options, char *braille_options);
+extern int braille_unregister_console(struct console *);

extern int console_suspend_enabled;

diff -ur linux-2.6.24.1-orig/kernel/printk.c linux-2.6.24.1-perso/kernel/printk.c
--- linux-2.6.24.1-orig/kernel/printk.c 2008-02-20 21:47:09.000000000 +0100
+++ linux-2.6.24.1-perso/kernel/printk.c 2008-02-21 12:09:06.000000000 +0100
@@ -105,6 +105,7 @@
char name[8]; /* Name of the driver */
int index; /* Minor dev. to use */
char *options; /* Options for the driver */
+ char *brl_options; /* Options for braille driver */
};

#define MAX_CMDLINECONSOLES 8
@@ -766,15 +767,59 @@

#endif

+static int __add_preferred_console(char *name, int idx, char *options,
+ char *brl_options)
+{
+ struct console_cmdline *c;
+ int i;
+
+ /*
+ * See if this tty is not yet registered, and
+ * if we have a slot free.
+ */
+ for (i = 0; i < MAX_CMDLINECONSOLES && console_cmdline[i].name[0]; i++)
+ if (strcmp(console_cmdline[i].name, name) == 0 &&
+ console_cmdline[i].index == idx) {
+ if (!brl_options)
+ selected_console = i;
+ return 0;
+ }
+ if (i == MAX_CMDLINECONSOLES)
+ return -E2BIG;
+ if (!brl_options)
+ selected_console = i;
+ c = &console_cmdline[i];
+ memcpy(c->name, name, sizeof(c->name));
+ c->name[sizeof(c->name) - 1] = 0;
+ c->options = options;
+ c->brl_options = brl_options;
+ c->index = idx;
+ return 0;
+}
/*
* Set up a list of consoles. Called from init/main.c
*/
static int __init console_setup(char *str)
{
char buf[sizeof(console_cmdline[0].name) + 4]; /* 4 for index */
- char *s, *options;
+ char *s, *options, *brl_options = NULL;
int idx;

+#ifdef CONFIG_A11Y_BRAILLE_CONSOLE
+ if (!memcmp(str, "brl,", 4)) {
+ brl_options = "";
+ str += 4;
+ } else if (!memcmp(str, "brl=", 4)) {
+ brl_options = str + 4;
+ str = strchr(brl_options, ',');
+ if (!str) {
+ printk(KERN_ERR "need port name after brl=\n");
+ return 1;
+ }
+ *(str++) = 0;
+ }
+#endif
+
/*
* Decode str into name, index, options.
*/
@@ -799,7 +844,7 @@
idx = simple_strtoul(s, NULL, 10);
*s = 0;

- add_preferred_console(buf, idx, options);
+ __add_preferred_console(buf, idx, options, brl_options);
return 1;
}
__setup("console=", console_setup);
@@ -819,28 +864,7 @@
*/
int add_preferred_console(char *name, int idx, char *options)
{
- struct console_cmdline *c;
- int i;
-
- /*
- * See if this tty is not yet registered, and
- * if we have a slot free.
- */
- for (i = 0; i < MAX_CMDLINECONSOLES && console_cmdline[i].name[0]; i++)
- if (strcmp(console_cmdline[i].name, name) == 0 &&
- console_cmdline[i].index == idx) {
- selected_console = i;
- return 0;
- }
- if (i == MAX_CMDLINECONSOLES)
- return -E2BIG;
- selected_console = i;
- c = &console_cmdline[i];
- memcpy(c->name, name, sizeof(c->name));
- c->name[sizeof(c->name) - 1] = 0;
- c->options = options;
- c->index = idx;
- return 0;
+ return __add_preferred_console(name, idx, options, NULL);
}

int update_console_cmdline(char *name, int idx, char *name_new, int idx_new, char *options)
@@ -1121,6 +1145,16 @@
continue;
if (console->index < 0)
console->index = console_cmdline[i].index;
+#ifdef CONFIG_A11Y_BRAILLE_CONSOLE
+ if (console_cmdline[i].brl_options) {
+ console->flags |= CON_BRL;
+ braille_register_console(console,
+ console_cmdline[i].index,
+ console_cmdline[i].options,
+ console_cmdline[i].brl_options);
+ return;
+ }
+#endif
if (console->setup &&
console->setup(console, console_cmdline[i].options) != 0)
break;
@@ -1179,6 +1213,11 @@
struct console *a, *b;
int res = 1;

+#ifdef CONFIG_A11Y_BRAILLE_CONSOLE
+ if (console->flags & CON_BRL)
+ return braille_unregister_console(console);
+#endif
+
acquire_console_sem();
if (console_drivers == console) {
console_drivers=console->next;
diff -urN linux-2.6.24.1-orig/drivers/accessibility/braille/braille_console.c linux-2.6.24.1-perso/drivers/accessibility/braille/braille_console.c
--- linux-2.6.24.1-orig/drivers/accessibility/braille/braille_console.c 1970-01-01 01:00:00.000000000 +0100
+++ linux-2.6.24.1-perso/drivers/accessibility/braille/braille_console.c 2008-02-21 12:27:41.000000000 +0100
@@ -0,0 +1,397 @@
+/*
+ * Minimalistic braille device kernel support.
+ *
+ * By default, shows console messages on the braille device.
+ * Pressing Insert switches to VC browsing.
+ *
+ * Copyright (C) Samuel Thibault <[email protected]>
+ *
+ * This program is free software ; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation ; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY ; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with the program ; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <linux/autoconf.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/console.h>
+#include <linux/notifier.h>
+
+#include <linux/selection.h>
+#include <linux/vt_kern.h>
+#include <linux/consolemap.h>
+
+#include <linux/keyboard.h>
+#include <linux/kbd_kern.h>
+#include <linux/input.h>
+
+MODULE_AUTHOR("[email protected]");
+MODULE_DESCRIPTION("braille device");
+MODULE_LICENSE("GPL");
+
+/*
+ * Braille device support part.
+ */
+
+/* Emit various sounds */
+static int sound;
+module_param(sound, bool, 0);
+MODULE_PARM_DESC(sound, "emit sounds");
+
+static void beep(unsigned int freq)
+{
+ if (sound)
+ kd_mksound(freq, HZ/10);
+}
+
+/* mini console */
+#define WIDTH 40
+#define BRAILLE_KEY KEY_INSERT
+static u16 console_buf[WIDTH];
+static int console_cursor;
+
+/* mini view of VC */
+static int vc_x, vc_y, lastvc_x, lastvc_y;
+
+/* show console ? (or show VC) */
+static int console_show = 1;
+/* pending newline ? */
+static int console_newline = 1;
+static int lastVC = -1;
+
+static struct console *braille_co;
+
+/* Very VisioBraille-specific */
+static void braille_write(u16 *buf)
+{
+ static u16 lastwrite[WIDTH];
+ unsigned char data[1 + 1 + 2*WIDTH + 2 + 1], csum = 0, *c;
+ u16 out;
+ int i;
+
+ if (!braille_co)
+ return;
+
+ if (!memcmp(lastwrite, buf, WIDTH * sizeof(*buf)))
+ return;
+ memcpy(lastwrite, buf, WIDTH * sizeof(*buf));
+
+#define SOH 1
+#define STX 2
+#define ETX 2
+#define EOT 4
+#define ENQ 5
+ data[0] = STX;
+ data[1] = '>';
+ csum ^= '>';
+ c = &data[2];
+ for (i = 0; i < WIDTH; i++) {
+ out = buf[i];
+ if (out >= 0x100)
+ out = '?';
+ else if (out == 0x00)
+ out = ' ';
+ csum ^= out;
+ if (out <= 0x05) {
+ *c++ = SOH;
+ out |= 0x40;
+ }
+ *c++ = out;
+ }
+
+ if (csum <= 0x05) {
+ *c++ = SOH;
+ csum |= 0x40;
+ }
+ *c++ = csum;
+ *c++ = ETX;
+
+ braille_co->write(braille_co, data, c - data);
+}
+
+/* Follow the VC cursor*/
+static void vc_follow_cursor(struct vc_data *vc)
+{
+ vc_x = vc->vc_x - (vc->vc_x % WIDTH);
+ vc_y = vc->vc_y;
+ lastvc_x = vc->vc_x;
+ lastvc_y = vc->vc_y;
+}
+
+/* Maybe the VC cursor moved, if so follow it */
+static void vc_maybe_cursor_moved(struct vc_data *vc)
+{
+ if (vc->vc_x != lastvc_x || vc->vc_y != lastvc_y)
+ vc_follow_cursor(vc);
+}
+
+/* Show portion of VC at vc_x, vc_y */
+static void vc_refresh(struct vc_data *vc)
+{
+ u16 buf[WIDTH];
+ int i;
+
+ for (i = 0; i < WIDTH; i++) {
+ u16 glyph = screen_glyph(vc,
+ 2 * (vc_x + i) + vc_y * vc->vc_size_row);
+ buf[i] = inverse_translate(vc, glyph, 1);
+ }
+ braille_write(buf);
+}
+
+/*
+ * Link to keyboard
+ */
+
+static int keyboard_notifier_call(struct notifier_block *blk,
+ unsigned long code, void *_param)
+{
+ struct keyboard_notifier_param *param = _param;
+ struct vc_data *vc = param->vc;
+ int ret = NOTIFY_OK;
+
+ if (!param->down)
+ return ret;
+
+ switch (code) {
+ case KBD_KEYCODE:
+ if (console_show) {
+ if (param->value == BRAILLE_KEY) {
+ console_show = 0;
+ beep(880);
+ vc_maybe_cursor_moved(vc);
+ vc_refresh(vc);
+ ret = NOTIFY_STOP;
+ }
+ } else {
+ ret = NOTIFY_STOP;
+ switch (param->value) {
+ case KEY_INSERT:
+ beep(440);
+ console_show = 1;
+ lastVC = -1;
+ braille_write(console_buf);
+ break;
+ case KEY_LEFT:
+ if (vc_x > 0) {
+ vc_x -= WIDTH;
+ if (vc_x < 0)
+ vc_x = 0;
+ } else if (vc_y >= 1) {
+ beep(880);
+ vc_y--;
+ vc_x = vc->vc_cols-WIDTH;
+ } else
+ beep(220);
+ break;
+ case KEY_RIGHT:
+ if (vc_x + WIDTH < vc->vc_cols) {
+ vc_x += WIDTH;
+ } else if (vc_y + 1 < vc->vc_rows) {
+ beep(880);
+ vc_y++;
+ vc_x = 0;
+ } else
+ beep(220);
+ break;
+ case KEY_DOWN:
+ if (vc_y + 1 < vc->vc_rows)
+ vc_y++;
+ else
+ beep(220);
+ break;
+ case KEY_UP:
+ if (vc_y >= 1)
+ vc_y--;
+ else
+ beep(220);
+ break;
+ case KEY_HOME:
+ vc_follow_cursor(vc);
+ break;
+ case KEY_PAGEUP:
+ vc_x = 0;
+ vc_y = 0;
+ break;
+ case KEY_PAGEDOWN:
+ vc_x = 0;
+ vc_y = vc->vc_rows-1;
+ break;
+ default:
+ ret = NOTIFY_OK;
+ break;
+ }
+ if (ret == NOTIFY_STOP)
+ vc_refresh(vc);
+ }
+ break;
+ case KBD_POST_KEYSYM:
+ {
+ unsigned char type = KTYP(param->value) - 0xf0;
+ if (type == KT_SPEC) {
+ unsigned char val = KVAL(param->value);
+ int on_off = -1;
+
+ switch (val) {
+ case KVAL(K_CAPS):
+ on_off = vc_kbd_led(kbd_table + fg_console,
+ VC_CAPSLOCK);
+ break;
+ case KVAL(K_NUM):
+ on_off = vc_kbd_led(kbd_table + fg_console,
+ VC_NUMLOCK);
+ break;
+ case KVAL(K_HOLD):
+ on_off = vc_kbd_led(kbd_table + fg_console,
+ VC_SCROLLOCK);
+ break;
+ }
+ if (on_off == 1)
+ beep(880);
+ else if (on_off == 0)
+ beep(440);
+ }
+ }
+ case KBD_UNBOUND_KEYCODE:
+ case KBD_UNICODE:
+ case KBD_KEYSYM:
+ /* Unused */
+ break;
+ }
+ return ret;
+}
+
+static struct notifier_block keyboard_notifier_block = {
+ .notifier_call = keyboard_notifier_call,
+};
+
+static int vt_notifier_call(struct notifier_block *blk,
+ unsigned long code, void *_param)
+{
+ struct vt_notifier_param *param = _param;
+ struct vc_data *vc = param->vc;
+ switch (code) {
+ case VT_ALLOCATE:
+ break;
+ case VT_DEALLOCATE:
+ break;
+ case VT_WRITE:
+ {
+ unsigned char c = param->c;
+ if (vc->vc_num != fg_console)
+ break;
+ switch (c) {
+ case '\b':
+ case 127:
+ if (console_cursor > 0) {
+ console_cursor--;
+ console_buf[console_cursor] = ' ';
+ }
+ break;
+ case '\n':
+ case '\v':
+ case '\f':
+ case '\r':
+ console_newline = 1;
+ break;
+ case '\t':
+ c = ' ';
+ /* Fallthrough */
+ default:
+ if (c < 32)
+ /* Ignore other control sequences */
+ break;
+ if (console_newline) {
+ memset(console_buf, 0, sizeof(console_buf));
+ console_cursor = 0;
+ console_newline = 0;
+ }
+ if (console_cursor == WIDTH)
+ memmove(console_buf, &console_buf[1],
+ (WIDTH-1) * sizeof(*console_buf));
+ else
+ console_cursor++;
+ console_buf[console_cursor-1] = c;
+ break;
+ }
+ if (console_show)
+ braille_write(console_buf);
+ else {
+ vc_maybe_cursor_moved(vc);
+ vc_refresh(vc);
+ }
+ break;
+ }
+ case VT_UPDATE:
+ /* Maybe a VT switch, flush */
+ if (console_show) {
+ if (vc->vc_num != lastVC) {
+ lastVC = vc->vc_num;
+ memset(console_buf, 0, sizeof(console_buf));
+ console_cursor = 0;
+ braille_write(console_buf);
+ }
+ } else {
+ vc_maybe_cursor_moved(vc);
+ vc_refresh(vc);
+ }
+ break;
+ }
+ return NOTIFY_OK;
+}
+
+static struct notifier_block vt_notifier_block = {
+ .notifier_call = vt_notifier_call,
+};
+
+/*
+ * Called from printk.c when console=brl is given
+ */
+
+int braille_register_console(struct console *console, int index,
+ char *console_options, char *braille_options)
+{
+ int ret;
+ if (!console_options)
+ /* Only support VisioBraille for now */
+ console_options = "57600o8";
+ if (braille_co)
+ return -ENODEV;
+ if (console->setup) {
+ ret = console->setup(console, console_options);
+ if (ret != 0)
+ return ret;
+ }
+ console->flags |= CON_ENABLED;
+ console->index = index;
+ braille_co = console;
+ return 0;
+}
+
+int braille_unregister_console(struct console *console)
+{
+ if (braille_co != console)
+ return -EINVAL;
+ braille_co = NULL;
+ return 0;
+}
+
+static int __init braille_init(void)
+{
+ register_keyboard_notifier(&keyboard_notifier_block);
+ register_vt_notifier(&vt_notifier_block);
+ return 0;
+}
+
+console_initcall(braille_init);
diff -urN linux-2.6.24.1-orig/drivers/accessibility/Kconfig linux-2.6.24.1-perso/drivers/accessibility/Kconfig
--- linux-2.6.24.1-orig/drivers/accessibility/Kconfig 1970-01-01 01:00:00.000000000 +0100
+++ linux-2.6.24.1-perso/drivers/accessibility/Kconfig 2008-02-20 21:54:26.000000000 +0100
@@ -0,0 +1,22 @@
+menuconfig ACCESSIBILITY
+ bool "Accessibility support"
+ ---help---
+ Enable a submenu where accessibility items may be enabled.
+
+ If unsure, say N.
+
+if ACCESSIBILITY
+config A11Y_BRAILLE_CONSOLE
+ bool "Console on braille device"
+ depends on SERIAL_CORE_CONSOLE
+ ---help---
+ Enables console output on a braille device connected to a 8250
+ serial port. For now only the VisioBraille device is supported.
+
+ To actually enable it, you need to pass option
+ console=brl,ttyS0
+ to the kernel. Options are the same as for serial console.
+
+ If unsure, say N.
+
+endif # ACCESSIBILITY
diff -urN linux-2.6.24.1-orig/drivers/accessibility/Makefile linux-2.6.24.1-perso/drivers/accessibility/Makefile
--- linux-2.6.24.1-orig/drivers/accessibility/Makefile 1970-01-01 01:00:00.000000000 +0100
+++ linux-2.6.24.1-perso/drivers/accessibility/Makefile 2008-02-04 02:42:32.000000000 +0100
@@ -0,0 +1 @@
+obj-$(CONFIG_A11Y_BRAILLE_CONSOLE) += braille/braille_console.o

2008-02-23 08:17:38

by Andrew Morton

[permalink] [raw]
Subject: Re: [PATCH2] Basic braille screen reader support

On Fri, 22 Feb 2008 01:28:22 +0100 Samuel Thibault <[email protected]> wrote:

> Samuel Thibault, le Wed 06 Feb 2008 02:04:23 +0000, a __crit :
> > Andrew Morton, le Tue 05 Feb 2008 16:58:53 -0800, a __crit :
> > > On Tue, 5 Feb 2008 22:00:54 +0000
> > > Samuel Thibault <[email protected]> wrote:
> > > > + serial8250_console.write(braille_co, data, c - data);
> > >
> > > hm. Is it appropriate that this driver wire itself directly into
> > > serial8250?
> > > What if the screen reader is attached to some other sort of
> > > uart, or a terminal server, or...
> >
> > Indeed that's an issue. For now, there is no clean way to attach to the
> > early serial drivers, that's why I chose 8250,
>
> In the patch below, I hook into kernel/printk.c's console= parser, which
> now gives me attachment to any kind of console.
>
>
>
>
> This adds a minimalistic braille screen reader support.
> This is meant to be used by blind people e.g. on boot failures or when /
> cannot be mounted etc and thus the userland screen readers can not work.
>

Sorry, but I can't say that this is my favoritest ever patch. But I can't
immediately think of any way of significantly improving it :( Jiri and
Dmitry appear to be hiding.

> +++ linux-2.6.24.1-perso/kernel/printk.c 2008-02-21 12:09:06.000000000 +0100
> @@ -105,6 +105,7 @@

Please use `diff -p'

> char name[8]; /* Name of the driver */
> int index; /* Minor dev. to use */
> char *options; /* Options for the driver */
> + char *brl_options; /* Options for braille driver */
> };

Should this depend on CONFIG_A11Y_BRAILLE_CONSOLE or whatever?

> #define MAX_CMDLINECONSOLES 8
> @@ -766,15 +767,59 @@
>
> #endif
>
> +static int __add_preferred_console(char *name, int idx, char *options,
> + char *brl_options)
> +{
> + struct console_cmdline *c;
> + int i;
> +
> + /*
> + * See if this tty is not yet registered, and
> + * if we have a slot free.
> + */
> + for (i = 0; i < MAX_CMDLINECONSOLES && console_cmdline[i].name[0]; i++)
> + if (strcmp(console_cmdline[i].name, name) == 0 &&
> + console_cmdline[i].index == idx) {
> + if (!brl_options)
> + selected_console = i;
> + return 0;
> + }
> + if (i == MAX_CMDLINECONSOLES)
> + return -E2BIG;

Does the array of consles have any locking here?

> + if (!brl_options)
> + selected_console = i;
> + c = &console_cmdline[i];
> + memcpy(c->name, name, sizeof(c->name));
> + c->name[sizeof(c->name) - 1] = 0;

strlcpy()?

> + c->options = options;
> + c->brl_options = brl_options;
> + c->index = idx;
> + return 0;
> +}
> /*
> * Set up a list of consoles. Called from init/main.c
> */
> static int __init console_setup(char *str)
> {
> char buf[sizeof(console_cmdline[0].name) + 4]; /* 4 for index */
> - char *s, *options;
> + char *s, *options, *brl_options = NULL;
> int idx;
>
> +#ifdef CONFIG_A11Y_BRAILLE_CONSOLE
> + if (!memcmp(str, "brl,", 4)) {
> + brl_options = "";
> + str += 4;
> + } else if (!memcmp(str, "brl=", 4)) {
> + brl_options = str + 4;
> + str = strchr(brl_options, ',');
> + if (!str) {
> + printk(KERN_ERR "need port name after brl=\n");
> + return 1;
> + }
> + *(str++) = 0;
> + }
> +#endif

Update Documentation/kernel-parameters.txt, please. And additional
documentation would be nice, if justified?

> /*
> * Decode str into name, index, options.
> */
> @@ -799,7 +844,7 @@
> idx = simple_strtoul(s, NULL, 10);
> *s = 0;
>
> - add_preferred_console(buf, idx, options);
> + __add_preferred_console(buf, idx, options, brl_options);
> return 1;
> }
>
> ...
>
> +static void beep(unsigned int freq)
> +{
> + if (sound)
> + kd_mksound(freq, HZ/10);
> +}

hm, do we have enough Kconfig dependencies here to ensure that kd_mksound()
is always available?

2008-02-23 13:19:18

by Samuel Thibault

[permalink] [raw]
Subject: Re: [PATCH2] Basic braille screen reader support

Andrew Morton, le Sat 23 Feb 2008 00:04:10 -0800, a ?crit :
> > +++ linux-2.6.24.1-perso/kernel/printk.c 2008-02-21 12:09:06.000000000 +0100
> > @@ -105,6 +105,7 @@
>
> Please use `diff -p'

Argl, that's editdiff's fault. We need to fix it to keep the -p
comments.

> > char name[8]; /* Name of the driver */
> > int index; /* Minor dev. to use */
> > char *options; /* Options for the driver */
> > + char *brl_options; /* Options for braille driver */
> > };
>
> Should this depend on CONFIG_A11Y_BRAILLE_CONSOLE or whatever?

It can, indeed. It just makes the code a little more clumsy to save 32
or 64 bytes.

> > + for (i = 0; i < MAX_CMDLINECONSOLES && console_cmdline[i].name[0]; i++)
> > + if (strcmp(console_cmdline[i].name, name) == 0 &&
> > + console_cmdline[i].index == idx) {
> > + if (!brl_options)
> > + selected_console = i;
> > + return 0;
> > + }
> > + if (i == MAX_CMDLINECONSOLES)
> > + return -E2BIG;
>
> Does the array of consles have any locking here?

Well, that's actually just the original code that I moved a bit earlier,
so the code path is not changed.

> > + if (!brl_options)
> > + selected_console = i;
> > + c = &console_cmdline[i];
> > + memcpy(c->name, name, sizeof(c->name));
> > + c->name[sizeof(c->name) - 1] = 0;
>
> strlcpy()?

Again, that's the original code, unmodified, but we can put an strlcpy
here yes.

> > +static void beep(unsigned int freq)
> > +{
> > + if (sound)
> > + kd_mksound(freq, HZ/10);
> > +}
>
> hm, do we have enough Kconfig dependencies here to ensure that kd_mksound()
> is always available?

Ah, CONFIG_VT is needed indeed.

I'll address those in replies to this mail.

Samuel

2008-02-23 13:19:37

by Samuel Thibault

[permalink] [raw]
Subject: [PATCH] Braille screen reader fixes

Braille screen reader fixes:
- console_cmdline's brl_options field is only required when braille
console support is enabled.
- Use strlcpy to copy the console name.
- braille console support depends on VT support.

Signed-off-by: Samuel Thibault <[email protected]>

--- linux-2.6.24.1-orig/kernel/printk.c 2008-02-21 12:09:06.000000000 +0100
+++ linux-2.6.24.1-perso/kernel/printk.c 2008-02-23 12:57:42.000000000 +0100
@@ -105,7 +105,9 @@ struct console_cmdline
char name[8]; /* Name of the driver */
int index; /* Minor dev. to use */
char *options; /* Options for the driver */
+#ifdef CONFIG_A11Y_BRAILLE_CONSOLE
char *brl_options; /* Options for braille driver */
+#endif
};

#define MAX_CMDLINECONSOLES 8
@@ -789,10 +791,11 @@ static int __add_preferred_console
if (!brl_options)
selected_console = i;
c = &console_cmdline[i];
- memcpy(c->name, name, sizeof(c->name));
- c->name[sizeof(c->name) - 1] = 0;
+ strlcpy(c->name, name, sizeof(c->name));
c->options = options;
+#ifdef CONFIG_A11Y_BRAILLE_CONSOLE
c->brl_options = brl_options;
+#endif
c->index = idx;
return 0;
}
--- linux-2.6.24.1-orig/drivers/accessibility/Kconfig 2008-02-23 13:32:38.000000000 +0100
+++ linux-2.6.24.1-perso/drivers/accessibility/Kconfig 2008-02-23 13:23:21.000000000 +0100
@@ -8,6 +8,7 @@ menuconfig ACCESSIBILITY
if ACCESSIBILITY
config A11Y_BRAILLE_CONSOLE
bool "Console on braille device"
+ depends on VT
depends on SERIAL_CORE_CONSOLE
---help---
Enables console output on a braille device connected to a 8250

2008-02-23 13:19:52

by Samuel Thibault

[permalink] [raw]
Subject: [PATCH] Braille screen reader documentation

Document the console=brl option and the usage of the braille screen
reader.

Signed-off-by: Samuel Thibault <[email protected]>

--- linux-2.6.24.1-orig/Documentation/kernel-parameters.txt 2008-01-25 09:31:45.000000000 +0100
+++ linux-2.6.24.1-perso/Documentation/kernel-parameters.txt 2008-02-23 13:21:27.000000000 +0100
@@ -463,6 +463,11 @@
switching to the matching ttyS device later. The
options are the same as for ttyS, above.

+ If the device connected to the port is not a TTY but a braille
+ device, prepend "brl," before the device type, for instance
+ console=brl,ttyS0
+ For now, only VisioBraille is supported.
+
earlycon= [KNL] Output early console device and options.
uart[8250],io,<addr>[,options]
uart[8250],mmio,<addr>[,options]
--- linux-2.6.24.1-orig/Documentation/braille-console.txt 1970-01-01 01:00:00.000000000 +0100
+++ linux-2.6.24.1-perso/Documentation/braille-console.txt 2008-02-23 13:20:31.000000000 +0100
@@ -0,0 +1,34 @@
+ Linux Braille Console
+
+To get early boot messages on a braille device (before userspace screen
+readers can start), you first need to compile the support for the usual serial
+console (see serial-console.txt), and for braille device (in Device Drivers -
+Accessibility).
+
+Then you need to specify a console=brl, option on the kernel command line, the
+format is:
+
+ console=brl,serial_options...
+
+where serial_options... are the same as described in serial-console.txt
+
+So for instance you can use console=brl,ttyS0 if the braille device is connected
+to the first serial port, and console=brl,ttyS0,115200 to override the baud rate
+to 115200, etc.
+
+By default, the braille device will just show the last kernel message (console
+mode). To review previous messages, press the Insert key to switch to the VT
+review mode. In review mode, the arrow keys permit to browse in the VT content,
+page up/down keys go at the top/bottom of the screen, and the home key goes back
+to the cursor, hence providing very basic screen reviewing facility.
+
+Sound feedback can be obtained by adding the braille_console.sound=1 kernel
+parameter.
+
+For simplicity, only one braille console can be enabled, other uses of
+console=brl,... will be discarded. Also note that it does not interfere with
+the console selection mecanism described in serial-console.txt
+
+For now, only the VisioBraille device is supported.
+
+Samuel Thibault <[email protected]>

2008-03-20 02:08:20

by Samuel Thibault

[permalink] [raw]
Subject: Re: [mmotm build error] Re: [PATCH,RESEND] Basic braille screen reader support

Randy Dunlap, le Wed 19 Mar 2008 11:57:26 -0700, a ?crit :
> when O=dir is used in make:
>
> CC drivers/accessibility/braille/braille_console.o
> Assembler messages:
> Fatal error: can't create drivers/accessibility/braille/braille_console.o: No such file or directory
> CC crypto/aes_generic.o
> make[3]: *** [drivers/accessibility/braille/braille_console.o] Error 2
> make[2]: *** [drivers/accessibility] Error 2
> make[1]: *** [drivers] Error 2

Oh, right, the patch below should fix it



Properly recurse Makefiles into accessibility and accessibility/braille/

Signed-off-by: Samuel Thibault <[email protected]>

--- linux-2.6.24.1-perso/drivers/accessibility/Makefile.orig 2008-03-20 01:51:09.000000000 +0000
+++ linux-2.6.24.1-perso/drivers/accessibility/Makefile 2008-03-20 01:52:30.000000000 +0000
@@ -1 +1 @@
-obj-$(CONFIG_A11Y_BRAILLE_CONSOLE) += braille/braille_console.o
+obj-y += braille/
--- /dev/null 2008-03-20 02:39:28.130012041 +0000
+++ linux-2.6.24.1-perso/drivers/accessibility/braille/Makefile 2008-03-20 01:52:44.000000000 +0000
@@ -0,0 +1 @@
+obj-$(CONFIG_A11Y_BRAILLE_CONSOLE) += braille_console.o

2008-03-20 04:20:40

by Randy Dunlap

[permalink] [raw]
Subject: Re: [mmotm build error] Re: [PATCH,RESEND] Basic braille screen reader support

On Thu, 20 Mar 2008 02:07:59 +0000 Samuel Thibault wrote:

> Randy Dunlap, le Wed 19 Mar 2008 11:57:26 -0700, a ?crit :
> > when O=dir is used in make:
> >
> > CC drivers/accessibility/braille/braille_console.o
> > Assembler messages:
> > Fatal error: can't create drivers/accessibility/braille/braille_console.o: No such file or directory
> > CC crypto/aes_generic.o
> > make[3]: *** [drivers/accessibility/braille/braille_console.o] Error 2
> > make[2]: *** [drivers/accessibility] Error 2
> > make[1]: *** [drivers] Error 2
>
> Oh, right, the patch below should fix it
>

Acked-by: Randy Dunlap <[email protected]>

Thanks.

>
> Properly recurse Makefiles into accessibility and accessibility/braille/
>
> Signed-off-by: Samuel Thibault <[email protected]>
>
> --- linux-2.6.24.1-perso/drivers/accessibility/Makefile.orig 2008-03-20 01:51:09.000000000 +0000
> +++ linux-2.6.24.1-perso/drivers/accessibility/Makefile 2008-03-20 01:52:30.000000000 +0000
> @@ -1 +1 @@
> -obj-$(CONFIG_A11Y_BRAILLE_CONSOLE) += braille/braille_console.o
> +obj-y += braille/
> --- /dev/null 2008-03-20 02:39:28.130012041 +0000
> +++ linux-2.6.24.1-perso/drivers/accessibility/braille/Makefile 2008-03-20 01:52:44.000000000 +0000
> @@ -0,0 +1 @@
> +obj-$(CONFIG_A11Y_BRAILLE_CONSOLE) += braille_console.o
> --
> To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
> the body of a message to [email protected]
> More majordomo info at http://vger.kernel.org/majordomo-info.html
> Please read the FAQ at http://www.tux.org/lkml/
>


---
~Randy

2008-03-20 06:21:21

by Randy Dunlap

[permalink] [raw]
Subject: [mmotm build error] Re: [PATCH,RESEND] Basic braille screen reader support

when O=dir is used in make:

CC drivers/accessibility/braille/braille_console.o
Assembler messages:
Fatal error: can't create drivers/accessibility/braille/braille_console.o: No such file or directory
CC crypto/aes_generic.o
make[3]: *** [drivers/accessibility/braille/braille_console.o] Error 2
make[2]: *** [drivers/accessibility] Error 2
make[1]: *** [drivers] Error 2

---
~Randy


Attachments:
config-rand9 (38.50 kB)