New terminal outputs using serial: morse and spkmodem.
This commit is contained in:
		
							parent
							
								
									34f71cb866
								
							
						
					
					
						commit
						b78d6c32e3
					
				
					 10 changed files with 512 additions and 132 deletions
				
			
		|  | @ -1,3 +1,7 @@ | ||||||
|  | 2013-01-16  Vladimir Serbinenko  <phcoder@gmail.com> | ||||||
|  | 
 | ||||||
|  | 	New terminal outputs using serial: morse and spkmodem. | ||||||
|  | 
 | ||||||
| 2013-01-16  Vladimir Serbinenko  <phcoder@gmail.com> | 2013-01-16  Vladimir Serbinenko  <phcoder@gmail.com> | ||||||
| 
 | 
 | ||||||
| 	Improve bidi handling in entry editor. | 	Improve bidi handling in entry editor. | ||||||
|  |  | ||||||
|  | @ -1229,9 +1229,9 @@ Select the terminal input device.  You may select multiple devices here, | ||||||
| separated by spaces. | separated by spaces. | ||||||
| 
 | 
 | ||||||
| Valid terminal input names depend on the platform, but may include | Valid terminal input names depend on the platform, but may include | ||||||
| @samp{console} (PC BIOS and EFI consoles), @samp{serial} (serial terminal), | @samp{console} (native platform console), @samp{serial} (serial terminal), | ||||||
| @samp{ofconsole} (Open Firmware console), @samp{at_keyboard} (PC AT | @samp{serial_<port>} (serial terminal with explicit port selection), | ||||||
| keyboard, mainly useful with Coreboot), or @samp{usb_keyboard} (USB keyboard | @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 | using the HID Boot Protocol, for cases where the firmware does not handle | ||||||
| this). | this). | ||||||
| 
 | 
 | ||||||
|  | @ -1242,9 +1242,21 @@ Select the terminal output device.  You may select multiple devices here, | ||||||
| separated by spaces. | separated by spaces. | ||||||
| 
 | 
 | ||||||
