[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 SpeakerChange(VOID)
38 {
39 BYTE Port61hState = IOReadB(CONTROL_SYSTEM_PORT61H);
40 BOOLEAN IsConnectedToPITChannel2 = !!(Port61hState & 0x01);
41 BOOLEAN SpeakerDataOn = !!(Port61hState & 0x02);
42
43 if (PitChannel2 && IsConnectedToPITChannel2 && SpeakerDataOn)
44 {
45 /* Start beeping - Adapted from kernel32:Beep() */
46 NTSTATUS Status;
47 IO_STATUS_BLOCK IoStatusBlock;
48 BEEP_SET_PARAMETERS BeepSetParameters;
49
50 DWORD PitChannel2ReloadValue = PitChannel2->ReloadValue;
51 if (PitChannel2ReloadValue == 0) PitChannel2ReloadValue = 65536;
52
53 DPRINT("(1) PitChannel2(Bcd = %s, Mode = %d ; ReloadValue = %d)\n", PitChannel2->Bcd ? "true" : "false", PitChannel2->Mode, PitChannel2ReloadValue);
54
55 if (OldMode == PitChannel2->Mode && OldReloadValue == PitChannel2ReloadValue)
56 return;
57
58 OldMode = PitChannel2->Mode;
59 OldReloadValue = PitChannel2ReloadValue;
60
61 DPRINT("(2) PitChannel2(Bcd = %s, Mode = %d ; ReloadValue = %d)\n", PitChannel2->Bcd ? "true" : "false", PitChannel2->Mode, PitChannel2ReloadValue);
62
63 /* Set beep data */
64 BeepSetParameters.Frequency = (PIT_BASE_FREQUENCY / PitChannel2ReloadValue);
65 BeepSetParameters.Duration = INFINITE;
66
67 /* Send the beep */
68 Status = NtDeviceIoControlFile(hBeep,
69 NULL,
70 NULL,
71 NULL,
72 &IoStatusBlock,
73 IOCTL_BEEP_SET,
74 &BeepSetParameters,
75 sizeof(BeepSetParameters),
76 NULL,
77 0);
78 if (!NT_SUCCESS(Status))
79 {
80 DPRINT1("Beep (%lu, %lu) failed, Status 0x%08lx\n",
81 BeepSetParameters.Frequency,
82 BeepSetParameters.Duration,
83 Status);
84 }
85 }
86 else
87 {
88 /* Stop beeping */
89 NTSTATUS Status;
90 IO_STATUS_BLOCK IoStatusBlock;
91 BEEP_SET_PARAMETERS BeepSetParameters;
92
93 OldMode = 0;
94 OldReloadValue = 0;
95
96 /* Set beep data */
97 BeepSetParameters.Frequency = 0x00;
98 BeepSetParameters.Duration = 0x00;
99
100 /* Send the beep */
101 Status = NtDeviceIoControlFile(hBeep,
102 NULL,
103 NULL,
104 NULL,
105 &IoStatusBlock,
106 IOCTL_BEEP_SET,
107 &BeepSetParameters,
108 sizeof(BeepSetParameters),
109 NULL,
110 0);
111 if (!NT_SUCCESS(Status))
112 {
113 DPRINT1("Beep (%lu, %lu) failed, Status 0x%08lx\n",
114 BeepSetParameters.Frequency,
115 BeepSetParameters.Duration,
116 Status);
117 }
118 }
119 }
120
121 VOID SpeakerInitialize(VOID)
122 {
123 NTSTATUS Status;
124 UNICODE_STRING BeepDevice;
125 OBJECT_ATTRIBUTES ObjectAttributes;
126 IO_STATUS_BLOCK IoStatusBlock;
127
128 /* Adapted from kernel32:Beep() */
129
130 //
131 // On TS systems, we need to Load Winsta.dll and call WinstationBeepOpen
132 // after doing a GetProcAddress for it
133 //
134
135 /* Open the device */
136 RtlInitUnicodeString(&BeepDevice, L"\\Device\\Beep");
137 InitializeObjectAttributes(&ObjectAttributes, &BeepDevice, 0, NULL, NULL);
138 Status = NtCreateFile(&hBeep,
139 FILE_READ_DATA | FILE_WRITE_DATA,
140 &ObjectAttributes,
141 &IoStatusBlock,
142 NULL,
143 0,
144 FILE_SHARE_READ | FILE_SHARE_WRITE,
145 FILE_OPEN_IF,
146 0,
147 NULL,
148 0);
149 if (!NT_SUCCESS(Status))
150 {
151 DPRINT1("Failed to open Beep driver, Status 0x%08lx\n", Status);
152 }
153 }
154
155 VOID SpeakerCleanup(VOID)
156 {
157 NtClose(hBeep);
158 }
159
160 /* EOF */