mirror of https://github.com/lianthony/NT4.0
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
1006 lines
20 KiB
1006 lines
20 KiB
/*++
|
|
|
|
Copyright (c) 1990 Microsoft Corporation
|
|
|
|
Module Name:
|
|
|
|
beep.c
|
|
|
|
Abstract:
|
|
|
|
Beep driver.
|
|
|
|
Author:
|
|
|
|
Lee A. Smith (lees) 02-Aug-1991.
|
|
|
|
Environment:
|
|
|
|
Kernel mode only.
|
|
|
|
Notes:
|
|
|
|
|
|
Revision History:
|
|
|
|
--*/
|
|
|
|
#include "stdarg.h"
|
|
#include "stdio.h"
|
|
#include "ntddk.h"
|
|
#include <ntddbeep.h>
|
|
#include "beep.h"
|
|
|
|
// Private declaration of 'HalMakeBeep' because it's not in the ddk.
|
|
BOOLEAN
|
|
HalMakeBeep(
|
|
IN ULONG Frequency
|
|
);
|
|
|
|
|
|
NTSTATUS
|
|
DriverEntry(
|
|
IN PDRIVER_OBJECT DriverObject,
|
|
IN PUNICODE_STRING RegistryPath
|
|
);
|
|
|
|
VOID
|
|
BeepCancel(
|
|
IN PDEVICE_OBJECT DeviceObject,
|
|
IN PIRP Irp
|
|
);
|
|
|
|
NTSTATUS
|
|
BeepCleanup(
|
|
IN PDEVICE_OBJECT DeviceObject,
|
|
IN PIRP Irp
|
|
);
|
|
|
|
#if DBG
|
|
|
|
VOID
|
|
BeepDebugPrint(
|
|
ULONG DebugPrintLevel,
|
|
PCCHAR DebugMessage,
|
|
...
|
|
);
|
|
|
|
//
|
|
// Declare the global debug flag for this driver.
|
|
//
|
|
|
|
ULONG BeepDebug = 0;
|
|
#define BeepPrint(x) BeepDebugPrint x
|
|
#else
|
|
#define BeepPrint(x)
|
|
#endif
|
|
|
|
NTSTATUS
|
|
BeepDeviceControl(
|
|
IN PDEVICE_OBJECT DeviceObject,
|
|
IN PIRP Irp
|
|
);
|
|
|
|
NTSTATUS
|
|
BeepOpen(
|
|
IN PDEVICE_OBJECT DeviceObject,
|
|
IN PIRP Irp
|
|
);
|
|
|
|
NTSTATUS
|
|
BeepClose(
|
|
IN PDEVICE_OBJECT DeviceObject,
|
|
IN PIRP Irp
|
|
);
|
|
|
|
VOID
|
|
BeepStartIo(
|
|
IN PDEVICE_OBJECT DeviceObject,
|
|
IN PIRP Irp
|
|
);
|
|
|
|
VOID
|
|
BeepTimeOut(
|
|
IN PKDPC Dpc,
|
|
IN PDEVICE_OBJECT DeviceObject,
|
|
IN PVOID SystemArgument1,
|
|
IN PVOID SystemArgument2
|
|
);
|
|
|
|
VOID
|
|
BeepUnload(
|
|
IN PDRIVER_OBJECT DriverObject
|
|
);
|
|
|
|
//
|
|
// Coud use the alloc_text pragma to specify the driver initialization
|
|
// routines (they can be paged out). Unfortunately, in this case that
|
|
// actually ends up using more space (because of the section boundaries?)/
|
|
// so don't bother. [Verify using coff -dump].
|
|
//
|
|
|
|
#if 0
|
|
#ifdef ALLOC_PRAGMA
|
|
#pragma alloc_text(INIT,DriverEntry)
|
|
#endif
|
|
#endif
|
|
|
|
|
|
NTSTATUS
|
|
DriverEntry(
|
|
IN PDRIVER_OBJECT DriverObject,
|
|
IN PUNICODE_STRING RegistryPath
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine initializes the beep driver.
|
|
|
|
Arguments:
|
|
|
|
DriverObject - Pointer to driver object created by system.
|
|
|
|
RegistryPath - Pointer to the Unicode name of the registry path
|
|
for this driver.
|
|
|
|
Return Value:
|
|
|
|
The function value is the final status from the initialization operation.
|
|
|
|
--*/
|
|
|
|
{
|
|
UNICODE_STRING unicodeString;
|
|
PDEVICE_OBJECT deviceObject;
|
|
PDEVICE_EXTENSION deviceExtension;
|
|
NTSTATUS status;
|
|
|
|
BeepPrint((2,"\n\nBEEP-BeepInitialize: enter\n"));
|
|
//
|
|
// Create non-exclusive device object for beep device.
|
|
//
|
|
|
|
RtlInitUnicodeString(&unicodeString, DD_BEEP_DEVICE_NAME_U);
|
|
|
|
status = IoCreateDevice(
|
|
DriverObject,
|
|
sizeof(DEVICE_EXTENSION),
|
|
&unicodeString,
|
|
FILE_DEVICE_BEEP,
|
|
0,
|
|
FALSE,
|
|
&deviceObject
|
|
);
|
|
|
|
if (status != STATUS_SUCCESS) {
|
|
BeepPrint((
|
|
1,
|
|
"BEEP-BeepInitialize: Could not create device object\n"
|
|
));
|
|
return(status);
|
|
}
|
|
|
|
deviceObject->Flags |= DO_BUFFERED_IO;
|
|
deviceExtension =
|
|
(PDEVICE_EXTENSION)deviceObject->DeviceExtension;
|
|
|
|
//
|
|
// Initialize the timer DPC queue (we use the device object DPC) and
|
|
// the timer itself.
|
|
//
|
|
|
|
IoInitializeDpcRequest(
|
|
deviceObject,
|
|
(PKDEFERRED_ROUTINE) BeepTimeOut
|
|
);
|
|
|
|
KeInitializeTimer(&deviceExtension->Timer);
|
|
deviceExtension->TimerSet = FALSE;
|
|
|
|
//
|
|
// Initialize the fast mutex and set the reference count to zero.
|
|
//
|
|
ExInitializeFastMutex(&deviceExtension->Mutex);
|
|
deviceExtension->ReferenceCount = 0;
|
|
|
|
//
|
|
// Set the driver to be completely paged out.
|
|
//
|
|
MmPageEntireDriver(DriverEntry);
|
|
|
|
//
|
|
// Set up the device driver entry points.
|
|
//
|
|
|
|
DriverObject->DriverStartIo = BeepStartIo;
|
|
DriverObject->DriverUnload = BeepUnload;
|
|
DriverObject->MajorFunction[IRP_MJ_CREATE] = BeepOpen;
|
|
DriverObject->MajorFunction[IRP_MJ_CLOSE] = BeepClose;
|
|
DriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL] =
|
|
BeepDeviceControl;
|
|
DriverObject->MajorFunction[IRP_MJ_CLEANUP] = BeepCleanup;
|
|
|
|
#ifdef _PNP_POWER_
|
|
//
|
|
// The HAL is in charge of the beeping, it will take care
|
|
// of the power management on the device
|
|
//
|
|
|
|
deviceObject->DeviceObjectExtension->PowerControlNeeded = FALSE;
|
|
#endif
|
|
|
|
BeepPrint((2,"BEEP-BeepInitialize: exit\n"));
|
|
|
|
return(STATUS_SUCCESS);
|
|
|
|
}
|
|
|
|
VOID
|
|
BeepCancel(
|
|
IN PDEVICE_OBJECT DeviceObject,
|
|
IN PIRP Irp
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine is called from the I/O system when a request is cancelled.
|
|
|
|
N.B. The cancel spinlock is already held upon entry to this routine.
|
|
|
|
Arguments:
|
|
|
|
DeviceObject - Pointer to class device object.
|
|
|
|
Irp - Pointer to the request packet to be cancelled.
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
|
|
{
|
|
|
|
BeepPrint((2,"BEEP-BeepCancel: enter\n"));
|
|
|
|
if (Irp == DeviceObject->CurrentIrp) {
|
|
|
|
//
|
|
// The current request is being cancelled. Set the CurrentIrp to
|
|
// null and release the cancel spinlock before starting the next packet.
|
|
//
|
|
|
|
DeviceObject->CurrentIrp = NULL;
|
|
IoReleaseCancelSpinLock(Irp->CancelIrql);
|
|
IoStartNextPacket(DeviceObject, TRUE);
|
|
} else {
|
|
|
|
//
|
|
// Cancel a request in the device queue. Remove it from queue and
|
|
// release the cancel spinlock.
|
|
//
|
|
|
|
if (TRUE != KeRemoveEntryDeviceQueue(
|
|
&DeviceObject->DeviceQueue,
|
|
&Irp->Tail.Overlay.DeviceQueueEntry
|
|
)) {
|
|
BeepPrint((
|
|
1,
|
|
"BEEP-BeepCancel: Irp 0x%x not in device queue?!?\n",
|
|
Irp
|
|
));
|
|
}
|
|
IoReleaseCancelSpinLock(Irp->CancelIrql);
|
|
}
|
|
|
|
//
|
|
// Complete the request with STATUS_CANCELLED.
|
|
//
|
|
|
|
Irp->IoStatus.Status = STATUS_CANCELLED;
|
|
Irp->IoStatus.Information = 0;
|
|
IoCompleteRequest (Irp, IO_NO_INCREMENT);
|
|
|
|
BeepPrint((2,"BEEP-BeepCancel: exit\n"));
|
|
|
|
return;
|
|
}
|
|
|
|
NTSTATUS
|
|
BeepCleanup(
|
|
IN PDEVICE_OBJECT DeviceObject,
|
|
IN PIRP Irp
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine is the dispatch routine for cleanup requests.
|
|
All queued beep requests are completed with STATUS_CANCELLED,
|
|
and the speaker is stopped.
|
|
|
|
Arguments:
|
|
|
|
DeviceObject - Pointer to class device object.
|
|
|
|
Irp - Pointer to the request packet.
|
|
|
|
Return Value:
|
|
|
|
Status is returned.
|
|
|
|
--*/
|
|
|
|
{
|
|
KIRQL currentIrql;
|
|
KIRQL cancelIrql;
|
|
PKDEVICE_QUEUE_ENTRY packet;
|
|
PIRP currentIrp;
|
|
|
|
BeepPrint((2,"BEEP-BeepCleanup: enter\n"));
|
|
|
|
//
|
|
// Raise IRQL to DISPATCH_LEVEL.
|
|
//
|
|
|
|
KeRaiseIrql(DISPATCH_LEVEL, ¤tIrql);
|
|
|
|
//
|
|
// Acquire the cancel spinlock.
|
|
//
|
|
|
|
IoAcquireCancelSpinLock(&cancelIrql);
|
|
|
|
//
|
|
// Complete all queued requests with STATUS_CANCELLED.
|
|
// Start with the real CurrentIrp, and run down the list of requests in the
|
|
// device queue. Be sure to set the real CurrentIrp to NULL, so that
|
|
// the interrupt service callback routine won't attempt to complete it.
|
|
//
|
|
|
|
currentIrp = DeviceObject->CurrentIrp;
|
|
DeviceObject->CurrentIrp = NULL;
|
|
|
|
while (currentIrp != NULL) {
|
|
|
|
//
|
|
// Remove the CurrentIrp from the cancellable state.
|
|
//
|
|
//
|
|
|
|
IoSetCancelRoutine(currentIrp, NULL);
|
|
|
|
//
|
|
// Set Status to CANCELLED, release the cancel spinlock,
|
|
// and complete the request. Note that the IRQL is reset to
|
|
// DISPATCH_LEVEL when we release the cancel spinlock.
|
|
//
|
|
|
|
currentIrp->IoStatus.Status = STATUS_CANCELLED;
|
|
currentIrp->IoStatus.Information = 0;
|
|
|
|
IoReleaseCancelSpinLock(cancelIrql);
|
|
IoCompleteRequest(currentIrp, IO_NO_INCREMENT);
|
|
|
|
//
|
|
// Reacquire the cancel spinlock.
|
|
//
|
|
|
|
IoAcquireCancelSpinLock(&cancelIrql);
|
|
|
|
//
|
|
// Dequeue the next packet (IRP) from the device work queue.
|
|
//
|
|
|
|
packet = KeRemoveDeviceQueue(&DeviceObject->DeviceQueue);
|
|
if (packet != NULL) {
|
|
currentIrp =
|
|
CONTAINING_RECORD(packet, IRP, Tail.Overlay.DeviceQueueEntry);
|
|
} else {
|
|
currentIrp = (PIRP) NULL;
|
|
}
|
|
} // end while
|
|
|
|
//
|
|
// Release the cancel spinlock and lower IRQL.
|
|
//
|
|
|
|
IoReleaseCancelSpinLock(cancelIrql);
|
|
KeLowerIrql(currentIrql);
|
|
|
|
//
|
|
// Complete the cleanup request with STATUS_SUCCESS.
|
|
//
|
|
|
|
Irp->IoStatus.Status = STATUS_SUCCESS;
|
|
Irp->IoStatus.Information = 0;
|
|
IoCompleteRequest (Irp, IO_NO_INCREMENT);
|
|
|
|
//
|
|
// Call HalMakeBeep() to stop any outstanding beep.
|
|
//
|
|
|
|
(VOID) HalMakeBeep(0);
|
|
|
|
BeepPrint((2,"BEEP-BeepCleanup: exit\n"));
|
|
|
|
return(STATUS_SUCCESS);
|
|
|
|
}
|
|
|
|
#if DBG
|
|
VOID
|
|
BeepDebugPrint(
|
|
ULONG DebugPrintLevel,
|
|
PCCHAR DebugMessage,
|
|
...
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Debug print routine.
|
|
|
|
Arguments:
|
|
|
|
Debug print level between 0 and 3, with 3 being the most verbose.
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
|
|
{
|
|
va_list ap;
|
|
|
|
va_start(ap, DebugMessage);
|
|
|
|
if (DebugPrintLevel <= BeepDebug) {
|
|
|
|
char buffer[128];
|
|
|
|
(VOID) vsprintf(buffer, DebugMessage, ap);
|
|
|
|
DbgPrint(buffer);
|
|
}
|
|
|
|
va_end(ap);
|
|
|
|
}
|
|
#endif
|
|
|
|
NTSTATUS
|
|
BeepDeviceControl(
|
|
IN PDEVICE_OBJECT DeviceObject,
|
|
IN PIRP Irp
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine is the dispatch routine for device control requests.
|
|
The IOCTL_BEEP_SET subfunction is processed and completed
|
|
in this routine.
|
|
|
|
Arguments:
|
|
|
|
DeviceObject - Pointer to class device object.
|
|
|
|
Irp - Pointer to the request packet.
|
|
|
|
Return Value:
|
|
|
|
Status is returned.
|
|
|
|
--*/
|
|
|
|
{
|
|
PIO_STACK_LOCATION irpSp;
|
|
NTSTATUS status;
|
|
PBEEP_SET_PARAMETERS beepParameters;
|
|
|
|
BeepPrint((2,"BEEP-BeepDeviceControl: enter\n"));
|
|
|
|
//
|
|
// Get a pointer to the current parameters for this request. The
|
|
// information is contained in the current stack location.
|
|
//
|
|
|
|
irpSp = IoGetCurrentIrpStackLocation(Irp);
|
|
|
|
//
|
|
// Case on the device control subfunction that is being performed by the
|
|
// requestor.
|
|
//
|
|
|
|
switch (irpSp->Parameters.DeviceIoControl.IoControlCode) {
|
|
|
|
//
|
|
// Make a beep. Validate the beep function parameters and return
|
|
// status pending.
|
|
//
|
|
|
|
case IOCTL_BEEP_SET:
|
|
beepParameters = (PBEEP_SET_PARAMETERS)
|
|
(Irp->AssociatedIrp.SystemBuffer);
|
|
if (irpSp->Parameters.DeviceIoControl.InputBufferLength <
|
|
sizeof(BEEP_SET_PARAMETERS)) {
|
|
status = STATUS_INVALID_PARAMETER;
|
|
} else if ((beepParameters->Frequency != 0)
|
|
&& (beepParameters->Duration == 0)) {
|
|
status = STATUS_SUCCESS;
|
|
} else {
|
|
|
|
status = STATUS_PENDING;
|
|
}
|
|
|
|
break;
|
|
|
|
//
|
|
// Unrecognized device control request.
|
|
//
|
|
|
|
default:
|
|
|
|
status = STATUS_INVALID_PARAMETER;
|
|
break;
|
|
}
|
|
|
|
//
|
|
// If status is pending, mark the packet pending and start the packet
|
|
// in a cancellable state. Otherwise, complete the request.
|
|
//
|
|
|
|
Irp->IoStatus.Status = status;
|
|
Irp->IoStatus.Information = 0;
|
|
if (status == STATUS_PENDING) {
|
|
IoMarkIrpPending(Irp);
|
|
IoStartPacket(DeviceObject, Irp, (PULONG)NULL, BeepCancel);
|
|
} else {
|
|
IoCompleteRequest(Irp, IO_NO_INCREMENT);
|
|
}
|
|
|
|
BeepPrint((2,"BEEP-BeepDeviceControl: exit\n"));
|
|
|
|
return(status);
|
|
|
|
}
|
|
|
|
NTSTATUS
|
|
BeepOpen(
|
|
IN PDEVICE_OBJECT DeviceObject,
|
|
IN PIRP Irp
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine is the dispatch routine for create/open requests.
|
|
Open requests are completed here.
|
|
|
|
Arguments:
|
|
|
|
DeviceObject - Pointer to class device object.
|
|
|
|
Irp - Pointer to the request packet.
|
|
|
|
Return Value:
|
|
|
|
Status is returned.
|
|
|
|
--*/
|
|
|
|
{
|
|
PDEVICE_EXTENSION deviceExtension;
|
|
PFAST_MUTEX mutex;
|
|
|
|
BeepPrint((2,"BEEP-BeepOpenClose: enter\n"));
|
|
|
|
//
|
|
// Increment the reference count. If this is the first reference,
|
|
// reset the driver paging.
|
|
//
|
|
deviceExtension = DeviceObject->DeviceExtension;
|
|
mutex = &deviceExtension->Mutex;
|
|
ExAcquireFastMutex(mutex);
|
|
if (++deviceExtension->ReferenceCount == 1) {
|
|
MmResetDriverPaging(BeepOpen);
|
|
}
|
|
ExReleaseFastMutex(mutex);
|
|
|
|
//
|
|
// Complete the request and return status.
|
|
//
|
|
|
|
Irp->IoStatus.Status = STATUS_SUCCESS;
|
|
Irp->IoStatus.Information = 0;
|
|
IoCompleteRequest(Irp, IO_NO_INCREMENT);
|
|
|
|
BeepPrint((2,"BEEP-BeepOpenClose: exit\n"));
|
|
|
|
return(STATUS_SUCCESS);
|
|
}
|
|
|
|
NTSTATUS
|
|
BeepClose(
|
|
IN PDEVICE_OBJECT DeviceObject,
|
|
IN PIRP Irp
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine is the dispatch routine for close requests.
|
|
Close requests are completed here.
|
|
|
|
Arguments:
|
|
|
|
DeviceObject - Pointer to class device object.
|
|
|
|
Irp - Pointer to the request packet.
|
|
|
|
Return Value:
|
|
|
|
Status is returned.
|
|
|
|
--*/
|
|
|
|
{
|
|
PDEVICE_EXTENSION deviceExtension;
|
|
PFAST_MUTEX mutex;
|
|
|
|
BeepPrint((2,"BEEP-BeepOpenClose: enter\n"));
|
|
|
|
//
|
|
// Decrement the reference count. If this is the last reference,
|
|
// page the driver out
|
|
//
|
|
deviceExtension = DeviceObject->DeviceExtension;
|
|
mutex = &deviceExtension->Mutex;
|
|
ExAcquireFastMutex(mutex);
|
|
if (--deviceExtension->ReferenceCount == 0) {
|
|
|
|
//
|
|
// If there is a timer queued, attempt to cancel it before paging out
|
|
// the driver. If we cannot cancel it, it may already be queued for
|
|
// execution on another processor. This is highly unlikely, so just
|
|
// don't page out the entire driver if a timer has been set but cannot
|
|
// be canceled.
|
|
//
|
|
|
|
if ((!deviceExtension->TimerSet) ||
|
|
(deviceExtension->TimerSet &&
|
|
KeCancelTimer(&deviceExtension->Timer))) {
|
|
|
|
MmPageEntireDriver(BeepClose);
|
|
}
|
|
|
|
}
|
|
ExReleaseFastMutex(mutex);
|
|
|
|
//
|
|
// Complete the request and return status.
|
|
//
|
|
|
|
Irp->IoStatus.Status = STATUS_SUCCESS;
|
|
Irp->IoStatus.Information = 0;
|
|
IoCompleteRequest(Irp, IO_NO_INCREMENT);
|
|
|
|
BeepPrint((2,"BEEP-BeepOpenClose: exit\n"));
|
|
|
|
return(STATUS_SUCCESS);
|
|
}
|
|
|
|
VOID
|
|
BeepStartIo(
|
|
IN PDEVICE_OBJECT DeviceObject,
|
|
IN PIRP Irp
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine is the StartIo routine. It is invoked to start a beep
|
|
request.
|
|
|
|
N.B. Requests enter BeepStartIo in a cancellable state.
|
|
|
|
Arguments:
|
|
|
|
DeviceObject - Pointer to the device object.
|
|
|
|
Irp - Pointer to the request packet.
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
|
|
{
|
|
PDEVICE_EXTENSION deviceExtension;
|
|
PIO_STACK_LOCATION irpSp;
|
|
KIRQL cancelIrql;
|
|
PBEEP_SET_PARAMETERS beepParameters;
|
|
LARGE_INTEGER time;
|
|
NTSTATUS status;
|
|
|
|
BeepPrint((2,"BEEP-BeepStartIo: enter\n"));
|
|
|
|
deviceExtension = DeviceObject->DeviceExtension;
|
|
|
|
//
|
|
// Acquire the cancel spinlock and verify that the CurrentIrp has not been
|
|
// cancelled.
|
|
//
|
|
|
|
IoAcquireCancelSpinLock(&cancelIrql);
|
|
if (Irp == NULL) {
|
|
IoReleaseCancelSpinLock(cancelIrql);
|
|
return;
|
|
}
|
|
|
|
//
|
|
// Remove the request from the cancellable state and release the cancel
|
|
// spinlock.
|
|
//
|
|
|
|
IoSetCancelRoutine(Irp, NULL);
|
|
IoReleaseCancelSpinLock(cancelIrql);
|
|
|
|
//
|
|
// Get a pointer to the current parameters for this request. The
|
|
// information is contained in the current stack location.
|
|
//
|
|
|
|
irpSp = IoGetCurrentIrpStackLocation(Irp);
|
|
|
|
//
|
|
// Case on the device control subfunction that is being performed by the
|
|
// requestor.
|
|
//
|
|
|
|
switch (irpSp->Parameters.DeviceIoControl.IoControlCode) {
|
|
|
|
//
|
|
// Make a beep. Call HalMakeBeep() to do the real work, and start
|
|
// a timer that will fire when the beep duration is reached. Finally,
|
|
// complete the request.
|
|
//
|
|
|
|
case IOCTL_BEEP_SET:
|
|
|
|
//
|
|
// Get the beep parameters.
|
|
//
|
|
|
|
beepParameters = (PBEEP_SET_PARAMETERS)
|
|
(Irp->AssociatedIrp.SystemBuffer);
|
|
|
|
BeepPrint((
|
|
3,
|
|
"BEEP-BeepStartIo: frequency %x, duration %d\n",
|
|
beepParameters->Frequency,
|
|
beepParameters->Duration
|
|
));
|
|
|
|
//
|
|
// Cancel the current timer (if any).
|
|
//
|
|
|
|
if (deviceExtension->TimerSet) {
|
|
if (KeCancelTimer(&deviceExtension->Timer)) {
|
|
|
|
//
|
|
// Timer successfully cancelled
|
|
//
|
|
|
|
deviceExtension->TimerSet = FALSE;
|
|
} else {
|
|
|
|
//
|
|
// The timer has already expired and
|
|
// been queued, it will reset the
|
|
// TimerSet flag when it runs.
|
|
//
|
|
|
|
}
|
|
}
|
|
|
|
//
|
|
// Call the HAL to actually start the beep (synchronizes
|
|
// access to the i8254 speaker.
|
|
//
|
|
|
|
if (HalMakeBeep(beepParameters->Frequency)) {
|
|
|
|
status = STATUS_SUCCESS;
|
|
|
|
//
|
|
// Set the timer so the beep will time out after
|
|
// the user-specified number of milliseconds (converted
|
|
// to 100ns resolution).
|
|
//
|
|
|
|
time.QuadPart = (LONGLONG)beepParameters->Duration * -10000;
|
|
|
|
BeepPrint((
|
|
3,
|
|
"BEEP-BeepStartIo: negative duration in 100ns %x.%x\n",
|
|
time.HighPart,
|
|
time.LowPart
|
|
));
|
|
|
|
deviceExtension->TimerSet = TRUE;
|
|
|
|
(VOID) KeSetTimer(
|
|
&deviceExtension->Timer,
|
|
time,
|
|
&DeviceObject->Dpc
|
|
);
|
|
|
|
} else {
|
|
status = STATUS_INVALID_PARAMETER;
|
|
}
|
|
|
|
break;
|
|
|
|
//
|
|
// Unrecognized device control request.
|
|
//
|
|
|
|
default:
|
|
|
|
status = STATUS_INVALID_PARAMETER;
|
|
break;
|
|
}
|
|
|
|
//
|
|
// Start the next packet, and complete this request.
|
|
//
|
|
|
|
Irp->IoStatus.Status = status;
|
|
Irp->IoStatus.Information = 0;
|
|
IoStartNextPacket(DeviceObject, TRUE);
|
|
IoCompleteRequest(Irp, IO_NO_INCREMENT);
|
|
|
|
BeepPrint((2,"BEEP-BeepStartIo: exit\n"));
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
VOID
|
|
BeepTimeOut(
|
|
IN PKDPC Dpc,
|
|
IN PDEVICE_OBJECT DeviceObject,
|
|
IN PVOID SystemArgument1,
|
|
IN PVOID SystemArgument2
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This is the driver's timeout routine. It is called when the beep
|
|
duration expires. The timer is started in StartIo.
|
|
|
|
N.B. The request is removed from the cancellable state prior to
|
|
the timer start, so there is no need to check the cancellation status
|
|
here.
|
|
|
|
Arguments:
|
|
|
|
DeviceObject - Pointer to the device object.
|
|
|
|
Context - Unused.
|
|
|
|
SystemArgument1 - Unused.
|
|
|
|
SystemArgument2 - Unused.
|
|
|
|
Return Value:
|
|
|
|
--*/
|
|
|
|
{
|
|
PDEVICE_EXTENSION deviceExtension;
|
|
|
|
BeepPrint((2, "BEEP-BeepTimeOut: enter\n"));
|
|
|
|
deviceExtension = DeviceObject->DeviceExtension;
|
|
|
|
//
|
|
// Stop the beep.
|
|
//
|
|
|
|
(VOID) HalMakeBeep(0);
|
|
|
|
//
|
|
// Clear the TimerSet flag
|
|
//
|
|
deviceExtension->TimerSet = FALSE;
|
|
|
|
//
|
|
// We don't have a request at this point -- it was completed in StartIo
|
|
// when the beep was started. So, there's no more work to do here.
|
|
//
|
|
|
|
BeepPrint((2, "BEEP-BeepTimeOut: exit\n"));
|
|
}
|
|
|
|
VOID
|
|
BeepUnload(
|
|
IN PDRIVER_OBJECT DriverObject
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine is the beep driver unload routine.
|
|
|
|
Arguments:
|
|
|
|
DriverObject - Pointer to class driver object.
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
|
|
{
|
|
PDEVICE_OBJECT deviceObject;
|
|
PDEVICE_EXTENSION deviceExtension;
|
|
|
|
|
|
|
|
BeepPrint((1,"BEEP-BeepUnload: enter\n"));
|
|
|
|
deviceObject = DriverObject->DeviceObject;
|
|
deviceExtension = deviceObject->DeviceExtension;
|
|
|
|
//
|
|
// Cancel the timer.
|
|
//
|
|
|
|
if (deviceExtension->TimerSet) {
|
|
if (KeCancelTimer(&deviceExtension->Timer)) {
|
|
|
|
//
|
|
// Timer successfully cancelled
|
|
//
|
|
|
|
deviceExtension->TimerSet = FALSE;
|
|
} else {
|
|
|
|
//
|
|
// The timer has already expired and
|
|
// been queued, it will reset the
|
|
// TimerSet flag when it runs.
|
|
//
|
|
|
|
}
|
|
}
|
|
|
|
//
|
|
// Delete the device object.
|
|
//
|
|
|
|
IoDeleteDevice(deviceObject);
|
|
BeepPrint((1,"BEEP-BeepUnload: exit\n"));
|
|
|
|
return;
|
|
}
|