1294 lines
28 KiB
C
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;
|
|
}
|