1
/* play.c - command to play a tune */
3
* GRUB -- GRand Unified Bootloader
4
* Copyright (C) 2005 Free Software Foundation, Inc.
6
* GRUB is free software; you can redistribute it and/or modify
7
* it under the terms of the GNU General Public License as published by
8
* the Free Software Foundation; either version 2 of the License, or
9
* (at your option) any later version.
11
* This program is distributed in the hope that it will be useful,
12
* but WITHOUT ANY WARRANTY; without even the implied warranty of
13
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14
* GNU General Public License for more details.
16
* You should have received a copy of the GNU General Public License
17
* along with GRUB; if not, write to the Free Software
18
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
21
/* Lots of this file is borrowed from GNU/Hurd generic-speaker driver. */
23
#include <grub/normal.h>
26
#include <grub/file.h>
27
#include <grub/disk.h>
28
#include <grub/term.h>
29
#include <grub/misc.h>
31
#define BASE_TEMPO 120
33
/* Read a byte from a port. */
34
static inline unsigned char
35
inb (unsigned short port)
38
asm volatile ("inb %w1, %0" : "=a" (value) : "Nd" (port));
42
/* Write a byte to a port. */
44
outb (unsigned short port, unsigned char value)
46
asm volatile ("outb %b0, %w1" : : "a" (value), "Nd" (port));
49
/* The speaker port. */
52
/* If 0, follow state of SPEAKER_DATA bit, otherwise enable output
54
#define SPEAKER_TMR2 0x01
56
/* If SPEAKER_TMR2 is not set, this provides direct input into the
57
speaker. Otherwise, this enables or disables the output from the
59
#define SPEAKER_DATA 0x02
61
/* The PIT channel value ports. You can write to and read from them.
62
Do not mess with timer 0 or 1. */
63
#define PIT_COUNTER_0 0x40
64
#define PIT_COUNTER_1 0x41
65
#define PIT_COUNTER_2 0x42
67
/* The frequency of the PIT clock. */
68
#define PIT_FREQUENCY 0x1234dd
70
/* The PIT control port. You can only write to it. Do not mess with
73
#define PIT_CTRL_SELECT_MASK 0xc0
74
#define PIT_CTRL_SELECT_0 0x00
75
#define PIT_CTRL_SELECT_1 0x40
76
#define PIT_CTRL_SELECT_2 0x80
78
/* Read and load control. */
79
#define PIT_CTRL_READLOAD_MASK 0x30
80
#define PIT_CTRL_COUNTER_LATCH 0x00 /* Hold timer value until read. */
81
#define PIT_CTRL_READLOAD_LSB 0x10 /* Read/load the LSB. */
82
#define PIT_CTRL_READLOAD_MSB 0x20 /* Read/load the MSB. */
83
#define PIT_CTRL_READLOAD_WORD 0x30 /* Read/load the LSB then the MSB. */
86
#define PIT_CTRL_MODE_MASK 0x0e
88
/* Interrupt on terminal count. Setting the mode sets output to low.
89
When counter is set and terminated, output is set to high. */
90
#define PIT_CTRL_INTR_ON_TERM 0x00
92
/* Programmable one-shot. When loading counter, output is set to
93
high. When counter terminated, output is set to low. Can be
94
triggered again from that point on by setting the gate pin to
96
#define PIT_CTRL_PROGR_ONE_SHOT 0x02
98
/* Rate generator. Output is low for one period of the counter, and
99
high for the other. */
100
#define PIT_CTRL_RATE_GEN 0x04
102
/* Square wave generator. Output is low for one half of the period,
103
and high for the other half. */
104
#define PIT_CTRL_SQUAREWAVE_GEN 0x06
106
/* Software triggered strobe. Setting the mode sets output to high.
107
When counter is set and terminated, output is set to low. */
108
#define PIT_CTRL_SOFTSTROBE 0x08
110
/* Hardware triggered strobe. Like software triggered strobe, but
111
only starts the counter when the gate pin is set to high. */
112
#define PIT_CTRL_HARDSTROBE 0x0a
115
#define PIT_CTRL_COUNT_MASK 0x01
116
#define PIT_CTRL_COUNT_BINARY 0x00 /* 16-bit binary counter. */
117
#define PIT_CTRL_COUNT_BCD 0x01 /* 4-decade BCD counter. */
119
#define T_REST ((short) 0)
120
#define T_FINE ((short) -1)
131
unsigned char status;
133
status = inb (SPEAKER);
134
outb (SPEAKER, status & ~(SPEAKER_TMR2 | SPEAKER_DATA));
138
beep_on (short pitch)
140
unsigned char status;
141
unsigned int counter;
145
else if (pitch > 20000)
148
counter = PIT_FREQUENCY / pitch;
150
/* Program timer 2. */
151
outb (PIT_CTRL, PIT_CTRL_SELECT_2 | PIT_CTRL_READLOAD_WORD
152
| PIT_CTRL_SQUAREWAVE_GEN | PIT_CTRL_COUNT_BINARY);
153
outb (PIT_COUNTER_2, counter & 0xff); /* LSB */
154
outb (PIT_COUNTER_2, (counter >> 8) & 0xff); /* MSB */
157
status = inb (SPEAKER);
158
outb (SPEAKER, status | SPEAKER_TMR2 | SPEAKER_DATA);
163
grub_cmd_play (struct grub_arg_list *state __attribute__ ((unused)),
164
int argc, char **args)
172
return grub_error (GRUB_ERR_BAD_ARGUMENT, "file name required");
174
file = grub_file_open (args[0]);
176
return grub_error (GRUB_ERR_FILE_NOT_FOUND, "file not found");
178
if (grub_file_read (file, (void *) &tempo, sizeof(tempo)) != sizeof(tempo))
180
grub_file_close (file);
181
return grub_error (GRUB_ERR_FILE_READ_ERROR,
182
"file doesn't even contains a full tempo record");
185
grub_dprintf ("play","tempo = %d\n", tempo);
187
while (grub_file_read (file, (void *) &buf,
188
sizeof (struct note)) == sizeof (struct note)
189
&& buf.pitch != T_FINE && grub_checkkey () < 0)
192
grub_dprintf ("play", "pitch = %d, duration = %d\n", buf.pitch,
206
to = grub_get_rtc () + BASE_TEMPO * buf.duration / tempo;
207
while (((unsigned int) grub_get_rtc () <= to) && (grub_checkkey () < 0))
214
grub_file_close (file);
216
while (grub_checkkey () > 0)
225
(void)mod; /* To stop warning. */
226
grub_register_command ("play", grub_cmd_play, GRUB_COMMAND_FLAG_BOTH,
227
"play FILE", "Play a tune", 0);
232
grub_unregister_command ("play");