1 /*
2  * PROJECT:         ReactOS Kernel
3  * LICENSE:         GPL - See COPYING in the top level directory
4  * FILE:            dll/win32/kernel32/client/file/deviceio.c
5  * PURPOSE:         Device I/O Base Client Functionality
6  * PROGRAMMERS:     Alex Ionescu (alex.ionescu@reactos.org)
7  */
8 
9 /* INCLUDES *******************************************************************/
10 
11 #include <k32.h>
12 
13 #include <ntddbeep.h>
14 
15 #define NDEBUG
16 #include <debug.h>
17 
18 /* FUNCTIONS ******************************************************************/
19 
20 VOID
21 WINAPI
NotifySoundSentry(VOID)22 NotifySoundSentry(VOID)
23 {
24     BASE_API_MESSAGE ApiMessage;
25     PBASE_SOUND_SENTRY SoundSentryRequest = &ApiMessage.Data.SoundSentryRequest;
26 
27     /* Get the video mode */
28     if (!GetConsoleDisplayMode(&SoundSentryRequest->VideoMode))
29     {
30         SoundSentryRequest->VideoMode = 0;
31     }
32 
33     /* Make sure it's not fullscreen, and send the message if not */
34     if (SoundSentryRequest->VideoMode == 0)
35     {
36         CsrClientCallServer((PCSR_API_MESSAGE)&ApiMessage,
37                             NULL,
38                             CSR_CREATE_API_NUMBER(BASESRV_SERVERDLL_INDEX, BasepSoundSentryNotification),
39                             sizeof(*SoundSentryRequest));
40     }
41 }
42 
43 /*
44  * @implemented
45  */
46 BOOL
47 WINAPI
Beep(IN DWORD dwFreq,IN DWORD dwDuration)48 Beep(IN DWORD dwFreq,
49      IN DWORD dwDuration)
50 {
51     HANDLE hBeep;
52     UNICODE_STRING BeepDevice;
53     OBJECT_ATTRIBUTES ObjectAttributes;
54     IO_STATUS_BLOCK IoStatusBlock;
55     BEEP_SET_PARAMETERS BeepSetParameters;
56     NTSTATUS Status;
57 
58     //
59     // On TS systems, we need to Load Winsta.dll and call WinstationBeepOpen
60     // after doing a GetProcAddress for it
61     //
62 
63     /* Open the device */
64     RtlInitUnicodeString(&BeepDevice, L"\\Device\\Beep");
65     InitializeObjectAttributes(&ObjectAttributes, &BeepDevice, 0, NULL, NULL);
66     Status = NtCreateFile(&hBeep,
67                           FILE_READ_DATA | FILE_WRITE_DATA,
68                           &ObjectAttributes,
69                           &IoStatusBlock,
70                           NULL,
71                           0,
72                           FILE_SHARE_READ | FILE_SHARE_WRITE,
73                           FILE_OPEN_IF,
74                           0,
75                           NULL,
76                           0);
77     if (!NT_SUCCESS(Status))
78     {
79         BaseSetLastNTError(Status);
80         return FALSE;
81     }
82 
83     /* check the parameters */
84     if ((dwFreq >= 0x25 && dwFreq <= 0x7FFF) ||
85         (dwFreq == 0x0 && dwDuration == 0x0))
86     {
87         /* Set beep data */
88         BeepSetParameters.Frequency = dwFreq;
89         BeepSetParameters.Duration = dwDuration;
90 
91         /* Send the beep */
92         Status = NtDeviceIoControlFile(hBeep,
93                                        NULL,
94                                        NULL,
95                                        NULL,
96                                        &IoStatusBlock,
97                                        IOCTL_BEEP_SET,
98                                        &BeepSetParameters,
99                                        sizeof(BeepSetParameters),
100                                        NULL,
101                                        0);
102     }
103     else
104     {
105         /* We'll fail the call, but still notify the sound sentry */
106         Status = STATUS_INVALID_PARAMETER;
107     }
108 
109     /* Notify the sound sentry */
110     NotifySoundSentry();
111 
112     /* Bail out if the hardware beep failed */
113     if (!NT_SUCCESS(Status))
114     {
115         NtClose(hBeep);
116         BaseSetLastNTError(Status);
117         return FALSE;
118     }
119 
120     /* If an actual beep was emitted, wait for it */
121     if (((dwFreq != 0x0) || (dwDuration != 0x0)) && (dwDuration != MAXDWORD))
122     {
123         SleepEx(dwDuration, TRUE);
124     }
125 
126     /* Close the handle and return success */
127     NtClose(hBeep);
128     return TRUE;
129 }
130 
131 /*
132  * @implemented
133  */
134 BOOL
135 WINAPI
DeviceIoControl(IN HANDLE hDevice,IN DWORD dwIoControlCode,IN LPVOID lpInBuffer OPTIONAL,IN DWORD nInBufferSize OPTIONAL,OUT LPVOID lpOutBuffer OPTIONAL,IN DWORD nOutBufferSize OPTIONAL,OUT LPDWORD lpBytesReturned OPTIONAL,IN LPOVERLAPPED lpOverlapped OPTIONAL)136 DeviceIoControl(IN HANDLE hDevice,
137                 IN DWORD dwIoControlCode,
138                 IN LPVOID lpInBuffer OPTIONAL,
139                 IN DWORD nInBufferSize OPTIONAL,
140                 OUT LPVOID lpOutBuffer OPTIONAL,
141                 IN DWORD nOutBufferSize OPTIONAL,
142                 OUT LPDWORD lpBytesReturned OPTIONAL,
143                 IN LPOVERLAPPED lpOverlapped OPTIONAL)
144 {
145     BOOL FsIoCtl;
146     NTSTATUS Status;
147     PVOID ApcContext;
148     IO_STATUS_BLOCK Iosb;
149 
150     //
151     // Note: on a TS Machine, we should call IsTSAppCompatEnabled and unless the
152     // IOCTLs are IOCTL_STORAGE_EJECT_MEDIA, IOCTL_DISK_EJECT_MEDIA, FSCTL_DISMOUNT_VOLUME
153     // we should call IsCallerAdminOrSystem and return STATUS_ACCESS_DENIED for
154     // any other IOCTLs.
155     //
156 
157     /* Check what kind of IOCTL to send */
158     FsIoCtl = ((dwIoControlCode >> 16) == FILE_DEVICE_FILE_SYSTEM);
159 
160     /* CHeck for async */
161     if (lpOverlapped != NULL)
162     {
163         /* Set pending status */
164         lpOverlapped->Internal = STATUS_PENDING;
165 
166         /* Check if there's an APC context */
167         ApcContext = (((ULONG_PTR)lpOverlapped->hEvent & 0x1) ? NULL : lpOverlapped);
168 
169         /* Send file system control? */
170         if (FsIoCtl)
171         {
172             /* Send it */
173             Status = NtFsControlFile(hDevice,
174                                      lpOverlapped->hEvent,
175                                      NULL,
176                                      ApcContext,
177                                      (PIO_STATUS_BLOCK)lpOverlapped,
178                                      dwIoControlCode,
179                                      lpInBuffer,
180                                      nInBufferSize,
181                                      lpOutBuffer,
182                                      nOutBufferSize);
183         }
184         else
185         {
186             /* Otherwise send a device control */
187             Status = NtDeviceIoControlFile(hDevice,
188                                            lpOverlapped->hEvent,
189                                            NULL,
190                                            ApcContext,
191                                            (PIO_STATUS_BLOCK)lpOverlapped,
192                                            dwIoControlCode,
193                                            lpInBuffer,
194                                            nInBufferSize,
195                                            lpOutBuffer,
196                                            nOutBufferSize);
197         }
198 
199         /* Check for or information instead of failure */
200         if (!(NT_ERROR(Status)) && (lpBytesReturned))
201         {
202             /* Protect with SEH */
203             _SEH2_TRY
204             {
205                 /* Return the bytes */
206                 *lpBytesReturned = lpOverlapped->InternalHigh;
207             }
208             _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
209             {
210                 /* Return zero bytes */
211                 *lpBytesReturned = 0;
212             }
213             _SEH2_END;
214         }
215 
216         /* Now check for any kind of failure except pending*/
217         if (!(NT_SUCCESS(Status)) || (Status == STATUS_PENDING))
218         {
219             /* Fail */
220             BaseSetLastNTError(Status);
221             return FALSE;
222         }
223     }
224     else
225     {
226         /* Sync case -- send file system code? */
227         if (FsIoCtl)
228         {
229             /* Do it */
230             Status = NtFsControlFile(hDevice,
231                                      NULL,
232                                      NULL,
233                                      NULL,
234                                      &Iosb,
235                                      dwIoControlCode,
236                                      lpInBuffer,
237                                      nInBufferSize,
238                                      lpOutBuffer,
239                                      nOutBufferSize);
240         }
241         else
242         {
243             /* Send device code instead */
244             Status = NtDeviceIoControlFile(hDevice,
245                                            NULL,
246                                            NULL,
247                                            NULL,
248                                            &Iosb,
249                                            dwIoControlCode,
250                                            lpInBuffer,
251                                            nInBufferSize,
252                                            lpOutBuffer,
253                                            nOutBufferSize);
254         }
255 
256         /* Now check if the operation isn't done yet */
257         if (Status == STATUS_PENDING)
258         {
259             /* Wait for it and get the final status */
260             Status = NtWaitForSingleObject(hDevice, FALSE, NULL);
261             if (NT_SUCCESS(Status)) Status = Iosb.Status;
262         }
263 
264         /* Check for success */
265         if (NT_SUCCESS(Status))
266         {
267             /* Return the byte count */
268             *lpBytesReturned = Iosb.Information;
269         }
270         else
271         {
272             /* Check for informational or warning failure */
273             if (!NT_ERROR(Status)) *lpBytesReturned = Iosb.Information;
274 
275             /* Return a failure */
276             BaseSetLastNTError(Status);
277             return FALSE;
278         }
279     }
280 
281     /* Return success */
282     return TRUE;
283 }
284 
285 /*
286  * @implemented
287  */
288 BOOL
289 WINAPI
CancelIo(IN HANDLE hFile)290 CancelIo(IN HANDLE hFile)
291 {
292     IO_STATUS_BLOCK IoStatusBlock;
293     NTSTATUS Status;
294 
295     Status = NtCancelIoFile(hFile, &IoStatusBlock);
296     if (!NT_SUCCESS(Status))
297     {
298         BaseSetLastNTError(Status);
299         return FALSE;
300     }
301 
302     return TRUE;
303 }
304 
305 /* EOF */
306