415 lines
13 KiB
C++
415 lines
13 KiB
C++
/*++
|
|
|
|
Copyright (c) 1991 - 2001 Microsoft Corporation
|
|
|
|
Module Name:
|
|
|
|
#### ##### #### ###### ## #### ##### #####
|
|
## ## ## ## # ## ## ## # ## ## ## ##
|
|
## ## ## ## ## ## ## ## ## ## ##
|
|
## ## ## ## ## ## ## ## ## ## ##
|
|
## ## ## ## ## ## ## ##### #####
|
|
## ## ## ## # ## ## ## ## # ## ##
|
|
#### ##### #### ## ##### ## #### ## ##
|
|
|
|
Abstract:
|
|
|
|
This module contains the dispatcher for processing all
|
|
IOCTL requests. This module also contains all code for
|
|
device controls that are global to all miniport drivers.
|
|
|
|
Author:
|
|
|
|
Wesley Witt (wesw) 1-Oct-2001
|
|
|
|
Environment:
|
|
|
|
Kernel mode only.
|
|
|
|
Notes:
|
|
|
|
|
|
--*/
|
|
|
|
#include "internal.h"
|
|
|
|
|
|
#ifdef ALLOC_PRAGMA
|
|
#pragma alloc_text(PAGE,SaPortDeviceControl)
|
|
#endif
|
|
|
|
|
|
|
|
//
|
|
// IOCTL dispatch table
|
|
//
|
|
|
|
typedef NTSTATUS (*PIOCTL_DISPATCH_FUNC)(
|
|
IN PDEVICE_OBJECT DeviceObject,
|
|
IN PIRP Irp,
|
|
IN PDEVICE_EXTENSION DeviceExtension,
|
|
IN PVOID InputBuffer,
|
|
IN ULONG InputBufferLength,
|
|
IN PVOID OutputBuffer,
|
|
IN ULONG OutputBufferLength
|
|
);
|
|
|
|
//
|
|
// All IOCTLs are dispatched through this table. There are 16 dispatch
|
|
// entry points for the public miniports, all private IOCTLs must
|
|
// follow these dispatch entry points.
|
|
//
|
|
|
|
PIOCTL_DISPATCH_FUNC IoctlDispatchTable[] =
|
|
{
|
|
HandleGetVersion, // 0 FUNC_SA_GET_VERSION,
|
|
HandleGetCaps, // 1 FUNC_SA_GET_CAPABILITIES,
|
|
HandleWdDisable, // 2 FUNC_SAWD_DISABLE,
|
|
HandleWdQueryExpireBehavior, // 3 FUNC_SAWD_QUERY_EXPIRE_BEHAVIOR,
|
|
HandleWdSetExpireBehavior, // 4 FUNC_SAWD_SET_EXPIRE_BEHAVIOR,
|
|
HandleWdPing, // 5 FUNC_SAWD_PING,
|
|
HandleWdQueryTimer, // 6 FUNC_SAWD_QUERY_TIMER,
|
|
HandleWdSetTimer, // 7 FUNC_SAWD_SET_TIMER,
|
|
HandleWdDelayBoot, // 8 FUNC_SAWD_DELAY_BOOT
|
|
HandleNvramWriteBootCounter, // 9 FUNC_NVRAM_WRITE_BOOT_COUNTER,
|
|
HandleNvramReadBootCounter, // A FUNC_NVRAM_READ_BOOT_COUNTER,
|
|
DefaultIoctlHandler, // B
|
|
HandleDisplayLock, // C FUNC_SADISPLAY_LOCK,
|
|
HandleDisplayUnlock, // D FUNC_SADISPLAY_UNLOCK,
|
|
HandleDisplayBusyMessage, // E FUNC_SADISPLAY_BUSY_MESSAGE,
|
|
HandleDisplayShutdownMessage, // F FUNC_SADISPLAY_SHUTDOWN_MESSAGE,
|
|
HandleDisplayChangeLanguage, // 10 FUNC_SADISPLAY_CHANGE_LANGUAGE,
|
|
HandleDisplayStoreBitmap, // 11 FUNC_DISPLAY_STORE_BITMAP
|
|
DefaultIoctlHandler, // 12
|
|
DefaultIoctlHandler, // 13
|
|
DefaultIoctlHandler, // 14
|
|
DefaultIoctlHandler, // 15
|
|
DefaultIoctlHandler, // 16
|
|
DefaultIoctlHandler, // 17
|
|
DefaultIoctlHandler, // 18
|
|
DefaultIoctlHandler, // 19
|
|
DefaultIoctlHandler, // 1A
|
|
DefaultIoctlHandler, // 1B
|
|
DefaultIoctlHandler, // 1C
|
|
DefaultIoctlHandler, // 1D
|
|
DefaultIoctlHandler, // 1E
|
|
DefaultIoctlHandler, // 1F
|
|
DefaultIoctlHandler // 20
|
|
};
|
|
|
|
|
|
|
|
DECLARE_IOCTL_HANDLER( UnsupportedIoctlHandler )
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine handles all unsupported IOCTLs. It's job is to simply complete
|
|
the IRP with the status code set to STATUS_INVALID_DEVICE_REQUEST.
|
|
|
|
Arguments:
|
|
|
|
DeviceObject - The device object for the target device.
|
|
Irp - Pointer to an IRP structure that describes the requested I/O operation.
|
|
DeviceExtension - Pointer to the main port driver device extension.
|
|
InputBuffer - Pointer to the user's input buffer
|
|
InputBufferLength - Length in bytes of the input buffer
|
|
OutputBuffer - Pointer to the user's output buffer
|
|
OutputBufferLength - Length in bytes of the output buffer
|
|
|
|
Return Value:
|
|
|
|
Always STATUS_INVALID_DEVICE_REQUEST.
|
|
|
|
--*/
|
|
|
|
{
|
|
return CompleteRequest( Irp, STATUS_INVALID_DEVICE_REQUEST, 0 );
|
|
}
|
|
|
|
|
|
DECLARE_IOCTL_HANDLER( DefaultIoctlHandler )
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine is called by all of the subsequent IOCTL handlers. It's job
|
|
is to call the IOCTL handler in the associated miniport driver and then
|
|
complete the IRP.
|
|
|
|
Arguments:
|
|
|
|
DeviceObject - The device object for the target device.
|
|
Irp - Pointer to an IRP structure that describes the requested I/O operation.
|
|
DeviceExtension - Pointer to the main port driver device extension.
|
|
InputBuffer - Pointer to the user's input buffer
|
|
InputBufferLength - Length in bytes of the input buffer
|
|
OutputBuffer - Pointer to the user's output buffer
|
|
OutputBufferLength - Length in bytes of the output buffer
|
|
|
|
Return Value:
|
|
|
|
NT status code.
|
|
|
|
--*/
|
|
|
|
{
|
|
PIO_STACK_LOCATION IrpSp = IoGetCurrentIrpStackLocation(Irp);
|
|
|
|
NTSTATUS Status = DeviceExtension->InitData->DeviceIoctl(
|
|
DeviceExtension->MiniPortDeviceExtension,
|
|
Irp,
|
|
IrpSp->FileObject ? IrpSp->FileObject->FsContext : NULL,
|
|
IoGetFunctionCodeFromCtlCode( IrpSp->Parameters.DeviceIoControl.IoControlCode ),
|
|
InputBuffer,
|
|
InputBufferLength,
|
|
OutputBuffer,
|
|
OutputBufferLength
|
|
);
|
|
|
|
if (Status != STATUS_PENDING) {
|
|
if (!NT_SUCCESS(Status)) {
|
|
REPORT_ERROR( DeviceExtension->DeviceType, "Miniport device control routine failed", Status );
|
|
}
|
|
Status = CompleteRequest( Irp, Status, OutputBufferLength );
|
|
}
|
|
|
|
return Status;
|
|
}
|
|
|
|
|
|
DECLARE_IOCTL_HANDLER( HandleGetVersion )
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine processes the IOCTL_SA_GET_VERSION request for all
|
|
miniport drivers. It is required that all miniports support
|
|
this IOCTL.
|
|
|
|
Arguments:
|
|
|
|
DeviceObject - The device object for the target device.
|
|
Irp - Pointer to an IRP structure that describes the requested I/O operation.
|
|
DeviceExtension - Pointer to the main port driver device extension.
|
|
InputBuffer - Pointer to the user's input buffer
|
|
InputBufferLength - Length in bytes of the input buffer
|
|
OutputBuffer - Pointer to the user's output buffer
|
|
OutputBufferLength - Length in bytes of the output buffer
|
|
|
|
Return Value:
|
|
|
|
NT status code.
|
|
|
|
--*/
|
|
|
|
{
|
|
if (OutputBufferLength != sizeof(ULONG)) {
|
|
REPORT_ERROR( DeviceExtension->DeviceType, "Output buffer length != sizeof(ULONG)", STATUS_INVALID_BUFFER_SIZE );
|
|
return CompleteRequest( Irp, STATUS_INVALID_BUFFER_SIZE, 0 );
|
|
}
|
|
|
|
return DO_DEFAULT();
|
|
}
|
|
|
|
|
|
DECLARE_IOCTL_HANDLER( HandleGetCaps )
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine processes the IOCTL_SA_GET_CAPABILITIES request for all
|
|
miniport drivers. It is required that all miniports support
|
|
this IOCTL. Eventhough this function process the IOCTL for all miniports
|
|
the specifics of any given miniport driver is cased in various switch
|
|
statements.
|
|
|
|
Arguments:
|
|
|
|
DeviceObject - The device object for the target device.
|
|
Irp - Pointer to an IRP structure that describes the requested I/O operation.
|
|
DeviceExtension - Pointer to the main port driver device extension.
|
|
InputBuffer - Pointer to the user's input buffer
|
|
InputBufferLength - Length in bytes of the input buffer
|
|
OutputBuffer - Pointer to the user's output buffer
|
|
OutputBufferLength - Length in bytes of the output buffer
|
|
|
|
Return Value:
|
|
|
|
NT status code.
|
|
|
|
--*/
|
|
|
|
{
|
|
NTSTATUS Status;
|
|
PIO_STACK_LOCATION IrpSp = IoGetCurrentIrpStackLocation(Irp);
|
|
ULONG DeviceCapsSize = 0;
|
|
|
|
|
|
switch (DeviceExtension->InitData->DeviceType) {
|
|
case SA_DEVICE_DISPLAY:
|
|
DeviceCapsSize = sizeof(SA_DISPLAY_CAPS);
|
|
break;
|
|
|
|
case SA_DEVICE_KEYPAD:
|
|
DeviceCapsSize = 0;
|
|
break;
|
|
|
|
case SA_DEVICE_NVRAM:
|
|
DeviceCapsSize = sizeof(SA_NVRAM_CAPS);
|
|
break;
|
|
|
|
case SA_DEVICE_WATCHDOG:
|
|
DeviceCapsSize = sizeof(SA_WD_CAPS);
|
|
break;
|
|
|
|
default:
|
|
DeviceCapsSize = 0;
|
|
break;
|
|
}
|
|
|
|
if (OutputBufferLength != DeviceCapsSize) {
|
|
REPORT_ERROR( DeviceExtension->DeviceType, "Output buffer wrong length", STATUS_INVALID_BUFFER_SIZE );
|
|
return CompleteRequest( Irp, STATUS_INVALID_BUFFER_SIZE, DeviceCapsSize );
|
|
}
|
|
|
|
Status = DeviceExtension->InitData->DeviceIoctl(
|
|
DeviceExtension->MiniPortDeviceExtension,
|
|
Irp,
|
|
NULL,
|
|
IoGetFunctionCodeFromCtlCode( IrpSp->Parameters.DeviceIoControl.IoControlCode ),
|
|
InputBuffer,
|
|
InputBufferLength,
|
|
OutputBuffer,
|
|
OutputBufferLength
|
|
);
|
|
if (NT_SUCCESS(Status)) {
|
|
switch (DeviceExtension->InitData->DeviceType) {
|
|
case SA_DEVICE_DISPLAY:
|
|
break;
|
|
|
|
case SA_DEVICE_KEYPAD:
|
|
break;
|
|
|
|
case SA_DEVICE_NVRAM:
|
|
{
|
|
PSA_NVRAM_CAPS NvramCaps = (PSA_NVRAM_CAPS)OutputBuffer;
|
|
if (NvramCaps->NvramSize < SA_NVRAM_MINIMUM_SIZE) {
|
|
Status = STATUS_INVALID_BUFFER_SIZE;
|
|
} else {
|
|
NvramCaps->NvramSize -= NVRAM_RESERVED_BOOTCOUNTER_SLOTS;
|
|
NvramCaps->NvramSize -= NVRAM_RESERVED_DRIVER_SLOTS;
|
|
}
|
|
}
|
|
break;
|
|
|
|
case SA_DEVICE_WATCHDOG:
|
|
break;
|
|
|
|
default:
|
|
break;
|
|
}
|
|
} else {
|
|
REPORT_ERROR( DeviceExtension->DeviceType, "Miniport device control routine failed", Status );
|
|
}
|
|
|
|
return CompleteRequest( Irp, Status, OutputBufferLength );
|
|
}
|
|
|
|
|
|
NTSTATUS
|
|
SaPortDeviceControl(
|
|
IN PDEVICE_OBJECT DeviceObject,
|
|
IN PIRP Irp
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine is called by the I/O system to perform a device I/O
|
|
control function.
|
|
|
|
Arguments:
|
|
|
|
DeviceObject - a pointer to the object that represents the device
|
|
that I/O is to be done on.
|
|
|
|
Irp - a pointer to the I/O Request Packet for this request.
|
|
|
|
Return Value:
|
|
|
|
STATUS_SUCCESS or STATUS_PENDING if recognized I/O control code,
|
|
STATUS_INVALID_DEVICE_REQUEST otherwise.
|
|
|
|
--*/
|
|
|
|
{
|
|
PIO_STACK_LOCATION IrpSp = IoGetCurrentIrpStackLocation(Irp);
|
|
PDEVICE_EXTENSION DeviceExtension = (PDEVICE_EXTENSION) DeviceObject->DeviceExtension;
|
|
NTSTATUS Status;
|
|
ULONG FuncCode;
|
|
ULONG Idx;
|
|
PVOID OutputBuffer;
|
|
ULONG OutputBufferLength;
|
|
PIOCTL_DISPATCH_FUNC DispatchFunc;
|
|
|
|
|
|
if (DeviceExtension->IsRemoved) {
|
|
return CompleteRequest( Irp, STATUS_DELETE_PENDING, 0 );
|
|
}
|
|
|
|
if (!DeviceExtension->IsStarted) {
|
|
return CompleteRequest( Irp, STATUS_NO_SUCH_DEVICE, 0 );
|
|
}
|
|
|
|
DebugPrint(( DeviceExtension->DeviceType, SAPORT_DEBUG_INFO_LEVEL, "IOCTL - [0x%08x] %s\n",
|
|
IrpSp->Parameters.DeviceIoControl.IoControlCode,
|
|
IoctlString(IrpSp->Parameters.DeviceIoControl.IoControlCode)
|
|
));
|
|
|
|
if (DEVICE_TYPE_FROM_CTL_CODE(IrpSp->Parameters.DeviceIoControl.IoControlCode) != FILE_DEVICE_SERVER_AVAILABILITY) {
|
|
return CompleteRequest( Irp, STATUS_INVALID_PARAMETER_1, 0 );
|
|
}
|
|
|
|
FuncCode = IoGetFunctionCodeFromCtlCode( IrpSp->Parameters.DeviceIoControl.IoControlCode );
|
|
Idx = FuncCode - IOCTL_SERVERAVAILABILITY_BASE;
|
|
|
|
if (Irp->MdlAddress) {
|
|
OutputBuffer = (PVOID) MmGetSystemAddressForMdlSafe( Irp->MdlAddress, NormalPagePriority );
|
|
if (OutputBuffer == NULL) {
|
|
REPORT_ERROR( DeviceExtension->DeviceType, "MmGetSystemAddressForMdlSafe failed", STATUS_INSUFFICIENT_RESOURCES );
|
|
return CompleteRequest( Irp, STATUS_INSUFFICIENT_RESOURCES, 0 );
|
|
}
|
|
OutputBufferLength = IrpSp->Parameters.DeviceIoControl.OutputBufferLength;
|
|
} else {
|
|
OutputBuffer = NULL;
|
|
OutputBufferLength = 0;
|
|
}
|
|
|
|
if ((Idx > sizeof(IoctlDispatchTable)/sizeof(PIOCTL_DISPATCH_FUNC)) || (DeviceExtension->InitData->DeviceIoctl == NULL)) {
|
|
DispatchFunc = UnsupportedIoctlHandler;
|
|
} else {
|
|
DispatchFunc = IoctlDispatchTable[Idx];
|
|
}
|
|
|
|
Status = DispatchFunc(
|
|
DeviceObject,
|
|
Irp,
|
|
DeviceExtension,
|
|
Irp->AssociatedIrp.SystemBuffer,
|
|
IrpSp->Parameters.DeviceIoControl.InputBufferLength,
|
|
OutputBuffer,
|
|
OutputBufferLength
|
|
);
|
|
if (!NT_SUCCESS(Status)) {
|
|
REPORT_ERROR( DeviceExtension->DeviceType, "Device control dispatch routine failed", Status );
|
|
}
|
|
|
|
return Status;
|
|
}
|