windows-nt/Source/XPSP1/NT/net/irda/irenum/enum.c

1004 lines
21 KiB
C
Raw Normal View History

2020-09-26 03:20:57 -05:00
/*++
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 <af_irda.h>
//#include <irdatdi.h>
//#include <ircommtdi.h>
#define MAX_DEVICES 16
#define STATIC_DEVICE_NAME L"Incoming IRCOMM"
#define STATIC_HARDWARE_ID L"IR_NULL_IN"
int sprintf(char *, ...);
typedef struct _ENUM_OBJECT {
PVOID ThreadObject;
KEVENT WaitEvent;
KTIMER Timer;
PDEVICE_OBJECT Fdo;
ULONG DeviceCount;
IR_DEVICE Devices[MAX_DEVICES];
PASSIVE_LOCK PassiveLock;
} 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
)
{
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->Present=TRUE;
IrDevice->Static=TRUE;
EnumObject->DeviceCount++;
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--;
return Status;
}
NTSTATUS
CreateEnumObject(
PDEVICE_OBJECT Fdo,
ENUM_HANDLE *Object,
BOOLEAN StaticDevice
)
{
NTSTATUS Status;
PENUM_OBJECT EnumObject;
HANDLE ThreadHandle;
*Object=NULL;
EnumObject=ALLOCATE_NONPAGED_POOL(sizeof(*EnumObject));
if (EnumObject==NULL) {
return STATUS_NO_MEMORY;
}
RtlZeroMemory(EnumObject,sizeof(*EnumObject));
EnumObject->Fdo=Fdo;
if (StaticDevice) {
CreateStaticDevice(EnumObject);
}
INIT_PASSIVE_LOCK(&EnumObject->PassiveLock);
KeInitializeEvent(
&EnumObject->WaitEvent,
NotificationEvent,
FALSE
);
KeInitializeTimer(
&EnumObject->Timer
);
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);
} else {
ASSERT(0);
}
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);
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;
}
VOID
WorkerThread(
PVOID Context
)
{
NTSTATUS Status;
PENUM_OBJECT EnumObject=Context;
PVOID ObjectArray[2];
D_PNP(DbgPrint("IRENUM: WorkerThread: started\n");)
ObjectArray[0]=&EnumObject->WaitEvent;
ObjectArray[1]=&EnumObject->Timer;
while (1) {
LARGE_INTEGER DueTime;
DueTime.QuadPart = -10*1000*10000;
KeSetTimer(
&EnumObject->Timer,
DueTime,
NULL
);
Status=KeWaitForMultipleObjects(
2,
&ObjectArray[0],
WaitAny,
Executive,
KernelMode,
FALSE,
NULL,
NULL
);
if (Status == 0) {
//
// the event was signaled, time to exit
//
break;
} else {
if (Status == 1) {
//
// the time expired, check for devices
//
// D_PNP(DbgPrint("IRENUM: WorkerThread: Timer expired\n");)
ACQUIRE_PASSIVE_LOCK(&EnumObject->PassiveLock);
EnumIrda(EnumObject);
RELEASE_PASSIVE_LOCK(&EnumObject->PassiveLock);
} else {
ASSERT(0);
}
}
}
KeCancelTimer(&EnumObject->Timer);
D_PNP(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;
UCHAR DevListBuf[512];
PDEVICELIST pDevList = (PDEVICELIST) DevListBuf;
ULONG DevListLen = sizeof(DevListBuf);
ULONG i;
ULONG j;
BOOLEAN InvalidateDeviceRelations=FALSE;
Status = IrdaDiscoverDevices(pDevList, &DevListLen);
if (!NT_SUCCESS(Status)) {
D_ERROR(DbgPrint("IRENUM: DiscoveryFailed %08lx\n",Status);)
return Status;
}
// D_PNP(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].Present=FALSE;
}
}
for (i=0; i < pDevList->numDevice; i++) {
PIRDA_DEVICE_INFO DeviceInfo=&pDevList->Device[i];
ULONG DeviceId;
RtlCopyMemory(&DeviceId, &DeviceInfo->irdaDeviceID[0],4);
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].Present=TRUE;
if (DeviceId != EnumObject->Devices[j].DeviceId) {
D_ERROR(DbgPrint("IRENUM: Found Dup device %x devices\n",DeviceId);)
RtlCopyMemory(&EnumObject->Devices[j].DeviceId,&DeviceInfo->irdaDeviceID[0],4);
}
break;
}
}
}
if ( j < MAX_DEVICES) {
//
// We found a match, skip this one
//
continue;
}
//
// at this point we have a new device
//
if ((DeviceInfo->irdaDeviceHints2 & 4)) {
//
// it is an ircomm device
//
for (j=0; j< MAX_DEVICES; j++) {
//
// find a slot not in use
//
if (!EnumObject->Devices[j].InUse) {
//
// found a slot for it, zero the info
//
RtlZeroMemory(&EnumObject->Devices[j],sizeof(EnumObject->Devices[j]));
//
// inuse now
//
EnumObject->Devices[j].InUse=TRUE;
EnumObject->Devices[j].Present=TRUE;
RtlCopyMemory(&EnumObject->Devices[j].DeviceId,&DeviceInfo->irdaDeviceID[0],4);
EnumObject->Devices[j].Hint1=DeviceInfo->irdaDeviceHints1;
EnumObject->Devices[j].Hint2=DeviceInfo->irdaDeviceHints2;
DeviceNameFromDeviceInfo(
DeviceInfo,
EnumObject->Devices[j].DeviceName,
sizeof(EnumObject->Devices[j].DeviceName)/sizeof(WCHAR)
);
DoIasQueries(
&EnumObject->Devices[j]
);
if (EnumObject->Devices[j].HardwareId != NULL) {
Status=CreatePdo(
EnumObject->Fdo,
&EnumObject->Devices[j]
);
D_PNP(DbgPrint(
"IRENUM: Name %ws, device id=%08lx, hint1=%x, hint2=%x\n",
EnumObject->Devices[j].DeviceName,
EnumObject->Devices[j].DeviceId,
EnumObject->Devices[j].Hint1,
EnumObject->Devices[j].Hint2
);)
//
// new device
//
InvalidateDeviceRelations=TRUE;
EnumObject->DeviceCount++;
} else {
//
// the device did not report a pnp hardware id
//
RtlZeroMemory(&EnumObject->Devices[j],sizeof(EnumObject->Devices[j]));
}
break;
}
}
}
}
for (j=0; j< MAX_DEVICES; j++) {
//
// lets see if any thing disappeared
//
if (EnumObject->Devices[j].InUse) {
//
// found a slot that is in use
//
if (!EnumObject->Devices[j].Present) {
//
// but it does not have a device present
//
InvalidateDeviceRelations=TRUE;
}
}
}
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->UnEnumerated=FALSE;
PdoExtension->DeviceDescription=IrDevice;
IrDevice->Pdo = NewPdo;
NewPdo->Flags |= DO_POWER_PAGABLE;
NewPdo->Flags &= ~DO_DEVICE_INITIALIZING;
} else {
D_PNP(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)) {
DbgPrint("IRENUM: got pnp manufacturer %ws\n",IrDevice->Manufacturer);
}
Status=IrdaIASStringQuery(
IrDevice->DeviceId,
"PnP",
"Name",
&IrDevice->Name
);
if (NT_SUCCESS(Status)) {
DbgPrint("IRENUM: got pnp name %ws\n",IrDevice->Name);
}
Status=IrdaIASStringQuery(
IrDevice->DeviceId,
"PnP",
"DeviceID",
&IrDevice->HardwareId
);
if (NT_SUCCESS(Status)) {
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)) {
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);)
}
}
}
//
// 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_PNP(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].Present) {
EnumObject->Devices[i].Enumerated=TRUE;
D_PNP(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=IrDevice->Pdo->DeviceExtension;
ULONG i;
for (i=0; i < MAX_DEVICES; i++) {
//
// find this device in the array
//
if (EnumObject->Devices[i].Pdo == IrDevice->Pdo) {
break;
}
}
if (IrDevice->HardwareId != NULL) {
FREE_POOL(IrDevice->HardwareId);
}
if (IrDevice->Name != NULL) {
FREE_POOL(IrDevice->Name);
}
if (IrDevice->Manufacturer != NULL) {
FREE_POOL(IrDevice->Manufacturer);
}
PdoDeviceExtension->DoType=DO_TYPE_DEL_PDO;
IoDeleteDevice(IrDevice->Pdo);
RtlZeroMemory(&EnumObject->Devices[i],sizeof(IR_DEVICE));
EnumObject->DeviceCount--;
}
RELEASE_PASSIVE_LOCK(&EnumObject->PassiveLock);
return;
}