mirror of
https://github.com/reactos/reactos.git
synced 2024-12-29 10:35:28 +00:00
476 lines
13 KiB
C
476 lines
13 KiB
C
/*
|
|
* PROJECT: ReactOS ISA PnP Bus driver
|
|
* FILE: isapnp.c
|
|
* PURPOSE: Driver entry
|
|
* PROGRAMMERS: Cameron Gutman (cameron.gutman@reactos.org)
|
|
*/
|
|
|
|
#include <isapnp.h>
|
|
|
|
#define NDEBUG
|
|
#include <debug.h>
|
|
|
|
NTSTATUS
|
|
NTAPI
|
|
IsaPnpDuplicateUnicodeString(
|
|
IN ULONG Flags,
|
|
IN PCUNICODE_STRING SourceString,
|
|
OUT PUNICODE_STRING DestinationString)
|
|
{
|
|
if (SourceString == NULL ||
|
|
DestinationString == NULL ||
|
|
SourceString->Length > SourceString->MaximumLength ||
|
|
(SourceString->Length == 0 && SourceString->MaximumLength > 0 && SourceString->Buffer == NULL) ||
|
|
Flags == RTL_DUPLICATE_UNICODE_STRING_ALLOCATE_NULL_STRING ||
|
|
Flags >= 4)
|
|
{
|
|
return STATUS_INVALID_PARAMETER;
|
|
}
|
|
|
|
if ((SourceString->Length == 0) &&
|
|
(Flags != (RTL_DUPLICATE_UNICODE_STRING_NULL_TERMINATE |
|
|
RTL_DUPLICATE_UNICODE_STRING_ALLOCATE_NULL_STRING)))
|
|
{
|
|
DestinationString->Length = 0;
|
|
DestinationString->MaximumLength = 0;
|
|
DestinationString->Buffer = NULL;
|
|
}
|
|
else
|
|
{
|
|
USHORT DestMaxLength = SourceString->Length;
|
|
|
|
if (Flags & RTL_DUPLICATE_UNICODE_STRING_NULL_TERMINATE)
|
|
DestMaxLength += sizeof(UNICODE_NULL);
|
|
|
|
DestinationString->Buffer = ExAllocatePool(PagedPool, DestMaxLength);
|
|
if (DestinationString->Buffer == NULL)
|
|
return STATUS_NO_MEMORY;
|
|
|
|
RtlCopyMemory(DestinationString->Buffer, SourceString->Buffer, SourceString->Length);
|
|
DestinationString->Length = SourceString->Length;
|
|
DestinationString->MaximumLength = DestMaxLength;
|
|
|
|
if (Flags & RTL_DUPLICATE_UNICODE_STRING_NULL_TERMINATE)
|
|
DestinationString->Buffer[DestinationString->Length / sizeof(WCHAR)] = 0;
|
|
}
|
|
|
|
return STATUS_SUCCESS;
|
|
}
|
|
|
|
static
|
|
NTSTATUS
|
|
NTAPI
|
|
IsaFdoCreateDeviceIDs(
|
|
IN PISAPNP_PDO_EXTENSION PdoExt)
|
|
{
|
|
PISAPNP_LOGICAL_DEVICE LogDev = PdoExt->IsaPnpDevice;
|
|
UNICODE_STRING TempString;
|
|
WCHAR TempBuffer[256];
|
|
PWCHAR End;
|
|
NTSTATUS Status;
|
|
USHORT i;
|
|
|
|
TempString.Buffer = TempBuffer;
|
|
TempString.MaximumLength = sizeof(TempBuffer);
|
|
TempString.Length = 0;
|
|
|
|
/* Device ID */
|
|
Status = RtlStringCbPrintfExW(TempString.Buffer,
|
|
TempString.MaximumLength / sizeof(WCHAR),
|
|
&End,
|
|
NULL, 0,
|
|
L"ISAPNP\\%3S%04X",
|
|
LogDev->VendorId,
|
|
LogDev->ProdId);
|
|
if (!NT_SUCCESS(Status))
|
|
return Status;
|
|
TempString.Length = (End - TempString.Buffer) * sizeof(WCHAR);
|
|
Status = IsaPnpDuplicateUnicodeString(
|
|
RTL_DUPLICATE_UNICODE_STRING_NULL_TERMINATE,
|
|
&TempString,
|
|
&PdoExt->DeviceID);
|
|
if (!NT_SUCCESS(Status))
|
|
return Status;
|
|
|
|
/* HardwareIDs */
|
|
Status = RtlStringCbPrintfExW(TempString.Buffer,
|
|
TempString.MaximumLength / sizeof(WCHAR),
|
|
&End,
|
|
NULL, 0,
|
|
L"ISAPNP\\%3S%04X@"
|
|
L"*%3S%04X@",
|
|
LogDev->VendorId,
|
|
LogDev->ProdId,
|
|
LogDev->VendorId,
|
|
LogDev->ProdId);
|
|
if (!NT_SUCCESS(Status))
|
|
return Status;
|
|
TempString.Length = (End - TempString.Buffer) * sizeof(WCHAR);
|
|
Status = IsaPnpDuplicateUnicodeString(
|
|
RTL_DUPLICATE_UNICODE_STRING_NULL_TERMINATE,
|
|
&TempString,
|
|
&PdoExt->HardwareIDs);
|
|
if (!NT_SUCCESS(Status))
|
|
return Status;
|
|
for (i = 0; i < PdoExt->HardwareIDs.Length / sizeof(WCHAR); i++)
|
|
if (PdoExt->HardwareIDs.Buffer[i] == '@')
|
|
PdoExt->HardwareIDs.Buffer[i] = UNICODE_NULL;
|
|
|
|
/* InstanceID */
|
|
Status = RtlStringCbPrintfExW(TempString.Buffer,
|
|
TempString.MaximumLength / sizeof(WCHAR),
|
|
&End,
|
|
NULL, 0,
|
|
L"%X",
|
|
LogDev->SerialNumber);
|
|
if (!NT_SUCCESS(Status))
|
|
return Status;
|
|
TempString.Length = (End - TempString.Buffer) * sizeof(WCHAR);
|
|
Status = IsaPnpDuplicateUnicodeString(
|
|
RTL_DUPLICATE_UNICODE_STRING_NULL_TERMINATE,
|
|
&TempString,
|
|
&PdoExt->InstanceID);
|
|
if (!NT_SUCCESS(Status))
|
|
return Status;
|
|
|
|
return STATUS_SUCCESS;
|
|
}
|
|
|
|
NTSTATUS
|
|
NTAPI
|
|
IsaPnpFillDeviceRelations(
|
|
IN PISAPNP_FDO_EXTENSION FdoExt,
|
|
IN PIRP Irp,
|
|
IN BOOLEAN IncludeDataPort)
|
|
{
|
|
PISAPNP_PDO_EXTENSION PdoExt;
|
|
NTSTATUS Status = STATUS_SUCCESS;
|
|
PLIST_ENTRY CurrentEntry;
|
|
PISAPNP_LOGICAL_DEVICE IsaDevice;
|
|
PDEVICE_RELATIONS DeviceRelations;
|
|
ULONG i = 0;
|
|
|
|
DeviceRelations = ExAllocatePool(NonPagedPool,
|
|
sizeof(DEVICE_RELATIONS) + sizeof(DEVICE_OBJECT) * FdoExt->DeviceCount);
|
|
if (!DeviceRelations)
|
|
{
|
|
return STATUS_NO_MEMORY;
|
|
}
|
|
|
|
if (IncludeDataPort)
|
|
{
|
|
DeviceRelations->Objects[i++] = FdoExt->DataPortPdo;
|
|
ObReferenceObject(FdoExt->DataPortPdo);
|
|
}
|
|
|
|
CurrentEntry = FdoExt->DeviceListHead.Flink;
|
|
while (CurrentEntry != &FdoExt->DeviceListHead)
|
|
{
|
|
IsaDevice = CONTAINING_RECORD(CurrentEntry, ISAPNP_LOGICAL_DEVICE, ListEntry);
|
|
|
|
if (!IsaDevice->Pdo)
|
|
{
|
|
Status = IoCreateDevice(FdoExt->DriverObject,
|
|
sizeof(ISAPNP_PDO_EXTENSION),
|
|
NULL,
|
|
FILE_DEVICE_CONTROLLER,
|
|
FILE_DEVICE_SECURE_OPEN | FILE_AUTOGENERATED_DEVICE_NAME,
|
|
FALSE,
|
|
&IsaDevice->Pdo);
|
|
if (!NT_SUCCESS(Status))
|
|
{
|
|
break;
|
|
}
|
|
|
|
IsaDevice->Pdo->Flags &= ~DO_DEVICE_INITIALIZING;
|
|
|
|
//Device->Pdo->Flags |= DO_POWER_PAGABLE;
|
|
|
|
PdoExt = (PISAPNP_PDO_EXTENSION)IsaDevice->Pdo->DeviceExtension;
|
|
|
|
RtlZeroMemory(PdoExt, sizeof(ISAPNP_PDO_EXTENSION));
|
|
|
|
PdoExt->Common.IsFdo = FALSE;
|
|
PdoExt->Common.Self = IsaDevice->Pdo;
|
|
PdoExt->Common.State = dsStopped;
|
|
PdoExt->IsaPnpDevice = IsaDevice;
|
|
PdoExt->FdoExt = FdoExt;
|
|
|
|
Status = IsaFdoCreateDeviceIDs(PdoExt);
|
|
if (!NT_SUCCESS(Status))
|
|
{
|
|
IoDeleteDevice(IsaDevice->Pdo);
|
|
IsaDevice->Pdo = NULL;
|
|
break;
|
|
}
|
|
}
|
|
DeviceRelations->Objects[i++] = IsaDevice->Pdo;
|
|
|
|
ObReferenceObject(IsaDevice->Pdo);
|
|
|
|
CurrentEntry = CurrentEntry->Flink;
|
|
}
|
|
|
|
DeviceRelations->Count = i;
|
|
|
|
Irp->IoStatus.Information = (ULONG_PTR)DeviceRelations;
|
|
|
|
return Status;
|
|
}
|
|
|
|
|
|
static IO_COMPLETION_ROUTINE ForwardIrpCompletion;
|
|
|
|
static
|
|
NTSTATUS
|
|
NTAPI
|
|
ForwardIrpCompletion(
|
|
IN PDEVICE_OBJECT DeviceObject,
|
|
IN PIRP Irp,
|
|
IN PVOID Context)
|
|
{
|
|
UNREFERENCED_PARAMETER(DeviceObject);
|
|
|
|
if (Irp->PendingReturned)
|
|
KeSetEvent((PKEVENT)Context, IO_NO_INCREMENT, FALSE);
|
|
|
|
return STATUS_MORE_PROCESSING_REQUIRED;
|
|
}
|
|
|
|
NTSTATUS
|
|
NTAPI
|
|
IsaForwardIrpSynchronous(
|
|
IN PISAPNP_FDO_EXTENSION FdoExt,
|
|
IN PIRP Irp)
|
|
{
|
|
KEVENT Event;
|
|
NTSTATUS Status;
|
|
|
|
KeInitializeEvent(&Event, NotificationEvent, FALSE);
|
|
IoCopyCurrentIrpStackLocationToNext(Irp);
|
|
|
|
IoSetCompletionRoutine(Irp, ForwardIrpCompletion, &Event, TRUE, TRUE, TRUE);
|
|
|
|
Status = IoCallDriver(FdoExt->Ldo, Irp);
|
|
if (Status == STATUS_PENDING)
|
|
{
|
|
Status = KeWaitForSingleObject(&Event, Suspended, KernelMode, FALSE, NULL);
|
|
if (NT_SUCCESS(Status))
|
|
Status = Irp->IoStatus.Status;
|
|
}
|
|
|
|
return Status;
|
|
}
|
|
|
|
static DRIVER_DISPATCH IsaCreateClose;
|
|
|
|
static
|
|
NTSTATUS
|
|
NTAPI
|
|
IsaCreateClose(
|
|
IN PDEVICE_OBJECT DeviceObject,
|
|
IN PIRP Irp)
|
|
{
|
|
Irp->IoStatus.Status = STATUS_SUCCESS;
|
|
Irp->IoStatus.Information = FILE_OPENED;
|
|
|
|
DPRINT("%s(%p, %p)\n", __FUNCTION__, DeviceObject, Irp);
|
|
|
|
IoCompleteRequest(Irp, IO_NO_INCREMENT);
|
|
|
|
return STATUS_SUCCESS;
|
|
}
|
|
|
|
static DRIVER_DISPATCH IsaIoctl;
|
|
|
|
static
|
|
NTSTATUS
|
|
NTAPI
|
|
IsaIoctl(
|
|
IN PDEVICE_OBJECT DeviceObject,
|
|
IN PIRP Irp)
|
|
{
|
|
PIO_STACK_LOCATION IrpSp = IoGetCurrentIrpStackLocation(Irp);
|
|
NTSTATUS Status;
|
|
|
|
DPRINT("%s(%p, %p)\n", __FUNCTION__, DeviceObject, Irp);
|
|
|
|
switch (IrpSp->Parameters.DeviceIoControl.IoControlCode)
|
|
{
|
|
default:
|
|
DPRINT1("Unknown ioctl code: %x\n", IrpSp->Parameters.DeviceIoControl.IoControlCode);
|
|
Status = STATUS_NOT_SUPPORTED;
|
|
break;
|
|
}
|
|
|
|
Irp->IoStatus.Status = Status;
|
|
IoCompleteRequest(Irp, IO_NO_INCREMENT);
|
|
|
|
return Status;
|
|
}
|
|
|
|
static DRIVER_DISPATCH IsaReadWrite;
|
|
|
|
static
|
|
NTSTATUS
|
|
NTAPI
|
|
IsaReadWrite(
|
|
IN PDEVICE_OBJECT DeviceObject,
|
|
IN PIRP Irp)
|
|
{
|
|
DPRINT("%s(%p, %p)\n", __FUNCTION__, DeviceObject, Irp);
|
|
|
|
Irp->IoStatus.Status = STATUS_NOT_SUPPORTED;
|
|
Irp->IoStatus.Information = 0;
|
|
|
|
IoCompleteRequest(Irp, IO_NO_INCREMENT);
|
|
|
|
return STATUS_NOT_SUPPORTED;
|
|
}
|
|
|
|
static
|
|
NTSTATUS
|
|
NTAPI
|
|
IsaPnpCreateReadPortDO(PISAPNP_FDO_EXTENSION FdoExt)
|
|
{
|
|
UNICODE_STRING DeviceID = RTL_CONSTANT_STRING(L"ISAPNP\\ReadDataPort\0");
|
|
UNICODE_STRING HardwareIDs = RTL_CONSTANT_STRING(L"ISAPNP\\ReadDataPort\0\0");
|
|
UNICODE_STRING InstanceID = RTL_CONSTANT_STRING(L"0\0");
|
|
PISAPNP_PDO_EXTENSION PdoExt;
|
|
|
|
NTSTATUS Status;
|
|
Status = IoCreateDevice(FdoExt->DriverObject,
|
|
sizeof(ISAPNP_PDO_EXTENSION),
|
|
NULL,
|
|
FILE_DEVICE_CONTROLLER,
|
|
FILE_DEVICE_SECURE_OPEN,
|
|
FALSE,
|
|
&FdoExt->DataPortPdo);
|
|
if (!NT_SUCCESS(Status))
|
|
return Status;
|
|
PdoExt = (PISAPNP_PDO_EXTENSION)FdoExt->DataPortPdo->DeviceExtension;
|
|
RtlZeroMemory(PdoExt, sizeof(ISAPNP_PDO_EXTENSION));
|
|
PdoExt->Common.IsFdo = FALSE;
|
|
PdoExt->Common.Self = FdoExt->DataPortPdo;
|
|
PdoExt->Common.State = dsStopped;
|
|
PdoExt->FdoExt = FdoExt;
|
|
|
|
Status = IsaPnpDuplicateUnicodeString(0,
|
|
&DeviceID,
|
|
&PdoExt->DeviceID);
|
|
if (!NT_SUCCESS(Status))
|
|
return Status;
|
|
|
|
Status = IsaPnpDuplicateUnicodeString(0,
|
|
&HardwareIDs,
|
|
&PdoExt->HardwareIDs);
|
|
if (!NT_SUCCESS(Status))
|
|
return Status;
|
|
|
|
Status = IsaPnpDuplicateUnicodeString(0,
|
|
&InstanceID,
|
|
&PdoExt->InstanceID);
|
|
if (!NT_SUCCESS(Status))
|
|
return Status;
|
|
|
|
return Status;
|
|
}
|
|
|
|
static
|
|
NTSTATUS
|
|
NTAPI
|
|
IsaAddDevice(
|
|
IN PDRIVER_OBJECT DriverObject,
|
|
IN PDEVICE_OBJECT PhysicalDeviceObject)
|
|
{
|
|
PDEVICE_OBJECT Fdo;
|
|
PISAPNP_FDO_EXTENSION FdoExt;
|
|
NTSTATUS Status;
|
|
|
|
DPRINT("%s(%p, %p)\n", __FUNCTION__, DriverObject, PhysicalDeviceObject);
|
|
|
|
Status = IoCreateDevice(DriverObject,
|
|
sizeof(*FdoExt),
|
|
NULL,
|
|
FILE_DEVICE_BUS_EXTENDER,
|
|
FILE_DEVICE_SECURE_OPEN,
|
|
TRUE,
|
|
&Fdo);
|
|
if (!NT_SUCCESS(Status))
|
|
{
|
|
DPRINT1("Failed to create FDO (0x%x)\n", Status);
|
|
return Status;
|
|
}
|
|
|
|
FdoExt = Fdo->DeviceExtension;
|
|
RtlZeroMemory(FdoExt, sizeof(*FdoExt));
|
|
|
|
FdoExt->Common.Self = Fdo;
|
|
FdoExt->Common.IsFdo = TRUE;
|
|
FdoExt->Common.State = dsStopped;
|
|
FdoExt->DriverObject = DriverObject;
|
|
FdoExt->Pdo = PhysicalDeviceObject;
|
|
FdoExt->Ldo = IoAttachDeviceToDeviceStack(Fdo,
|
|
PhysicalDeviceObject);
|
|
|
|
InitializeListHead(&FdoExt->DeviceListHead);
|
|
KeInitializeSpinLock(&FdoExt->Lock);
|
|
|
|
Status = IsaPnpCreateReadPortDO(FdoExt);
|
|
if (!NT_SUCCESS(Status))
|
|
return Status;
|
|
|
|
Fdo->Flags &= ~DO_DEVICE_INITIALIZING;
|
|
FdoExt->DataPortPdo->Flags &= ~DO_DEVICE_INITIALIZING;
|
|
|
|
return STATUS_SUCCESS;
|
|
}
|
|
|
|
static DRIVER_DISPATCH IsaPnp;
|
|
|
|
static
|
|
NTSTATUS
|
|
NTAPI
|
|
IsaPnp(
|
|
IN PDEVICE_OBJECT DeviceObject,
|
|
IN PIRP Irp)
|
|
{
|
|
PIO_STACK_LOCATION IrpSp = IoGetCurrentIrpStackLocation(Irp);
|
|
PISAPNP_COMMON_EXTENSION DevExt = DeviceObject->DeviceExtension;
|
|
|
|
DPRINT("%s(%p, %p)\n", __FUNCTION__, DeviceObject, Irp);
|
|
|
|
if (DevExt->IsFdo)
|
|
{
|
|
return IsaFdoPnp((PISAPNP_FDO_EXTENSION)DevExt,
|
|
Irp,
|
|
IrpSp);
|
|
}
|
|
else
|
|
{
|
|
return IsaPdoPnp((PISAPNP_PDO_EXTENSION)DevExt,
|
|
Irp,
|
|
IrpSp);
|
|
}
|
|
}
|
|
|
|
NTSTATUS
|
|
NTAPI
|
|
DriverEntry(
|
|
IN PDRIVER_OBJECT DriverObject,
|
|
IN PUNICODE_STRING RegistryPath)
|
|
{
|
|
DPRINT("%s(%p, %wZ)\n", __FUNCTION__, DriverObject, RegistryPath);
|
|
|
|
DriverObject->MajorFunction[IRP_MJ_CREATE] = IsaCreateClose;
|
|
DriverObject->MajorFunction[IRP_MJ_CLOSE] = IsaCreateClose;
|
|
DriverObject->MajorFunction[IRP_MJ_READ] = IsaReadWrite;
|
|
DriverObject->MajorFunction[IRP_MJ_WRITE] = IsaReadWrite;
|
|
DriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL] = IsaIoctl;
|
|
DriverObject->MajorFunction[IRP_MJ_PNP] = IsaPnp;
|
|
DriverObject->DriverExtension->AddDevice = IsaAddDevice;
|
|
|
|
return STATUS_SUCCESS;
|
|
}
|
|
|
|
/* EOF */
|