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.
460 lines
13 KiB
460 lines
13 KiB
/*++
|
|
|
|
Copyright (c) 1991 - 2002 Microsoft Corporation
|
|
|
|
Module Name:
|
|
|
|
## ## ### ##### #### ### ##### #### ##### #####
|
|
### ### ## # ## ## ## ## # ## ## ## # ## ## ## ##
|
|
######## ### ## ## ## ### ## ## ## ## ## ## ##
|
|
# ### ## ### ## ## ## ### ## ## ## ## ## ## ##
|
|
# # ## ### ## ## ## ### ##### ## ##### #####
|
|
# ## # ## ## ## ## # ## ## ## ## # ## ##
|
|
# ## ### ##### #### ### ## ## #### ## ##
|
|
|
|
Abstract:
|
|
|
|
This module contains the entire implementation of
|
|
the Microsoft virtual display miniport driver.
|
|
|
|
@@BEGIN_DDKSPLIT
|
|
Author:
|
|
|
|
Wesley Witt (wesw) 1-Oct-2001
|
|
|
|
@@END_DDKSPLIT
|
|
Environment:
|
|
|
|
Kernel mode only.
|
|
|
|
Notes:
|
|
|
|
--*/
|
|
|
|
#include "msdisp.h"
|
|
|
|
|
|
#ifdef ALLOC_PRAGMA
|
|
#pragma alloc_text(INIT,DriverEntry)
|
|
#endif
|
|
|
|
|
|
|
|
NTSTATUS
|
|
MsDispHwInitialize(
|
|
IN PDEVICE_OBJECT DeviceObject,
|
|
IN PIRP Irp,
|
|
IN PVOID DeviceExtensionIn,
|
|
IN PCM_PARTIAL_RESOURCE_DESCRIPTOR PartialResources,
|
|
IN ULONG PartialResourceCount
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine is the driver's entry point, called by the I/O system
|
|
to load the driver. The driver's entry points are initialized and
|
|
a mutex to control paging is initialized.
|
|
|
|
In DBG mode, this routine also examines the registry for special
|
|
debug parameters.
|
|
|
|
Arguments:
|
|
DeviceObject - Miniport's device object
|
|
Irp - Current IRP in progress
|
|
DeviceExtensionIn - Miniport's device extension
|
|
PartialResources - List of resources that are assigned to the miniport
|
|
PartialResourceCount - Number of assigned resources
|
|
|
|
Return Value:
|
|
|
|
NT status code
|
|
|
|
--*/
|
|
|
|
{
|
|
PDEVICE_EXTENSION DeviceExtension;
|
|
UNICODE_STRING EventName;
|
|
|
|
|
|
DeviceExtension = (PDEVICE_EXTENSION) DeviceExtensionIn;
|
|
DeviceExtension->DeviceObject = DeviceObject;
|
|
|
|
KeInitializeMutex( &DeviceExtension->DeviceLock, 0 );
|
|
DeviceExtension->DisplayBufferLength = SA_DISPLAY_MAX_BITMAP_SIZE;
|
|
DeviceExtension->DisplayBuffer = (PUCHAR) SaPortAllocatePool( DeviceExtension, DeviceExtension->DisplayBufferLength+128 );
|
|
if (DeviceExtension->DisplayBuffer == NULL) {
|
|
return STATUS_INSUFFICIENT_RESOURCES;
|
|
}
|
|
RtlZeroMemory( DeviceExtension->DisplayBuffer, DeviceExtension->DisplayBufferLength+128 );
|
|
|
|
return STATUS_SUCCESS;
|
|
}
|
|
|
|
|
|
NTSTATUS
|
|
MsDispCreate(
|
|
IN PVOID DeviceExtensionIn,
|
|
IN PIRP Irp,
|
|
IN PVOID FsContextIn
|
|
)
|
|
{
|
|
PDEVICE_EXTENSION DeviceExtension = (PDEVICE_EXTENSION) DeviceExtensionIn;
|
|
PMSDISP_FSCONTEXT FsContext = (PMSDISP_FSCONTEXT) FsContextIn;
|
|
|
|
FsContext->HasLockedPages = 0;
|
|
|
|
return STATUS_SUCCESS;
|
|
}
|
|
|
|
|
|
NTSTATUS
|
|
MsDispClose(
|
|
IN PVOID DeviceExtensionIn,
|
|
IN PIRP Irp,
|
|
IN PVOID FsContextIn
|
|
)
|
|
{
|
|
PDEVICE_EXTENSION DeviceExtension = (PDEVICE_EXTENSION) DeviceExtensionIn;
|
|
PMSDISP_FSCONTEXT FsContext = (PMSDISP_FSCONTEXT) FsContextIn;
|
|
|
|
|
|
if (FsContext->HasLockedPages) {
|
|
KeAcquireMutex( &DeviceExtension->DeviceLock );
|
|
IoFreeMdl( FsContext->Mdl );
|
|
KeReleaseMutex( &DeviceExtension->DeviceLock, FALSE );
|
|
}
|
|
|
|
return STATUS_SUCCESS;
|
|
}
|
|
|
|
|
|
VOID
|
|
MsDispCreateEventsWorker(
|
|
IN PDEVICE_OBJECT DeviceObject,
|
|
IN PVOID Context
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This delayed work routine creates the necessary events used
|
|
to communicate with the user mode application.
|
|
|
|
Arguments:
|
|
|
|
DeviceObject - Display device object
|
|
Context - Context pointer
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
|
|
{
|
|
PMSDISP_WORK_ITEM WorkItem = (PMSDISP_WORK_ITEM)Context;
|
|
PDEVICE_EXTENSION DeviceExtension = WorkItem->DeviceExtension;
|
|
NTSTATUS Status;
|
|
|
|
|
|
WorkItem->Status = STATUS_SUCCESS;
|
|
DeviceExtension->EventHandle = NULL;
|
|
DeviceExtension->Event = NULL;
|
|
|
|
KeAcquireMutex( &DeviceExtension->DeviceLock );
|
|
|
|
Status = SaPortCreateBasenamedEvent(
|
|
DeviceExtension,
|
|
MSDISP_EVENT_NAME,
|
|
&DeviceExtension->Event,
|
|
&DeviceExtension->EventHandle
|
|
);
|
|
if (!NT_SUCCESS(Status)) {
|
|
REPORT_ERROR( SA_DEVICE_DISPLAY, "SaPortCreateBasenamedEvent failed", Status );
|
|
}
|
|
|
|
WorkItem->Status = Status;
|
|
|
|
KeReleaseMutex( &DeviceExtension->DeviceLock, FALSE );
|
|
|
|
IoFreeWorkItem( WorkItem->WorkItem );
|
|
KeSetEvent( &WorkItem->Event, IO_NO_INCREMENT, FALSE );
|
|
}
|
|
|
|
|
|
NTSTATUS
|
|
MsDispDeviceIoctl(
|
|
IN PVOID DeviceExtensionIn,
|
|
IN PIRP Irp,
|
|
IN PVOID FsContextIn,
|
|
IN ULONG FunctionCode,
|
|
IN PVOID InputBuffer,
|
|
IN ULONG InputBufferLength,
|
|
IN PVOID OutputBuffer,
|
|
IN ULONG OutputBufferLength
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine processes the device control requests for the
|
|
local display miniport.
|
|
|
|
Arguments:
|
|
|
|
DeviceExtension - Miniport's device extension
|
|
FunctionCode - Device control function code
|
|
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 = STATUS_SUCCESS;
|
|
PDEVICE_EXTENSION DeviceExtension = (PDEVICE_EXTENSION) DeviceExtensionIn;
|
|
PSA_DISPLAY_CAPS DeviceCaps;
|
|
PMSDISP_BUFFER_DATA BufferData;
|
|
PMSDISP_FSCONTEXT FsContext;
|
|
MSDISP_WORK_ITEM WorkItem;
|
|
|
|
|
|
|
|
switch (FunctionCode) {
|
|
case FUNC_SA_GET_VERSION:
|
|
*((PULONG)OutputBuffer) = SA_INTERFACE_VERSION;
|
|
break;
|
|
|
|
case FUNC_SA_GET_CAPABILITIES:
|
|
DeviceCaps = (PSA_DISPLAY_CAPS)OutputBuffer;
|
|
DeviceCaps->SizeOfStruct = sizeof(SA_DISPLAY_CAPS);
|
|
DeviceCaps->DisplayType = SA_DISPLAY_TYPE_BIT_MAPPED_LCD;
|
|
DeviceCaps->CharacterSet = SA_DISPLAY_CHAR_ASCII;
|
|
DeviceCaps->DisplayHeight = DISPLAY_HEIGHT;
|
|
DeviceCaps->DisplayWidth = DISPLAY_WIDTH;
|
|
break;
|
|
|
|
case FUNC_VDRIVER_INIT:
|
|
if (DeviceExtension->Event == NULL) {
|
|
WorkItem.DeviceExtension = DeviceExtension;
|
|
WorkItem.Status = 0;
|
|
WorkItem.WorkItem = IoAllocateWorkItem( DeviceExtension->DeviceObject );
|
|
if (WorkItem.WorkItem) {
|
|
KeInitializeEvent( &WorkItem.Event, NotificationEvent, FALSE );
|
|
IoQueueWorkItem( WorkItem.WorkItem, MsDispCreateEventsWorker, DelayedWorkQueue, &WorkItem );
|
|
KeWaitForSingleObject( &WorkItem.Event, Executive, KernelMode, FALSE, NULL );
|
|
} else {
|
|
WorkItem.Status = STATUS_INSUFFICIENT_RESOURCES;
|
|
}
|
|
} else {
|
|
WorkItem.Status = STATUS_SUCCESS;
|
|
}
|
|
if (WorkItem.Status == STATUS_SUCCESS) {
|
|
BufferData = (PMSDISP_BUFFER_DATA) OutputBuffer;
|
|
FsContext = (PMSDISP_FSCONTEXT) FsContextIn;
|
|
FsContext->Mdl = IoAllocateMdl( DeviceExtension->DisplayBuffer, DeviceExtension->DisplayBufferLength, FALSE, TRUE, NULL );
|
|
if (FsContext->Mdl) {
|
|
MmBuildMdlForNonPagedPool( FsContext->Mdl );
|
|
BufferData->DisplayBuffer = MmMapLockedPagesSpecifyCache(
|
|
FsContext->Mdl,
|
|
UserMode,
|
|
MmCached,
|
|
NULL,
|
|
FALSE,
|
|
NormalPagePriority
|
|
);
|
|
if (BufferData->DisplayBuffer == NULL) {
|
|
IoFreeMdl( FsContext->Mdl );
|
|
Status = STATUS_INSUFFICIENT_RESOURCES;
|
|
REPORT_ERROR( SA_DEVICE_DISPLAY, "MmMapLockedPagesSpecifyCache failed", Status );
|
|
} else {
|
|
FsContext->HasLockedPages = 1;
|
|
}
|
|
} else {
|
|
Status = STATUS_INSUFFICIENT_RESOURCES;
|
|
REPORT_ERROR( SA_DEVICE_DISPLAY, "IoAllocateMdl failed", Status );
|
|
}
|
|
} else {
|
|
Status = WorkItem.Status;
|
|
}
|
|
break;
|
|
|
|
default:
|
|
Status = STATUS_NOT_SUPPORTED;
|
|
REPORT_ERROR( SA_DEVICE_DISPLAY, "Unsupported device control", Status );
|
|
break;
|
|
}
|
|
|
|
return Status;
|
|
}
|
|
|
|
|
|
VOID
|
|
MsDispWriteWorker(
|
|
IN PDEVICE_OBJECT DeviceObject,
|
|
IN PVOID Context
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This delayed work routine completes a write operation.
|
|
|
|
Arguments:
|
|
|
|
DeviceObject - Display device object
|
|
Context - Context pointer
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
|
|
{
|
|
PMSDISP_WORK_ITEM WorkItem = (PMSDISP_WORK_ITEM)Context;
|
|
PDEVICE_EXTENSION DeviceExtension = WorkItem->DeviceExtension;
|
|
NTSTATUS Status;
|
|
|
|
|
|
KeAcquireMutex( &DeviceExtension->DeviceLock );
|
|
RtlZeroMemory( DeviceExtension->DisplayBuffer, DeviceExtension->DisplayBufferLength );
|
|
RtlCopyMemory( DeviceExtension->DisplayBuffer, WorkItem->SaDisplay->Bits, (WorkItem->SaDisplay->Width/8)*WorkItem->SaDisplay->Height );
|
|
KeReleaseMutex( &DeviceExtension->DeviceLock, FALSE );
|
|
|
|
if (DeviceExtension->Event) {
|
|
KeSetEvent( DeviceExtension->Event, 0, FALSE );
|
|
}
|
|
|
|
IoFreeWorkItem( WorkItem->WorkItem );
|
|
SaPortFreePool( DeviceExtension, WorkItem );
|
|
|
|
SaPortCompleteRequest( DeviceExtension, NULL, 0, STATUS_SUCCESS, FALSE );
|
|
}
|
|
|
|
|
|
NTSTATUS
|
|
MsDispWrite(
|
|
IN PVOID DeviceExtensionIn,
|
|
IN PIRP Irp,
|
|
IN PVOID FsContextIn,
|
|
IN LONGLONG StartingOffset,
|
|
IN PVOID DataBuffer,
|
|
IN ULONG DataBufferLength
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine processes the write request for the local display miniport.
|
|
|
|
Arguments:
|
|
|
|
DeviceExtensionIn - Miniport's device extension
|
|
StartingOffset - Starting offset for the I/O
|
|
DataBuffer - Pointer to the data buffer
|
|
DataBufferLength - Length of the data buffer in bytes
|
|
|
|
Return Value:
|
|
|
|
NT status code.
|
|
|
|
--*/
|
|
|
|
{
|
|
PDEVICE_EXTENSION DeviceExtension = (PDEVICE_EXTENSION) DeviceExtensionIn;
|
|
PSA_DISPLAY_SHOW_MESSAGE SaDisplay = (PSA_DISPLAY_SHOW_MESSAGE) DataBuffer;
|
|
NTSTATUS Status = STATUS_SUCCESS;
|
|
PMSDISP_WORK_ITEM WorkItem;
|
|
|
|
|
|
if ((ULONG)((SaDisplay->Width/8)*SaDisplay->Height) > DeviceExtension->DisplayBufferLength) {
|
|
return STATUS_INVALID_PARAMETER;
|
|
}
|
|
|
|
WorkItem = (PMSDISP_WORK_ITEM) SaPortAllocatePool( DeviceExtension, sizeof(MSDISP_WORK_ITEM) );
|
|
if (WorkItem == NULL) {
|
|
return STATUS_INSUFFICIENT_RESOURCES;
|
|
}
|
|
|
|
WorkItem->DeviceExtension = DeviceExtension;
|
|
WorkItem->SaDisplay = (PSA_DISPLAY_SHOW_MESSAGE) DataBuffer;
|
|
WorkItem->WorkItem = IoAllocateWorkItem( DeviceExtension->DeviceObject );
|
|
if (WorkItem->WorkItem) {
|
|
IoQueueWorkItem( WorkItem->WorkItem, MsDispWriteWorker, DelayedWorkQueue, WorkItem );
|
|
Status = STATUS_PENDING;
|
|
} else {
|
|
Status = STATUS_INSUFFICIENT_RESOURCES;
|
|
}
|
|
|
|
return Status;
|
|
}
|
|
|
|
|
|
NTSTATUS
|
|
DriverEntry(
|
|
IN PDRIVER_OBJECT DriverObject,
|
|
IN PUNICODE_STRING RegistryPath
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine is the driver's entry point, called by the I/O system
|
|
to load the driver. The driver's entry points are initialized and
|
|
a mutex to control paging is initialized.
|
|
|
|
In DBG mode, this routine also examines the registry for special
|
|
debug parameters.
|
|
|
|
Arguments:
|
|
|
|
DriverObject - a pointer to the object that represents this device
|
|
driver.
|
|
|
|
RegistryPath - a pointer to this driver's key in the Services tree.
|
|
|
|
Return Value:
|
|
|
|
STATUS_SUCCESS
|
|
|
|
--*/
|
|
|
|
{
|
|
NTSTATUS Status;
|
|
SAPORT_INITIALIZATION_DATA SaPortInitData;
|
|
|
|
|
|
RtlZeroMemory( &SaPortInitData, sizeof(SAPORT_INITIALIZATION_DATA) );
|
|
|
|
SaPortInitData.StructSize = sizeof(SAPORT_INITIALIZATION_DATA);
|
|
SaPortInitData.DeviceType = SA_DEVICE_DISPLAY;
|
|
SaPortInitData.HwInitialize = MsDispHwInitialize;
|
|
SaPortInitData.Write = MsDispWrite;
|
|
SaPortInitData.DeviceIoctl = MsDispDeviceIoctl;
|
|
SaPortInitData.CloseRoutine = MsDispClose;
|
|
SaPortInitData.CreateRoutine = MsDispCreate;
|
|
|
|
SaPortInitData.DeviceExtensionSize = sizeof(DEVICE_EXTENSION);
|
|
SaPortInitData.FileContextSize = sizeof(MSDISP_FSCONTEXT);
|
|
|
|
Status = SaPortInitialize( DriverObject, RegistryPath, &SaPortInitData );
|
|
if (!NT_SUCCESS(Status)) {
|
|
REPORT_ERROR( SA_DEVICE_DISPLAY, "SaPortInitialize failed\n", Status );
|
|
return Status;
|
|
}
|
|
|
|
return STATUS_SUCCESS;
|
|
}
|