mirror of
https://github.com/reactos/reactos.git
synced 2025-02-22 16:36:33 +00:00
Add serial port enumerator driver:
- Enumerate legacy mice - Should also detect PnP serial devices even if they are not yet reported It is implemented as an upper filter for serial port driver (serial.sys) Add corresponding registry entries svn path=/trunk/; revision=14512
This commit is contained in:
parent
c6779bb5c2
commit
353bc6197c
12 changed files with 1578 additions and 3 deletions
|
@ -34,8 +34,8 @@ COMPONENTS = ntoskrnl
|
|||
HALS = halx86/up halx86/mp
|
||||
|
||||
# Bus drivers
|
||||
# acpi isapnp pci
|
||||
BUS = acpi isapnp pci
|
||||
# acpi isapnp pci serenum
|
||||
BUS = acpi isapnp pci serenum
|
||||
|
||||
# Filesystem libraries
|
||||
# vfatlib
|
||||
|
|
|
@ -469,6 +469,19 @@ HKLM,"SYSTEM\CurrentControlSet\Services\Keyboard","ImagePath",0x00020000,"system
|
|||
HKLM,"SYSTEM\CurrentControlSet\Services\Keyboard","Start",0x00010001,0x00000001
|
||||
HKLM,"SYSTEM\CurrentControlSet\Services\Keyboard","Type",0x00010001,0x00000001
|
||||
|
||||
; Serial port enumerator
|
||||
HKLM,"SYSTEM\CurrentControlSet\Services\serenum","ErrorControl",0x00010001,0x00000001
|
||||
HKLM,"SYSTEM\CurrentControlSet\Services\serenum","Group",0x00000000,"PNP Filter"
|
||||
HKLM,"SYSTEM\CurrentControlSet\Services\serenum","ImagePath",0x00020000,"system32\drivers\serenum.sys"
|
||||
HKLM,"SYSTEM\CurrentControlSet\Services\serenum","Start",0x00010001,0x00000003
|
||||
HKLM,"SYSTEM\CurrentControlSet\Services\serenum","Type",0x00010001,0x00000001
|
||||
;hard coded values
|
||||
HKLM,"SYSTEM\CurrentControlSet\Services\serenum\Enum","0",0x00000000,"ACPI\PNP0501"
|
||||
HKLM,"SYSTEM\CurrentControlSet\Services\serenum\Enum","Count",0x00010001,0x00000001
|
||||
HKLM,"SYSTEM\CurrentControlSet\Services\serenum\Enum","NextInstance",0x00010001,0x00000001
|
||||
HKLM,"SYSTEM\CurrentControlSet\Enum\ACPI\PNP0501\1","UpperFilters",0x00010000,"serenum"
|
||||
HKLM,"SYSTEM\CurrentControlSet\Enum\ACPI\PNP0501\2","UpperFilters",0x00010000,"serenum"
|
||||
|
||||
; SB16 driver
|
||||
HKLM,"SYSTEM\CurrentControlSet\Services\sndblst","Group",0x00000000,"Base"
|
||||
HKLM,"SYSTEM\CurrentControlSet\Services\sndblst","ServiceType",0x00010001,0x00000001
|
||||
|
|
|
@ -29,6 +29,7 @@ Signature = "$ReactOS$"
|
|||
drivers\bus\acpi\acpi.sys 2
|
||||
drivers\bus\isapnp\isapnp.sys 2
|
||||
drivers\bus\pci\pci.sys 2
|
||||
drivers\bus\serenum\serenum.sys 2
|
||||
drivers\dd\beep\beep.sys 2
|
||||
drivers\dd\bootvid\bootvid.sys 2
|
||||
drivers\dd\null\null.sys 2
|
||||
|
|
|
@ -6,7 +6,7 @@ PATH_TO_TOP = ../..
|
|||
|
||||
include $(PATH_TO_TOP)/rules.mak
|
||||
|
||||
DRIVERS = acpi isapnp pci
|
||||
DRIVERS = acpi isapnp pci serenum
|
||||
|
||||
all: $(DRIVERS)
|
||||
|
||||
|
|
541
reactos/drivers/bus/serenum/detect.c
Normal file
541
reactos/drivers/bus/serenum/detect.c
Normal file
|
@ -0,0 +1,541 @@
|
|||
/* $Id:
|
||||
*
|
||||
* COPYRIGHT: See COPYING in the top level directory
|
||||
* PROJECT: ReactOS Serial enumerator driver
|
||||
* FILE: drivers/bus/serenum/detect.c
|
||||
* PURPOSE: Detection of serial devices
|
||||
*
|
||||
* PROGRAMMERS: Jason Filby (jasonfilby@yahoo.com)
|
||||
* Filip Navara (xnavara@volny.cz)
|
||||
* Hervé Poussineau (hpoussin@reactos.com)
|
||||
*/
|
||||
|
||||
#define NDEBUG
|
||||
#include "serenum.h"
|
||||
|
||||
static NTSTATUS
|
||||
SerenumDeviceIoControl(
|
||||
IN PDEVICE_OBJECT DeviceObject,
|
||||
IN ULONG CtlCode,
|
||||
IN PVOID InputBuffer OPTIONAL,
|
||||
IN ULONG InputBufferSize,
|
||||
IN OUT PVOID OutputBuffer OPTIONAL,
|
||||
IN OUT PULONG OutputBufferSize)
|
||||
{
|
||||
KEVENT Event;
|
||||
PIRP Irp;
|
||||
IO_STATUS_BLOCK IoStatus;
|
||||
NTSTATUS Status;
|
||||
|
||||
KeInitializeEvent (&Event, NotificationEvent, FALSE);
|
||||
|
||||
Irp = IoBuildDeviceIoControlRequest(CtlCode,
|
||||
DeviceObject,
|
||||
InputBuffer,
|
||||
InputBufferSize,
|
||||
OutputBuffer,
|
||||
(OutputBufferSize) ? *OutputBufferSize : 0,
|
||||
FALSE,
|
||||
&Event,
|
||||
&IoStatus);
|
||||
if (Irp == NULL)
|
||||
{
|
||||
DPRINT("Serenum: IoBuildDeviceIoControlRequest() failed\n");
|
||||
return STATUS_INSUFFICIENT_RESOURCES;
|
||||
}
|
||||
|
||||
Status = IoCallDriver(DeviceObject, Irp);
|
||||
|
||||
if (Status == STATUS_PENDING)
|
||||
{
|
||||
DPRINT("Serenum: Operation pending\n");
|
||||
KeWaitForSingleObject(&Event, Suspended, KernelMode, FALSE, NULL);
|
||||
Status = IoStatus.Status;
|
||||
}
|
||||
|
||||
if (OutputBufferSize)
|
||||
{
|
||||
*OutputBufferSize = IoStatus.Information;
|
||||
}
|
||||
|
||||
return Status;
|
||||
}
|
||||
|
||||
static NTSTATUS
|
||||
ReadBytes(
|
||||
IN PDEVICE_OBJECT LowerDevice,
|
||||
OUT PUCHAR Buffer,
|
||||
IN ULONG BufferSize,
|
||||
OUT PULONG FilledBytes)
|
||||
{
|
||||
PIRP Irp;
|
||||
IO_STATUS_BLOCK ioStatus;
|
||||
KEVENT event;
|
||||
NTSTATUS Status;
|
||||
|
||||
KeInitializeEvent(&event, NotificationEvent, FALSE);
|
||||
Irp = IoBuildSynchronousFsdRequest(
|
||||
IRP_MJ_READ,
|
||||
LowerDevice,
|
||||
Buffer, BufferSize,
|
||||
0,
|
||||
&event,
|
||||
&ioStatus);
|
||||
if (!Irp)
|
||||
return FALSE;
|
||||
|
||||
Status = IoCallDriver(LowerDevice, Irp);
|
||||
if (Status == STATUS_PENDING)
|
||||
{
|
||||
KeWaitForSingleObject(&event, Suspended, KernelMode, FALSE, NULL);
|
||||
Status = ioStatus.Status;
|
||||
}
|
||||
DPRINT("Serenum: bytes received: %lu/%lu\n",
|
||||
ioStatus.Information, BufferSize);
|
||||
*FilledBytes = ioStatus.Information;
|
||||
return Status;
|
||||
}
|
||||
|
||||
static NTSTATUS
|
||||
ReportDetectedDevice(
|
||||
IN PDEVICE_OBJECT DeviceObject,
|
||||
IN PUNICODE_STRING DeviceDescription,
|
||||
IN PUNICODE_STRING DeviceId,
|
||||
IN PUNICODE_STRING HardwareIds,
|
||||
IN PUNICODE_STRING CompatibleIds)
|
||||
{
|
||||
PDEVICE_OBJECT Pdo = NULL;
|
||||
PPDO_DEVICE_EXTENSION PdoDeviceExtension;
|
||||
PFDO_DEVICE_EXTENSION FdoDeviceExtension;
|
||||
NTSTATUS Status;
|
||||
|
||||
DPRINT("Serenum: SerenumReportDetectedDevice() called with %wZ (%wZ) detected\n", DeviceId, DeviceDescription);
|
||||
|
||||
Status = IoCreateDevice(
|
||||
DeviceObject->DriverObject,
|
||||
sizeof(PDO_DEVICE_EXTENSION),
|
||||
NULL,
|
||||
FILE_DEVICE_CONTROLLER,
|
||||
FILE_AUTOGENERATED_DEVICE_NAME,
|
||||
FALSE,
|
||||
&Pdo);
|
||||
if (!NT_SUCCESS(Status)) goto ByeBye;
|
||||
|
||||
Pdo->Flags |= DO_BUS_ENUMERATED_DEVICE;
|
||||
Pdo->Flags |= DO_POWER_PAGABLE;
|
||||
PdoDeviceExtension = (PPDO_DEVICE_EXTENSION)Pdo->DeviceExtension;
|
||||
FdoDeviceExtension = (PFDO_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
|
||||
RtlZeroMemory(PdoDeviceExtension, sizeof(PDO_DEVICE_EXTENSION));
|
||||
PdoDeviceExtension->Common.IsFDO = FALSE;
|
||||
Status = SerenumDuplicateUnicodeString(&PdoDeviceExtension->DeviceDescription, DeviceDescription, PagedPool);
|
||||
if (!NT_SUCCESS(Status)) goto ByeBye;
|
||||
Status = SerenumDuplicateUnicodeString(&PdoDeviceExtension->DeviceId, DeviceId, PagedPool);
|
||||
if (!NT_SUCCESS(Status)) goto ByeBye;
|
||||
Status = SerenumDuplicateUnicodeString(&PdoDeviceExtension->HardwareIds, HardwareIds, PagedPool);
|
||||
if (!NT_SUCCESS(Status)) goto ByeBye;
|
||||
Status = SerenumDuplicateUnicodeString(&PdoDeviceExtension->CompatibleIds, CompatibleIds, PagedPool);
|
||||
if (!NT_SUCCESS(Status)) goto ByeBye;
|
||||
|
||||
/* Device attached to serial port (Pdo) may delegate work to
|
||||
* serial port stack (Fdo = DeviceObject variable) */
|
||||
Pdo->StackSize = DeviceObject->StackSize + 1;
|
||||
|
||||
FdoDeviceExtension->AttachedPdo = Pdo;
|
||||
PdoDeviceExtension->AttachedFdo = DeviceObject;
|
||||
|
||||
Pdo->Flags |= DO_BUFFERED_IO;
|
||||
Pdo->Flags &= ~DO_DEVICE_INITIALIZING;
|
||||
|
||||
return STATUS_SUCCESS;
|
||||
|
||||
ByeBye:
|
||||
if (Pdo)
|
||||
{
|
||||
if (PdoDeviceExtension->DeviceDescription.Buffer)
|
||||
RtlFreeUnicodeString(&PdoDeviceExtension->DeviceDescription);
|
||||
if (PdoDeviceExtension->DeviceId.Buffer)
|
||||
RtlFreeUnicodeString(&PdoDeviceExtension->DeviceId);
|
||||
if (PdoDeviceExtension->HardwareIds.Buffer)
|
||||
RtlFreeUnicodeString(&PdoDeviceExtension->HardwareIds);
|
||||
if (PdoDeviceExtension->CompatibleIds.Buffer)
|
||||
RtlFreeUnicodeString(&PdoDeviceExtension->CompatibleIds);
|
||||
IoDeleteDevice(Pdo);
|
||||
}
|
||||
return Status;
|
||||
}
|
||||
|
||||
static BOOLEAN
|
||||
SerenumIsValidPnpIdString(
|
||||
IN PUCHAR Buffer,
|
||||
IN ULONG BufferLength)
|
||||
{
|
||||
/* FIXME: SerenumIsValidPnpIdString not implemented */
|
||||
DPRINT1("Serenum: SerenumIsValidPnpIdString() unimplemented\n");
|
||||
return STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
static NTSTATUS
|
||||
ReportDetectedPnpDevice(
|
||||
IN PUCHAR Buffer,
|
||||
IN ULONG BufferLength)
|
||||
{
|
||||
ULONG i;
|
||||
/* FIXME: ReportDetectedPnpDevice not implemented */
|
||||
DPRINT1("Serenum: ReportDetectedPnpDevice() unimplemented\n");
|
||||
DPRINT1("");
|
||||
for (i = 0; i < BufferLength; i++)
|
||||
DbgPrint("%c", Buffer[i]);
|
||||
DbgPrint("\n");
|
||||
/* Call ReportDetectedDevice */
|
||||
return STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
#define BEGIN_ID '('
|
||||
#define END_ID ')'
|
||||
|
||||
static NTSTATUS
|
||||
SerenumWait(ULONG milliseconds)
|
||||
{
|
||||
KTIMER Timer;
|
||||
LARGE_INTEGER DueTime;
|
||||
|
||||
DueTime.QuadPart = -milliseconds * 10;
|
||||
KeInitializeTimer(&Timer);
|
||||
KeSetTimer(&Timer, DueTime, NULL);
|
||||
return KeWaitForSingleObject(&Timer, Executive, KernelMode, FALSE, NULL);
|
||||
}
|
||||
|
||||
NTSTATUS
|
||||
SerenumDetectPnpDevice(
|
||||
IN PDEVICE_OBJECT DeviceObject,
|
||||
IN PDEVICE_OBJECT LowerDevice)
|
||||
{
|
||||
UCHAR Buffer[256];
|
||||
ULONG BaudRate;
|
||||
ULONG TotalBytesReceived = 0;
|
||||
ULONG Size;
|
||||
ULONG Msr, Purge;
|
||||
ULONG i;
|
||||
BOOLEAN BufferContainsBeginId, BufferContainsEndId;
|
||||
SERIAL_LINE_CONTROL Lcr;
|
||||
SERIAL_TIMEOUTS Timeouts;
|
||||
SERIALPERF_STATS PerfStats;
|
||||
NTSTATUS Status;
|
||||
|
||||
/* 1. COM port initialization, check for device enumerate */
|
||||
CHECKPOINT;
|
||||
Status = SerenumDeviceIoControl(LowerDevice, IOCTL_SERIAL_CLR_DTR,
|
||||
NULL, 0, NULL, NULL);
|
||||
if (!NT_SUCCESS(Status)) return Status;
|
||||
Status = SerenumDeviceIoControl(LowerDevice, IOCTL_SERIAL_CLR_RTS,
|
||||
NULL, 0, NULL, NULL);
|
||||
if (!NT_SUCCESS(Status)) return Status;
|
||||
SerenumWait(200);
|
||||
Size = sizeof(Msr);
|
||||
Status = SerenumDeviceIoControl(LowerDevice, IOCTL_SERIAL_GET_MODEMSTATUS,
|
||||
NULL, 0, &Msr, &Size);
|
||||
if (!NT_SUCCESS(Status)) return Status;
|
||||
if ((Msr & SR_MSR_DSR) == 0) goto SerenumDisconnectIdle;
|
||||
|
||||
/* 2. COM port setup, 1st phase */
|
||||
CHECKPOINT;
|
||||
BaudRate = SERIAL_BAUD_1200;
|
||||
Status = SerenumDeviceIoControl(LowerDevice, IOCTL_SERIAL_SET_BAUD_RATE,
|
||||
&BaudRate, sizeof(BaudRate), NULL, 0);
|
||||
if (!NT_SUCCESS(Status)) return Status;
|
||||
Lcr.WordLength = 7;
|
||||
Lcr.Parity = NO_PARITY;
|
||||
Lcr.StopBits = STOP_BIT_1;
|
||||
Status = SerenumDeviceIoControl(LowerDevice, IOCTL_SERIAL_SET_LINE_CONTROL,
|
||||
&Lcr, sizeof(Lcr), NULL, NULL);
|
||||
if (!NT_SUCCESS(Status)) return Status;
|
||||
Status = SerenumDeviceIoControl(LowerDevice, IOCTL_SERIAL_CLR_DTR,
|
||||
NULL, 0, NULL, NULL);
|
||||
if (!NT_SUCCESS(Status)) return Status;
|
||||
Status = SerenumDeviceIoControl(LowerDevice, IOCTL_SERIAL_CLR_RTS,
|
||||
NULL, 0, NULL, NULL);
|
||||
if (!NT_SUCCESS(Status)) return Status;
|
||||
SerenumWait(200);
|
||||
Status = SerenumDeviceIoControl(LowerDevice, IOCTL_SERIAL_SET_DTR,
|
||||
NULL, 0, NULL, NULL);
|
||||
if (!NT_SUCCESS(Status)) return Status;
|
||||
SerenumWait(200);
|
||||
|
||||
/* 3. Wait for response, 1st phase */
|
||||
CHECKPOINT;
|
||||
Status = SerenumDeviceIoControl(LowerDevice, IOCTL_SERIAL_SET_RTS,
|
||||
NULL, 0, NULL, NULL);
|
||||
if (!NT_SUCCESS(Status)) return Status;
|
||||
Timeouts.ReadIntervalTimeout = 0;
|
||||
Timeouts.ReadTotalTimeoutMultiplier = 0;
|
||||
Timeouts.ReadTotalTimeoutConstant = 200;
|
||||
Timeouts.WriteTotalTimeoutMultiplier = Timeouts.WriteTotalTimeoutConstant = 0;
|
||||
Status = SerenumDeviceIoControl(LowerDevice, IOCTL_SERIAL_SET_TIMEOUTS,
|
||||
&Timeouts, sizeof(Timeouts), NULL, NULL);
|
||||
if (!NT_SUCCESS(Status)) return Status;
|
||||
Status = ReadBytes(LowerDevice, Buffer, sizeof(Buffer), &Size);
|
||||
if (!NT_SUCCESS(Status)) return Status;
|
||||
if (Size != 0) goto SerenumCollectPnpComDeviceId;
|
||||
|
||||
/* 4. COM port setup, 2nd phase */
|
||||
CHECKPOINT;
|
||||
Status = SerenumDeviceIoControl(LowerDevice, IOCTL_SERIAL_CLR_DTR,
|
||||
NULL, 0, NULL, NULL);
|
||||
if (!NT_SUCCESS(Status)) return Status;
|
||||
Status = SerenumDeviceIoControl(LowerDevice, IOCTL_SERIAL_CLR_RTS,
|
||||
NULL, 0, NULL, NULL);
|
||||
if (!NT_SUCCESS(Status)) return Status;
|
||||
Purge = SERIAL_PURGE_RXABORT | SERIAL_PURGE_RXCLEAR;
|
||||
Status = SerenumDeviceIoControl(LowerDevice, IOCTL_SERIAL_PURGE,
|
||||
&Purge, 0, NULL, NULL);
|
||||
if (!NT_SUCCESS(Status)) return Status;
|
||||
SerenumWait(200);
|
||||
|
||||
/* 5. Wait for response, 2nd phase */
|
||||
CHECKPOINT;
|
||||
Status = SerenumDeviceIoControl(LowerDevice, IOCTL_SERIAL_SET_DTR,
|
||||
NULL, 0, NULL, NULL);
|
||||
if (!NT_SUCCESS(Status)) return Status;
|
||||
Status = SerenumDeviceIoControl(LowerDevice, IOCTL_SERIAL_SET_RTS,
|
||||
NULL, 0, NULL, NULL);
|
||||
if (!NT_SUCCESS(Status)) return Status;
|
||||
Status = ReadBytes(LowerDevice, Buffer, 1, &TotalBytesReceived);
|
||||
if (!NT_SUCCESS(Status)) return Status;
|
||||
if (TotalBytesReceived != 0) goto SerenumCollectPnpComDeviceId;
|
||||
Size = sizeof(Msr);
|
||||
Status = SerenumDeviceIoControl(LowerDevice, IOCTL_SERIAL_GET_MODEMSTATUS,
|
||||
NULL, 0, &Msr, &Size);
|
||||
if (!NT_SUCCESS(Status)) return Status;
|
||||
if ((Msr & SR_MSR_DSR) == 0) goto SerenumVerifyDisconnect; else goto SerenumConnectIdle;
|
||||
|
||||
/* 6. Collect PnP COM device ID */
|
||||
SerenumCollectPnpComDeviceId:
|
||||
CHECKPOINT;
|
||||
Timeouts.ReadIntervalTimeout = 200;
|
||||
Timeouts.ReadTotalTimeoutMultiplier = 0;
|
||||
Timeouts.ReadTotalTimeoutConstant = 2200;
|
||||
Status = SerenumDeviceIoControl(LowerDevice, IOCTL_SERIAL_SET_TIMEOUTS,
|
||||
&Timeouts, sizeof(Timeouts), NULL, NULL);
|
||||
if (!NT_SUCCESS(Status)) return Status;
|
||||
Status = ReadBytes(LowerDevice, &Buffer[TotalBytesReceived], sizeof(Buffer) - TotalBytesReceived, &Size);
|
||||
if (!NT_SUCCESS(Status)) return Status;
|
||||
TotalBytesReceived += Size;
|
||||
Size = sizeof(PerfStats);
|
||||
Status = SerenumDeviceIoControl(LowerDevice, IOCTL_SERIAL_GET_STATS,
|
||||
NULL, 0, &PerfStats, &Size);
|
||||
if (!NT_SUCCESS(Status)) return Status;
|
||||
if (PerfStats.FrameErrorCount + PerfStats.ParityErrorCount != 0) goto SerenumConnectIdle;
|
||||
BufferContainsBeginId = BufferContainsEndId = FALSE;
|
||||
for (i = 0; i < TotalBytesReceived; i++)
|
||||
{
|
||||
if (Buffer[i] == BEGIN_ID) BufferContainsBeginId = TRUE;
|
||||
if (Buffer[i] == END_ID) BufferContainsEndId = TRUE;
|
||||
}
|
||||
if (TotalBytesReceived == 1 || BufferContainsEndId)
|
||||
{
|
||||
if (SerenumIsValidPnpIdString(Buffer, TotalBytesReceived))
|
||||
return ReportDetectedPnpDevice(Buffer, TotalBytesReceived);
|
||||
goto SerenumConnectIdle;
|
||||
}
|
||||
if (!BufferContainsBeginId) goto SerenumConnectIdle;
|
||||
if (!BufferContainsEndId) goto SerenumConnectIdle;
|
||||
Size = sizeof(Msr);
|
||||
Status = SerenumDeviceIoControl(LowerDevice, IOCTL_SERIAL_GET_MODEMSTATUS,
|
||||
NULL, 0, &Msr, &Size);
|
||||
if (!NT_SUCCESS(Status)) return Status;
|
||||
if ((Msr & SR_MSR_DSR) == 0) goto SerenumVerifyDisconnect;
|
||||
|
||||
/* 7. Verify disconnect */
|
||||
SerenumVerifyDisconnect:
|
||||
CHECKPOINT;
|
||||
Status = SerenumDeviceIoControl(LowerDevice, IOCTL_SERIAL_SET_DTR,
|
||||
NULL, 0, NULL, NULL);
|
||||
if (!NT_SUCCESS(Status)) return Status;
|
||||
Status = SerenumDeviceIoControl(LowerDevice, IOCTL_SERIAL_CLR_RTS,
|
||||
NULL, 0, NULL, NULL);
|
||||
if (!NT_SUCCESS(Status)) return Status;
|
||||
SerenumWait(5000);
|
||||
goto SerenumDisconnectIdle;
|
||||
|
||||
/* 8. Connect idle */
|
||||
SerenumConnectIdle:
|
||||
CHECKPOINT;
|
||||
Status = SerenumDeviceIoControl(LowerDevice, IOCTL_SERIAL_SET_DTR,
|
||||
NULL, 0, NULL, NULL);
|
||||
if (!NT_SUCCESS(Status)) return Status;
|
||||
Status = SerenumDeviceIoControl(LowerDevice, IOCTL_SERIAL_CLR_RTS,
|
||||
NULL, 0, NULL, NULL);
|
||||
if (!NT_SUCCESS(Status)) return Status;
|
||||
BaudRate = SERIAL_BAUD_300;
|
||||
Status = SerenumDeviceIoControl(LowerDevice, IOCTL_SERIAL_SET_BAUD_RATE,
|
||||
&BaudRate, sizeof(BaudRate), NULL, NULL);
|
||||
if (!NT_SUCCESS(Status)) return Status;
|
||||
Lcr.WordLength = 7;
|
||||
Lcr.Parity = NO_PARITY;
|
||||
Lcr.StopBits = STOP_BIT_1;
|
||||
Status = SerenumDeviceIoControl(LowerDevice, IOCTL_SERIAL_SET_LINE_CONTROL,
|
||||
&Lcr, sizeof(Lcr), NULL, NULL);
|
||||
if (!NT_SUCCESS(Status)) return Status;
|
||||
if (TotalBytesReceived == 0)
|
||||
return STATUS_DEVICE_NOT_CONNECTED;
|
||||
else
|
||||
return STATUS_SUCCESS;
|
||||
|
||||
/* 9. Disconnect idle */
|
||||
SerenumDisconnectIdle:
|
||||
CHECKPOINT;
|
||||
/* FIXME: report to OS device removal, if it was present */
|
||||
Status = SerenumDeviceIoControl(LowerDevice, IOCTL_SERIAL_SET_DTR,
|
||||
NULL, 0, NULL, NULL);
|
||||
if (!NT_SUCCESS(Status)) return Status;
|
||||
Status = SerenumDeviceIoControl(LowerDevice, IOCTL_SERIAL_CLR_RTS,
|
||||
NULL, 0, NULL, NULL);
|
||||
if (!NT_SUCCESS(Status)) return Status;
|
||||
BaudRate = SERIAL_BAUD_300;
|
||||
Status = SerenumDeviceIoControl(LowerDevice, IOCTL_SERIAL_SET_BAUD_RATE,
|
||||
&BaudRate, sizeof(BaudRate), NULL, NULL);
|
||||
if (!NT_SUCCESS(Status)) return Status;
|
||||
Lcr.WordLength = 7;
|
||||
Lcr.Parity = NO_PARITY;
|
||||
Lcr.StopBits = STOP_BIT_1;
|
||||
Status = SerenumDeviceIoControl(LowerDevice, IOCTL_SERIAL_SET_LINE_CONTROL,
|
||||
&Lcr, sizeof(Lcr), NULL, NULL);
|
||||
if (!NT_SUCCESS(Status)) return Status;
|
||||
return STATUS_DEVICE_NOT_CONNECTED;
|
||||
}
|
||||
|
||||
NTSTATUS
|
||||
SerenumDetectLegacyDevice(
|
||||
IN PDEVICE_OBJECT DeviceObject,
|
||||
IN PDEVICE_OBJECT LowerDevice)
|
||||
{
|
||||
ULONG Fcr, Mcr;
|
||||
ULONG BaudRate;
|
||||
ULONG Command;
|
||||
SERIAL_TIMEOUTS Timeouts;
|
||||
SERIAL_LINE_CONTROL LCR;
|
||||
ULONG i, Count;
|
||||
UCHAR Buffer[16];
|
||||
UNICODE_STRING DeviceDescription;
|
||||
UNICODE_STRING DeviceId;
|
||||
UNICODE_STRING HardwareIds;
|
||||
UNICODE_STRING CompatibleIds;
|
||||
NTSTATUS Status;
|
||||
|
||||
RtlZeroMemory(Buffer, sizeof(Buffer));
|
||||
|
||||
/* Reset UART */
|
||||
CHECKPOINT;
|
||||
Mcr = 0; /* MCR: DTR/RTS/OUT2 off */
|
||||
Status = SerenumDeviceIoControl(LowerDevice, IOCTL_SERIAL_SET_MODEM_CONTROL,
|
||||
&Mcr, sizeof(Mcr), NULL, NULL);
|
||||
if (!NT_SUCCESS(Status)) return Status;
|
||||
|
||||
/* Set communications parameters */
|
||||
CHECKPOINT;
|
||||
/* DLAB off */
|
||||
Fcr = 0;
|
||||
Status = SerenumDeviceIoControl(LowerDevice, IOCTL_SERIAL_SET_FIFO_CONTROL,
|
||||
&Fcr, sizeof(Fcr), NULL, NULL);
|
||||
if (!NT_SUCCESS(Status)) return Status;
|
||||
/* Set serial port speed */
|
||||
BaudRate = SERIAL_BAUD_1200;
|
||||
Status = SerenumDeviceIoControl(LowerDevice, IOCTL_SERIAL_SET_BAUD_RATE,
|
||||
&BaudRate, sizeof(BaudRate), NULL, NULL);
|
||||
if (!NT_SUCCESS(Status)) return Status;
|
||||
/* Set LCR */
|
||||
LCR.WordLength = 7;
|
||||
LCR.Parity = NO_PARITY;
|
||||
LCR.StopBits = STOP_BITS_2;
|
||||
Status = SerenumDeviceIoControl(LowerDevice, IOCTL_SERIAL_SET_LINE_CONTROL,
|
||||
&LCR, sizeof(LCR), NULL, NULL);
|
||||
if (!NT_SUCCESS(Status)) return Status;
|
||||
|
||||
/* Flush receive buffer */
|
||||
CHECKPOINT;
|
||||
Command = SERIAL_PURGE_RXCLEAR;
|
||||
Status = SerenumDeviceIoControl(LowerDevice, IOCTL_SERIAL_SET_MODEM_CONTROL,
|
||||
&Command, sizeof(Command), NULL, NULL);
|
||||
if (!NT_SUCCESS(Status)) return Status;
|
||||
/* Wait 100 ms */
|
||||
SerenumWait(100);
|
||||
|
||||
/* Enable DTR/RTS */
|
||||
CHECKPOINT;
|
||||
Status = SerenumDeviceIoControl(LowerDevice, IOCTL_SERIAL_SET_DTR,
|
||||
NULL, 0, NULL, NULL);
|
||||
if (!NT_SUCCESS(Status)) return Status;
|
||||
Status = SerenumDeviceIoControl(LowerDevice, IOCTL_SERIAL_SET_RTS,
|
||||
NULL, 0, NULL, NULL);
|
||||
if (!NT_SUCCESS(Status)) return Status;
|
||||
|
||||
/* Set timeout to 500 microseconds */
|
||||
CHECKPOINT;
|
||||
Timeouts.ReadIntervalTimeout = 100;
|
||||
Timeouts.ReadTotalTimeoutMultiplier = 0;
|
||||
Timeouts.ReadTotalTimeoutConstant = 500;
|
||||
Timeouts.WriteTotalTimeoutMultiplier = Timeouts.WriteTotalTimeoutConstant = 0;
|
||||
Status = SerenumDeviceIoControl(LowerDevice, IOCTL_SERIAL_SET_TIMEOUTS,
|
||||
&Timeouts, sizeof(Timeouts), NULL, NULL);
|
||||
if (!NT_SUCCESS(Status)) return Status;
|
||||
|
||||
/* Fill the read buffer */
|
||||
CHECKPOINT;
|
||||
Status = ReadBytes(LowerDevice, Buffer, sizeof(Buffer)/sizeof(Buffer[0]), &Count);
|
||||
if (!NT_SUCCESS(Status)) return Status;
|
||||
|
||||
for (i = 0; i < Count; i++)
|
||||
{
|
||||
if (Buffer[i] == 'B')
|
||||
{
|
||||
/* Sign for Microsoft Ballpoint */
|
||||
/* Hardware id: *PNP0F09
|
||||
* Compatible id: *PNP0F0F, SERIAL_MOUSE
|
||||
*/
|
||||
RtlInitUnicodeString(&DeviceDescription, L"Microsoft Ballpoint device");
|
||||
RtlInitUnicodeString(&DeviceId, L"*PNP0F09");
|
||||
SerenumInitMultiSzString(&HardwareIds, "*PNP0F09", NULL);
|
||||
SerenumInitMultiSzString(&CompatibleIds, "*PNP0F0F", "SERIAL_MOUSE", NULL);
|
||||
Status = ReportDetectedDevice(DeviceObject,
|
||||
&DeviceDescription, &DeviceId, &HardwareIds, &CompatibleIds);
|
||||
RtlFreeUnicodeString(&HardwareIds);
|
||||
RtlFreeUnicodeString(&CompatibleIds);
|
||||
return Status;
|
||||
}
|
||||
else if (Buffer[i] == 'M')
|
||||
{
|
||||
/* Sign for Microsoft Mouse protocol followed by button specifier */
|
||||
if (i == sizeof(Buffer) - 1)
|
||||
{
|
||||
/* Overflow Error */
|
||||
return STATUS_DEVICE_NOT_CONNECTED;
|
||||
}
|
||||
switch (Buffer[i + 1])
|
||||
{
|
||||
case '3':
|
||||
/* Hardware id: *PNP0F08
|
||||
* Compatible id: SERIAL_MOUSE
|
||||
*/
|
||||
RtlInitUnicodeString(&DeviceDescription, L"Microsoft Mouse with 3-buttons");
|
||||
RtlInitUnicodeString(&DeviceId, L"*PNP0F08");
|
||||
SerenumInitMultiSzString(&HardwareIds, "*PNP0F08", NULL);
|
||||
SerenumInitMultiSzString(&CompatibleIds, "SERIAL_MOUSE", NULL);
|
||||
default:
|
||||
/* Hardware id: *PNP0F01
|
||||
* Compatible id: SERIAL_MOUSE
|
||||
*/
|
||||
RtlInitUnicodeString(&DeviceDescription, L"Microsoft Mouse with 2-buttons or Microsoft Wheel Mouse");
|
||||
RtlInitUnicodeString(&DeviceId, L"*PNP0F01");
|
||||
SerenumInitMultiSzString(&HardwareIds, "*PNP0F01", NULL);
|
||||
SerenumInitMultiSzString(&CompatibleIds, "SERIAL_MOUSE", NULL);
|
||||
}
|
||||
Status = ReportDetectedDevice(DeviceObject,
|
||||
&DeviceDescription, &DeviceId, &HardwareIds, &CompatibleIds);
|
||||
RtlFreeUnicodeString(&HardwareIds);
|
||||
RtlFreeUnicodeString(&CompatibleIds);
|
||||
return Status;
|
||||
}
|
||||
}
|
||||
|
||||
return STATUS_DEVICE_NOT_CONNECTED;
|
||||
}
|
213
reactos/drivers/bus/serenum/fdo.c
Normal file
213
reactos/drivers/bus/serenum/fdo.c
Normal file
|
@ -0,0 +1,213 @@
|
|||
/* $Id:
|
||||
*
|
||||
* COPYRIGHT: See COPYING in the top level directory
|
||||
* PROJECT: ReactOS Serial enumerator driver
|
||||
* FILE: drivers/bus/serenum/fdo.c
|
||||
* PURPOSE: IRP_MJ_PNP operations for FDOs
|
||||
*
|
||||
* PROGRAMMERS: Hervé Poussineau (hpoussin@reactos.com)
|
||||
*/
|
||||
|
||||
#define NDEBUG
|
||||
#include "serenum.h"
|
||||
|
||||
NTSTATUS STDCALL
|
||||
SerenumAddDevice(
|
||||
IN PDRIVER_OBJECT DriverObject,
|
||||
IN PDEVICE_OBJECT Pdo)
|
||||
{
|
||||
PDEVICE_OBJECT Fdo;
|
||||
PFDO_DEVICE_EXTENSION DeviceExtension;
|
||||
//UNICODE_STRING SymbolicLinkName;
|
||||
NTSTATUS Status;
|
||||
|
||||
DPRINT("Serenum: SerenumAddDevice called. Pdo = %p\n", Pdo);
|
||||
|
||||
/* Create new device object */
|
||||
Status = IoCreateDevice(DriverObject,
|
||||
sizeof(FDO_DEVICE_EXTENSION),
|
||||
NULL,
|
||||
FILE_DEVICE_BUS_EXTENDER,
|
||||
FILE_DEVICE_SECURE_OPEN,
|
||||
FALSE,
|
||||
&Fdo);
|
||||
if (!NT_SUCCESS(Status))
|
||||
{
|
||||
DPRINT("Serenum: IoCreateDevice() failed with status 0x%08lx\n", Status);
|
||||
return Status;
|
||||
}
|
||||
|
||||
/* Register device interface */
|
||||
#if 0 /* FIXME: activate */
|
||||
Status = IoRegisterDeviceInterface(Pdo, &GUID_DEVINTERFACE_SERENUM_BUS_ENUMERATOR, NULL, &SymbolicLinkName);
|
||||
if (!NT_SUCCESS(Status))
|
||||
{
|
||||
DPRINT("Serenum: IoRegisterDeviceInterface() failed with status 0x%08lx\n", Status);
|
||||
goto ByeBye;
|
||||
}
|
||||
DPRINT1("Serenum: IoRegisterDeviceInterface() returned '%wZ'\n", &SymbolicLinkName);
|
||||
Status = IoSetDeviceInterfaceState(&SymbolicLinkName, TRUE);
|
||||
if (!NT_SUCCESS(Status))
|
||||
{
|
||||
DPRINT("Serenum: IoSetDeviceInterfaceState() failed with status 0x%08lx\n", Status);
|
||||
goto ByeBye;
|
||||
}
|
||||
RtlFreeUnicodeString(&SymbolicLinkName);
|
||||
#endif
|
||||
|
||||
DeviceExtension = (PFDO_DEVICE_EXTENSION)Fdo->DeviceExtension;
|
||||
RtlZeroMemory(DeviceExtension, sizeof(FDO_DEVICE_EXTENSION));
|
||||
DeviceExtension->Common.IsFDO = TRUE;
|
||||
DeviceExtension->Common.PnpState = dsStopped;
|
||||
DeviceExtension->Pdo = Pdo;
|
||||
IoInitializeRemoveLock(&DeviceExtension->RemoveLock, SERENUM_TAG, 0, 0);
|
||||
Fdo->Flags |= DO_POWER_PAGABLE;
|
||||
Status = IoAttachDeviceToDeviceStackSafe(Fdo, Pdo, &DeviceExtension->LowerDevice);
|
||||
if (!NT_SUCCESS(Status))
|
||||
{
|
||||
DPRINT("Serenum: IoAttachDeviceToDeviceStackSafe() failed with status 0x%08lx\n", Status);
|
||||
IoDeleteDevice(Fdo);
|
||||
return Status;
|
||||
}
|
||||
Fdo->Flags |= DO_BUFFERED_IO;
|
||||
Fdo->Flags &= ~DO_DEVICE_INITIALIZING;
|
||||
|
||||
return STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
NTSTATUS STDCALL
|
||||
SerenumFdoStartDevice(
|
||||
IN PDEVICE_OBJECT DeviceObject,
|
||||
IN PIRP Irp)
|
||||
{
|
||||
PCOMMON_DEVICE_EXTENSION DeviceExtension;
|
||||
|
||||
DPRINT("Serenum: SerenumFdoStartDevice() called\n");
|
||||
DeviceExtension = (PCOMMON_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
|
||||
|
||||
ASSERT(DeviceExtension->PnpState == dsStopped);
|
||||
DeviceExtension->PnpState = dsStarted;
|
||||
|
||||
return STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
NTSTATUS
|
||||
SerenumFdoQueryBusRelations(
|
||||
IN PDEVICE_OBJECT DeviceObject,
|
||||
OUT PDEVICE_RELATIONS* pDeviceRelations)
|
||||
{
|
||||
PFDO_DEVICE_EXTENSION DeviceExtension;
|
||||
PDEVICE_RELATIONS DeviceRelations;
|
||||
ULONG NumPDO;
|
||||
ULONG i;
|
||||
NTSTATUS Status;
|
||||
|
||||
DeviceExtension = (PFDO_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
|
||||
ASSERT(DeviceExtension->Common.IsFDO);
|
||||
|
||||
/* Do enumeration if needed */
|
||||
if (!(DeviceExtension->Flags & FLAG_ENUMERATION_DONE))
|
||||
{
|
||||
ASSERT(DeviceExtension->AttachedPdo == NULL);
|
||||
/* Detect plug-and-play devices */
|
||||
Status = SerenumDetectPnpDevice(DeviceObject, DeviceExtension->LowerDevice);
|
||||
if (Status == STATUS_DEVICE_NOT_CONNECTED)
|
||||
{
|
||||
/* Detect legacy devices */
|
||||
Status = SerenumDetectLegacyDevice(DeviceObject, DeviceExtension->LowerDevice);
|
||||
if (Status == STATUS_DEVICE_NOT_CONNECTED)
|
||||
Status = STATUS_SUCCESS;
|
||||
}
|
||||
DeviceExtension->Flags |= FLAG_ENUMERATION_DONE;
|
||||
}
|
||||
NumPDO = (DeviceExtension->AttachedPdo != NULL ? 1 : 0);
|
||||
|
||||
DeviceRelations = (PDEVICE_RELATIONS)ExAllocatePoolWithTag(
|
||||
PagedPool,
|
||||
sizeof(DEVICE_RELATIONS) + sizeof(PDEVICE_OBJECT) * (NumPDO - 1),
|
||||
SERENUM_TAG);
|
||||
if (!DeviceRelations)
|
||||
return STATUS_INSUFFICIENT_RESOURCES;
|
||||
|
||||
/* Fill returned structure */
|
||||
DeviceRelations->Count = NumPDO;
|
||||
for (i = 0; i < NumPDO; i++)
|
||||
{
|
||||
ObReferenceObject(DeviceExtension->AttachedPdo);
|
||||
DeviceRelations->Objects[i] = DeviceExtension->AttachedPdo;
|
||||
}
|
||||
|
||||
*pDeviceRelations = DeviceRelations;
|
||||
return Status;
|
||||
}
|
||||
|
||||
NTSTATUS
|
||||
SerenumFdoPnp(
|
||||
IN PDEVICE_OBJECT DeviceObject,
|
||||
IN PIRP Irp)
|
||||
{
|
||||
ULONG MinorFunction;
|
||||
PIO_STACK_LOCATION Stack;
|
||||
ULONG_PTR Information = 0;
|
||||
NTSTATUS Status;
|
||||
|
||||
Stack = IoGetCurrentIrpStackLocation(Irp);
|
||||
MinorFunction = Stack->MinorFunction;
|
||||
|
||||
switch (MinorFunction)
|
||||
{
|
||||
/* FIXME: do all these minor functions
|
||||
IRP_MN_QUERY_REMOVE_DEVICE 0x1
|
||||
IRP_MN_REMOVE_DEVICE 0x2
|
||||
IRP_MN_CANCEL_REMOVE_DEVICE 0x3
|
||||
IRP_MN_STOP_DEVICE 0x4
|
||||
IRP_MN_QUERY_STOP_DEVICE 0x5
|
||||
IRP_MN_CANCEL_STOP_DEVICE 0x6
|
||||
IRP_MN_QUERY_DEVICE_RELATIONS / RemovalRelations (optional) 0x7
|
||||
IRP_MN_QUERY_INTERFACE (optional) 0x8
|
||||
IRP_MN_QUERY_CAPABILITIES (optional) 0x9
|
||||
IRP_MN_FILTER_RESOURCE_REQUIREMENTS (optional or required) 0xb
|
||||
IRP_MN_QUERY_PNP_DEVICE_STATE (optional) 0x14
|
||||
IRP_MN_DEVICE_USAGE_NOTIFICATION (required or optional) 0x16
|
||||
IRP_MN_SURPRISE_REMOVAL 0x17
|
||||
*/
|
||||
case IRP_MN_START_DEVICE: /* 0x0 */
|
||||
{
|
||||
DPRINT("Serenum: IRP_MJ_PNP / IRP_MN_START_DEVICE\n");
|
||||
/* Call lower driver */
|
||||
Status = ForwardIrpAndWait(DeviceObject, Irp);
|
||||
if (NT_SUCCESS(Status))
|
||||
Status = SerenumFdoStartDevice(DeviceObject, Irp);
|
||||
break;
|
||||
}
|
||||
case IRP_MN_QUERY_DEVICE_RELATIONS: /* 0x7 */
|
||||
{
|
||||
switch (Stack->Parameters.QueryDeviceRelations.Type)
|
||||
{
|
||||
case BusRelations:
|
||||
{
|
||||
PDEVICE_RELATIONS DeviceRelations;
|
||||
DPRINT("Serenum: IRP_MJ_PNP / IRP_MN_QUERY_DEVICE_RELATIONS / BusRelations\n");
|
||||
Status = SerenumFdoQueryBusRelations(DeviceObject, &DeviceRelations);
|
||||
Information = (ULONG_PTR)DeviceRelations;
|
||||
break;
|
||||
}
|
||||
default:
|
||||
DPRINT1("Serenum: IRP_MJ_PNP / IRP_MN_QUERY_DEVICE_RELATIONS / Unknown type 0x%lx\n",
|
||||
Stack->Parameters.QueryDeviceRelations.Type);
|
||||
return ForwardIrpAndForget(DeviceObject, Irp);
|
||||
}
|
||||
break;
|
||||
}
|
||||
default:
|
||||
{
|
||||
DPRINT1("Serenum: IRP_MJ_PNP / unknown minor function 0x%lx\n", MinorFunction);
|
||||
return ForwardIrpAndForget(DeviceObject, Irp);
|
||||
}
|
||||
}
|
||||
|
||||
Irp->IoStatus.Information = Information;
|
||||
Irp->IoStatus.Status = Status;
|
||||
IoCompleteRequest(Irp, IO_NO_INCREMENT);
|
||||
return Status;
|
||||
}
|
20
reactos/drivers/bus/serenum/makefile
Normal file
20
reactos/drivers/bus/serenum/makefile
Normal file
|
@ -0,0 +1,20 @@
|
|||
# $Id: makefile 12852 2005-01-06 13:58:04Z mf $
|
||||
|
||||
PATH_TO_TOP = ../../..
|
||||
|
||||
TARGET_TYPE = driver
|
||||
|
||||
TARGET_NAME = serenum
|
||||
|
||||
TARGET_CFLAGS = -Wall -Werror -D__USE_W32API
|
||||
|
||||
TARGET_OBJECTS = \
|
||||
detect.o \
|
||||
fdo.o \
|
||||
misc.o \
|
||||
pdo.o \
|
||||
serenum.o
|
||||
|
||||
include $(PATH_TO_TOP)/rules.mak
|
||||
|
||||
include $(TOOLS_PATH)/helper.mk
|
201
reactos/drivers/bus/serenum/misc.c
Normal file
201
reactos/drivers/bus/serenum/misc.c
Normal file
|
@ -0,0 +1,201 @@
|
|||
/* $Id:
|
||||
*
|
||||
* COPYRIGHT: See COPYING in the top level directory
|
||||
* PROJECT: ReactOS Serial enumerator driver
|
||||
* FILE: drivers/dd/serenum/misc.c
|
||||
* PURPOSE: Misceallenous operations
|
||||
*
|
||||
* PROGRAMMERS: Hervé Poussineau (hpoussin@reactos.com)
|
||||
*/
|
||||
|
||||
#define NDEBUG
|
||||
#include "serenum.h"
|
||||
#include <stdarg.h>
|
||||
|
||||
NTSTATUS
|
||||
SerenumDuplicateUnicodeString(
|
||||
OUT PUNICODE_STRING Destination,
|
||||
IN PUNICODE_STRING Source,
|
||||
IN POOL_TYPE PoolType)
|
||||
{
|
||||
if (Source == NULL)
|
||||
{
|
||||
RtlInitUnicodeString(Destination, NULL);
|
||||
return STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
Destination->Buffer = ExAllocatePool(PoolType, Source->MaximumLength);
|
||||
if (Destination->Buffer == NULL)
|
||||
{
|
||||
return STATUS_INSUFFICIENT_RESOURCES;
|
||||
}
|
||||
|
||||
Destination->MaximumLength = Source->MaximumLength;
|
||||
Destination->Length = Source->Length;
|
||||
RtlCopyMemory(Destination->Buffer, Source->Buffer, Source->MaximumLength);
|
||||
|
||||
return STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
/* I really want ANSI strings as last arguments because
|
||||
* PnP ids are ANSI-encoded in PnP device string
|
||||
* identification */
|
||||
NTSTATUS
|
||||
SerenumInitMultiSzString(
|
||||
OUT PUNICODE_STRING Destination,
|
||||
... /* list of PCSZ */)
|
||||
{
|
||||
va_list args;
|
||||
PCSZ Source;
|
||||
ANSI_STRING AnsiString;
|
||||
UNICODE_STRING UnicodeString;
|
||||
ULONG DestinationSize = 0;
|
||||
NTSTATUS Status = STATUS_SUCCESS;
|
||||
|
||||
/* Calculate length needed for destination unicode string */
|
||||
va_start(args, Destination);
|
||||
Source = va_arg(args, PCSZ);
|
||||
while (Source != NULL)
|
||||
{
|
||||
RtlInitAnsiString(&AnsiString, Source);
|
||||
DestinationSize += RtlAnsiStringToUnicodeSize(&AnsiString)
|
||||
+ sizeof(WCHAR) /* final NULL */;
|
||||
Source = va_arg(args, PCSZ);
|
||||
}
|
||||
va_end(args);
|
||||
if (DestinationSize == 0)
|
||||
{
|
||||
RtlInitUnicodeString(Destination, NULL);
|
||||
return STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
/* Initialize destination string */
|
||||
DestinationSize += sizeof(WCHAR); // final NULL
|
||||
Destination->Buffer = (PWSTR)ExAllocatePoolWithTag(PagedPool, DestinationSize, SERENUM_TAG);
|
||||
if (!Destination->Buffer)
|
||||
return STATUS_INSUFFICIENT_RESOURCES;
|
||||
Destination->Length = 0;
|
||||
Destination->MaximumLength = (USHORT)DestinationSize;
|
||||
|
||||
/* Copy arguments to destination string */
|
||||
/* Use a temporary unicode string, which buffer is shared with
|
||||
* destination string, to copy arguments */
|
||||
UnicodeString.Length = Destination->Length;
|
||||
UnicodeString.MaximumLength = Destination->MaximumLength;
|
||||
UnicodeString.Buffer = Destination->Buffer;
|
||||
va_start(args, Destination);
|
||||
Source = va_arg(args, PCSZ);
|
||||
while (Source != NULL)
|
||||
{
|
||||
RtlInitAnsiString(&AnsiString, Source);
|
||||
Status = RtlAnsiStringToUnicodeString(&UnicodeString, &AnsiString, FALSE);
|
||||
if (!NT_SUCCESS(Status))
|
||||
{
|
||||
ExFreePoolWithTag(Destination->Buffer, SERENUM_TAG);
|
||||
break;
|
||||
}
|
||||
Destination->Length += UnicodeString.Length + sizeof(WCHAR);
|
||||
UnicodeString.MaximumLength -= UnicodeString.Length + sizeof(WCHAR);
|
||||
UnicodeString.Buffer += UnicodeString.Length / sizeof(WCHAR) + 1;
|
||||
UnicodeString.Length = 0;
|
||||
Source = va_arg(args, PCSZ);
|
||||
}
|
||||
va_end(args);
|
||||
if (NT_SUCCESS(Status))
|
||||
{
|
||||
/* Finish multi-sz string */
|
||||
Destination->Buffer[Destination->Length / sizeof(WCHAR)] = L'\0';
|
||||
Destination->Length += sizeof(WCHAR);
|
||||
}
|
||||
return Status;
|
||||
}
|
||||
|
||||
NTSTATUS STDCALL
|
||||
ForwardIrpAndWaitCompletion(
|
||||
IN PDEVICE_OBJECT DeviceObject,
|
||||
IN PIRP Irp,
|
||||
IN PVOID Context)
|
||||
{
|
||||
if (Irp->PendingReturned)
|
||||
KeSetEvent((PKEVENT)Context, IO_NO_INCREMENT, FALSE);
|
||||
return STATUS_MORE_PROCESSING_REQUIRED;
|
||||
}
|
||||
|
||||
NTSTATUS
|
||||
ForwardIrpAndWait(
|
||||
IN PDEVICE_OBJECT DeviceObject,
|
||||
IN PIRP Irp)
|
||||
{
|
||||
PDEVICE_OBJECT LowerDevice;
|
||||
KEVENT Event;
|
||||
NTSTATUS Status;
|
||||
|
||||
ASSERT(((PCOMMON_DEVICE_EXTENSION)DeviceObject->DeviceExtension)->IsFDO);
|
||||
LowerDevice = ((PFDO_DEVICE_EXTENSION)DeviceObject->DeviceExtension)->LowerDevice;
|
||||
|
||||
KeInitializeEvent(&Event, NotificationEvent, FALSE);
|
||||
IoCopyCurrentIrpStackLocationToNext(Irp);
|
||||
|
||||
DPRINT("Serenum: Calling lower device %p [%wZ]\n", LowerDevice, &LowerDevice->DriverObject->DriverName);
|
||||
IoSetCompletionRoutine(Irp, ForwardIrpAndWaitCompletion, &Event, TRUE, TRUE, TRUE);
|
||||
|
||||
Status = IoCallDriver(LowerDevice, Irp);
|
||||
if (Status == STATUS_PENDING)
|
||||
{
|
||||
Status = KeWaitForSingleObject(&Event, Suspended, KernelMode, FALSE, NULL);
|
||||
if (NT_SUCCESS(Status))
|
||||
Status = Irp->IoStatus.Status;
|
||||
}
|
||||
|
||||
return Status;
|
||||
}
|
||||
|
||||
NTSTATUS STDCALL
|
||||
ForwardIrpToLowerDeviceAndForget(
|
||||
IN PDEVICE_OBJECT DeviceObject,
|
||||
IN PIRP Irp)
|
||||
{
|
||||
PFDO_DEVICE_EXTENSION DeviceExtension;
|
||||
PDEVICE_OBJECT LowerDevice;
|
||||
|
||||
DeviceExtension = (PFDO_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
|
||||
ASSERT(DeviceExtension->Common.IsFDO);
|
||||
|
||||
LowerDevice = DeviceExtension->LowerDevice;
|
||||
DPRINT("Serenum: calling lower device 0x%p [%wZ]\n",
|
||||
LowerDevice, &LowerDevice->DriverObject->DriverName);
|
||||
IoSkipCurrentIrpStackLocation(Irp);
|
||||
return IoCallDriver(LowerDevice, Irp);
|
||||
}
|
||||
|
||||
NTSTATUS STDCALL
|
||||
ForwardIrpToAttachedFdoAndForget(
|
||||
IN PDEVICE_OBJECT DeviceObject,
|
||||
IN PIRP Irp)
|
||||
{
|
||||
PPDO_DEVICE_EXTENSION DeviceExtension;
|
||||
PDEVICE_OBJECT Fdo;
|
||||
|
||||
DeviceExtension = (PPDO_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
|
||||
ASSERT(!DeviceExtension->Common.IsFDO);
|
||||
|
||||
Fdo = DeviceExtension->AttachedFdo;
|
||||
DPRINT("Serenum: calling attached Fdo 0x%p [%wZ]\n",
|
||||
Fdo, &Fdo->DriverObject->DriverName);
|
||||
IoSkipCurrentIrpStackLocation(Irp);
|
||||
return IoCallDriver(Fdo, Irp);
|
||||
}
|
||||
|
||||
NTSTATUS STDCALL
|
||||
ForwardIrpAndForget(
|
||||
IN PDEVICE_OBJECT DeviceObject,
|
||||
IN PIRP Irp)
|
||||
{
|
||||
PDEVICE_OBJECT LowerDevice;
|
||||
|
||||
ASSERT(((PCOMMON_DEVICE_EXTENSION)DeviceObject->DeviceExtension)->IsFDO);
|
||||
LowerDevice = ((PFDO_DEVICE_EXTENSION)DeviceObject->DeviceExtension)->LowerDevice;
|
||||
|
||||
IoSkipCurrentIrpStackLocation(Irp);
|
||||
return IoCallDriver(LowerDevice, Irp);
|
||||
}
|
313
reactos/drivers/bus/serenum/pdo.c
Normal file
313
reactos/drivers/bus/serenum/pdo.c
Normal file
|
@ -0,0 +1,313 @@
|
|||
/* $Id:
|
||||
*
|
||||
* COPYRIGHT: See COPYING in the top level directory
|
||||
* PROJECT: ReactOS Serial enumerator driver
|
||||
* FILE: drivers/bus/serenum/pdo.c
|
||||
* PURPOSE: IRP_MJ_PNP operations for PDOs
|
||||
*
|
||||
* PROGRAMMERS: Hervé Poussineau (hpoussin@reactos.com)
|
||||
*/
|
||||
|
||||
#define NDEBUG
|
||||
#include "serenum.h"
|
||||
|
||||
static NTSTATUS
|
||||
SerenumPdoStartDevice(
|
||||
IN PDEVICE_OBJECT DeviceObject)
|
||||
{
|
||||
PPDO_DEVICE_EXTENSION DeviceExtension;
|
||||
|
||||
DeviceExtension = (PPDO_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
|
||||
|
||||
ASSERT(DeviceExtension->Common.PnpState == dsStopped);
|
||||
|
||||
DeviceExtension->Common.PnpState = dsStarted;
|
||||
return STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
static NTSTATUS
|
||||
SerenumPdoQueryId(
|
||||
IN PDEVICE_OBJECT DeviceObject,
|
||||
IN PIRP Irp,
|
||||
OUT ULONG_PTR* Information)
|
||||
{
|
||||
PPDO_DEVICE_EXTENSION DeviceExtension;
|
||||
ULONG IdType;
|
||||
PUNICODE_STRING SourceString;
|
||||
UNICODE_STRING String;
|
||||
NTSTATUS Status;
|
||||
|
||||
IdType = IoGetCurrentIrpStackLocation(Irp)->Parameters.QueryId.IdType;
|
||||
DeviceExtension = (PPDO_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
|
||||
RtlInitUnicodeString(&String, NULL);
|
||||
|
||||
switch (IdType)
|
||||
{
|
||||
case BusQueryDeviceID:
|
||||
{
|
||||
DPRINT("Serenum: IRP_MJ_PNP / IRP_MN_QUERY_ID / BusQueryDeviceID\n");
|
||||
SourceString = &DeviceExtension->DeviceId;
|
||||
break;
|
||||
}
|
||||
case BusQueryHardwareIDs:
|
||||
{
|
||||
DPRINT("Serenum: IRP_MJ_PNP / IRP_MN_QUERY_ID / BusQueryHardwareIDs\n");
|
||||
SourceString = &DeviceExtension->HardwareIds;
|
||||
break;
|
||||
}
|
||||
case BusQueryCompatibleIDs:
|
||||
DPRINT("Serenum: IRP_MJ_PNP / IRP_MN_QUERY_ID / BusQueryCompatibleIDs\n");
|
||||
SourceString = &DeviceExtension->CompatibleIds;
|
||||
break;
|
||||
case BusQueryInstanceID:
|
||||
{
|
||||
/* We don't have any instance id to report, and
|
||||
* this query is optional, so ignore it.
|
||||
*/
|
||||
*Information = Irp->IoStatus.Information;
|
||||
return Irp->IoStatus.Status;
|
||||
}
|
||||
default:
|
||||
DPRINT1("Serenum: IRP_MJ_PNP / IRP_MN_QUERY_ID / unknown query id type 0x%lx\n", IdType);
|
||||
return STATUS_NOT_SUPPORTED;
|
||||
}
|
||||
|
||||
Status = SerenumDuplicateUnicodeString(
|
||||
&String,
|
||||
SourceString,
|
||||
PagedPool);
|
||||
*Information = (ULONG_PTR)String.Buffer;
|
||||
return Status;
|
||||
}
|
||||
|
||||
static NTSTATUS
|
||||
SerenumPdoQueryDeviceRelations(
|
||||
IN PDEVICE_OBJECT DeviceObject,
|
||||
OUT PDEVICE_RELATIONS* pDeviceRelations)
|
||||
{
|
||||
PFDO_DEVICE_EXTENSION DeviceExtension;
|
||||
PDEVICE_RELATIONS DeviceRelations;
|
||||
|
||||
DeviceExtension = (PFDO_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
|
||||
ASSERT(DeviceExtension->Common.IsFDO);
|
||||
|
||||
DeviceRelations = (PDEVICE_RELATIONS)ExAllocatePoolWithTag(
|
||||
PagedPool,
|
||||
sizeof(DEVICE_RELATIONS),
|
||||
SERENUM_TAG);
|
||||
if (!DeviceRelations)
|
||||
return STATUS_INSUFFICIENT_RESOURCES;
|
||||
|
||||
ObReferenceObject(DeviceObject);
|
||||
DeviceRelations->Objects[0] = DeviceObject;
|
||||
|
||||
*pDeviceRelations = DeviceRelations;
|
||||
return STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
NTSTATUS
|
||||
SerenumPdoPnp(
|
||||
IN PDEVICE_OBJECT DeviceObject,
|
||||
IN PIRP Irp)
|
||||
{
|
||||
ULONG MinorFunction;
|
||||
PIO_STACK_LOCATION Stack;
|
||||
ULONG_PTR Information = 0;
|
||||
NTSTATUS Status;
|
||||
|
||||
Stack = IoGetCurrentIrpStackLocation(Irp);
|
||||
MinorFunction = Stack->MinorFunction;
|
||||
|
||||
switch (MinorFunction)
|
||||
{
|
||||
/* FIXME: do all these minor functions
|
||||
IRP_MN_QUERY_REMOVE_DEVICE 0x1
|
||||
IRP_MN_REMOVE_DEVICE 0x2
|
||||
IRP_MN_CANCEL_REMOVE_DEVICE 0x3
|
||||
IRP_MN_STOP_DEVICE 0x4
|
||||
IRP_MN_QUERY_STOP_DEVICE 0x5
|
||||
IRP_MN_CANCEL_STOP_DEVICE 0x6
|
||||
IRP_MN_QUERY_DEVICE_RELATIONS / EjectionRelations (optional) 0x7
|
||||
IRP_MN_QUERY_INTERFACE (required or optional) 0x8
|
||||
IRP_MN_READ_CONFIG (required or optional) 0xf
|
||||
IRP_MN_WRITE_CONFIG (required or optional) 0x10
|
||||
IRP_MN_EJECT (required or optional) 0x11
|
||||
IRP_MN_SET_LOCK (required or optional) 0x12
|
||||
IRP_MN_QUERY_ID / BusQueryDeviceID 0x13
|
||||
IRP_MN_QUERY_ID / BusQueryCompatibleIDs (optional) 0x13
|
||||
IRP_MN_QUERY_ID / BusQueryInstanceID (optional) 0x13
|
||||
IRP_MN_QUERY_PNP_DEVICE_STATE (optional) 0x14
|
||||
IRP_MN_DEVICE_USAGE_NOTIFICATION (required or optional) 0x16
|
||||
IRP_MN_SURPRISE_REMOVAL 0x17
|
||||
*/
|
||||
case IRP_MN_START_DEVICE: /* 0x0 */
|
||||
{
|
||||
DPRINT("Serenum: IRP_MJ_PNP / IRP_MN_START_DEVICE\n");
|
||||
Status = SerenumPdoStartDevice(DeviceObject);
|
||||
break;
|
||||
}
|
||||
case IRP_MN_QUERY_DEVICE_RELATIONS: /* 0x7 */
|
||||
{
|
||||
switch (Stack->Parameters.QueryDeviceRelations.Type)
|
||||
{
|
||||
case RemovalRelations:
|
||||
{
|
||||
return ForwardIrpToAttachedFdoAndForget(DeviceObject, Irp);
|
||||
}
|
||||
case TargetDeviceRelation:
|
||||
{
|
||||
PDEVICE_RELATIONS DeviceRelations;
|
||||
DPRINT("Serenum: IRP_MJ_PNP / IRP_MN_QUERY_DEVICE_RELATIONS / TargetDeviceRelation\n");
|
||||
Status = SerenumPdoQueryDeviceRelations(DeviceObject, &DeviceRelations);
|
||||
Information = (ULONG_PTR)DeviceRelations;
|
||||
break;
|
||||
}
|
||||
default:
|
||||
{
|
||||
DPRINT1("Serenum: IRP_MJ_PNP / IRP_MN_QUERY_DEVICE_RELATIONS / Unknown type 0x%lx\n",
|
||||
Stack->Parameters.QueryDeviceRelations.Type);
|
||||
Status = STATUS_NOT_IMPLEMENTED;
|
||||
break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
case IRP_MN_QUERY_CAPABILITIES: /* 0x9 */
|
||||
{
|
||||
PDEVICE_CAPABILITIES DeviceCapabilities;
|
||||
ULONG i;
|
||||
DPRINT("Serenum: IRP_MJ_PNP / IRP_MN_QUERY_CAPABILITIES\n");
|
||||
|
||||
DeviceCapabilities = (PDEVICE_CAPABILITIES)Stack->Parameters.DeviceCapabilities.Capabilities;
|
||||
/* FIXME: capabilities can change with connected device */
|
||||
DeviceCapabilities->LockSupported = FALSE;
|
||||
DeviceCapabilities->EjectSupported = FALSE;
|
||||
DeviceCapabilities->Removable = TRUE;
|
||||
DeviceCapabilities->DockDevice = FALSE;
|
||||
DeviceCapabilities->UniqueID = FALSE;
|
||||
DeviceCapabilities->SilentInstall = FALSE;
|
||||
DeviceCapabilities->RawDeviceOK = TRUE;
|
||||
DeviceCapabilities->SurpriseRemovalOK = TRUE;
|
||||
DeviceCapabilities->HardwareDisabled = FALSE; /* FIXME */
|
||||
//DeviceCapabilities->NoDisplayInUI = FALSE; /* FIXME */
|
||||
DeviceCapabilities->DeviceState[0] = PowerDeviceD0; /* FIXME */
|
||||
for (i = 0; i < PowerSystemMaximum; i++)
|
||||
DeviceCapabilities->DeviceState[i] = PowerDeviceD3; /* FIXME */
|
||||
//DeviceCapabilities->DeviceWake = PowerDeviceUndefined; /* FIXME */
|
||||
DeviceCapabilities->D1Latency = 0; /* FIXME */
|
||||
DeviceCapabilities->D2Latency = 0; /* FIXME */
|
||||
DeviceCapabilities->D3Latency = 0; /* FIXME */
|
||||
Status = STATUS_SUCCESS;
|
||||
break;
|
||||
}
|
||||
case IRP_MN_QUERY_RESOURCES: /* 0xa */
|
||||
{
|
||||
DPRINT("Serenum: IRP_MJ_PNP / IRP_MN_QUERY_RESOURCES\n");
|
||||
/* Serial devices don't need resources, except the ones of
|
||||
* the serial port. This PDO is the serial device PDO, so
|
||||
* report no resource by not changing Information and
|
||||
* Status
|
||||
*/
|
||||
Information = Irp->IoStatus.Information;
|
||||
Status = Irp->IoStatus.Status;
|
||||
break;
|
||||
}
|
||||
case IRP_MN_QUERY_RESOURCE_REQUIREMENTS: /* 0xb */
|
||||
{
|
||||
DPRINT("Serenum: IRP_MJ_PNP / IRP_MN_QUERY_RESOURCE_REQUIREMENTS\n");
|
||||
/* Serial devices don't need resources, except the ones of
|
||||
* the serial port. This PDO is the serial device PDO, so
|
||||
* report no resource by not changing Information and
|
||||
* Status
|
||||
*/
|
||||
Information = Irp->IoStatus.Information;
|
||||
Status = Irp->IoStatus.Status;
|
||||
break;
|
||||
}
|
||||
case IRP_MN_QUERY_DEVICE_TEXT: /* 0xc */
|
||||
{
|
||||
switch (Stack->Parameters.QueryDeviceText.DeviceTextType)
|
||||
{
|
||||
case DeviceTextDescription:
|
||||
{
|
||||
PUNICODE_STRING Source;
|
||||
PWSTR Description;
|
||||
DPRINT("Serenum: IRP_MJ_PNP / IRP_MN_QUERY_DEVICE_TEXT / DeviceTextDescription\n");
|
||||
|
||||
Source = &((PPDO_DEVICE_EXTENSION)DeviceObject->DeviceExtension)->DeviceDescription;
|
||||
Description = ExAllocatePool(PagedPool, Source->Length + sizeof(WCHAR));
|
||||
if (!Description)
|
||||
Status = STATUS_INSUFFICIENT_RESOURCES;
|
||||
else
|
||||
{
|
||||
RtlCopyMemory(Description, Source->Buffer, Source->Length);
|
||||
Description[Source->Length / sizeof(WCHAR)] = L'\0';
|
||||
Information = (ULONG_PTR)Description;
|
||||
Status = STATUS_SUCCESS;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case DeviceTextLocationInformation:
|
||||
{
|
||||
/* We don't have any text location to report,
|
||||
* and this query is optional, so ignore it.
|
||||
*/
|
||||
Information = Irp->IoStatus.Information;
|
||||
Status = Irp->IoStatus.Status;
|
||||
break;
|
||||
}
|
||||
default:
|
||||
{
|
||||
DPRINT1("Serenum: IRP_MJ_PNP / IRP_MN_QUERY_DEVICE_TEXT / unknown type 0x%lx\n",
|
||||
Stack->Parameters.QueryDeviceText.DeviceTextType);
|
||||
Status = STATUS_NOT_SUPPORTED;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
case IRP_MN_FILTER_RESOURCE_REQUIREMENTS: /* 0xd */
|
||||
{
|
||||
return ForwardIrpToAttachedFdoAndForget(DeviceObject, Irp);
|
||||
}
|
||||
case IRP_MN_QUERY_ID: /* 0x13 */
|
||||
{
|
||||
Status = SerenumPdoQueryId(DeviceObject, Irp, &Information);
|
||||
break;
|
||||
}
|
||||
case IRP_MN_QUERY_BUS_INFORMATION: /* 0x15 */
|
||||
{
|
||||
PPNP_BUS_INFORMATION BusInfo;
|
||||
DPRINT("Serenum: IRP_MJ_PNP / IRP_MN_QUERY_BUS_INFORMATION\n");
|
||||
|
||||
BusInfo = (PPNP_BUS_INFORMATION)ExAllocatePool(PagedPool, sizeof(PNP_BUS_INFORMATION));
|
||||
if (!BusInfo)
|
||||
Status = STATUS_INSUFFICIENT_RESOURCES;
|
||||
else
|
||||
{
|
||||
BusInfo->BusTypeGuid = GUID_BUS_TYPE_SERENUM;
|
||||
/* FIXME: real value should be PNPBus, but PNPBus seems to be
|
||||
* the only value in INTERFACE_TYPE enum that doesn't work...
|
||||
*/
|
||||
BusInfo->LegacyBusType = PNPISABus;
|
||||
/* We're the only serial bus enumerator on the computer */
|
||||
BusInfo->BusNumber = 0;
|
||||
Information = (ULONG_PTR)BusInfo;
|
||||
Status = STATUS_SUCCESS;
|
||||
}
|
||||
break;
|
||||
}
|
||||
default:
|
||||
{
|
||||
/* We can't forward request to the lower driver, because
|
||||
* we are a Pdo, so we don't have lower driver... */
|
||||
DPRINT1("Serenum: IRP_MJ_PNP / unknown minor function 0x%lx\n", MinorFunction);
|
||||
Information = Irp->IoStatus.Information;
|
||||
Status = Irp->IoStatus.Status;
|
||||
}
|
||||
}
|
||||
|
||||
Irp->IoStatus.Information = Information;
|
||||
Irp->IoStatus.Status = Status;
|
||||
IoCompleteRequest(Irp, IO_NO_INCREMENT);
|
||||
return Status;
|
||||
}
|
114
reactos/drivers/bus/serenum/serenum.c
Normal file
114
reactos/drivers/bus/serenum/serenum.c
Normal file
|
@ -0,0 +1,114 @@
|
|||
/* $Id:
|
||||
*
|
||||
* COPYRIGHT: See COPYING in the top level directory
|
||||
* PROJECT: ReactOS Serial enumerator driver
|
||||
* FILE: drivers/bus/serenum/serenum.c
|
||||
* PURPOSE: Serial enumeration driver entry point
|
||||
*
|
||||
* PROGRAMMERS: Hervé Poussineau (hpoussin@reactos.com)
|
||||
*/
|
||||
|
||||
//#define NDEBUG
|
||||
#define INITGUID
|
||||
#include "serenum.h"
|
||||
|
||||
NTSTATUS STDCALL
|
||||
SerenumPnp(
|
||||
IN PDEVICE_OBJECT DeviceObject,
|
||||
IN PIRP Irp)
|
||||
{
|
||||
if (((PCOMMON_DEVICE_EXTENSION)DeviceObject->DeviceExtension)->IsFDO)
|
||||
return SerenumFdoPnp(DeviceObject, Irp);
|
||||
else
|
||||
return SerenumPdoPnp(DeviceObject, Irp);
|
||||
}
|
||||
|
||||
VOID STDCALL
|
||||
DriverUnload(IN PDRIVER_OBJECT DriverObject)
|
||||
{
|
||||
// nothing to do here yet
|
||||
}
|
||||
|
||||
NTSTATUS STDCALL
|
||||
IrpStub(
|
||||
IN PDEVICE_OBJECT DeviceObject,
|
||||
IN PIRP Irp)
|
||||
{
|
||||
NTSTATUS Status = STATUS_NOT_SUPPORTED;
|
||||
|
||||
if (((PCOMMON_DEVICE_EXTENSION)DeviceObject->DeviceExtension)->IsFDO)
|
||||
{
|
||||
/* Forward some IRPs to lower device */
|
||||
switch (IoGetCurrentIrpStackLocation(Irp)->MajorFunction)
|
||||
{
|
||||
case IRP_MJ_CREATE:
|
||||
case IRP_MJ_CLOSE:
|
||||
case IRP_MJ_CLEANUP:
|
||||
case IRP_MJ_READ:
|
||||
case IRP_MJ_WRITE:
|
||||
case IRP_MJ_DEVICE_CONTROL:
|
||||
return ForwardIrpToLowerDeviceAndForget(DeviceObject, Irp);
|
||||
default:
|
||||
{
|
||||
DPRINT1("Serenum: FDO stub for major function 0x%lx\n",
|
||||
IoGetCurrentIrpStackLocation(Irp)->MajorFunction);
|
||||
DbgBreakPoint();
|
||||
Status = Irp->IoStatus.Status;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Forward some IRPs to attached FDO */
|
||||
switch (IoGetCurrentIrpStackLocation(Irp)->MajorFunction)
|
||||
{
|
||||
case IRP_MJ_CREATE:
|
||||
case IRP_MJ_CLOSE:
|
||||
case IRP_MJ_CLEANUP:
|
||||
case IRP_MJ_READ:
|
||||
case IRP_MJ_WRITE:
|
||||
case IRP_MJ_DEVICE_CONTROL:
|
||||
return ForwardIrpToAttachedFdoAndForget(DeviceObject, Irp);
|
||||
default:
|
||||
{
|
||||
DPRINT1("Serenum: PDO stub for major function 0x%lx\n",
|
||||
IoGetCurrentIrpStackLocation(Irp)->MajorFunction);
|
||||
DbgBreakPoint();
|
||||
Status = Irp->IoStatus.Status;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Irp->IoStatus.Status = Status;
|
||||
IoCompleteRequest(Irp, IO_NO_INCREMENT);
|
||||
return Status;
|
||||
}
|
||||
|
||||
/*
|
||||
* Standard DriverEntry method.
|
||||
*/
|
||||
NTSTATUS STDCALL
|
||||
DriverEntry(
|
||||
IN PDRIVER_OBJECT DriverObject,
|
||||
IN PUNICODE_STRING RegPath)
|
||||
{
|
||||
ULONG i;
|
||||
|
||||
DriverObject->DriverUnload = DriverUnload;
|
||||
DriverObject->DriverExtension->AddDevice = SerenumAddDevice;
|
||||
|
||||
for (i = 0; i < IRP_MJ_MAXIMUM_FUNCTION; i++)
|
||||
DriverObject->MajorFunction[i] = IrpStub;
|
||||
|
||||
/*DriverObject->MajorFunction[IRP_MJ_CREATE] = SerialCreate;
|
||||
DriverObject->MajorFunction[IRP_MJ_CLOSE] = SerialClose;
|
||||
DriverObject->MajorFunction[IRP_MJ_CLEANUP] = SerialCleanup;
|
||||
DriverObject->MajorFunction[IRP_MJ_READ] = SerialRead;
|
||||
DriverObject->MajorFunction[IRP_MJ_WRITE] = SerialWrite;*/
|
||||
//DriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL] = Serenum;
|
||||
//DriverObject->MajorFunction[IRP_MJ_QUERY_INFORMATION] = SerialQueryInformation;
|
||||
DriverObject->MajorFunction[IRP_MJ_PNP] = SerenumPnp;
|
||||
//DriverObject->MajorFunction[IRP_MJ_POWER] = SerialPower;
|
||||
|
||||
return STATUS_SUCCESS;
|
||||
}
|
152
reactos/drivers/bus/serenum/serenum.h
Normal file
152
reactos/drivers/bus/serenum/serenum.h
Normal file
|
@ -0,0 +1,152 @@
|
|||
#if defined(__GNUC__)
|
||||
#include <ddk/ntddk.h>
|
||||
#include <ddk/ntddser.h>
|
||||
#include <ddk/wdmguid.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#include <debug.h>
|
||||
|
||||
#define SR_MSR_DSR 0x20
|
||||
#define ExFreePoolWithTag(p, tag) ExFreePool(p)
|
||||
|
||||
/* FIXME: these prototypes MUST NOT be here! */
|
||||
NTSTATUS STDCALL
|
||||
IoAttachDeviceToDeviceStackSafe(
|
||||
IN PDEVICE_OBJECT SourceDevice,
|
||||
IN PDEVICE_OBJECT TargetDevice,
|
||||
OUT PDEVICE_OBJECT *AttachedToDeviceObject);
|
||||
|
||||
#elif defined(_MSC_VER)
|
||||
#include <ntddk.h>
|
||||
#include <ntddser.h>
|
||||
#include <c:/progra~1/winddk/inc/ddk/wdm/wxp/wdmguid.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#define STDCALL
|
||||
|
||||
#define DPRINT1 DbgPrint("(%s:%d) ", __FILE__, __LINE__), DbgPrint
|
||||
#define CHECKPOINT1 DbgPrint("(%s:%d)\n")
|
||||
|
||||
#define TAG(A, B, C, D) (ULONG)(((A)<<0) + ((B)<<8) + ((C)<<16) + ((D)<<24))
|
||||
|
||||
NTSTATUS STDCALL
|
||||
IoAttachDeviceToDeviceStackSafe(
|
||||
IN PDEVICE_OBJECT SourceDevice,
|
||||
IN PDEVICE_OBJECT TargetDevice,
|
||||
OUT PDEVICE_OBJECT *AttachedToDeviceObject);
|
||||
|
||||
#define DPRINT DPRINT1
|
||||
#define CHECKPOINT CHECKPOINT1
|
||||
|
||||
#define SR_MSR_DSR 0x20
|
||||
#else
|
||||
#error Unknown compiler!
|
||||
#endif
|
||||
|
||||
typedef enum
|
||||
{
|
||||
dsStopped,
|
||||
dsStarted,
|
||||
dsPaused,
|
||||
dsRemoved,
|
||||
dsSurpriseRemoved
|
||||
} SERENUM_DEVICE_STATE;
|
||||
|
||||
typedef struct _COMMON_DEVICE_EXTENSION
|
||||
{
|
||||
BOOLEAN IsFDO;
|
||||
SERENUM_DEVICE_STATE PnpState;
|
||||
} COMMON_DEVICE_EXTENSION, *PCOMMON_DEVICE_EXTENSION;
|
||||
|
||||
typedef struct _FDO_DEVICE_EXTENSION
|
||||
{
|
||||
COMMON_DEVICE_EXTENSION Common;
|
||||
|
||||
PDEVICE_OBJECT LowerDevice;
|
||||
PDEVICE_OBJECT Pdo;
|
||||
IO_REMOVE_LOCK RemoveLock;
|
||||
|
||||
PDEVICE_OBJECT AttachedPdo;
|
||||
ULONG Flags;
|
||||
} FDO_DEVICE_EXTENSION, *PFDO_DEVICE_EXTENSION;
|
||||
|
||||
typedef struct _PDO_DEVICE_EXTENSION
|
||||
{
|
||||
COMMON_DEVICE_EXTENSION Common;
|
||||
|
||||
PDEVICE_OBJECT AttachedFdo;
|
||||
|
||||
UNICODE_STRING DeviceDescription; // REG_SZ
|
||||
UNICODE_STRING DeviceId; // REG_SZ
|
||||
UNICODE_STRING HardwareIds; // REG_MULTI_SZ
|
||||
UNICODE_STRING CompatibleIds; // REG_MULTI_SZ
|
||||
} PDO_DEVICE_EXTENSION, *PPDO_DEVICE_EXTENSION;
|
||||
|
||||
#define SERENUM_TAG TAG('S', 'e', 'r', 'e')
|
||||
|
||||
/* Flags */
|
||||
#define FLAG_ENUMERATION_DONE 0x01
|
||||
|
||||
/************************************ detect.c */
|
||||
|
||||
NTSTATUS
|
||||
SerenumDetectPnpDevice(
|
||||
IN PDEVICE_OBJECT DeviceObject,
|
||||
IN PDEVICE_OBJECT LowerDevice);
|
||||
|
||||
NTSTATUS
|
||||
SerenumDetectLegacyDevice(
|
||||
IN PDEVICE_OBJECT DeviceObject,
|
||||
IN PDEVICE_OBJECT LowerDevice);
|
||||
|
||||
/************************************ fdo.c */
|
||||
|
||||
NTSTATUS STDCALL
|
||||
SerenumAddDevice(
|
||||
IN PDRIVER_OBJECT DriverObject,
|
||||
IN PDEVICE_OBJECT Pdo);
|
||||
|
||||
NTSTATUS
|
||||
SerenumFdoPnp(
|
||||
IN PDEVICE_OBJECT DeviceObject,
|
||||
IN PIRP Irp);
|
||||
|
||||
/************************************ misc.c */
|
||||
|
||||
NTSTATUS
|
||||
SerenumDuplicateUnicodeString(
|
||||
OUT PUNICODE_STRING Destination,
|
||||
IN PUNICODE_STRING Source,
|
||||
IN POOL_TYPE PoolType);
|
||||
|
||||
NTSTATUS
|
||||
SerenumInitMultiSzString(
|
||||
OUT PUNICODE_STRING Destination,
|
||||
... /* list of ANSI_STRINGs */);
|
||||
|
||||
NTSTATUS
|
||||
ForwardIrpAndWait(
|
||||
IN PDEVICE_OBJECT DeviceObject,
|
||||
IN PIRP Irp);
|
||||
|
||||
NTSTATUS STDCALL
|
||||
ForwardIrpToLowerDeviceAndForget(
|
||||
IN PDEVICE_OBJECT DeviceObject,
|
||||
IN PIRP Irp);
|
||||
|
||||
NTSTATUS STDCALL
|
||||
ForwardIrpToAttachedFdoAndForget(
|
||||
IN PDEVICE_OBJECT DeviceObject,
|
||||
IN PIRP Irp);
|
||||
|
||||
NTSTATUS STDCALL
|
||||
ForwardIrpAndForget(
|
||||
IN PDEVICE_OBJECT DeviceObject,
|
||||
IN PIRP Irp);
|
||||
|
||||
/************************************ pdo.c */
|
||||
|
||||
NTSTATUS
|
||||
SerenumPdoPnp(
|
||||
IN PDEVICE_OBJECT DeviceObject,
|
||||
IN PIRP Irp);
|
7
reactos/drivers/bus/serenum/serenum.rc
Normal file
7
reactos/drivers/bus/serenum/serenum.rc
Normal file
|
@ -0,0 +1,7 @@
|
|||
/* $Id$ */
|
||||
|
||||
#define REACTOS_VERSION_DLL
|
||||
#define REACTOS_STR_FILE_DESCRIPTION "Serial port enumerator\0"
|
||||
#define REACTOS_STR_INTERNAL_NAME "serenum\0"
|
||||
#define REACTOS_STR_ORIGINAL_FILENAME "serenum.sys\0"
|
||||
#include <reactos/version.rc>
|
Loading…
Reference in a new issue