1 /* 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) 7 * Eric Kohl 8 */ 9 10 /* INCLUDES ******************************************************************/ 11 12 #include <ntddk.h> 13 #include <ntddbeep.h> 14 #ifndef NDEBUG 15 #define NDEBUG 16 #endif 17 #include <debug.h> 18 19 /* TYPES *********************************************************************/ 20 21 typedef struct _BEEP_DEVICE_EXTENSION 22 { 23 LONG ReferenceCount; 24 FAST_MUTEX Mutex; 25 KTIMER Timer; 26 LONG TimerActive; 27 PVOID SectionHandle; 28 } DEVICE_EXTENSION, *PDEVICE_EXTENSION; 29 30 /* FUNCTIONS *****************************************************************/ 31 32 VOID 33 NTAPI 34 BeepDPC(IN PKDPC Dpc, 35 IN PDEVICE_OBJECT DeviceObject, 36 IN PVOID SystemArgument1, 37 IN PVOID SystemArgument2) 38 { 39 PDEVICE_EXTENSION DeviceExtension = DeviceObject->DeviceExtension; 40 41 UNREFERENCED_PARAMETER(Dpc); 42 UNREFERENCED_PARAMETER(SystemArgument1); 43 UNREFERENCED_PARAMETER(SystemArgument2); 44 45 /* Stop the beep */ 46 HalMakeBeep(0); 47 48 /* Disable the timer */ 49 InterlockedDecrement(&DeviceExtension->TimerActive); 50 } 51 52 DRIVER_DISPATCH BeepCreate; 53 NTSTATUS 54 NTAPI 55 BeepCreate(IN PDEVICE_OBJECT DeviceObject, 56 IN PIRP Irp) 57 { 58 PDEVICE_EXTENSION DeviceExtension = DeviceObject->DeviceExtension; 59 60 /* Acquire the mutex and increase reference count */ 61 ExAcquireFastMutex(&DeviceExtension->Mutex); 62 if (++DeviceExtension->ReferenceCount == 1) 63 { 64 /* First reference, lock the data section */ 65 DeviceExtension->SectionHandle = MmLockPagableDataSection(BeepCreate); 66 } 67 68 /* Release it */ 69 ExReleaseFastMutex(&DeviceExtension->Mutex); 70 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; 76 } 77 78 DRIVER_DISPATCH BeepClose; 79 NTSTATUS 80 NTAPI 81 BeepClose(IN PDEVICE_OBJECT DeviceObject, 82 IN PIRP Irp) 83 { 84 PDEVICE_EXTENSION DeviceExtension = DeviceObject->DeviceExtension; 85 86 /* Acquire the mutex and decrease reference count */ 87 ExAcquireFastMutex(&DeviceExtension->Mutex); 88 if (!(--DeviceExtension->ReferenceCount)) 89 { 90 /* Check for active timer */ 91 if (DeviceExtension->TimerActive) 92 { 93 /* Cancel it */ 94 if (KeCancelTimer(&DeviceExtension->Timer)) 95 { 96 /* Mark it as cancelled */ 97 InterlockedDecrement(&DeviceExtension->TimerActive); 98 } 99 } 100 101 /* Page the driver */ 102 MmUnlockPagableImageSection(DeviceExtension->SectionHandle); 103 } 104 105 /* Release the lock */ 106 ExReleaseFastMutex(&DeviceExtension->Mutex); 107 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; 113 } 114 115 DRIVER_CANCEL BeepCancel; 116 VOID 117 NTAPI 118 BeepCancel(IN PDEVICE_OBJECT DeviceObject, 119 IN PIRP Irp) 120 { 121 /* Check if this is the current request */ 122 if (Irp == DeviceObject->CurrentIrp) 123 { 124 /* Clear it */ 125 DeviceObject->CurrentIrp = NULL; 126 127 /* Release the cancel lock and start the next packet */ 128 IoReleaseCancelSpinLock(Irp->CancelIrql); 129 IoStartNextPacket(DeviceObject, TRUE); 130 } 131 else 132 { 133 /* Otherwise, remove the packet from the queue and release the lock */ 134 KeRemoveEntryDeviceQueue(&DeviceObject->DeviceQueue, 135 &Irp->Tail.Overlay.DeviceQueueEntry); 136 IoReleaseCancelSpinLock(Irp->CancelIrql); 137 } 138 139 /* Complete the request */ 140 Irp->IoStatus.Status = STATUS_CANCELLED; 141 Irp->IoStatus.Information = 0; 142 IoCompleteRequest (Irp, IO_NO_INCREMENT); 143 } 144 145 DRIVER_DISPATCH BeepCleanup; 146 NTSTATUS 147 NTAPI 148 BeepCleanup(IN PDEVICE_OBJECT DeviceObject, 149 IN PIRP Irp) 150 { 151 KIRQL OldIrql, CancelIrql; 152 PKDEVICE_QUEUE_ENTRY Packet; 153 PIRP CurrentIrp; 154 155 /* Raise IRQL and acquire the cancel lock */ 156 KeRaiseIrql(DISPATCH_LEVEL, &OldIrql); 157 IoAcquireCancelSpinLock(&CancelIrql); 158 159 /* Get the current IRP */ 160 CurrentIrp = DeviceObject->CurrentIrp; 161 DeviceObject->CurrentIrp = NULL; 162 while (CurrentIrp) 163 { 164 /* Clear its cancel routine */ 165 (VOID)IoSetCancelRoutine(CurrentIrp, NULL); 166 167 /* Cancel the IRP */ 168 CurrentIrp->IoStatus.Status = STATUS_CANCELLED; 169 CurrentIrp->IoStatus.Information = 0; 170 171 /* Release the cancel lock and complete it */ 172 IoReleaseCancelSpinLock(CancelIrql); 173 IoCompleteRequest(CurrentIrp, IO_NO_INCREMENT); 174 175 /* Reacquire the lock and get the next queue packet */ 176 IoAcquireCancelSpinLock(&CancelIrql); 177 Packet = KeRemoveDeviceQueue(&DeviceObject->DeviceQueue); 178 if (Packet) 179 { 180 /* Get the IRP */ 181 CurrentIrp = CONTAINING_RECORD(Packet, 182 IRP, 183 Tail.Overlay.DeviceQueueEntry); 184 } 185 else 186 { 187 /* No more IRPs */ 188 CurrentIrp = NULL; 189 } 190 } 191 192 /* Release lock and go back to low IRQL */ 193 IoReleaseCancelSpinLock(CancelIrql); 194 KeLowerIrql(OldIrql); 195 196 /* Complete the IRP */ 197 Irp->IoStatus.Status = STATUS_SUCCESS; 198 Irp->IoStatus.Information = 0; 199 IoCompleteRequest(Irp, IO_NO_INCREMENT); 200 201 /* Stop and beep and return */ 202 HalMakeBeep(0); 203 return STATUS_SUCCESS; 204 } 205 206 DRIVER_DISPATCH BeepDeviceControl; 207 NTSTATUS 208 NTAPI 209 BeepDeviceControl(IN PDEVICE_OBJECT DeviceObject, 210 IN PIRP Irp) 211 { 212 PIO_STACK_LOCATION Stack; 213 PBEEP_SET_PARAMETERS BeepParam; 214 NTSTATUS Status; 215 216 /* Get the stack location and parameters */ 217 Stack = IoGetCurrentIrpStackLocation(Irp); 218 BeepParam = (PBEEP_SET_PARAMETERS)Irp->AssociatedIrp.SystemBuffer; 219 220 /* We only support one IOCTL */ 221 if (Stack->Parameters.DeviceIoControl.IoControlCode != IOCTL_BEEP_SET) 222 { 223 /* Unsupported command */ 224 Status = STATUS_NOT_IMPLEMENTED; 225 } 226 else 227 { 228 /* Validate the input buffer length */ 229 if (Stack->Parameters.DeviceIoControl.InputBufferLength < 230 sizeof(BEEP_SET_PARAMETERS)) 231 { 232 /* Invalid buffer */ 233 Status = STATUS_INVALID_PARAMETER; 234 } 235 else if ((BeepParam->Frequency != 0) && !(BeepParam->Duration)) 236 { 237 /* No duration, return immediately */ 238 Status = STATUS_SUCCESS; 239 } 240 else 241 { 242 /* We'll queue this request */ 243 Status = STATUS_PENDING; 244 } 245 } 246 247 /* Set packet information */ 248 Irp->IoStatus.Status = Status; 249 Irp->IoStatus.Information = 0; 250 251 /* Check if we're completing or queuing a packet */ 252 if (Status == STATUS_PENDING) 253 { 254 /* Start the queue */ 255 IoMarkIrpPending(Irp); 256 IoStartPacket(DeviceObject, Irp, NULL, BeepCancel); 257 } 258 else 259 { 260 /* Complete the request */ 261 IoCompleteRequest(Irp, IO_NO_INCREMENT); 262 } 263 264 /* Return */ 265 return Status; 266 } 267 268 DRIVER_UNLOAD BeepUnload; 269 VOID 270 NTAPI 271 BeepUnload(IN PDRIVER_OBJECT DriverObject) 272 { 273 PDEVICE_EXTENSION DeviceExtension; 274 PDEVICE_OBJECT DeviceObject; 275 276 /* Get DO and DE */ 277 DeviceObject = DriverObject->DeviceObject; 278 DeviceExtension = DeviceObject->DeviceExtension; 279 280 /* Check if the timer is active */ 281 if (DeviceExtension->TimerActive) 282 { 283 /* Cancel it */ 284 if (KeCancelTimer(&DeviceExtension->Timer)) 285 { 286 /* All done */ 287 InterlockedDecrement(&DeviceExtension->TimerActive); 288 } 289 } 290 291 /* Delete the object */ 292 IoDeleteDevice(DeviceObject); 293 } 294 295 DRIVER_STARTIO BeepStartIo; 296 VOID 297 NTAPI 298 BeepStartIo(IN PDEVICE_OBJECT DeviceObject, 299 IN PIRP Irp) 300 { 301 PDEVICE_EXTENSION DeviceExtension = DeviceObject->DeviceExtension; 302 KIRQL CancelIrql; 303 PIO_STACK_LOCATION IoStack; 304 PBEEP_SET_PARAMETERS BeepParam; 305 LARGE_INTEGER DueTime; 306 NTSTATUS Status; 307 308 /* Acquire the cancel lock and make sure the IRP is valid */ 309 IoAcquireCancelSpinLock(&CancelIrql); 310 if (!Irp) 311 { 312 /* It's not, release the lock and quit */ 313 IoReleaseCancelSpinLock(CancelIrql); 314 return; 315 } 316 317 /* Remove the cancel routine and release the lock */ 318 (VOID)IoSetCancelRoutine(Irp, NULL); 319 IoReleaseCancelSpinLock(CancelIrql); 320 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) 325 { 326 /* Check if we have an active timer */ 327 if (DeviceExtension->TimerActive) 328 { 329 /* Cancel it */ 330 if (KeCancelTimer(&DeviceExtension->Timer)) 331 { 332 /* Set the state */ 333 InterlockedDecrement(&DeviceExtension->TimerActive); 334 } 335 } 336 337 /* Make the beep */ 338 if (HalMakeBeep(BeepParam->Frequency)) 339 { 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); 345 } 346 else 347 { 348 /* Beep has failed */ 349 Status = STATUS_INVALID_PARAMETER; 350 } 351 } 352 else 353 { 354 /* Invalid request */ 355 Status = STATUS_INVALID_PARAMETER; 356 } 357 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); 363 } 364 365 NTSTATUS 366 NTAPI 367 DriverEntry(IN PDRIVER_OBJECT DriverObject, 368 IN PUNICODE_STRING RegistryPath) 369 { 370 PDEVICE_EXTENSION DeviceExtension; 371 PDEVICE_OBJECT DeviceObject; 372 UNICODE_STRING DeviceName = RTL_CONSTANT_STRING(L"\\Device\\Beep"); 373 NTSTATUS Status; 374 375 UNREFERENCED_PARAMETER(RegistryPath); 376 377 /* Create the device */ 378 Status = IoCreateDevice(DriverObject, 379 sizeof(DEVICE_EXTENSION), 380 &DeviceName, 381 FILE_DEVICE_BEEP, 382 0, 383 FALSE, 384 &DeviceObject); 385 if (!NT_SUCCESS(Status)) return Status; 386 387 /* Make it use buffered I/O */ 388 DeviceObject->Flags |= DO_BUFFERED_IO; 389 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; 397 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); 405 406 /* Page the entire driver */ 407 MmPageEntireDriver(DriverEntry); 408 return STATUS_SUCCESS; 409 } 410 411 /* EOF */ 412