Reactos
1/*
2 * PROJECT: ReactOS HAL
3 * LICENSE: BSD - See COPYING.ARM in the top level directory
4 * FILE: hal/halx86/generic/beep.c
5 * PURPOSE: Speaker support (beeping)
6 * PROGRAMMERS: ReactOS Portable Systems Group
7 */
8
9/* INCLUDES ******************************************************************/
10
11#include <hal.h>
12#define NDEBUG
13#include <debug.h>
14
15/* FUNCTIONS *****************************************************************/
16
17/*
18 * @implemented
19 */
20BOOLEAN
21NTAPI
22HalMakeBeep(IN ULONG Frequency)
23{
24 SYSTEM_CONTROL_PORT_B_REGISTER SystemControl;
25 TIMER_CONTROL_PORT_REGISTER TimerControl;
26 ULONG Divider;
27 BOOLEAN Result = FALSE;
28
29 //
30 // Acquire CMOS Lock
31 //
32 HalpAcquireCmosSpinLock();
33
34 //
35 // Turn the timer off by disconnecting its output pin and speaker gate
36 //
37 SystemControl.Bits = __inbyte(SYSTEM_CONTROL_PORT_B);
38 SystemControl.SpeakerDataEnable = FALSE;
39 SystemControl.Timer2GateToSpeaker = FALSE;
40 __outbyte(SYSTEM_CONTROL_PORT_B, SystemControl.Bits);
41
42 //
43 // Check if we have a frequency
44 //
45 if (Frequency)
46 {
47 //
48 // Set the divider
49 //
50 Divider = PIT_FREQUENCY / Frequency;
51
52 //
53 // Check if it's too large
54 //
55 if (Divider <= 0x10000)
56 {
57 //
58 // Program the PIT for binary mode
59 //
60 TimerControl.BcdMode = FALSE;
61
62 //
63 // Program the PIT to generate a square wave (Mode 3) on channel 2.
64 // Channel 0 is used for the IRQ0 clock interval timer, and channel
65 // 1 is used for DRAM refresh.
66 //
67 // Mode 2 gives much better accuracy, but generates an output signal
68 // that drops to low for each input signal cycle at 0.8381 useconds.
69 // This is too fast for the PC speaker to process and would result
70 // in no sound being emitted.
71 //
72 // Mode 3 will generate a high pulse that is a bit longer and will
73 // allow the PC speaker to notice. Additionally, take note that on
74 // channel 2, when input goes low the counter will stop and output
75 // will go to high.
76 //
77 TimerControl.OperatingMode = PitOperatingMode3;
78 TimerControl.Channel = PitChannel2;
79
80 //
81 // Set the access mode that we'll use to program the reload value.
82 //
83 TimerControl.AccessMode = PitAccessModeLowHigh;
84
85 //
86 // Now write the programming bits
87 //
88 __outbyte(TIMER_CONTROL_PORT, TimerControl.Bits);
89
90 //
91 // Next we write the reload value for channel 2
92 //
93 __outbyte(TIMER_CHANNEL2_DATA_PORT, Divider & 0xFF);
94 __outbyte(TIMER_CHANNEL2_DATA_PORT, (Divider >> 8) & 0xFF);
95
96 //
97 // Reconnect the speaker to the timer and re-enable the output pin
98 //
99 SystemControl.Bits = __inbyte(SYSTEM_CONTROL_PORT_B);
100 SystemControl.SpeakerDataEnable = TRUE;
101 SystemControl.Timer2GateToSpeaker = TRUE;
102 __outbyte(SYSTEM_CONTROL_PORT_B, SystemControl.Bits);
103 Result = TRUE;
104 }
105 }
106
107 //
108 // Release CMOS lock
109 //
110 HalpReleaseCmosSpinLock();
111
112 //
113 // Return success
114 //
115 return Result;
116}