2 * PROJECT: ReactOS Kernel
3 * LICENSE: GPL - See COPYING in the top level directory
4 * FILE: drivers/base/beep/beep.c
5 * PURPOSE: Beep Device Driver
6 * PROGRAMMERS: Alex Ionescu (alex.ionescu@reactos.org)
10 /* INCLUDES ******************************************************************/
19 /* TYPES *********************************************************************/
21 typedef struct _BEEP_DEVICE_EXTENSION
28 } DEVICE_EXTENSION
, *PDEVICE_EXTENSION
;
30 /* FUNCTIONS *****************************************************************/
35 IN PDEVICE_OBJECT DeviceObject
,
36 IN PVOID SystemArgument1
,
37 IN PVOID SystemArgument2
)
39 PDEVICE_EXTENSION DeviceExtension
= DeviceObject
->DeviceExtension
;
41 UNREFERENCED_PARAMETER(Dpc
);
42 UNREFERENCED_PARAMETER(SystemArgument1
);
43 UNREFERENCED_PARAMETER(SystemArgument2
);
48 /* Disable the timer */
49 InterlockedDecrement(&DeviceExtension
->TimerActive
);
52 DRIVER_DISPATCH BeepCreate
;
55 BeepCreate(IN PDEVICE_OBJECT DeviceObject
,
58 PDEVICE_EXTENSION DeviceExtension
= DeviceObject
->DeviceExtension
;
60 /* Acquire the mutex and increase reference count */
61 ExAcquireFastMutex(&DeviceExtension
->Mutex
);
62 if (++DeviceExtension
->ReferenceCount
== 1)
64 /* First reference, lock the data section */
65 DeviceExtension
->SectionHandle
= MmLockPagableDataSection(BeepCreate
);
69 ExReleaseFastMutex(&DeviceExtension
->Mutex
);
71 /* Complete the request */
72 Irp
->IoStatus
.Status
= STATUS_SUCCESS
;
73 Irp
->IoStatus
.Information
= 0;
74 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
75 return STATUS_SUCCESS
;
78 DRIVER_DISPATCH BeepClose
;
81 BeepClose(IN PDEVICE_OBJECT DeviceObject
,
84 PDEVICE_EXTENSION DeviceExtension
= DeviceObject
->DeviceExtension
;
86 /* Acquire the mutex and decrease reference count */
87 ExAcquireFastMutex(&DeviceExtension
->Mutex
);
88 if (!(--DeviceExtension
->ReferenceCount
))
90 /* Check for active timer */
91 if (DeviceExtension
->TimerActive
)
94 if (KeCancelTimer(&DeviceExtension
->Timer
))
96 /* Mark it as cancelled */
97 InterlockedDecrement(&DeviceExtension
->TimerActive
);
101 /* Page the driver */
102 MmUnlockPagableImageSection(DeviceExtension
->SectionHandle
);
105 /* Release the lock */
106 ExReleaseFastMutex(&DeviceExtension
->Mutex
);
108 /* Complete the request */
109 Irp
->IoStatus
.Status
= STATUS_SUCCESS
;
110 Irp
->IoStatus
.Information
= 0;
111 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
112 return STATUS_SUCCESS
;
115 DRIVER_CANCEL BeepCancel
;
118 BeepCancel(IN PDEVICE_OBJECT DeviceObject
,
121 /* Check if this is the current request */
122 if (Irp
== DeviceObject
->CurrentIrp
)
125 DeviceObject
->CurrentIrp
= NULL
;
127 /* Release the cancel lock and start the next packet */
128 IoReleaseCancelSpinLock(Irp
->CancelIrql
);
129 IoStartNextPacket(DeviceObject
, TRUE
);
133 /* Otherwise, remove the packet from the queue and relelase the lock */
134 KeRemoveEntryDeviceQueue(&DeviceObject
->DeviceQueue
,
135 &Irp
->Tail
.Overlay
.DeviceQueueEntry
);
136 IoReleaseCancelSpinLock(Irp
->CancelIrql
);
139 /* Complete the request */
140 Irp
->IoStatus
.Status
= STATUS_CANCELLED
;
141 Irp
->IoStatus
.Information
= 0;
142 IoCompleteRequest (Irp
, IO_NO_INCREMENT
);
145 DRIVER_DISPATCH BeepCleanup
;
148 BeepCleanup(IN PDEVICE_OBJECT DeviceObject
,
151 KIRQL OldIrql
, CancelIrql
;
152 PKDEVICE_QUEUE_ENTRY Packet
;
155 /* Raise IRQL and acquire the cancel lock */
156 KeRaiseIrql(DISPATCH_LEVEL
, &OldIrql
);
157 IoAcquireCancelSpinLock(&CancelIrql
);
159 /* Get the current IRP */
160 CurrentIrp
= DeviceObject
->CurrentIrp
;
161 DeviceObject
->CurrentIrp
= NULL
;
164 /* Clear its cancel routine */
165 (VOID
)IoSetCancelRoutine(CurrentIrp
, NULL
);
168 CurrentIrp
->IoStatus
.Status
= STATUS_CANCELLED
;
169 CurrentIrp
->IoStatus
.Information
= 0;
171 /* Release the cancel lock and complete it */
172 IoReleaseCancelSpinLock(CancelIrql
);
173 IoCompleteRequest(CurrentIrp
, IO_NO_INCREMENT
);
175 /* Reacquire the lock and get the next queue packet */
176 IoAcquireCancelSpinLock(&CancelIrql
);
177 Packet
= KeRemoveDeviceQueue(&DeviceObject
->DeviceQueue
);
181 CurrentIrp
= CONTAINING_RECORD(Packet
,
183 Tail
.Overlay
.DeviceQueueEntry
);
192 /* Release lock and go back to low IRQL */
193 IoReleaseCancelSpinLock(CancelIrql
);
194 KeLowerIrql(OldIrql
);
196 /* Complete the IRP */
197 Irp
->IoStatus
.Status
= STATUS_SUCCESS
;
198 Irp
->IoStatus
.Information
= 0;
199 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
201 /* Stop and beep and return */
203 return STATUS_SUCCESS
;
206 DRIVER_DISPATCH BeepDeviceControl
;
209 BeepDeviceControl(IN PDEVICE_OBJECT DeviceObject
,
212 PIO_STACK_LOCATION Stack
;
213 PBEEP_SET_PARAMETERS BeepParam
;
216 /* Get the stack location and parameters */
217 Stack
= IoGetCurrentIrpStackLocation(Irp
);
218 BeepParam
= (PBEEP_SET_PARAMETERS
)Irp
->AssociatedIrp
.SystemBuffer
;
220 /* We only support one IOCTL */
221 if (Stack
->Parameters
.DeviceIoControl
.IoControlCode
!= IOCTL_BEEP_SET
)
223 /* Unsupported command */
224 Status
= STATUS_NOT_IMPLEMENTED
;
228 /* Validate the input buffer length */
229 if (Stack
->Parameters
.DeviceIoControl
.InputBufferLength
<
230 sizeof(BEEP_SET_PARAMETERS
))
233 Status
= STATUS_INVALID_PARAMETER
;
235 else if ((BeepParam
->Frequency
!= 0) && !(BeepParam
->Duration
))
237 /* No duration, return imemdiately */
238 Status
= STATUS_SUCCESS
;
242 /* We'll queue this request */
243 Status
= STATUS_PENDING
;
247 /* Set packet information */
248 Irp
->IoStatus
.Status
= Status
;
249 Irp
->IoStatus
.Information
= 0;
251 /* Check if we're completing or queuing a packet */
252 if (Status
== STATUS_PENDING
)
254 /* Start the queue */
255 IoMarkIrpPending(Irp
);
256 IoStartPacket(DeviceObject
, Irp
, NULL
, BeepCancel
);
260 /* Complete the request */
261 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
268 DRIVER_UNLOAD BeepUnload
;
271 BeepUnload(IN PDRIVER_OBJECT DriverObject
)
273 PDEVICE_EXTENSION DeviceExtension
;
274 PDEVICE_OBJECT DeviceObject
;
277 DeviceObject
= DriverObject
->DeviceObject
;
278 DeviceExtension
= DeviceObject
->DeviceExtension
;
280 /* Check if the timer is active */
281 if (DeviceExtension
->TimerActive
)
284 if (KeCancelTimer(&DeviceExtension
->Timer
))
287 InterlockedDecrement(&DeviceExtension
->TimerActive
);
291 /* Delete the object */
292 IoDeleteDevice(DeviceObject
);
295 DRIVER_STARTIO BeepStartIo
;
298 BeepStartIo(IN PDEVICE_OBJECT DeviceObject
,
301 PDEVICE_EXTENSION DeviceExtension
= DeviceObject
->DeviceExtension
;
303 PIO_STACK_LOCATION IoStack
;
304 PBEEP_SET_PARAMETERS BeepParam
;
305 LARGE_INTEGER DueTime
;
308 /* Acquire the cancel lock and make sure the IRP is valid */
309 IoAcquireCancelSpinLock(&CancelIrql
);
312 /* It's not, release the lock and quit */
313 IoReleaseCancelSpinLock(CancelIrql
);
317 /* Remove the cancel routine and release the lock */
318 (VOID
)IoSetCancelRoutine(Irp
, NULL
);
319 IoReleaseCancelSpinLock(CancelIrql
);
321 /* Get the I/O Stack and make sure the request is valid */
322 BeepParam
= (PBEEP_SET_PARAMETERS
)Irp
->AssociatedIrp
.SystemBuffer
;
323 IoStack
= IoGetCurrentIrpStackLocation(Irp
);
324 if (IoStack
->Parameters
.DeviceIoControl
.IoControlCode
== IOCTL_BEEP_SET
)
326 /* Check if we have an active timer */
327 if (DeviceExtension
->TimerActive
)
330 if (KeCancelTimer(&DeviceExtension
->Timer
))
333 InterlockedDecrement(&DeviceExtension
->TimerActive
);
338 if (HalMakeBeep(BeepParam
->Frequency
))
340 /* Beep successful, queue a DPC to stop it */
341 Status
= STATUS_SUCCESS
;
342 DueTime
.QuadPart
= BeepParam
->Duration
* -10000LL;
343 InterlockedIncrement(&DeviceExtension
->TimerActive
);
344 KeSetTimer(&DeviceExtension
->Timer
, DueTime
, &DeviceObject
->Dpc
);
348 /* Beep has failed */
349 Status
= STATUS_INVALID_PARAMETER
;
354 /* Invalid request */
355 Status
= STATUS_INVALID_PARAMETER
;
358 /* Complete the request and start the next packet */
359 Irp
->IoStatus
.Status
= Status
;
360 Irp
->IoStatus
.Information
= 0;
361 IoStartNextPacket(DeviceObject
, TRUE
);
362 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
367 DriverEntry(IN PDRIVER_OBJECT DriverObject
,
368 IN PUNICODE_STRING RegistryPath
)
370 PDEVICE_EXTENSION DeviceExtension
;
371 PDEVICE_OBJECT DeviceObject
;
372 UNICODE_STRING DeviceName
= RTL_CONSTANT_STRING(L
"\\Device\\Beep");
375 UNREFERENCED_PARAMETER(RegistryPath
);
377 /* Create the device */
378 Status
= IoCreateDevice(DriverObject
,
379 sizeof(DEVICE_EXTENSION
),
385 if (!NT_SUCCESS(Status
)) return Status
;
387 /* Make it use buffered I/O */
388 DeviceObject
->Flags
|= DO_BUFFERED_IO
;
390 /* Setup the Driver Object */
391 DriverObject
->MajorFunction
[IRP_MJ_CREATE
] = BeepCreate
;
392 DriverObject
->MajorFunction
[IRP_MJ_CLOSE
] = BeepClose
;
393 DriverObject
->MajorFunction
[IRP_MJ_CLEANUP
] = BeepCleanup
;
394 DriverObject
->MajorFunction
[IRP_MJ_DEVICE_CONTROL
] = BeepDeviceControl
;
395 DriverObject
->DriverUnload
= BeepUnload
;
396 DriverObject
->DriverStartIo
= BeepStartIo
;
398 /* Set up device extension */
399 DeviceExtension
= DeviceObject
->DeviceExtension
;
400 DeviceExtension
->ReferenceCount
= 0;
401 DeviceExtension
->TimerActive
= FALSE
;
402 IoInitializeDpcRequest(DeviceObject
, (PIO_DPC_ROUTINE
)BeepDPC
);
403 KeInitializeTimer(&DeviceExtension
->Timer
);
404 ExInitializeFastMutex(&DeviceExtension
->Mutex
);
406 /* Page the entire driver */
407 MmPageEntireDriver(DriverEntry
);
408 return STATUS_SUCCESS
;