|
|
/*++
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; }
|