random: Fix behavior of kernel option "-rs".
[pintos-anon] / src / devices / speaker.c
1 #include "devices/speaker.h"
2 #include "devices/pit.h"
3 #include "threads/io.h"
4 #include "threads/interrupt.h"
5 #include "devices/timer.h"
6
7 /* Speaker port enable I/O register. */
8 #define SPEAKER_PORT_GATE       0x61
9
10 /* Speaker port enable bits. */
11 #define SPEAKER_GATE_ENABLE     0x03
12
13 /* Sets the PC speaker to emit a tone at the given FREQUENCY, in
14    Hz. */
15 void
16 speaker_on (int frequency)
17 {
18   if (frequency >= 20 && frequency <= 20000)
19     {
20       /* Set the timer channel that's connected to the speaker to
21          output a square wave at the given FREQUENCY, then
22          connect the timer channel output to the speaker. */
23       enum intr_level old_level = intr_disable ();
24       pit_configure_channel (2, 3, frequency);
25       outb (SPEAKER_PORT_GATE, inb (SPEAKER_PORT_GATE) | SPEAKER_GATE_ENABLE);
26       intr_set_level (old_level);
27     }
28   else
29     {
30       /* FREQUENCY is outside the range of normal human hearing.
31          Just turn off the speaker. */
32       speaker_off ();
33     }
34 }
35
36 /* Turn off the PC speaker, by disconnecting the timer channel's
37    output from the speaker. */
38 void
39 speaker_off (void)
40 {
41   enum intr_level old_level = intr_disable ();
42   outb (SPEAKER_PORT_GATE, inb (SPEAKER_PORT_GATE) & ~SPEAKER_GATE_ENABLE);
43   intr_set_level (old_level);
44 }
45
46 /* Briefly beep the PC speaker. */
47 void
48 speaker_beep (void)
49 {
50   /* Only attempt to beep the speaker if interrupts are enabled,
51      because we don't want to freeze the machine during the beep.
52      We could add a hook to the timer interrupt to avoid that
53      problem, but then we'd risk failing to ever stop the beep if
54      Pintos crashes for some unrelated reason.  There's nothing
55      more annoying than a machine whose beeping you can't stop
56      without a power cycle.
57
58      We can't just enable interrupts while we sleep.  For one
59      thing, we get called (indirectly) from printf, which should
60      always work, even during boot before we're ready to enable
61      interrupts. */
62   if (intr_get_level () == INTR_ON)
63     {
64       speaker_on (440);
65       timer_msleep (250);
66       speaker_off ();
67     }
68 }