[NTVDM]
[reactos.git] / subsystems / ntvdm / 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 BYTE Port61hState = 0x00;
29 HANDLE hBeep = NULL;
30
31 /* PUBLIC FUNCTIONS ***********************************************************/
32
33 BYTE SpeakerReadStatus(VOID)
34 {
35 return Port61hState;
36 }
37
38 VOID SpeakerWriteCommand(BYTE Value)
39 {
40 BOOLEAN IsConnectedToPITChannel2;
41 UCHAR SpeakerData;
42
43 Port61hState = Value;
44 IsConnectedToPITChannel2 = ((Port61hState & 0x01) != 0);
45 SpeakerData = (Port61hState & 0x02);
46
47 if (PitChannel2 && IsConnectedToPITChannel2)
48 {
49 /* Set bit 5 of Port 61h */
50 Port61hState |= 1 << 5;
51 }
52 else
53 {
54 /* Clear bit 5 of Port 61h */
55 Port61hState &= ~(1 << 5);
56 }
57
58 if (PitChannel2 && IsConnectedToPITChannel2 && (SpeakerData != 0))
59 {
60 /* Start beeping - Adapted from kernel32:Beep() */
61 NTSTATUS Status;
62 IO_STATUS_BLOCK IoStatusBlock;
63 BEEP_SET_PARAMETERS BeepSetParameters;
64
65 DWORD PitChannel2ReloadValue = PitChannel2->ReloadValue;
66 if (PitChannel2ReloadValue == 0) PitChannel2ReloadValue = 65536;
67
68 /* Set beep data */
69 BeepSetParameters.Frequency = (PIT_BASE_FREQUENCY / PitChannel2ReloadValue) *
70 (PitChannel2->Mode == PIT_MODE_SQUARE_WAVE ? 2 : 1);
71 BeepSetParameters.Duration = INFINITE;
72
73 /* Send the beep */
74 Status = NtDeviceIoControlFile(hBeep,
75 NULL,
76 NULL,
77 NULL,
78 &IoStatusBlock,
79 IOCTL_BEEP_SET,
80 &BeepSetParameters,
81 sizeof(BeepSetParameters),
82 NULL,
83 0);
84 if (!NT_SUCCESS(Status))
85 {
86 DPRINT1("Beep (%lu, %lu) failed, Status 0x%08lx\n",
87 BeepSetParameters.Frequency,
88 BeepSetParameters.Duration,
89 Status);
90 }
91 }
92 else
93 {
94 /* Stop beeping */
95 NTSTATUS Status;
96 IO_STATUS_BLOCK IoStatusBlock;
97 BEEP_SET_PARAMETERS BeepSetParameters;
98
99 /* Set beep data */
100 BeepSetParameters.Frequency = 0x00;
101 BeepSetParameters.Duration = 0x00;
102
103 /* Send the beep */
104 Status = NtDeviceIoControlFile(hBeep,
105 NULL,
106 NULL,
107 NULL,
108 &IoStatusBlock,
109 IOCTL_BEEP_SET,
110 &BeepSetParameters,
111 sizeof(BeepSetParameters),
112 NULL,
113 0);
114 if (!NT_SUCCESS(Status))
115 {
116 DPRINT1("Beep (%lu, %lu) failed, Status 0x%08lx\n",
117 BeepSetParameters.Frequency,
118 BeepSetParameters.Duration,
119 Status);
120 }
121 }
122 }
123
124 BYTE WINAPI SpeakerReadPort(ULONG Port)
125 {
126 return SpeakerReadStatus();
127 }
128
129 VOID WINAPI SpeakerWritePort(ULONG Port, BYTE Data)
130 {
131 SpeakerWriteCommand(Data);
132 }
133
134 VOID SpeakerInitialize(VOID)
135 {
136 NTSTATUS Status;
137 UNICODE_STRING BeepDevice;
138 OBJECT_ATTRIBUTES ObjectAttributes;
139 IO_STATUS_BLOCK IoStatusBlock;
140
141 /* Adapted from kernel32:Beep() */
142
143 //
144 // On TS systems, we need to Load Winsta.dll and call WinstationBeepOpen
145 // after doing a GetProcAddress for it
146 //
147
148 /* Open the device */
149 RtlInitUnicodeString(&BeepDevice, L"\\Device\\Beep");
150 InitializeObjectAttributes(&ObjectAttributes, &BeepDevice, 0, NULL, NULL);
151 Status = NtCreateFile(&hBeep,
152 FILE_READ_DATA | FILE_WRITE_DATA,
153 &ObjectAttributes,
154 &IoStatusBlock,
155 NULL,
156 0,
157 FILE_SHARE_READ | FILE_SHARE_WRITE,
158 FILE_OPEN_IF,
159 0,
160 NULL,
161 0);
162 if (!NT_SUCCESS(Status))
163 {
164 DPRINT1("Failed to open Beep driver, Status 0x%08lx\n", Status);
165 }
166
167 /* Register the I/O Ports */
168 RegisterIoPort(SPEAKER_CONTROL_PORT, SpeakerReadPort, SpeakerWritePort);
169 }
170
171 VOID SpeakerCleanup(VOID)
172 {
173 NtClose(hBeep);
174 }
175
176 /* EOF */