[NTVDM]
[reactos.git] / reactos / subsystems / ntvdm / hardware / speaker.c
1 /*
2 * COPYRIGHT: GPL - See COPYING in the top level directory
3 * PROJECT: ReactOS Virtual DOS Machine
4 * FILE: speaker.c
5 * PURPOSE: PC Speaker emulation
6 * PROGRAMMERS: Hermes Belusca-Maito (hermes.belusca@sfr.fr)
7 */
8
9 /* INCLUDES *******************************************************************/
10
11 #define NDEBUG
12
13 #include "emulator.h"
14 #include "speaker.h"
15 #include "io.h"
16 #include "timer.h"
17
18 /* Extra PSDK/NDK Headers */
19 #include <ndk/iofuncs.h>
20 #include <ndk/obfuncs.h>
21 #include <ndk/rtlfuncs.h>
22
23 /* DDK Driver Headers */
24 #include <ntddbeep.h>
25
26 /* PRIVATE VARIABLES **********************************************************/
27
28 static HANDLE hBeep = NULL;
29
30 /* PRIVATE FUNCTIONS **********************************************************/
31
32 static DWORD OldReloadValue = 0;
33 static PIT_MODE OldMode = 0;
34
35 /* PUBLIC FUNCTIONS ***********************************************************/
36
37 VOID PlaySound(DWORD Frequency,
38 DWORD Duration)
39 {
40 /* Adapted from kernel32:Beep() */
41
42 IO_STATUS_BLOCK IoStatusBlock;
43 BEEP_SET_PARAMETERS BeepSetParameters;
44
45 /* Set beep data */
46 BeepSetParameters.Frequency = Frequency;
47 BeepSetParameters.Duration = Duration;
48
49 /* Send the beep */
50 NtDeviceIoControlFile(hBeep,
51 NULL,
52 NULL,
53 NULL,
54 &IoStatusBlock,
55 IOCTL_BEEP_SET,
56 &BeepSetParameters,
57 sizeof(BeepSetParameters),
58 NULL,
59 0);
60 }
61
62 VOID SpeakerChange(VOID)
63 {
64 BYTE Port61hState = IOReadB(CONTROL_SYSTEM_PORT61H);
65 BOOLEAN IsConnectedToPITChannel2 = !!(Port61hState & 0x01);
66 BOOLEAN SpeakerDataOn = !!(Port61hState & 0x02);
67
68 if (PitChannel2 && IsConnectedToPITChannel2 && SpeakerDataOn)
69 {
70 /* Start beeping */
71
72 DWORD Frequency, Duration;
73
74 DWORD PitChannel2ReloadValue = PitChannel2->ReloadValue;
75 if (PitChannel2ReloadValue == 0) PitChannel2ReloadValue = 65536;
76
77 DPRINT("(1) PitChannel2(Mode = %d ; ReloadValue = %d)\n", PitChannel2->Mode, PitChannel2ReloadValue);
78
79 if (OldMode == PitChannel2->Mode && OldReloadValue == PitChannel2ReloadValue)
80 return;
81
82 OldMode = PitChannel2->Mode;
83 OldReloadValue = PitChannel2ReloadValue;
84
85 DPRINT("(2) PitChannel2(Mode = %d ; ReloadValue = %d)\n", PitChannel2->Mode, PitChannel2ReloadValue);
86
87 Frequency = (PIT_BASE_FREQUENCY / PitChannel2ReloadValue);
88 Duration = INFINITE;
89
90 PlaySound(Frequency, Duration);
91 }
92 else
93 {
94 /* Stop beeping */
95
96 OldMode = 0;
97 OldReloadValue = 0;
98
99 PlaySound(0x00, 0x00);
100 }
101 }
102
103 VOID SpeakerInitialize(VOID)
104 {
105 NTSTATUS Status;
106 UNICODE_STRING BeepDevice;
107 OBJECT_ATTRIBUTES ObjectAttributes;
108 IO_STATUS_BLOCK IoStatusBlock;
109
110 /* Adapted from kernel32:Beep() */
111
112 /* Open the device */
113 RtlInitUnicodeString(&BeepDevice, L"\\Device\\Beep");
114 InitializeObjectAttributes(&ObjectAttributes, &BeepDevice, 0, NULL, NULL);
115 Status = NtCreateFile(&hBeep,
116 FILE_READ_DATA | FILE_WRITE_DATA,
117 &ObjectAttributes,
118 &IoStatusBlock,
119 NULL,
120 0,
121 FILE_SHARE_READ | FILE_SHARE_WRITE,
122 FILE_OPEN_IF,
123 0,
124 NULL,
125 0);
126 if (!NT_SUCCESS(Status))
127 {
128 DPRINT1("Failed to open Beep driver, Status 0x%08lx\n", Status);
129 }
130 }
131
132 VOID SpeakerCleanup(VOID)
133 {
134 NtClose(hBeep);
135 }
136
137 /* EOF */