Updated PCI IDs to latest snapshot.
[tangerine.git] / arch / common / boot / grub2 / commands / i386 / pc / play.c
blob4fbae08302dfcd711e8759363753dd954d2cdd10
1 /* play.c - command to play a tune */
2 /*
3 * GRUB -- GRand Unified Bootloader
4 * Copyright (C) 2005,2007 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 3 of the License, or
9 * (at your option) any later version.
11 * GRUB 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, see <http://www.gnu.org/licenses/>.
20 /* Lots of this file is borrowed from GNU/Hurd generic-speaker driver. */
22 #include <grub/normal.h>
23 #include <grub/dl.h>
24 #include <grub/arg.h>
25 #include <grub/file.h>
26 #include <grub/disk.h>
27 #include <grub/term.h>
28 #include <grub/misc.h>
29 #include <grub/machine/time.h>
30 #include <grub/cpu/io.h>
32 #define BASE_TEMPO 120
34 /* The speaker port. */
35 #define SPEAKER 0x61
37 /* If 0, follow state of SPEAKER_DATA bit, otherwise enable output
38 from timer 2. */
39 #define SPEAKER_TMR2 0x01
41 /* If SPEAKER_TMR2 is not set, this provides direct input into the
42 speaker. Otherwise, this enables or disables the output from the
43 timer. */
44 #define SPEAKER_DATA 0x02
46 /* The PIT channel value ports. You can write to and read from them.
47 Do not mess with timer 0 or 1. */
48 #define PIT_COUNTER_0 0x40
49 #define PIT_COUNTER_1 0x41
50 #define PIT_COUNTER_2 0x42
52 /* The frequency of the PIT clock. */
53 #define PIT_FREQUENCY 0x1234dd
55 /* The PIT control port. You can only write to it. Do not mess with
56 timer 0 or 1. */
57 #define PIT_CTRL 0x43
58 #define PIT_CTRL_SELECT_MASK 0xc0
59 #define PIT_CTRL_SELECT_0 0x00
60 #define PIT_CTRL_SELECT_1 0x40
61 #define PIT_CTRL_SELECT_2 0x80
63 /* Read and load control. */
64 #define PIT_CTRL_READLOAD_MASK 0x30
65 #define PIT_CTRL_COUNTER_LATCH 0x00 /* Hold timer value until read. */
66 #define PIT_CTRL_READLOAD_LSB 0x10 /* Read/load the LSB. */
67 #define PIT_CTRL_READLOAD_MSB 0x20 /* Read/load the MSB. */
68 #define PIT_CTRL_READLOAD_WORD 0x30 /* Read/load the LSB then the MSB. */
70 /* Mode control. */
71 #define PIT_CTRL_MODE_MASK 0x0e
73 /* Interrupt on terminal count. Setting the mode sets output to low.
74 When counter is set and terminated, output is set to high. */
75 #define PIT_CTRL_INTR_ON_TERM 0x00
77 /* Programmable one-shot. When loading counter, output is set to
78 high. When counter terminated, output is set to low. Can be
79 triggered again from that point on by setting the gate pin to
80 high. */
81 #define PIT_CTRL_PROGR_ONE_SHOT 0x02
83 /* Rate generator. Output is low for one period of the counter, and
84 high for the other. */
85 #define PIT_CTRL_RATE_GEN 0x04
87 /* Square wave generator. Output is low for one half of the period,
88 and high for the other half. */
89 #define PIT_CTRL_SQUAREWAVE_GEN 0x06
91 /* Software triggered strobe. Setting the mode sets output to high.
92 When counter is set and terminated, output is set to low. */
93 #define PIT_CTRL_SOFTSTROBE 0x08
95 /* Hardware triggered strobe. Like software triggered strobe, but
96 only starts the counter when the gate pin is set to high. */
97 #define PIT_CTRL_HARDSTROBE 0x0a
99 /* Count mode. */
100 #define PIT_CTRL_COUNT_MASK 0x01
101 #define PIT_CTRL_COUNT_BINARY 0x00 /* 16-bit binary counter. */
102 #define PIT_CTRL_COUNT_BCD 0x01 /* 4-decade BCD counter. */
104 #define T_REST ((short) 0)
105 #define T_FINE ((short) -1)
107 struct note
109 short pitch;
110 short duration;
113 static void
114 beep_off (void)
116 unsigned char status;
118 status = grub_inb (SPEAKER);
119 grub_outb (status & ~(SPEAKER_TMR2 | SPEAKER_DATA), SPEAKER);
122 static void
123 beep_on (short pitch)
125 unsigned char status;
126 unsigned int counter;
128 if (pitch < 20)
129 pitch = 20;
130 else if (pitch > 20000)
131 pitch = 20000;
133 counter = PIT_FREQUENCY / pitch;
135 /* Program timer 2. */
136 grub_outb (PIT_CTRL_SELECT_2 | PIT_CTRL_READLOAD_WORD
137 | PIT_CTRL_SQUAREWAVE_GEN | PIT_CTRL_COUNT_BINARY, PIT_CTRL);
138 grub_outb (counter & 0xff, PIT_COUNTER_2); /* LSB */
139 grub_outb ((counter >> 8) & 0xff, PIT_COUNTER_2); /* MSB */
141 /* Start speaker. */
142 status = grub_inb (SPEAKER);
143 grub_outb (status | SPEAKER_TMR2 | SPEAKER_DATA, SPEAKER);
146 static grub_err_t
147 grub_cmd_play (struct grub_arg_list *state __attribute__ ((unused)),
148 int argc, char **args)
150 grub_file_t file;
151 struct note buf;
152 int tempo;
153 unsigned int to;
155 if (argc != 1)
156 return grub_error (GRUB_ERR_BAD_ARGUMENT, "file name required");
158 file = grub_file_open (args[0]);
159 if (! file)
160 return grub_error (GRUB_ERR_FILE_NOT_FOUND, "file not found");
162 if (grub_file_read (file, (void *) &tempo, sizeof(tempo)) != sizeof(tempo))
164 grub_file_close (file);
165 return grub_error (GRUB_ERR_FILE_READ_ERROR,
166 "file doesn't even contains a full tempo record");
169 grub_dprintf ("play","tempo = %d\n", tempo);
171 while (grub_file_read (file, (void *) &buf,
172 sizeof (struct note)) == sizeof (struct note)
173 && buf.pitch != T_FINE && grub_checkkey () < 0)
176 grub_dprintf ("play", "pitch = %d, duration = %d\n", buf.pitch,
177 buf.duration);
179 switch (buf.pitch)
181 case T_REST:
182 beep_off ();
183 break;
185 default:
186 beep_on (buf.pitch);
187 break;
190 to = grub_get_rtc () + BASE_TEMPO * buf.duration / tempo;
191 while (((unsigned int) grub_get_rtc () <= to) && (grub_checkkey () < 0))
196 beep_off ();
198 grub_file_close (file);
200 while (grub_checkkey () > 0)
201 grub_getkey ();
203 return 0;
207 GRUB_MOD_INIT(play)
209 (void)mod; /* To stop warning. */
210 grub_register_command ("play", grub_cmd_play, GRUB_COMMAND_FLAG_BOTH,
211 "play FILE", "Play a tune", 0);
214 GRUB_MOD_FINI(play)
216 grub_unregister_command ("play");