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
;
44 /* Disable the timer */
45 InterlockedDecrement(&DeviceExtension
->TimerActive
);
48 DRIVER_DISPATCH BeepCreate
;
51 BeepCreate(IN PDEVICE_OBJECT DeviceObject
,
54 PDEVICE_EXTENSION DeviceExtension
= DeviceObject
->DeviceExtension
;
56 /* Acquire the mutex and increase reference count */
57 ExAcquireFastMutex(&DeviceExtension
->Mutex
);
58 if (++DeviceExtension
->ReferenceCount
== 1)
60 /* First reference, lock the data section */
61 DeviceExtension
->SectionHandle
= MmLockPagableDataSection(BeepCreate
);
65 ExReleaseFastMutex(&DeviceExtension
->Mutex
);
67 /* Complete the request */
68 Irp
->IoStatus
.Status
= STATUS_SUCCESS
;
69 Irp
->IoStatus
.Information
= 0;
70 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
71 return STATUS_SUCCESS
;
74 DRIVER_DISPATCH BeepClose
;
77 BeepClose(IN PDEVICE_OBJECT DeviceObject
,
80 PDEVICE_EXTENSION DeviceExtension
= DeviceObject
->DeviceExtension
;
82 /* Acquire the mutex and decrease reference count */
83 ExAcquireFastMutex(&DeviceExtension
->Mutex
);
84 if (!(--DeviceExtension
->ReferenceCount
))
86 /* Check for active timer */
87 if (DeviceExtension
->TimerActive
)
90 if (KeCancelTimer(&DeviceExtension
->Timer
))
92 /* Mark it as cancelled */
93 InterlockedDecrement(&DeviceExtension
->TimerActive
);
98 MmUnlockPagableImageSection(DeviceExtension
->SectionHandle
);
101 /* Release the lock */
102 ExReleaseFastMutex(&DeviceExtension
->Mutex
);
104 /* Complete the request */
105 Irp
->IoStatus
.Status
= STATUS_SUCCESS
;
106 Irp
->IoStatus
.Information
= 0;
107 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
108 return STATUS_SUCCESS
;
111 DRIVER_CANCEL BeepCancel
;
114 BeepCancel(IN PDEVICE_OBJECT DeviceObject
,
117 /* Check if this is the current request */
118 if (Irp
== DeviceObject
->CurrentIrp
)
121 DeviceObject
->CurrentIrp
= NULL
;
123 /* Release the cancel lock and start the next packet */
124 IoReleaseCancelSpinLock(Irp
->CancelIrql
);
125 IoStartNextPacket(DeviceObject
, TRUE
);
129 /* Otherwise, remove the packet from the queue and relelase the lock */
130 KeRemoveEntryDeviceQueue(&DeviceObject
->DeviceQueue
,
131 &Irp
->Tail
.Overlay
.DeviceQueueEntry
);
132 IoReleaseCancelSpinLock(Irp
->CancelIrql
);
135 /* Complete the request */
136 Irp
->IoStatus
.Status
= STATUS_CANCELLED
;
137 Irp
->IoStatus
.Information
= 0;
138 IoCompleteRequest (Irp
, IO_NO_INCREMENT
);
141 DRIVER_DISPATCH BeepCleanup
;
144 BeepCleanup(IN PDEVICE_OBJECT DeviceObject
,
147 KIRQL OldIrql
, CancelIrql
;
148 PKDEVICE_QUEUE_ENTRY Packet
;
151 /* Raise IRQL and acquire the cancel lock */
152 KeRaiseIrql(DISPATCH_LEVEL
, &OldIrql
);
153 IoAcquireCancelSpinLock(&CancelIrql
);
155 /* Get the current IRP */
156 CurrentIrp
= DeviceObject
->CurrentIrp
;
157 DeviceObject
->CurrentIrp
= NULL
;
160 /* Clear its cancel routine */
161 (VOID
)IoSetCancelRoutine(CurrentIrp
, NULL
);
164 CurrentIrp
->IoStatus
.Status
= STATUS_CANCELLED
;
165 CurrentIrp
->IoStatus
.Information
= 0;
167 /* Release the cancel lock and complete it */
168 IoReleaseCancelSpinLock(CancelIrql
);
169 IoCompleteRequest(CurrentIrp
, IO_NO_INCREMENT
);
171 /* Reacquire the lock and get the next queue packet */
172 IoAcquireCancelSpinLock(&CancelIrql
);
173 Packet
= KeRemoveDeviceQueue(&DeviceObject
->DeviceQueue
);
177 CurrentIrp
= CONTAINING_RECORD(Packet
,
179 Tail
.Overlay
.DeviceQueueEntry
);
188 /* Release lock and go back to low IRQL */
189 IoReleaseCancelSpinLock(CancelIrql
);
190 KeLowerIrql(OldIrql
);
192 /* Complete the IRP */
193 Irp
->IoStatus
.Status
= STATUS_SUCCESS
;
194 Irp
->IoStatus
.Information
= 0;
195 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
197 /* Stop and beep and return */
199 return STATUS_SUCCESS
;
202 DRIVER_DISPATCH BeepDeviceControl
;
205 BeepDeviceControl(IN PDEVICE_OBJECT DeviceObject
,
208 PIO_STACK_LOCATION Stack
;
209 PBEEP_SET_PARAMETERS BeepParam
;
212 /* Get the stack location and parameters */
213 Stack
= IoGetCurrentIrpStackLocation(Irp
);
214 BeepParam
= (PBEEP_SET_PARAMETERS
)Irp
->AssociatedIrp
.SystemBuffer
;
216 /* We only support one IOCTL */
217 if (Stack
->Parameters
.DeviceIoControl
.IoControlCode
!= IOCTL_BEEP_SET
)
219 /* Unsupported command */
220 Status
= STATUS_NOT_IMPLEMENTED
;
224 /* Validate the input buffer length */
225 if (Stack
->Parameters
.DeviceIoControl
.InputBufferLength
<
226 sizeof(BEEP_SET_PARAMETERS
))
229 Status
= STATUS_INVALID_PARAMETER
;
231 else if ((BeepParam
->Frequency
!= 0) && !(BeepParam
->Duration
))
233 /* No duration, return imemdiately */
234 Status
= STATUS_SUCCESS
;
238 /* We'll queue this request */
239 Status
= STATUS_PENDING
;
243 /* Set packet information */
244 Irp
->IoStatus
.Status
= Status
;
245 Irp
->IoStatus
.Information
= 0;
247 /* Check if we're completing or queuing a packet */
248 if (Status
== STATUS_PENDING
)
250 /* Start the queue */
251 IoMarkIrpPending(Irp
);
252 IoStartPacket(DeviceObject
, Irp
, NULL
, BeepCancel
);
256 /* Complete the request */
257 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
264 DRIVER_UNLOAD BeepUnload
;
267 BeepUnload(IN PDRIVER_OBJECT DriverObject
)
269 PDEVICE_EXTENSION DeviceExtension
;
270 PDEVICE_OBJECT DeviceObject
;
273 DeviceObject
= DriverObject
->DeviceObject
;
274 DeviceExtension
= DeviceObject
->DeviceExtension
;
276 /* Check if the timer is active */
277 if (DeviceExtension
->TimerActive
)
280 if (KeCancelTimer(&DeviceExtension
->Timer
))
283 InterlockedDecrement(&DeviceExtension
->TimerActive
);
287 /* Delete the object */
288 IoDeleteDevice(DeviceObject
);
291 DRIVER_STARTIO BeepStartIo
;
294 BeepStartIo(IN PDEVICE_OBJECT DeviceObject
,
297 PDEVICE_EXTENSION DeviceExtension
= DeviceObject
->DeviceExtension
;
299 PIO_STACK_LOCATION IoStack
;
300 PBEEP_SET_PARAMETERS BeepParam
;
301 LARGE_INTEGER DueTime
;
304 /* Acquire the cancel lock and make sure the IRP is valid */
305 IoAcquireCancelSpinLock(&CancelIrql
);
308 /* It's not, release the lock and quit */
309 IoReleaseCancelSpinLock(CancelIrql
);
313 /* Remove the cancel routine and release the lock */
314 (VOID
)IoSetCancelRoutine(Irp
, NULL
);
315 IoReleaseCancelSpinLock(CancelIrql
);
317 /* Get the I/O Stack and make sure the request is valid */
318 BeepParam
= (PBEEP_SET_PARAMETERS
)Irp
->AssociatedIrp
.SystemBuffer
;
319 IoStack
= IoGetCurrentIrpStackLocation(Irp
);
320 if (IoStack
->Parameters
.DeviceIoControl
.IoControlCode
== IOCTL_BEEP_SET
)
322 /* Check if we have an active timer */
323 if (DeviceExtension
->TimerActive
)
326 if (KeCancelTimer(&DeviceExtension
->Timer
))
329 InterlockedDecrement(&DeviceExtension
->TimerActive
);
334 if (HalMakeBeep(BeepParam
->Frequency
))
336 /* Beep successful, queue a DPC to stop it */
337 Status
= STATUS_SUCCESS
;
338 DueTime
.QuadPart
= BeepParam
->Duration
* -10000;
339 InterlockedIncrement(&DeviceExtension
->TimerActive
);
340 KeSetTimer(&DeviceExtension
->Timer
, DueTime
, &DeviceObject
->Dpc
);
344 /* Beep has failed */
345 Status
= STATUS_INVALID_PARAMETER
;
350 /* Invalid request */
351 Status
= STATUS_INVALID_PARAMETER
;
354 /* Complete the request and start the next packet */
355 Irp
->IoStatus
.Status
= Status
;
356 Irp
->IoStatus
.Information
= 0;
357 IoStartNextPacket(DeviceObject
, TRUE
);
358 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
363 DriverEntry(IN PDRIVER_OBJECT DriverObject
,
364 IN PUNICODE_STRING RegistryPath
)
366 PDEVICE_EXTENSION DeviceExtension
;
367 PDEVICE_OBJECT DeviceObject
;
368 UNICODE_STRING DeviceName
= RTL_CONSTANT_STRING(L
"\\Device\\Beep");
371 /* Create the device */
372 Status
= IoCreateDevice(DriverObject
,
373 sizeof(DEVICE_EXTENSION
),
379 if (!NT_SUCCESS(Status
)) return Status
;
381 /* Make it use buffered I/O */
382 DeviceObject
->Flags
|= DO_BUFFERED_IO
;
384 /* Setup the Driver Object */
385 DriverObject
->MajorFunction
[IRP_MJ_CREATE
] = BeepCreate
;
386 DriverObject
->MajorFunction
[IRP_MJ_CLOSE
] = BeepClose
;
387 DriverObject
->MajorFunction
[IRP_MJ_CLEANUP
] = BeepCleanup
;
388 DriverObject
->MajorFunction
[IRP_MJ_DEVICE_CONTROL
] = BeepDeviceControl
;
389 DriverObject
->DriverUnload
= BeepUnload
;
390 DriverObject
->DriverStartIo
= BeepStartIo
;
392 /* Set up device extension */
393 DeviceExtension
= DeviceObject
->DeviceExtension
;
394 DeviceExtension
->ReferenceCount
= 0;
395 DeviceExtension
->TimerActive
= FALSE
;
396 IoInitializeDpcRequest(DeviceObject
, (PIO_DPC_ROUTINE
)BeepDPC
);
397 KeInitializeTimer(&DeviceExtension
->Timer
);
398 ExInitializeFastMutex(&DeviceExtension
->Mutex
);
400 /* Page the entire driver */
401 MmPageEntireDriver(DriverEntry
);
402 return STATUS_SUCCESS
;