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