| Valid terminal output names depend on the platform, but may include | Valid terminal output names depend on the platform, but may include | ||||||
| @samp{console} (PC BIOS and EFI consoles), @samp{serial} (serial terminal), | @samp{console} (native platform console), @samp{serial} (serial terminal), | ||||||
| @samp{gfxterm} (graphics-mode output), @samp{ofconsole} (Open Firmware | @samp{serial_<port>} (serial terminal with explicit port selection), | ||||||
| console), or @samp{vga_text} (VGA text output, mainly useful with Coreboot). | @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. | The default is to use the platform's native terminal output. | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -778,6 +778,18 @@ module = { | ||||||
|   enable = x86; |   enable = x86; | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
|  | module = { | ||||||
|  |   name = spkmodem; | ||||||
|  |   x86 = term/spkmodem.c; | ||||||
|  |   enable = x86; | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | module = { | ||||||
|  |   name = morse; | ||||||
|  |   x86 = term/morse.c; | ||||||
|  |   enable = x86; | ||||||
|  | }; | ||||||
|  | 
 | ||||||
| module = { | module = { | ||||||
|   name = probe; |   name = probe; | ||||||
|   common = commands/probe.c; |   common = commands/probe.c; | ||||||
|  |  | ||||||
|  | @ -28,80 +28,12 @@ | ||||||
| #include <grub/command.h> | #include <grub/command.h> | ||||||
| #include <grub/i18n.h> | #include <grub/i18n.h> | ||||||
| #include <grub/time.h> | #include <grub/time.h> | ||||||
|  | #include <grub/speaker.h> | ||||||
| 
 | 
 | ||||||
| GRUB_MOD_LICENSE ("GPLv3+"); | GRUB_MOD_LICENSE ("GPLv3+"); | ||||||
| 
 | 
 | ||||||
| #define BASE_TEMPO (60 * 1000) | #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_REST			((grub_uint16_t) 0) | ||||||
| #define T_FINE			((grub_uint16_t) -1) | #define T_FINE			((grub_uint16_t) -1) | ||||||
|  | @ -112,39 +44,6 @@ struct note | ||||||
|   grub_uint16_t duration; |   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.  */ | /* Returns whether playing should continue.  */ | ||||||
| static int | static int | ||||||
| play (unsigned tempo, struct note *note) | play (unsigned tempo, struct note *note) | ||||||
|  | @ -160,11 +59,11 @@ play (unsigned tempo, struct note *note) | ||||||
|   switch (note->pitch) |   switch (note->pitch) | ||||||
|     { |     { | ||||||
|       case T_REST: |       case T_REST: | ||||||
|         beep_off (); |         grub_speaker_beep_off (); | ||||||
|         break; |         break; | ||||||
| 
 | 
 | ||||||
|       default: |       default: | ||||||
|         beep_on (note->pitch); |         grub_speaker_beep_on (note->pitch); | ||||||
|         break; |         break; | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|  | @ -263,7 +162,7 @@ grub_cmd_play (grub_command_t cmd __attribute__ ((unused)), | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|   beep_off (); |   grub_speaker_beep_off (); | ||||||
| 
 | 
 | ||||||
|   return 0; |   return 0; | ||||||
| } | } | ||||||
|  |  | ||||||
|  | @ -20,37 +20,30 @@ | ||||||
| #include <grub/i386/io.h> | #include <grub/i386/io.h> | ||||||
| #include <grub/i386/pit.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 | void | ||||||
| grub_pit_wait (grub_uint16_t tics) | grub_pit_wait (grub_uint16_t tics) | ||||||
| { | { | ||||||
|   /* Disable timer2 gate and speaker.  */ |   /* Disable timer2 gate and speaker.  */ | ||||||
|   grub_outb (grub_inb (TIMER2_REG_LATCH) & ~ (TIMER2_SPEAKER | TIMER2_GATE), |   grub_outb (grub_inb (GRUB_PIT_SPEAKER_PORT) | ||||||
|              TIMER2_REG_LATCH); | 	     & ~ (GRUB_PIT_SPK_DATA | GRUB_PIT_SPK_TMR2), | ||||||
|  |              GRUB_PIT_SPEAKER_PORT); | ||||||
| 
 | 
 | ||||||
|   /* Set tics.  */ |   /* Set tics.  */ | ||||||
|   grub_outb (TIMER2_SELECT | TIMER_ENABLE_LSB | TIMER_ENABLE_MSB, TIMER_REG_COMMAND); |   grub_outb (GRUB_PIT_CTRL_SELECT_2 | GRUB_PIT_CTRL_READLOAD_WORD, | ||||||
|   grub_outb (tics & 0xff, TIMER2_REG_CONTROL); | 	     GRUB_PIT_CTRL); | ||||||
|   grub_outb (tics >> 8, TIMER2_REG_CONTROL); |   grub_outb (tics & 0xff, GRUB_PIT_COUNTER_2); | ||||||
|  |   grub_outb (tics >> 8, GRUB_PIT_COUNTER_2); | ||||||
| 
 | 
 | ||||||
|   /* Enable timer2 gate, keep speaker disabled.  */ |   /* Enable timer2 gate, keep speaker disabled.  */ | ||||||
|   grub_outb ((grub_inb (TIMER2_REG_LATCH) & ~ TIMER2_SPEAKER) | TIMER2_GATE, |   grub_outb ((grub_inb (GRUB_PIT_SPEAKER_PORT) & ~ GRUB_PIT_SPK_DATA) | ||||||
|              TIMER2_REG_LATCH); | 	     | GRUB_PIT_SPK_TMR2, | ||||||
|  |              GRUB_PIT_SPEAKER_PORT); | ||||||
| 
 | 
 | ||||||
|   /* Wait.  */ |   /* 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.  */ |   /* Disable timer2 gate and speaker.  */ | ||||||
|   grub_outb (grub_inb (TIMER2_REG_LATCH) & ~ (TIMER2_SPEAKER | TIMER2_GATE), |   grub_outb (grub_inb (GRUB_PIT_SPEAKER_PORT) | ||||||
|              TIMER2_REG_LATCH); | 	     & ~ (GRUB_PIT_SPK_DATA | GRUB_PIT_SPK_TMR2), | ||||||
|  |              GRUB_PIT_SPEAKER_PORT); | ||||||
| } | } | ||||||
|  |  | ||||||
							
								
								
									
										131
									
								
								grub-core/term/morse.c
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										131
									
								
								grub-core/term/morse.c
									
										
									
									
									
										Normal file
									
								
							|  | @ -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); | ||||||
|  | } | ||||||
							
								
								
									
										106
									
								
								grub-core/term/spkmodem.c
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										106
									
								
								grub-core/term/spkmodem.c
									
										
									
									
									
										Normal file
									
								
							|  | @ -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); | ||||||
|  | } | ||||||
|  | @ -22,6 +22,84 @@ | ||||||
| #include <grub/types.h> | #include <grub/types.h> | ||||||
| #include <grub/err.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); | void EXPORT_FUNC(grub_pit_wait) (grub_uint16_t tics); | ||||||
| 
 | 
 | ||||||
| #endif /* ! KERNEL_CPU_PIT_HEADER */ | #endif /* ! KERNEL_CPU_PIT_HEADER */ | ||||||
|  |  | ||||||
							
								
								
									
										47
									
								
								include/grub/speaker.h
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										47
									
								
								include/grub/speaker.h
									
										
									
									
									
										Normal file
									
								
							|  | @ -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 | ||||||
							
								
								
									
										98
									
								
								util/spkmodem-recv.c
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										98
									
								
								util/spkmodem-recv.c
									
										
									
									
									
										Normal file
									
								
							|  | @ -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; | ||||||
|  | } | ||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue