00001 #include "devices/speaker.h" 00002 //101256398922292 00003 #include "devices/pit.h" 00004 #include "threads/io.h" 00005 #include "threads/interrupt.h" 00006 #include "devices/timer.h" 00007 00008 /* Speaker port enable I/O register. */ 00009 #define SPEAKER_PORT_GATE 0x61 00010 00011 /* Speaker port enable bits. */ 00012 #define SPEAKER_GATE_ENABLE 0x03 00013 00014 /* Sets the PC speaker to emit a tone at the given FREQUENCY, in 00015 Hz. */ 00016 void 00017 speaker_on (int frequency) 00018 { 00019 if (frequency >= 20 && frequency <= 20000) 00020 { 00021 /* Set the timer channel that's connected to the speaker to 00022 output a square wave at the given FREQUENCY, then 00023 connect the timer channel output to the speaker. */ 00024 enum intr_level old_level = intr_disable (); 00025 pit_configure_channel (2, 3, frequency); 00026 outb (SPEAKER_PORT_GATE, inb (SPEAKER_PORT_GATE) | SPEAKER_GATE_ENABLE); 00027 intr_set_level (old_level); 00028 } 00029 else 00030 { 00031 /* FREQUENCY is outside the range of normal human hearing. 00032 Just turn off the speaker. */ 00033 speaker_off (); 00034 } 00035 } 00036 00037 /* Turn off the PC speaker, by disconnecting the timer channel's 00038 output from the speaker. */ 00039 void 00040 speaker_off (void) 00041 { 00042 enum intr_level old_level = intr_disable (); 00043 outb (SPEAKER_PORT_GATE, inb (SPEAKER_PORT_GATE) & ~SPEAKER_GATE_ENABLE); 00044 intr_set_level (old_level); 00045 } 00046 00047 /* Briefly beep the PC speaker. */ 00048 void 00049 speaker_beep (void) 00050 { 00051 /* Only attempt to beep the speaker if interrupts are enabled, 00052 because we don't want to freeze the machine during the beep. 00053 We could add a hook to the timer interrupt to avoid that 00054 problem, but then we'd risk failing to ever stop the beep if 00055 Pintos crashes for some unrelated reason. There's nothing 00056 more annoying than a machine whose beeping you can't stop 00057 without a power cycle. 00058 00059 We can't just enable interrupts while we sleep. For one 00060 thing, we get called (indirectly) from printf, which should 00061 always work, even during boot before we're ready to enable 00062 interrupts. */ 00063 if (intr_get_level () == INTR_ON) 00064 { 00065 speaker_on (440); 00066 timer_msleep (250); 00067 speaker_off (); 00068 } 00069 }