grub2/0111-New-terminal-outputs-using-serial-morse-and-spkmodem.patch
Peter Jones f74b50e380 Rebase to upstream, fix a pile of bugs. The usual.
Signed-off-by: Peter Jones <pjones@redhat.com>
2013-06-12 15:37:08 -04:00

806 lines
23 KiB
Diff
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

From ded439de5b72d33474f96fbc08b9687a76c938ac Mon Sep 17 00:00:00 2001
From: Vladimir 'phcoder' Serbinenko <phcoder@gmail.com>
Date: Wed, 16 Jan 2013 20:39:54 +0100
Subject: [PATCH 111/482] New terminal outputs using serial: morse and
spkmodem.
---
ChangeLog | 4 ++
docs/grub.texi | 24 +++++--
grub-core/Makefile.core.def | 12 ++++
grub-core/commands/i386/pc/play.c | 109 ++-----------------------------
grub-core/kern/i386/pit.c | 35 ++++------
grub-core/term/morse.c | 131 ++++++++++++++++++++++++++++++++++++++
grub-core/term/spkmodem.c | 106 ++++++++++++++++++++++++++++++
include/grub/i386/pit.h | 78 +++++++++++++++++++++++
include/grub/speaker.h | 47 ++++++++++++++
util/spkmodem-recv.c | 98 ++++++++++++++++++++++++++++
10 files changed, 512 insertions(+), 132 deletions(-)
create mode 100644 grub-core/term/morse.c
create mode 100644 grub-core/term/spkmodem.c
create mode 100644 include/grub/speaker.h
create mode 100644 util/spkmodem-recv.c
diff --git a/ChangeLog b/ChangeLog
index 96aca66..f1c53e3 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,5 +1,9 @@
2013-01-16 Vladimir Serbinenko <phcoder@gmail.com>
+ New terminal outputs using serial: morse and spkmodem.
+
+2013-01-16 Vladimir Serbinenko <phcoder@gmail.com>
+
Improve bidi handling in entry editor.
2013-01-16 Vladimir Serbinenko <phcoder@gmail.com>
diff --git a/docs/grub.texi b/docs/grub.texi
index e75bae9..efedd27 100644
--- a/docs/grub.texi
+++ b/docs/grub.texi
@@ -1229,9 +1229,9 @@ Select the terminal input device. You may select multiple devices here,
separated by spaces.
Valid terminal input names depend on the platform, but may include
-@samp{console} (PC BIOS and EFI consoles), @samp{serial} (serial terminal),
-@samp{ofconsole} (Open Firmware console), @samp{at_keyboard} (PC AT
-keyboard, mainly useful with Coreboot), or @samp{usb_keyboard} (USB keyboard
+@samp{console} (native platform console), @samp{serial} (serial terminal),
+@samp{serial_<port>} (serial terminal with explicit port selection),
+@samp{at_keyboard} (PC AT keyboard), or @samp{usb_keyboard} (USB keyboard
using the HID Boot Protocol, for cases where the firmware does not handle
this).
@@ -1242,9 +1242,21 @@ Select the terminal output device. You may select multiple devices here,
separated by spaces.
Valid terminal output names depend on the platform, but may include
-@samp{console} (PC BIOS and EFI consoles), @samp{serial} (serial terminal),
-@samp{gfxterm} (graphics-mode output), @samp{ofconsole} (Open Firmware
-console), or @samp{vga_text} (VGA text output, mainly useful with Coreboot).
+@samp{console} (native platform console), @samp{serial} (serial terminal),
+@samp{serial_<port>} (serial terminal with explicit port selection),
+@samp{gfxterm} (graphics-mode output), @samp{vga_text} (VGA text output),
+@samp{mda_text} (MDA text output), @samp{morse} (Morse-coding using system
+beeper) or @samp{spkmodem} (simple data protocol using system speaker).
+
+@samp{spkmodem} is useful when no serial port is available. Connect the output
+of sending system (where GRUB is running) to line-in of receiving system
+(usually developper machine).
+On receiving system compile @samp{spkmodem-recv} from
+@samp{util/spkmodem-recv.c} and run:
+
+@example
+parecord --channels=1 --rate=48000 --format=s16le | ./spkmodem-recv
+@end example
The default is to use the platform's native terminal output.
diff --git a/grub-core/Makefile.core.def b/grub-core/Makefile.core.def
index f4dd645..baf80b8 100644
--- a/grub-core/Makefile.core.def
+++ b/grub-core/Makefile.core.def
@@ -779,6 +779,18 @@ module = {
};
module = {
+ name = spkmodem;
+ x86 = term/spkmodem.c;
+ enable = x86;
+};
+
+module = {
+ name = morse;
+ x86 = term/morse.c;
+ enable = x86;
+};
+
+module = {
name = probe;
common = commands/probe.c;
};
diff --git a/grub-core/commands/i386/pc/play.c b/grub-core/commands/i386/pc/play.c
index 10a0181..40798c9 100644
--- a/grub-core/commands/i386/pc/play.c
+++ b/grub-core/commands/i386/pc/play.c
@@ -28,80 +28,12 @@
#include <grub/command.h>
#include <grub/i18n.h>
#include <grub/time.h>
+#include <grub/speaker.h>
GRUB_MOD_LICENSE ("GPLv3+");
#define BASE_TEMPO (60 * 1000)
-/* The speaker port. */
-#define SPEAKER 0x61
-
-/* If 0, follow state of SPEAKER_DATA bit, otherwise enable output
- from timer 2. */
-#define SPEAKER_TMR2 0x01
-
-/* If SPEAKER_TMR2 is not set, this provides direct input into the
- speaker. Otherwise, this enables or disables the output from the
- timer. */
-#define SPEAKER_DATA 0x02
-
-/* The PIT channel value ports. You can write to and read from them.
- Do not mess with timer 0 or 1. */
-#define PIT_COUNTER_0 0x40
-#define PIT_COUNTER_1 0x41
-#define PIT_COUNTER_2 0x42
-
-/* The frequency of the PIT clock. */
-#define PIT_FREQUENCY 0x1234dd
-
-/* The PIT control port. You can only write to it. Do not mess with
- timer 0 or 1. */
-#define PIT_CTRL 0x43
-#define PIT_CTRL_SELECT_MASK 0xc0
-#define PIT_CTRL_SELECT_0 0x00
-#define PIT_CTRL_SELECT_1 0x40
-#define PIT_CTRL_SELECT_2 0x80
-
-/* Read and load control. */
-#define PIT_CTRL_READLOAD_MASK 0x30
-#define PIT_CTRL_COUNTER_LATCH 0x00 /* Hold timer value until read. */
-#define PIT_CTRL_READLOAD_LSB 0x10 /* Read/load the LSB. */
-#define PIT_CTRL_READLOAD_MSB 0x20 /* Read/load the MSB. */
-#define PIT_CTRL_READLOAD_WORD 0x30 /* Read/load the LSB then the MSB. */
-
-/* Mode control. */
-#define PIT_CTRL_MODE_MASK 0x0e
-
-/* Interrupt on terminal count. Setting the mode sets output to low.
- When counter is set and terminated, output is set to high. */
-#define PIT_CTRL_INTR_ON_TERM 0x00
-
-/* Programmable one-shot. When loading counter, output is set to
- high. When counter terminated, output is set to low. Can be
- triggered again from that point on by setting the gate pin to
- high. */
-#define PIT_CTRL_PROGR_ONE_SHOT 0x02
-
-/* Rate generator. Output is low for one period of the counter, and
- high for the other. */
-#define PIT_CTRL_RATE_GEN 0x04
-
-/* Square wave generator. Output is low for one half of the period,
- and high for the other half. */
-#define PIT_CTRL_SQUAREWAVE_GEN 0x06
-
-/* Software triggered strobe. Setting the mode sets output to high.
- When counter is set and terminated, output is set to low. */
-#define PIT_CTRL_SOFTSTROBE 0x08
-
-/* Hardware triggered strobe. Like software triggered strobe, but
- only starts the counter when the gate pin is set to high. */
-#define PIT_CTRL_HARDSTROBE 0x0a
-
-/* Count mode. */
-#define PIT_CTRL_COUNT_MASK 0x01
-#define PIT_CTRL_COUNT_BINARY 0x00 /* 16-bit binary counter. */
-#define PIT_CTRL_COUNT_BCD 0x01 /* 4-decade BCD counter. */
#define T_REST ((grub_uint16_t) 0)
#define T_FINE ((grub_uint16_t) -1)
@@ -112,39 +44,6 @@ struct note
grub_uint16_t duration;
};
-static void
-beep_off (void)
-{
- unsigned char status;
-
- status = grub_inb (SPEAKER);
- grub_outb (status & ~(SPEAKER_TMR2 | SPEAKER_DATA), SPEAKER);
-}
-
-static void
-beep_on (grub_uint16_t pitch)
-{
- unsigned char status;
- unsigned int counter;
-
- if (pitch < 20)
- pitch = 20;
- else if (pitch > 20000)
- pitch = 20000;
-
- counter = PIT_FREQUENCY / pitch;
-
- /* Program timer 2. */
- grub_outb (PIT_CTRL_SELECT_2 | PIT_CTRL_READLOAD_WORD
- | PIT_CTRL_SQUAREWAVE_GEN | PIT_CTRL_COUNT_BINARY, PIT_CTRL);
- grub_outb (counter & 0xff, PIT_COUNTER_2); /* LSB */
- grub_outb ((counter >> 8) & 0xff, PIT_COUNTER_2); /* MSB */
-
- /* Start speaker. */
- status = grub_inb (SPEAKER);
- grub_outb (status | SPEAKER_TMR2 | SPEAKER_DATA, SPEAKER);
-}
-
/* Returns whether playing should continue. */
static int
play (unsigned tempo, struct note *note)
@@ -160,11 +59,11 @@ play (unsigned tempo, struct note *note)
switch (note->pitch)
{
case T_REST:
- beep_off ();
+ grub_speaker_beep_off ();
break;
default:
- beep_on (note->pitch);
+ grub_speaker_beep_on (note->pitch);
break;
}
@@ -263,7 +162,7 @@ grub_cmd_play (grub_command_t cmd __attribute__ ((unused)),
}
}
- beep_off ();
+ grub_speaker_beep_off ();
return 0;
}
diff --git a/grub-core/kern/i386/pit.c b/grub-core/kern/i386/pit.c
index 82a17d3..092481a 100644
--- a/grub-core/kern/i386/pit.c
+++ b/grub-core/kern/i386/pit.c
@@ -20,37 +20,30 @@
#include <grub/i386/io.h>
#include <grub/i386/pit.h>
-#define TIMER2_REG_CONTROL 0x42
-#define TIMER_REG_COMMAND 0x43
-#define TIMER2_REG_LATCH 0x61
-
-#define TIMER2_SELECT 0x80
-#define TIMER_ENABLE_LSB 0x20
-#define TIMER_ENABLE_MSB 0x10
-#define TIMER2_LATCH 0x20
-#define TIMER2_SPEAKER 0x02
-#define TIMER2_GATE 0x01
-
void
grub_pit_wait (grub_uint16_t tics)
{
/* Disable timer2 gate and speaker. */
- grub_outb (grub_inb (TIMER2_REG_LATCH) & ~ (TIMER2_SPEAKER | TIMER2_GATE),
- TIMER2_REG_LATCH);
+ grub_outb (grub_inb (GRUB_PIT_SPEAKER_PORT)
+ & ~ (GRUB_PIT_SPK_DATA | GRUB_PIT_SPK_TMR2),
+ GRUB_PIT_SPEAKER_PORT);
/* Set tics. */
- grub_outb (TIMER2_SELECT | TIMER_ENABLE_LSB | TIMER_ENABLE_MSB, TIMER_REG_COMMAND);
- grub_outb (tics & 0xff, TIMER2_REG_CONTROL);
- grub_outb (tics >> 8, TIMER2_REG_CONTROL);
+ grub_outb (GRUB_PIT_CTRL_SELECT_2 | GRUB_PIT_CTRL_READLOAD_WORD,
+ GRUB_PIT_CTRL);
+ grub_outb (tics & 0xff, GRUB_PIT_COUNTER_2);
+ grub_outb (tics >> 8, GRUB_PIT_COUNTER_2);
/* Enable timer2 gate, keep speaker disabled. */
- grub_outb ((grub_inb (TIMER2_REG_LATCH) & ~ TIMER2_SPEAKER) | TIMER2_GATE,
- TIMER2_REG_LATCH);
+ grub_outb ((grub_inb (GRUB_PIT_SPEAKER_PORT) & ~ GRUB_PIT_SPK_DATA)
+ | GRUB_PIT_SPK_TMR2,
+ GRUB_PIT_SPEAKER_PORT);
/* Wait. */
- while ((grub_inb (TIMER2_REG_LATCH) & TIMER2_LATCH) == 0x00);
+ while ((grub_inb (GRUB_PIT_SPEAKER_PORT) & GRUB_PIT_SPK_TMR2_LATCH) == 0x00);
/* Disable timer2 gate and speaker. */
- grub_outb (grub_inb (TIMER2_REG_LATCH) & ~ (TIMER2_SPEAKER | TIMER2_GATE),
- TIMER2_REG_LATCH);
+ grub_outb (grub_inb (GRUB_PIT_SPEAKER_PORT)
+ & ~ (GRUB_PIT_SPK_DATA | GRUB_PIT_SPK_TMR2),
+ GRUB_PIT_SPEAKER_PORT);
}
diff --git a/grub-core/term/morse.c b/grub-core/term/morse.c
new file mode 100644
index 0000000..3d6c650
--- /dev/null
+++ b/grub-core/term/morse.c
@@ -0,0 +1,131 @@
+/*
+ * GRUB -- GRand Unified Bootloader
+ * Copyright (C) 2011,2012,2013 Free Software Foundation, Inc.
+ *
+ * GRUB 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 3 of the License, or
+ * (at your option) any later version.
+ *
+ * GRUB 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 GRUB. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <grub/term.h>
+#include <grub/misc.h>
+#include <grub/types.h>
+#include <grub/err.h>
+#include <grub/dl.h>
+#include <grub/time.h>
+#include <grub/speaker.h>
+
+GRUB_MOD_LICENSE ("GPLv3+");
+
+#define BASE_TIME 250
+
+static const char codes[0x80][6] =
+ {
+ ['0'] = { 3, 3, 3, 3, 3, 0 },
+ ['1'] = { 1, 3, 3, 3, 3, 0 },
+ ['2'] = { 1, 1, 3, 3, 3, 0 },
+ ['3'] = { 1, 1, 1, 3, 3, 0 },
+ ['4'] = { 1, 1, 1, 1, 3, 0 },
+ ['5'] = { 1, 1, 1, 1, 1, 0 },
+ ['6'] = { 3, 1, 1, 1, 1, 0 },
+ ['7'] = { 3, 3, 1, 1, 1, 0 },
+ ['8'] = { 3, 3, 3, 1, 1, 0 },
+ ['9'] = { 3, 3, 3, 3, 1, 0 },
+ ['a'] = { 1, 3, 0 },
+ ['b'] = { 3, 1, 1, 1, 0 },
+ ['c'] = { 3, 1, 3, 1, 0 },
+ ['d'] = { 3, 1, 1, 0 },
+ ['e'] = { 1, 0 },
+ ['f'] = { 1, 1, 3, 1, 0 },
+ ['g'] = { 3, 3, 1, 0 },
+ ['h'] = { 1, 1, 1, 1, 0 },
+ ['i'] = { 1, 1, 0 },
+ ['j'] = { 1, 3, 3, 3, 0 },
+ ['k'] = { 3, 1, 3, 0 },
+ ['l'] = { 1, 3, 1, 1, 0 },
+ ['m'] = { 3, 3, 0 },
+ ['n'] = { 3, 1, 0 },
+ ['o'] = { 3, 3, 3, 0 },
+ ['p'] = { 1, 3, 3, 1, 0 },
+ ['q'] = { 3, 3, 1, 3, 0 },
+ ['r'] = { 1, 3, 1, 0 },
+ ['s'] = { 1, 1, 1, 0 },
+ ['t'] = { 3, 0 },
+ ['u'] = { 1, 1, 3, 0 },
+ ['v'] = { 1, 1, 1, 3, 0 },
+ ['w'] = { 1, 3, 3, 0 },
+ ['x'] = { 3, 1, 1, 3, 0 },
+ ['y'] = { 3, 1, 3, 3, 0 },
+ ['z'] = { 3, 3, 1, 1, 0 }
+ };
+
+static void
+grub_audio_tone (int length)
+{
+ grub_speaker_beep_on (1000);
+ grub_millisleep (length);
+ grub_speaker_beep_off ();
+}
+
+static void
+grub_audio_putchar (struct grub_term_output *term __attribute__ ((unused)),
+ const struct grub_unicode_glyph *c_in)
+{
+ grub_uint8_t c;
+ int i;
+
+ /* For now, do not try to use a surrogate pair. */
+ if (c_in->base > 0x7f)
+ c = '?';
+ else
+ c = grub_tolower (c_in->base);
+ for (i = 0; codes[c][i]; i++)
+ {
+ grub_audio_tone (codes[c][i] * BASE_TIME);
+ grub_millisleep (BASE_TIME);
+ }
+ grub_millisleep (2 * BASE_TIME);
+}
+
+
+static int
+dummy (void)
+{
+ return 0;
+}
+
+static struct grub_term_output grub_audio_term_output =
+ {
+ .name = "morse",
+ .init = (void *) dummy,
+ .fini = (void *) dummy,
+ .putchar = grub_audio_putchar,
+ .getwh = (void *) dummy,
+ .getxy = (void *) dummy,
+ .gotoxy = (void *) dummy,
+ .cls = (void *) dummy,
+ .setcolorstate = (void *) dummy,
+ .setcursor = (void *) dummy,
+ .normal_color = GRUB_TERM_DEFAULT_NORMAL_COLOR,
+ .highlight_color = GRUB_TERM_DEFAULT_HIGHLIGHT_COLOR,
+ .flags = GRUB_TERM_CODE_TYPE_ASCII | GRUB_TERM_DUMB
+ };
+
+GRUB_MOD_INIT (morse)
+{
+ grub_term_register_output ("audio", &grub_audio_term_output);
+}
+
+GRUB_MOD_FINI (morse)
+{
+ grub_term_unregister_output (&grub_audio_term_output);
+}
diff --git a/grub-core/term/spkmodem.c b/grub-core/term/spkmodem.c
new file mode 100644
index 0000000..31dab65
--- /dev/null
+++ b/grub-core/term/spkmodem.c
@@ -0,0 +1,106 @@
+/* console.c -- Open Firmware console for GRUB. */
+/*
+ * GRUB -- GRand Unified Bootloader
+ * Copyright (C) 2003,2004,2005,2007,2008,2009 Free Software Foundation, Inc.
+ *
+ * GRUB 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 3 of the License, or
+ * (at your option) any later version.
+ *
+ * GRUB 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 GRUB. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <grub/term.h>
+#include <grub/types.h>
+#include <grub/misc.h>
+#include <grub/mm.h>
+#include <grub/time.h>
+#include <grub/terminfo.h>
+#include <grub/dl.h>
+#include <grub/speaker.h>
+
+GRUB_MOD_LICENSE ("GPLv3+");
+
+extern struct grub_terminfo_output_state grub_spkmodem_terminfo_output;
+
+static void
+put (struct grub_term_output *term __attribute__ ((unused)), const int c)
+{
+ int i;
+
+ for (i = 7; i >= 0; i--)
+ {
+ if ((c >> i) & 1)
+ grub_speaker_beep_on (2000);
+ else
+ grub_speaker_beep_on (4000);
+ grub_millisleep (10);
+ grub_speaker_beep_on (1000);
+ grub_millisleep (10);
+ }
+ grub_speaker_beep_on (50);
+}
+
+static grub_err_t
+grub_spkmodem_init_output (struct grub_term_output *term)
+{
+ grub_speaker_beep_on (50);
+ grub_millisleep (50);
+
+ grub_terminfo_output_init (term);
+
+ return 0;
+}
+
+static grub_err_t
+grub_spkmodem_fini_output (struct grub_term_output *term __attribute__ ((unused)))
+{
+ grub_speaker_beep_off ();
+ return 0;
+}
+
+
+
+
+struct grub_terminfo_output_state grub_spkmodem_terminfo_output =
+ {
+ .put = put,
+ .width = 80,
+ .height = 24
+ };
+
+static struct grub_term_output grub_spkmodem_term_output =
+ {
+ .name = "spkmodem",
+ .init = grub_spkmodem_init_output,
+ .fini = grub_spkmodem_fini_output,
+ .putchar = grub_terminfo_putchar,
+ .getxy = grub_terminfo_getxy,
+ .getwh = grub_terminfo_getwh,
+ .gotoxy = grub_terminfo_gotoxy,
+ .cls = grub_terminfo_cls,
+ .setcolorstate = grub_terminfo_setcolorstate,
+ .setcursor = grub_terminfo_setcursor,
+ .flags = GRUB_TERM_CODE_TYPE_ASCII,
+ .data = &grub_spkmodem_terminfo_output,
+ .normal_color = GRUB_TERM_DEFAULT_NORMAL_COLOR,
+ .highlight_color = GRUB_TERM_DEFAULT_HIGHLIGHT_COLOR,
+ };
+
+GRUB_MOD_INIT (spkmodem)
+{
+ grub_term_register_output ("spkmodem", &grub_spkmodem_term_output);
+}
+
+
+GRUB_MOD_FINI (spkmodem)
+{
+ grub_term_unregister_output (&grub_spkmodem_term_output);
+}
diff --git a/include/grub/i386/pit.h b/include/grub/i386/pit.h
index ff9b9a6..e1c92cd 100644
--- a/include/grub/i386/pit.h
+++ b/include/grub/i386/pit.h
@@ -22,6 +22,84 @@
#include <grub/types.h>
#include <grub/err.h>
+enum
+ {
+ /* The PIT channel value ports. You can write to and read from them.
+ Do not mess with timer 0 or 1. */
+ GRUB_PIT_COUNTER_0 = 0x40,
+ GRUB_PIT_COUNTER_1 = 0x41,
+ GRUB_PIT_COUNTER_2 = 0x42,
+ /* The PIT control port. You can only write to it. Do not mess with
+ timer 0 or 1. */
+ GRUB_PIT_CTRL = 0x43,
+ /* The speaker port. */
+ GRUB_PIT_SPEAKER_PORT = 0x61,
+ };
+
+
+/* The speaker port. */
+enum
+ {
+ /* If 0, follow state of SPEAKER_DATA bit, otherwise enable output
+ from timer 2. */
+ GRUB_PIT_SPK_TMR2 = 0x01,
+ /* If SPEAKER_TMR2 is not set, this provides direct input into the
+ speaker. Otherwise, this enables or disables the output from the
+ timer. */
+ GRUB_PIT_SPK_DATA = 0x02,
+
+ GRUB_PIT_SPK_TMR2_LATCH = 0x20
+ };
+
+/* The PIT control port. You can only write to it. Do not mess with
+ timer 0 or 1. */
+enum
+ {
+ GRUB_PIT_CTRL_SELECT_MASK = 0xc0,
+ GRUB_PIT_CTRL_SELECT_0 = 0x00,
+ GRUB_PIT_CTRL_SELECT_1 = 0x40,
+ GRUB_PIT_CTRL_SELECT_2 = 0x80,
+
+ /* Read and load control. */
+ GRUB_PIT_CTRL_READLOAD_MASK= 0x30,
+ GRUB_PIT_CTRL_COUNTER_LATCH = 0x00, /* Hold timer value until read. */
+ GRUB_PIT_CTRL_READLOAD_LSB = 0x10, /* Read/load the LSB. */
+ GRUB_PIT_CTRL_READLOAD_MSB = 0x20, /* Read/load the MSB. */
+ GRUB_PIT_CTRL_READLOAD_WORD = 0x30, /* Read/load the LSB then the MSB. */
+
+ /* Mode control. */
+ GRUB_PIT_CTRL_MODE_MASK = 0x0e,
+ /* Interrupt on terminal count. Setting the mode sets output to low.
+ When counter is set and terminated, output is set to high. */
+ GRUB_PIT_CTRL_INTR_ON_TERM = 0x00,
+ /* Programmable one-shot. When loading counter, output is set to
+ high. When counter terminated, output is set to low. Can be
+ triggered again from that point on by setting the gate pin to
+ high. */
+ GRUB_PIT_CTRL_PROGR_ONE_SHOT = 0x02,
+
+ /* Rate generator. Output is low for one period of the counter, and
+ high for the other. */
+ GRUB_PIT_CTRL_RATE_GEN = 0x04,
+
+ /* Square wave generator. Output is low for one half of the period,
+ and high for the other half. */
+ GRUB_PIT_CTRL_SQUAREWAVE_GEN = 0x06,
+ /* Software triggered strobe. Setting the mode sets output to high.
+ When counter is set and terminated, output is set to low. */
+ GRUB_PIT_CTRL_SOFTSTROBE = 0x08,
+
+ /* Hardware triggered strobe. Like software triggered strobe, but
+ only starts the counter when the gate pin is set to high. */
+ GRUB_PIT_CTRL_HARDSTROBE = 0x0a,
+
+
+ /* Count mode. */
+ GRUB_PIT_CTRL_COUNT_MASK = 0x01,
+ GRUB_PIT_CTRL_COUNT_BINARY = 0x00, /* 16-bit binary counter. */
+ GRUB_PIT_CTRL_COUNT_BCD = 0x01 /* 4-decade BCD counter. */
+ };
+
void EXPORT_FUNC(grub_pit_wait) (grub_uint16_t tics);
#endif /* ! KERNEL_CPU_PIT_HEADER */
diff --git a/include/grub/speaker.h b/include/grub/speaker.h
new file mode 100644
index 0000000..a076fcf
--- /dev/null
+++ b/include/grub/speaker.h
@@ -0,0 +1,47 @@
+#ifndef GRUB_SPEAKER_HEADER
+#define GRUB_SPEAKER_HEADER 1
+
+#include <grub/cpu/io.h>
+#include <grub/i386/pit.h>
+
+/* The frequency of the PIT clock. */
+#define GRUB_SPEAKER_PIT_FREQUENCY 0x1234dd
+
+static inline void
+grub_speaker_beep_off (void)
+{
+ unsigned char status;
+
+ status = grub_inb (GRUB_PIT_SPEAKER_PORT);
+ grub_outb (status & ~(GRUB_PIT_SPK_TMR2 | GRUB_PIT_SPK_DATA),
+ GRUB_PIT_SPEAKER_PORT);
+}
+
+static inline void
+grub_speaker_beep_on (grub_uint16_t pitch)
+{
+ unsigned char status;
+ unsigned int counter;
+
+ if (pitch < 20)
+ pitch = 20;
+ else if (pitch > 20000)
+ pitch = 20000;
+
+ counter = GRUB_SPEAKER_PIT_FREQUENCY / pitch;
+
+ /* Program timer 2. */
+ grub_outb (GRUB_PIT_CTRL_SELECT_2
+ | GRUB_PIT_CTRL_READLOAD_WORD
+ | GRUB_PIT_CTRL_SQUAREWAVE_GEN
+ | GRUB_PIT_CTRL_COUNT_BINARY, GRUB_PIT_CTRL);
+ grub_outb (counter & 0xff, GRUB_PIT_COUNTER_2); /* LSB */
+ grub_outb ((counter >> 8) & 0xff, GRUB_PIT_COUNTER_2); /* MSB */
+
+ /* Start speaker. */
+ status = grub_inb (GRUB_PIT_SPEAKER_PORT);
+ grub_outb (status | GRUB_PIT_SPK_TMR2 | GRUB_PIT_SPK_DATA,
+ GRUB_PIT_SPEAKER_PORT);
+}
+
+#endif
diff --git a/util/spkmodem-recv.c b/util/spkmodem-recv.c
new file mode 100644
index 0000000..cbec3af
--- /dev/null
+++ b/util/spkmodem-recv.c
@@ -0,0 +1,98 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+/* Compilation: gcc -o spkmodem-recv spkmodem-recv */
+/* Usage: parecord --channels=1 --rate=48000 --format=s16le | ./spkmodem-recv */
+
+#define RATE 48000
+#define SAMPLES_PER_TRAME 480
+#define AMPLITUDE_THRESHOLD 100000
+#define FREQ_SEP_MIN 15
+#define FREQ_SEP_NOM 20
+#define FREQ_SEP_MAX 25
+
+#define FREQ_DATA_MIN 10
+#define FREQ_DATA_THRESHOLD 60
+#define FREQ_DATA_MAX 120
+#define AMPLITUDE_SAMPLES 2 * SAMPLES_PER_TRAME
+
+#define THRESHOLD 1000
+
+#define DEBUG 0
+
+static signed short trame[2 * SAMPLES_PER_TRAME];
+static signed short pulse[2 * SAMPLES_PER_TRAME];
+static int ringpos = 0;
+static int pos, f1, f2;
+static int amplitude = 0;
+static int lp = 0;
+
+static void
+read_sample (void)
+{
+ amplitude -= abs (trame[ringpos]);
+ f1 -= pulse[ringpos];
+ f1 += pulse[(ringpos + SAMPLES_PER_TRAME) % (2 * SAMPLES_PER_TRAME)];
+ f2 -= pulse[(ringpos + SAMPLES_PER_TRAME) % (2 * SAMPLES_PER_TRAME)];
+ fread (trame + ringpos, 1, sizeof (trame[0]), stdin);
+ amplitude += abs (trame[ringpos]);
+
+ if (pos ? (trame[ringpos] < -THRESHOLD)
+ : (trame[ringpos] > +THRESHOLD))
+ {
+ pulse[ringpos] = 1;
+ pos = !pos;
+ f2++;
+ }
+ else
+ pulse[ringpos] = 0;
+ ringpos++;
+ ringpos %= 2 * SAMPLES_PER_TRAME;
+ lp++;
+}
+
+int
+main ()
+{
+ int bitn = 7;
+ char c = 0;
+ int i;
+ while (!feof (stdin))
+ {
+ if (lp > 20000)
+ {
+ fflush (stdout);
+ bitn = 7;
+ c = 0;
+ lp = 0;
+ }
+ if (f2 > 12 && f2 < 25
+ && f1 > 5 && f1 < 120)
+ {
+#if DEBUG
+ printf ("%d %d %d @%d\n", f1, f2, FREQ_DATA_THRESHOLD,
+ ftell (stdin) - sizeof (trame));
+#endif
+ if (f1 < 60)
+ c |= (1 << bitn);
+ bitn--;
+ if (bitn < 0)
+ {
+#if DEBUG
+ printf ("<%c, %x>", c, c);
+#else
+ printf ("%c", c);
+#endif
+ bitn = 7;
+ c = 0;
+ }
+ lp = 0;
+ for (i = 0; i < SAMPLES_PER_TRAME; i++)
+ read_sample ();
+ continue;
+ }
+ read_sample ();
+ }
+ return 0;
+}
--
1.8.2.1