windows-nt/Source/XPSP1/NT/net/irda/comm/irenum/enum.c
2020-09-26 16:20:57 +08:00

1294 lines
28 KiB
C

/*++
Copyright (c) 1995 Microsoft Corporation
Module Name:
initunlo.c
Abstract:
This module contains the code that is very specific to initialization
and unload operations in the irenum driver
Author:
Brian Lieuallen, 7-13-2000
Environment:
Kernel mode
Revision History :
--*/
#include "internal.h"
#define UINT ULONG //tmp
#include <irioctl.h>
#include <ircommtdi.h>
#define MAX_DEVICES 16
#define STATIC_DEVICE_NAME L"Incoming IRCOMM"
#define STATIC_HARDWARE_ID L"IR_NULL_IN"
#define GENERIC_MODEM_NAME L"Infrared Modem"
#define GENERIC_HARDWARE_ID L"PNPC103"
#define DEVICE_PRESENT_START_VALUE (1)
int sprintf(char *, ...);
typedef struct _ENUM_OBJECT {
PVOID ThreadObject;
KEVENT WaitEvent;
KTIMER Timer;
PASSIVE_LOCK PassiveLock;
HANDLE IoWaitEventHandle;
PKEVENT IoWaitEventObject;
IO_STATUS_BLOCK IoStatusBlock;
HANDLE ControlChannel;
PDEVICE_OBJECT Fdo;
ULONG DeviceCount;
ULONG EnumeratedDevices;
UCHAR DeviceListBuffer[512];
IR_DEVICE Devices[MAX_DEVICES];
} ENUM_OBJECT, *PENUM_OBJECT;
VOID
WorkerThread(
PVOID Context
);
NTSTATUS
EnumIrda(
PENUM_OBJECT EnumObject
);
NTSTATUS
DoIasQueries(
PIR_DEVICE IrDevice
);
NTSTATUS
CreatePdo(
PDEVICE_OBJECT Fdo,
PIR_DEVICE IrDevice
);
NTSTATUS
CreateStaticDevice(
PENUM_OBJECT EnumObject
);
VOID
CloseEnumObject(
ENUM_HANDLE Handle
);
NTSTATUS
DeviceNameFromDeviceInfo(
PIRDA_DEVICE_INFO DeviceInfo,
PWCHAR DeviceName,
ULONG NameLength
);
VOID
FixupDeviceId(
PWSTR HardwareId
);
#pragma alloc_text(PAGE,WorkerThread)
#pragma alloc_text(PAGE,EnumIrda)
#pragma alloc_text(PAGE,DoIasQueries)
#pragma alloc_text(PAGE,CreatePdo)
#pragma alloc_text(PAGE,CreateStaticDevice)
#pragma alloc_text(PAGE,CloseEnumObject)
#pragma alloc_text(PAGE,DeviceNameFromDeviceInfo)
#pragma alloc_text(PAGE,FixupDeviceId)
#pragma alloc_text(PAGE,GetDeviceList)
#pragma alloc_text(PAGE,RemoveDevice)
NTSTATUS
CreateStaticDevice(
PENUM_OBJECT EnumObject
)
{
NTSTATUS Status;
ULONG DeviceId=0;
PIR_DEVICE IrDevice=&EnumObject->Devices[0];
//
// zero the whole thing
//
RtlZeroMemory(IrDevice,sizeof(*IrDevice));
//
// inuse now
//
IrDevice->InUse=TRUE;
IrDevice->PresentCount=DEVICE_PRESENT_START_VALUE;
IrDevice->Static=TRUE;
EnumObject->DeviceCount++;
EnumObject->EnumeratedDevices++;
RtlCopyMemory(&IrDevice->DeviceId,&DeviceId,4);
RtlCopyMemory(
IrDevice->DeviceName,
STATIC_DEVICE_NAME,
sizeof(STATIC_DEVICE_NAME)
);
IrDevice->Name=ALLOCATE_PAGED_POOL(sizeof(STATIC_DEVICE_NAME));
if (IrDevice->Name == NULL) {
Status=STATUS_NO_MEMORY;
goto CleanUp;
}
RtlCopyMemory(
IrDevice->Name,
STATIC_DEVICE_NAME,
sizeof(STATIC_DEVICE_NAME)
);
IrDevice->HardwareId=ALLOCATE_PAGED_POOL(sizeof(STATIC_HARDWARE_ID));
if (IrDevice->HardwareId == NULL) {
Status=STATUS_NO_MEMORY;
goto CleanUp;
}
RtlCopyMemory(
IrDevice->HardwareId,
STATIC_HARDWARE_ID,
sizeof(STATIC_HARDWARE_ID)
);
Status=CreatePdo(
EnumObject->Fdo,
IrDevice
);
if (NT_SUCCESS(Status)) {
return Status;
}
CleanUp:
if (IrDevice->Name != NULL) {
FREE_POOL(IrDevice->Name);
}
if (IrDevice->HardwareId != NULL) {
FREE_POOL(IrDevice->HardwareId);
}
RtlZeroMemory(IrDevice,sizeof(&IrDevice));
EnumObject->DeviceCount--;
EnumObject->EnumeratedDevices--;
return Status;
}
NTSTATUS
CreateEnumObject(
PDEVICE_OBJECT Fdo,
ENUM_HANDLE *Object,
BOOLEAN StaticDevice
)
{
NTSTATUS Status;
PENUM_OBJECT EnumObject;
HANDLE ThreadHandle;
UNICODE_STRING EventName;
*Object=NULL;
EnumObject=ALLOCATE_NONPAGED_POOL(sizeof(*EnumObject));
if (EnumObject==NULL) {
return STATUS_NO_MEMORY;
}
RtlZeroMemory(EnumObject,sizeof(*EnumObject));
KeInitializeEvent(
&EnumObject->WaitEvent,
NotificationEvent,
FALSE
);
KeInitializeTimerEx(
&EnumObject->Timer,
SynchronizationTimer
);
INIT_PASSIVE_LOCK(&EnumObject->PassiveLock);
EnumObject->Fdo=Fdo;
if (StaticDevice) {
CreateStaticDevice(EnumObject);
}
RtlInitUnicodeString(
&EventName,
L"\\Device\\IrEnumIoEvent"
);
EnumObject->IoWaitEventObject=IoCreateNotificationEvent(
&EventName,
&EnumObject->IoWaitEventHandle
);
if (EnumObject->IoWaitEventObject == NULL) {
D_ERROR(DbgPrint("IRENUM: could not create event\n");)
goto CleanUp;
}
Status=PsCreateSystemThread(
&ThreadHandle,
THREAD_ALL_ACCESS,
NULL,
NULL,
NULL,
WorkerThread,
EnumObject
);
if (!NT_SUCCESS(Status)) {
goto CleanUp;
}
Status=ObReferenceObjectByHandle(
ThreadHandle,
0,
NULL,
KernelMode,
&EnumObject->ThreadObject,
NULL
);
ZwClose(ThreadHandle);
ThreadHandle=NULL;
if (!NT_SUCCESS(Status)) {
goto CleanUp;
}
*Object=EnumObject;
return Status;
CleanUp:
KeSetEvent(
&EnumObject->WaitEvent,
IO_NO_INCREMENT,
FALSE
);
//
// make sure we really got the object
//
if (EnumObject->ThreadObject != NULL) {
KeWaitForSingleObject(
EnumObject->ThreadObject,
Executive,
KernelMode,
FALSE,
NULL
);
ObDereferenceObject(EnumObject->ThreadObject);
}
if (EnumObject->IoWaitEventHandle != NULL) {
ZwClose(EnumObject->IoWaitEventHandle);
}
FREE_POOL(EnumObject);
return Status;
}
VOID
CloseEnumObject(
ENUM_HANDLE Handle
)
{
PENUM_OBJECT EnumObject=Handle;
ULONG j;
KeSetEvent(
&EnumObject->WaitEvent,
IO_NO_INCREMENT,
FALSE
);
KeWaitForSingleObject(
EnumObject->ThreadObject,
Executive,
KernelMode,
FALSE,
NULL
);
ObDereferenceObject(EnumObject->ThreadObject);
if (EnumObject->IoWaitEventHandle != NULL) {
ZwClose(EnumObject->IoWaitEventHandle);
}
for (j=0; j< MAX_DEVICES; j++) {
//
// if remove it
//
if (EnumObject->Devices[j].InUse) {
//
// not enumerated any more since tha parent is going away
//
EnumObject->Devices[j].Enumerated=FALSE;
RemoveDevice(EnumObject,&EnumObject->Devices[j]);
}
}
FREE_POOL(EnumObject);
return;
}
#define OBJECT_ARRAY_SIZE (3)
VOID
WorkerThread(
PVOID Context
)
{
NTSTATUS Status;
PENUM_OBJECT EnumObject=Context;
BOOLEAN ExitLoop=FALSE;
PKEVENT ObjectArray[OBJECT_ARRAY_SIZE];
LARGE_INTEGER DueTime;
DueTime.QuadPart = -10*1000*10000;
D_ENUM(DbgPrint("IRENUM: WorkerThread: started\n");)
KeClearEvent(EnumObject->IoWaitEventObject);
ObjectArray[0]=&EnumObject->WaitEvent;
ObjectArray[1]=(PKEVENT)&EnumObject->Timer;
ObjectArray[2]=EnumObject->IoWaitEventObject;
KeSetTimer(
&EnumObject->Timer,
DueTime,
NULL
);
while (!ExitLoop) {
Status=KeWaitForMultipleObjects(
OBJECT_ARRAY_SIZE,
&ObjectArray[0],
WaitAny,
Executive,
KernelMode,
FALSE,
NULL,
NULL
);
switch (Status) {
case 0:
//
// the event was signaled, time to exit
//
ExitLoop=TRUE;
break;
case 1:
//
// the timer expired, check for devices
//
if (EnumObject->ControlChannel == NULL) {
//
// we have not been able to open the control channel yet
//
Status=IrdaOpenControlChannel(&EnumObject->ControlChannel);
if (!NT_SUCCESS(Status)) {
EnumObject->ControlChannel=NULL;
}
}
if (EnumObject->ControlChannel != NULL) {
//
// we have the control handle, start the discover request
//
IrdaLazyDiscoverDevices(
EnumObject->ControlChannel,
EnumObject->IoWaitEventHandle,
&EnumObject->IoStatusBlock,
(PDEVICELIST)&EnumObject->DeviceListBuffer[0],
sizeof(EnumObject->DeviceListBuffer)
);
} else {
KeSetTimer(
&EnumObject->Timer,
DueTime,
NULL
);
}
break;
case 2:
//
// the discovery completed
//
KeResetEvent(EnumObject->IoWaitEventObject);
if (EnumObject->IoStatusBlock.Status == STATUS_SUCCESS) {
ACQUIRE_PASSIVE_LOCK(&EnumObject->PassiveLock);
EnumIrda(EnumObject);
RELEASE_PASSIVE_LOCK(&EnumObject->PassiveLock);
//
// start another io
//
IrdaLazyDiscoverDevices(
EnumObject->ControlChannel,
EnumObject->IoWaitEventHandle,
&EnumObject->IoStatusBlock,
(PDEVICELIST)&EnumObject->DeviceListBuffer[0],
sizeof(EnumObject->DeviceListBuffer)
);
} else {
//
// the discovery failed, just start the timer
//
KeSetTimer(
&EnumObject->Timer,
DueTime,
NULL
);
}
break;
default:
ASSERT(0);
break;
}
}
KeCancelTimer(&EnumObject->Timer);
D_ENUM(DbgPrint("IRENUM: WorkerThread: stopping\n");)
PsTerminateSystemThread(STATUS_SUCCESS);
return;
}
NTSTATUS
DeviceNameFromDeviceInfo(
PIRDA_DEVICE_INFO DeviceInfo,
PWCHAR DeviceName,
ULONG NameLength
)
{
NTSTATUS Status=STATUS_SUCCESS;
WCHAR TempBuffer[23];
UNICODE_STRING UnicodeString;
//
// zero out the temp buffer, so we can copy the remote device name,
// so we can be sure it is null terminated
//
RtlZeroMemory(TempBuffer,sizeof(TempBuffer));
RtlCopyMemory(TempBuffer,DeviceInfo->irdaDeviceName,sizeof(DeviceInfo->irdaDeviceName));
UnicodeString.Length=0;
UnicodeString.MaximumLength=(USHORT)(NameLength-1)*sizeof(WCHAR);
UnicodeString.Buffer=DeviceName;
RtlZeroMemory(UnicodeString.Buffer,UnicodeString.MaximumLength);
if (DeviceInfo->irdaCharSet == LmCharSetUNICODE) {
//
// the name is unicode
//
Status=RtlAppendUnicodeToString(&UnicodeString,TempBuffer);
} else {
//
// the name is ansi, need to convert unicode
//
ANSI_STRING AnsiString;
RtlInitAnsiString(
&AnsiString,
(PCSZ)TempBuffer
);
Status=RtlAnsiStringToUnicodeString(
&UnicodeString,
&AnsiString,
FALSE
);
}
return Status;
}
NTSTATUS
EnumIrda(
PENUM_OBJECT EnumObject
)
{
NTSTATUS Status;
PDEVICELIST pDevList = (PDEVICELIST)&EnumObject->DeviceListBuffer[0] ;
ULONG i;
ULONG j;
BOOLEAN InvalidateDeviceRelations=FALSE;
PIR_DEVICE IrDevice;
D_ENUM(DbgPrint("IRENUM: Found %d devices\n",pDevList->numDevice);)
for (j=0; j< MAX_DEVICES; j++) {
//
// first mark all the device not present
//
if (!EnumObject->Devices[j].Static) {
//
// only non-static device go away
//
EnumObject->Devices[j].PresentCount--;
}
}
for (i=0; i < pDevList->numDevice; i++) {
PIRDA_DEVICE_INFO DeviceInfo=&pDevList->Device[i];
ULONG DeviceId;
LONG EmptySlot=-1;
RtlCopyMemory(&DeviceId, &DeviceInfo->irdaDeviceID[0],4);
//
// now go through all of our slots to see if we have seen this device before
// based on the name it reports
//
for (j=0; j< MAX_DEVICES; j++) {
WCHAR TempBuffer[24];
if (EnumObject->Devices[j].InUse) {
DeviceNameFromDeviceInfo(
DeviceInfo,
TempBuffer,
sizeof(TempBuffer)/sizeof(WCHAR)
);
if (0 == wcscmp(TempBuffer, EnumObject->Devices[j].DeviceName)) {
//
// Already present
//
EnumObject->Devices[j].PresentCount=DEVICE_PRESENT_START_VALUE;
if (DeviceId != EnumObject->Devices[j].DeviceId) {
//
// the device id seems to have changed since we saw it last, just update it
//
D_ERROR(DbgPrint("IRENUM: Found Dup device %x devices\n",DeviceId);)
RtlCopyMemory(&EnumObject->Devices[j].DeviceId,&DeviceInfo->irdaDeviceID[0],4);
}
break;
}
} else {
//
// this slot is empty, remember this for later
//
if (EmptySlot == -1) {
//
// only set it for this first one
//
EmptySlot=j;
}
}
}
if ( j < MAX_DEVICES) {
//
// We found a match, skip this one
//
continue;
}
if (EmptySlot == -1) {
//
// All of the slots are used up
//
continue;
}
//
// at this point we have a new device
//
IrDevice=&EnumObject->Devices[EmptySlot];
//
// found a slot for it, zero the info
//
RtlZeroMemory(IrDevice,sizeof(*IrDevice));
EnumObject->DeviceCount++;
//
// inuse now
//
IrDevice->InUse=TRUE;
IrDevice->PresentCount=DEVICE_PRESENT_START_VALUE;
IrDevice->DeviceId=DeviceId;
IrDevice->Hint1=DeviceInfo->irdaDeviceHints1;
IrDevice->Hint2=DeviceInfo->irdaDeviceHints2;
DeviceNameFromDeviceInfo(
DeviceInfo,
IrDevice->DeviceName,
sizeof(IrDevice->DeviceName)/sizeof(WCHAR)
);
D_ENUM(DbgPrint(
"IRENUM: Name %ws, device id=%08lx, hint1=%x, hint2=%x\n",
IrDevice->DeviceName,
IrDevice->DeviceId,
IrDevice->Hint1,
IrDevice->Hint2
);)
if (DeviceInfo->irdaDeviceHints1 & LM_HB1_Printer) {
//
// the device says it is a printer
//
IrDevice->Printer=TRUE;
}
if ((DeviceInfo->irdaDeviceHints1 & LM_HB1_Modem) && (DeviceInfo->irdaDeviceHints2 & 4)) {
//
// Device reports that it is a modem that supports ircomm
//
IrDevice->Modem=TRUE;
}
if (DeviceInfo->irdaDeviceHints1 & LM_HB1_PnP) {
//
// the device says it is pnp aware
//
DoIasQueries(
IrDevice
);
if (IrDevice->HardwareId != NULL) {
//
// we were able to query it for a hardware id
//
Status=CreatePdo(
EnumObject->Fdo,
IrDevice
);
if (!NT_SUCCESS(Status)) {
//
// We could not create a PDO for the new device
//
if (IrDevice->Name != NULL) {
FREE_POOL(IrDevice->Name);
}
if (IrDevice->HardwareId != NULL) {
FREE_POOL(IrDevice->HardwareId);
}
} else {
//
// we created a PDO for a new child device
//
EnumObject->EnumeratedDevices++;
//
// new device
//
InvalidateDeviceRelations=TRUE;
}
} else {
//
// the device did not report a pnp hardware id
//
EnumObject->Devices[EmptySlot].Pdo=NULL;
}
} else {
//
// the device is not pnp aware, make something up
//
if ((DeviceInfo->irdaDeviceHints1 & LM_HB1_Modem) && (DeviceInfo->irdaDeviceHints2 & 4)) {
//
// the hint bits report the device as modem that supports ircomm
//
IrDevice->HardwareId=ALLOCATE_PAGED_POOL(sizeof(GENERIC_HARDWARE_ID));
if (IrDevice->HardwareId != NULL) {
wcscpy(IrDevice->HardwareId,GENERIC_HARDWARE_ID);
}
IrDevice->Name=ALLOCATE_NONPAGED_POOL((wcslen(IrDevice->DeviceName)+1)*sizeof(WCHAR));
if (IrDevice->Name != NULL) {
wcscpy(IrDevice->Name,IrDevice->DeviceName);
}
if (IrDevice->HardwareId != NULL) {
//
// we were able to query it for a hardware id
//
Status=CreatePdo(
EnumObject->Fdo,
IrDevice
);
if (!NT_SUCCESS(Status)) {
//
// We could not create a PDO for the new device
//
if (IrDevice->Name != NULL) {
FREE_POOL(IrDevice->Name);
}
if (IrDevice->HardwareId != NULL) {
FREE_POOL(IrDevice->HardwareId);
}
} else {
//
// we created a PDO for a new child device
//
EnumObject->EnumeratedDevices++;
//
// new device
//
InvalidateDeviceRelations=TRUE;
}
}
} else {
//
// the device does not support pnp and it is not an ircomm device
//
}
}
}
for (j=0; j< MAX_DEVICES; j++) {
//
// lets see if anything disappeared
//
if (EnumObject->Devices[j].InUse) {
//
// found a slot that is in use
//
if (EnumObject->Devices[j].PresentCount == 0) {
//
// but it does not have a device present
//
D_ENUM(DbgPrint("IRENUM: Name %ws, no longer present\n",EnumObject->Devices[j].Name);)
if (EnumObject->Devices[j].Pdo != NULL) {
//
// we have enumerated a child for this device
//
InvalidateDeviceRelations=TRUE;
} else {
//
// This one does not have a child, just zero it out
//
RtlZeroMemory(&EnumObject->Devices[j],sizeof(EnumObject->Devices[j]));
EnumObject->DeviceCount--;
}
}
}
}
if (InvalidateDeviceRelations) {
//
// tell the system to check the device relations because a device has appeared or
// disappeared
//
PFDO_DEVICE_EXTENSION FdoExtension=EnumObject->Fdo->DeviceExtension;
IoInvalidateDeviceRelations(FdoExtension->Pdo,BusRelations);
}
return Status;
}
NTSTATUS
CreatePdo(
PDEVICE_OBJECT Fdo,
PIR_DEVICE IrDevice
)
{
NTSTATUS Status;
PDEVICE_OBJECT NewPdo;
Status = IoCreateDevice(
Fdo->DriverObject,
sizeof(PDO_DEVICE_EXTENSION),
NULL,
FILE_DEVICE_BUS_EXTENDER,
FILE_AUTOGENERATED_DEVICE_NAME,
FALSE,
&NewPdo
);
if (NT_SUCCESS(Status)) {
//
// got the device
//
PPDO_DEVICE_EXTENSION PdoExtension=NewPdo->DeviceExtension;
PdoExtension->DoType=DO_TYPE_PDO;
PdoExtension->ParentFdo=Fdo;
PdoExtension->DeviceDescription=IrDevice;
IrDevice->Pdo = NewPdo;
NewPdo->Flags |= DO_POWER_PAGABLE;
NewPdo->Flags &= ~DO_DEVICE_INITIALIZING;
} else {
D_ENUM(DbgPrint("MODEM: CreateChildPdo: IoCreateDevice() failed %08lx\n",Status);)
}
return Status;
}
VOID
FixupDeviceId(
PWSTR HardwareId
)
{
//
// munge the hardware id to make sure it is compatable with the os requirements
//
while (*HardwareId != L'\0') {
if ((*HardwareId < L' ') || (*HardwareId > 127) || (*HardwareId == L',')) {
*HardwareId = L'?';
}
HardwareId++;
}
return;
}
NTSTATUS
DoIasQueries(
PIR_DEVICE IrDevice
)
{
NTSTATUS Status;
LONG CompatCount;
Status=IrdaIASStringQuery(
IrDevice->DeviceId,
"PnP",
"Manufacturer",
&IrDevice->Manufacturer
);
if (NT_SUCCESS(Status)) {
D_ENUM(DbgPrint("IRENUM: got pnp manufacturer %ws\n",IrDevice->Manufacturer);)
}
Status=IrdaIASStringQuery(
IrDevice->DeviceId,
"PnP",
"Name",
&IrDevice->Name
);
if (NT_SUCCESS(Status)) {
D_ENUM(DbgPrint("IRENUM: got pnp name %ws\n",IrDevice->Name);)
}
Status=IrdaIASStringQuery(
IrDevice->DeviceId,
"PnP",
"DeviceID",
&IrDevice->HardwareId
);
if (NT_SUCCESS(Status)) {
D_ENUM(DbgPrint("IRENUM: got pnp id %ws\n",IrDevice->HardwareId);)
FixupDeviceId(IrDevice->HardwareId);
}
//
// check for compat id's
//
IrDevice->CompatIdCount=0;
Status=IrdaIASIntegerQuery(
IrDevice->DeviceId,
"PnP",
"CompCnt",
&CompatCount
);
if (NT_SUCCESS(Status)) {
LONG i;
if ( CompatCount > 16) {
CompatCount=16;
} else {
if ( CompatCount < 0) {
CompatCount = 0;
}
}
for (i=0; i< CompatCount; i++) {
CHAR Attribute[20];
sprintf(Attribute,"Comp#%02d",i+1);
Status=IrdaIASStringQuery(
IrDevice->DeviceId,
"PnP",
Attribute,
&IrDevice->CompatId[IrDevice->CompatIdCount]
);
if (NT_SUCCESS(Status)) {
D_ENUM(DbgPrint("IRENUM: got compat pnp id %ws\n",IrDevice->CompatId[IrDevice->CompatIdCount]);)
FixupDeviceId(IrDevice->CompatId[IrDevice->CompatIdCount]);
IrDevice->CompatIdCount++;
} else {
D_ERROR(DbgPrint("IRENUM: could not get id for %s\n",Attribute);)
}
}
}
if (IrDevice->Modem && !IrDevice->Printer) {
//
// It the hint bits say this is a modem and it is not a printer then
//
// Create a standard compat ID for all devices, so we can load a standard driver
//
IrDevice->CompatId[IrDevice->CompatIdCount]=ALLOCATE_PAGED_POOL(sizeof(IRENUM_COMPAT_ID));
if (IrDevice->CompatId[IrDevice->CompatIdCount] != NULL) {
RtlCopyMemory(IrDevice->CompatId[IrDevice->CompatIdCount],IRENUM_COMPAT_ID,sizeof(IRENUM_COMPAT_ID));
IrDevice->CompatIdCount++;
}
}
return STATUS_SUCCESS;
}
NTSTATUS
GetDeviceList(
ENUM_HANDLE Handle,
PIRP Irp
)
{
PENUM_OBJECT EnumObject=Handle;
NTSTATUS Status=STATUS_SUCCESS;
PDEVICE_RELATIONS CurrentRelations=(PDEVICE_RELATIONS)Irp->IoStatus.Information;
PDEVICE_RELATIONS NewRelations=NULL;
ULONG DeviceCount=EnumObject->DeviceCount;
ULONG i;
ACQUIRE_PASSIVE_LOCK(&EnumObject->PassiveLock);
if (CurrentRelations != NULL) {
//
// we need to allocate a new relations structure and copy the old one to the new one
//
DeviceCount+=CurrentRelations->Count;
}
NewRelations=ALLOCATE_PAGED_POOL(sizeof(DEVICE_RELATIONS)+sizeof(PDEVICE_OBJECT)*DeviceCount);
if (NewRelations == NULL) {
Status= STATUS_INSUFFICIENT_RESOURCES;
} else {
NewRelations->Count=0;
if (CurrentRelations != NULL) {
D_ENUM(DbgPrint("IRENUM: GetDeviceList: %d existing devices\n",CurrentRelations->Count);)
for (i=0; i < CurrentRelations->Count; i++) {
NewRelations->Objects[i]=CurrentRelations->Objects[i];
NewRelations->Count++;
}
FREE_POOL(CurrentRelations);
}
for (i=0; i < MAX_DEVICES; i++) {
if ((EnumObject->Devices[i].Pdo != NULL) && (EnumObject->Devices[i].PresentCount > 0)) {
EnumObject->Devices[i].Enumerated=TRUE;
D_ENUM(DbgPrint("IRENUM: GetDeviceList: reporting DO %p\n",EnumObject->Devices[i].Pdo);)
NewRelations->Objects[NewRelations->Count]=EnumObject->Devices[i].Pdo;
ObReferenceObject(NewRelations->Objects[NewRelations->Count]);
NewRelations->Count++;
} else {
//
// the device is no longer present
//
EnumObject->Devices[i].Enumerated=FALSE;
}
}
Irp->IoStatus.Information=(ULONG_PTR)NewRelations;
}
RELEASE_PASSIVE_LOCK(&EnumObject->PassiveLock);
return Status;
}
VOID
RemoveDevice(
ENUM_HANDLE Handle,
PIR_DEVICE IrDevice
)
{
PENUM_OBJECT EnumObject=Handle;
ACQUIRE_PASSIVE_LOCK(&EnumObject->PassiveLock);
if (IrDevice->Enumerated) {
//
// the device is still present
//
// Just leave it alone
//
} else {
//
// the parent is not enumerating the device anymore
//
PPDO_DEVICE_EXTENSION PdoDeviceExtension;
LONG i;
//
// clean things up
//
if (IrDevice->HardwareId != NULL) {
FREE_POOL(IrDevice->HardwareId);
}
if (IrDevice->Name != NULL) {
FREE_POOL(IrDevice->Name);
}
if (IrDevice->Manufacturer != NULL) {
FREE_POOL(IrDevice->Manufacturer);
}
for (i=0; i< IrDevice->CompatIdCount; i++) {
if (IrDevice->CompatId[i] != NULL) {
FREE_POOL(IrDevice->CompatId[i]);
}
}
if (IrDevice->Pdo != NULL) {
PdoDeviceExtension=IrDevice->Pdo->DeviceExtension;
PdoDeviceExtension->DoType=DO_TYPE_DEL_PDO;
IoDeleteDevice(IrDevice->Pdo);
EnumObject->EnumeratedDevices--;
}
RtlZeroMemory(IrDevice,sizeof(*IrDevice));
EnumObject->DeviceCount--;
}
RELEASE_PASSIVE_LOCK(&EnumObject->PassiveLock);
return;
}