~darkmuggle-deactivatedaccount/ubuntu/quantal/grub2/fix-872244

« back to all changes in this revision

Viewing changes to commands/i386/pc/play.c

  • Committer: Bazaar Package Importer
  • Author(s): Otavio Salvador
  • Date: 2006-01-05 15:20:40 UTC
  • mto: (17.3.1 squeeze) (1.9.1 upstream)
  • mto: This revision was merged to the branch mainline in revision 4.
  • Revision ID: james.westby@ubuntu.com-20060105152040-b72i5pq1a82z22yi
Tags: upstream-1.92
ImportĀ upstreamĀ versionĀ 1.92

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/* play.c - command to play a tune  */
 
2
/*
 
3
 *  GRUB  --  GRand Unified Bootloader
 
4
 *  Copyright (C) 2005  Free Software Foundation, Inc.
 
5
 *
 
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.
 
10
 *
 
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.
 
15
 *
 
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.
 
19
 */
 
20
 
 
21
/* Lots of this file is borrowed from GNU/Hurd generic-speaker driver.  */
 
22
 
 
23
#include <grub/normal.h>
 
24
#include <grub/dl.h>
 
25
#include <grub/arg.h>
 
26
#include <grub/file.h>
 
27
#include <grub/disk.h>
 
28
#include <grub/term.h>
 
29
#include <grub/misc.h>
 
30
 
 
31
#define BASE_TEMPO 120
 
32
 
 
33
/* Read a byte from a port.  */
 
34
static inline unsigned char
 
35
inb (unsigned short port)
 
36
{
 
37
  unsigned char value;
 
38
  asm volatile ("inb    %w1, %0" : "=a" (value) : "Nd" (port));
 
39
  return value;
 
40
}
 
41
 
 
42
/* Write a byte to a port.  */
 
43
static inline void
 
44
outb (unsigned short port, unsigned char value)
 
45
{
 
46
  asm volatile ("outb   %b0, %w1" : : "a" (value), "Nd" (port));
 
47
}
 
48
 
 
49
/* The speaker port.  */
 
50
#define SPEAKER                 0x61
 
51
 
 
52
/* If 0, follow state of SPEAKER_DATA bit, otherwise enable output
 
53
   from timer 2.  */
 
54
#define SPEAKER_TMR2            0x01
 
55
 
 
56
/* If SPEAKER_TMR2 is not set, this provides direct input into the
 
57
   speaker.  Otherwise, this enables or disables the output from the
 
58
   timer.  */
 
59
#define SPEAKER_DATA            0x02
 
60
 
 
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
 
66
 
 
67
/* The frequency of the PIT clock.  */
 
68
#define PIT_FREQUENCY           0x1234dd
 
69
 
 
70
/* The PIT control port.  You can only write to it.  Do not mess with
 
71
   timer 0 or 1.  */
 
72
#define PIT_CTRL                0x43
 
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
 
77
 
 
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.  */
 
84
 
 
85
/* Mode control.  */
 
86
#define PIT_CTRL_MODE_MASK      0x0e
 
87
 
 
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
 
91
 
 
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
 
95
   high.  */
 
96
#define PIT_CTRL_PROGR_ONE_SHOT 0x02
 
97
 
 
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
 
101
 
 
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
 
105
 
 
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
 
109
 
 
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
 
113
 
 
114
/* Count mode.  */
 
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.  */
 
118
 
 
119
#define T_REST                  ((short) 0)
 
120
#define T_FINE                  ((short) -1)
 
121
 
 
122
struct note
 
123
{
 
124
  short pitch;
 
125
  short duration;
 
126
};
 
127
 
 
128
static void
 
129
beep_off (void)
 
130
{
 
131
  unsigned char status;
 
132
 
 
133
  status = inb (SPEAKER);
 
134
  outb (SPEAKER, status & ~(SPEAKER_TMR2 | SPEAKER_DATA));
 
135
}
 
136
 
 
137
static void
 
138
beep_on (short pitch)
 
139
{
 
140
  unsigned char status;
 
141
  unsigned int counter;
 
142
 
 
143
  if (pitch < 20)
 
144
    pitch = 20;
 
145
  else if (pitch > 20000)
 
146
    pitch = 20000;
 
147
 
 
148
  counter = PIT_FREQUENCY / pitch;
 
149
 
 
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 */
 
155
 
 
156
  /* Start speaker.  */
 
157
  status = inb (SPEAKER);
 
158
  outb (SPEAKER, status | SPEAKER_TMR2 | SPEAKER_DATA);
 
159
 
 
160
}
 
161
 
 
162
static grub_err_t
 
163
grub_cmd_play (struct grub_arg_list *state __attribute__ ((unused)),
 
164
               int argc, char **args)
 
165
{
 
166
  grub_file_t file;
 
167
  struct note buf;
 
168
  int tempo;
 
169
  unsigned int to;
 
170
 
 
171
  if (argc != 1)
 
172
    return grub_error (GRUB_ERR_BAD_ARGUMENT, "file name required");
 
173
 
 
174
  file = grub_file_open (args[0]);
 
175
  if (! file)
 
176
    return grub_error (GRUB_ERR_FILE_NOT_FOUND, "file not found");
 
177
 
 
178
  if (grub_file_read (file, (void *) &tempo, sizeof(tempo)) != sizeof(tempo))
 
179
    {
 
180
      grub_file_close (file);
 
181
      return grub_error (GRUB_ERR_FILE_READ_ERROR,
 
182
                         "file doesn't even contains a full tempo record");
 
183
    }
 
184
 
 
185
  grub_dprintf ("play","tempo = %d\n", tempo);
 
186
 
 
187
  while (grub_file_read (file, (void *) &buf,
 
188
                         sizeof (struct note)) == sizeof (struct note)
 
189
         && buf.pitch != T_FINE && grub_checkkey () < 0)
 
190
    {
 
191
      
 
192
      grub_dprintf ("play", "pitch = %d, duration = %d\n", buf.pitch,
 
193
                    buf.duration);
 
194
 
 
195
      switch (buf.pitch)
 
196
        {
 
197
          case T_REST:
 
198
            beep_off ();
 
199
            break;
 
200
 
 
201
          default:
 
202
            beep_on (buf.pitch);
 
203
            break;
 
204
        }
 
205
 
 
206
      to = grub_get_rtc () + BASE_TEMPO * buf.duration / tempo;
 
207
      while (((unsigned int) grub_get_rtc () <= to) && (grub_checkkey () < 0))
 
208
        ;
 
209
 
 
210
    }
 
211
 
 
212
  beep_off ();
 
213
 
 
214
  grub_file_close (file);
 
215
 
 
216
  while (grub_checkkey () > 0)
 
217
    grub_getkey ();
 
218
 
 
219
  return 0;
 
220
}
 
221
 
 
222
 
 
223
GRUB_MOD_INIT(play)
 
224
{
 
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);
 
228
}
 
229
 
 
230
GRUB_MOD_FINI(play)
 
231
{
 
232
  grub_unregister_command ("play");
 
233
}