mirror of https://github.com/tongzx/nt5src
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
1368 lines
49 KiB
1368 lines
49 KiB
//+-------------------------------------------------------------------------
|
|
//
|
|
// Microsoft Windows
|
|
//
|
|
// Copyright (C) Microsoft Corporation, 1998 - 1999
|
|
//
|
|
// File: rescan.c
|
|
//
|
|
//--------------------------------------------------------------------------
|
|
|
|
// rescan a parallel port for changes in the connected devices
|
|
|
|
#include "pch.h"
|
|
|
|
// typedef struct _PAR_DEVOBJ_STRUCT {
|
|
// PUCHAR Controller; // host controller address for devices in this structure
|
|
// PDEVICE_OBJECT LegacyPodo; // legacy or "raw" port device
|
|
// PDEVICE_OBJECT EndOfChainPdo; // End-Of-Chain PnP device
|
|
// PDEVICE_OBJECT Dot3Id0Pdo; // 1284.3 daisy chain device, 1284.3 deviceID == 0
|
|
// PDEVICE_OBJECT Dot3Id1Pdo;
|
|
// PDEVICE_OBJECT Dot3Id2Pdo;
|
|
// PDEVICE_OBJECT Dot3Id3Pdo; // 1284.3 daisy chain device, 1284.3 deviceID == 3
|
|
// PDEVICE_OBJECT LegacyZipPdo; // Legacy Zip Drive
|
|
// PFILE_OBJECT pFileObject; // Need an open handle to ParPort device to prevent it
|
|
// // from being removed out from under us
|
|
// struct _PAR_DEVOBJ_STRUCT *Next;
|
|
// } PAR_DEVOBJ_STRUCT, *PPAR_DEVOBJ_STRUCT;
|
|
|
|
typedef struct _DEVOBJ_ID_PAIR {
|
|
PDEVICE_OBJECT DevObj;
|
|
PCHAR Id;
|
|
} DEVOBJ_ID_PAIR, *PDEVOBJ_ID_PAIR;
|
|
|
|
|
|
ULONG gsuc = 1;
|
|
|
|
ULONG
|
|
ParTst() {
|
|
return gsuc;
|
|
}
|
|
|
|
PPAR_DEVOBJ_STRUCT
|
|
ParLockPortDeviceObjects(
|
|
IN PPAR_DEVOBJ_STRUCT DevObjStructHead
|
|
)
|
|
{
|
|
NTSTATUS status;
|
|
PPAR_DEVOBJ_STRUCT head = DevObjStructHead;
|
|
PPAR_DEVOBJ_STRUCT currentNode = head;
|
|
PPAR_DEVOBJ_STRUCT prevNode = NULL;
|
|
PPAR_DEVOBJ_STRUCT delNode;
|
|
|
|
DDPnP1(("## ParLockPortDeviceObjects - enter\n"));
|
|
|
|
while( currentNode ) {
|
|
|
|
PDEVICE_OBJECT currentDevObj;
|
|
PDEVICE_EXTENSION currentDevExt;
|
|
PUNICODE_STRING portDevName;
|
|
PFILE_OBJECT portFileObj;
|
|
PDEVICE_OBJECT portDevObj;
|
|
|
|
currentDevObj = currentNode->LegacyPodo;
|
|
currentDevExt = currentDevObj->DeviceExtension;
|
|
portDevName = ¤tDevExt->PortSymbolicLinkName;
|
|
|
|
status = IoGetDeviceObjectPointer(portDevName,
|
|
STANDARD_RIGHTS_ALL,
|
|
&portFileObj,
|
|
&portDevObj);
|
|
|
|
|
|
if( NT_SUCCESS(status) && portFileObj && portDevObj ) {
|
|
//
|
|
// We have a FILE open against the ParPort Device to
|
|
// lock the device into memory until we're done with the rescan.
|
|
//
|
|
// Save the pointer to the file object so we can unlock when we're done.
|
|
//
|
|
currentNode->pFileObject = portFileObj;
|
|
DDPnP1(("## ParLockPortDeviceObjects - opened FILE - PFILE= %x , %x\n",portFileObj,currentNode->Controller));
|
|
|
|
// advance pointers
|
|
prevNode = currentNode;
|
|
currentNode = currentNode->Next;
|
|
|
|
} else {
|
|
//
|
|
// we couldn't open a FILE open against the ParPort Device so the
|
|
// port must be gone. Remove this port from the list of ports to rescan.
|
|
//
|
|
DDPnP1(("## ParLockPortDeviceObjects - open FILE FAILED - %x\n",currentNode->Controller));
|
|
delNode = currentNode; // this is the node to delete
|
|
currentNode = currentNode->Next;
|
|
if( head == delNode ) {
|
|
// deleted node was list head - save updated current node as new list head
|
|
head = currentNode;
|
|
} else {
|
|
// link around node to be deleted
|
|
prevNode->Next = currentNode;
|
|
}
|
|
ExFreePool( delNode );
|
|
}
|
|
}
|
|
|
|
DDPnP1(("## ParLockPortDeviceObjects - exit\n"));
|
|
|
|
return head;
|
|
}
|
|
|
|
VOID
|
|
ParUnlockPortDeviceObjects(
|
|
IN PPAR_DEVOBJ_STRUCT DevObjStructHead
|
|
)
|
|
{
|
|
PPAR_DEVOBJ_STRUCT currentNode = DevObjStructHead;
|
|
|
|
DDPnP1(("## ParUnlockPortDeviceObjects - enter\n"));
|
|
while( currentNode ) {
|
|
if( currentNode->pFileObject ) {
|
|
ObDereferenceObject( currentNode->pFileObject );
|
|
DDPnP1(("## ParUnlockPortDeviceObjects - closed FILE - PFILE= %x , %x\n",currentNode->pFileObject,currentNode->Controller));
|
|
currentNode->pFileObject = NULL;
|
|
}
|
|
currentNode = currentNode->Next;
|
|
}
|
|
DDPnP1(("## ParUnlockPortDeviceObjects - exit\n"));
|
|
}
|
|
|
|
PCHAR
|
|
Par3Get1284InfString(PDEVICE_EXTENSION LegacyExt, UCHAR Dot3DeviceId)
|
|
{
|
|
NTSTATUS status;
|
|
PCHAR devId = NULL;
|
|
PCHAR infString = NULL;
|
|
ULONG devIdSize;
|
|
PDEVICE_OBJECT portDeviceObject = LegacyExt->PortDeviceObject;
|
|
ULONG maxIdTries = 3;
|
|
ULONG idTry = 1;
|
|
BOOLEAN bBuildStlDeviceId = FALSE ;
|
|
|
|
bBuildStlDeviceId = ParStlCheckIfStl (LegacyExt, Dot3DeviceId) ;
|
|
|
|
//
|
|
// Select the .3 daisy chain device, query for 1284 ID, and deselect device.
|
|
//
|
|
|
|
status = ParSelect1284_3Device(portDeviceObject, Dot3DeviceId);
|
|
if( !NT_SUCCESS( status ) ) {
|
|
// unable to select device, bail out
|
|
ParDump2(PARPNP1, ("rescan::Par3Get1284InfString - SELECT FAILED\n") );
|
|
goto targetExit;
|
|
}
|
|
|
|
while( (NULL==devId) && (idTry <= maxIdTries) ) {
|
|
devId = Par3QueryDeviceId(LegacyExt, NULL, 0, &devIdSize, FALSE, bBuildStlDeviceId);
|
|
if( NULL == devId ) {
|
|
ParDump2(PARPNP1, ("rescan::Par3Get1284InfString - no 1284 ID on try %d\n", idTry) );
|
|
KeStallExecutionProcessor(1);
|
|
++idTry;
|
|
} else {
|
|
ParDump2(PARPNP1, ("rescan::Par3Get1284InfString - <%s> on try %d\n", devId, idTry) );
|
|
}
|
|
}
|
|
|
|
status = ParDeselect1284_3Device(portDeviceObject, Dot3DeviceId);
|
|
if( !NT_SUCCESS( status ) ) {
|
|
ASSERTMSG("Unable to Deselect? - ParPort probably blocked now - this should never happen \n", FALSE);
|
|
goto targetExit;
|
|
}
|
|
|
|
if( NULL == devId ) {
|
|
// we didn't get a 1284 ID, bail out
|
|
ParDump2(PARPNP1, ("rescan::Par3Get1284InfString - didn't get a 1284 ID, bail out\n") );
|
|
goto targetExit;
|
|
}
|
|
|
|
|
|
//
|
|
// Massage the 1284 ID into the format used in the INF.
|
|
//
|
|
|
|
infString = ExAllocatePool( PagedPool, MAX_ID_SIZE + 1 );
|
|
if( NULL == infString ) {
|
|
ParDump2(PARPNP1, ("rescan::Par3Get1284InfString - no pool avail, bail out\n") );
|
|
// no pool available, bail out
|
|
goto targetExit;
|
|
}
|
|
|
|
RtlZeroMemory( infString, MAX_ID_SIZE + 1 );
|
|
|
|
status = ParPnpGetId(devId, BusQueryDeviceID, infString, NULL);
|
|
|
|
if( !NT_SUCCESS(status) ) {
|
|
// massage failed, bail out
|
|
ParDump2(PARPNP1, ("rescan::Par3Get1284InfString - ID massage failed, bail out\n") );
|
|
ExFreePool( infString );
|
|
infString = NULL;
|
|
}
|
|
|
|
targetExit:
|
|
|
|
if( NULL != devId ) {
|
|
ExFreePool( devId );
|
|
}
|
|
|
|
return infString;
|
|
}
|
|
|
|
VOID
|
|
dot3rescan( IN PPAR_DEVOBJ_STRUCT CurrentNode )
|
|
{
|
|
NTSTATUS status;
|
|
UCHAR oldDeviceCount;
|
|
UCHAR newDeviceCount;
|
|
UCHAR idx;
|
|
PDEVICE_OBJECT *oldDevObj;
|
|
DEVOBJ_ID_PAIR newDevObjIdPair[ IEEE_1284_3_DAISY_CHAIN_MAX_ID + 1 ];
|
|
BOOLEAN changeDetected = FALSE;
|
|
PDEVICE_OBJECT legacyPodo = CurrentNode->LegacyPodo;
|
|
PDEVICE_EXTENSION legacyExtension = legacyPodo->DeviceExtension;
|
|
PDEVICE_OBJECT portDeviceObject = legacyExtension->PortDeviceObject;
|
|
|
|
ParDump2(PARPNP1, ("rescan::ParRescan1284_3DaisyChain - Enter\n") );
|
|
|
|
//
|
|
// Count the number of .3 daisy chain devices we had on last scan
|
|
// of this port
|
|
//
|
|
idx = 0;
|
|
oldDevObj = &CurrentNode->Dot3Id0Pdo;
|
|
while( NULL != oldDevObj[idx] ) {
|
|
++idx;
|
|
}
|
|
oldDeviceCount = idx;
|
|
ParDump2(PARPNP1, ("rescan::ParRescan1284_3DaisyChain - Dot3 DeviceCount Before Rescan = %d\n", idx) );
|
|
|
|
|
|
//
|
|
// Reinitialize the 1284.3 daisy chain (reassign .3 IDs)
|
|
//
|
|
ParDump2(PARPNP1, ("rescan::ParRescan1284_3DaisyChain - reinitializing Dot3 bus\n") );
|
|
status = ParInit1284_3Bus( portDeviceObject );
|
|
if( !NT_SUCCESS(status) ) {
|
|
ASSERT(FALSE); // this should never happen
|
|
return;
|
|
}
|
|
|
|
|
|
//
|
|
// Ask ParPort how many .3 daisy chain devices were detected after
|
|
// the .3 reinitialize. Does the number differ from the number that
|
|
// we had prior to rescan?
|
|
//
|
|
newDeviceCount = ParGet1284_3DeviceCount( portDeviceObject );
|
|
|
|
|
|
//
|
|
// Did we detect a change in the .3 device daisy chain?
|
|
//
|
|
if( oldDeviceCount != newDeviceCount ) {
|
|
|
|
ParDump2(PARPNP1, ("rescan::ParRescan1284_3DaisyChain - deviceCount changed - old=%d, new=%d\n", oldDeviceCount, newDeviceCount) );
|
|
changeDetected=TRUE;
|
|
|
|
} else {
|
|
|
|
//
|
|
// The number of .3 devices stayed the same. Compare 1284 IDs read from
|
|
// the device with those saved in the PDOs from the previous rescan.
|
|
//
|
|
ParDump2(PARPNP1, ("rescan::ParRescan1284_3DaisyChain - deviceCount unchanged - old=new=%d - comparing IDs\n", newDeviceCount) );
|
|
for( idx=0 ; idx < oldDeviceCount ; ++idx ) {
|
|
ParDump2(PARPNP1, ("rescan::ParRescan1284_3DaisyChain - checking ID's - idx = %d\n", idx) );
|
|
if( NULL != oldDevObj[idx] ) {
|
|
//
|
|
// We had a PDO, check if the device is still here
|
|
//
|
|
PDEVICE_EXTENSION ext = oldDevObj[idx]->DeviceExtension;
|
|
PCHAR dot3InfString = Par3Get1284InfString( legacyExtension, idx );
|
|
|
|
if( NULL == dot3InfString ) {
|
|
|
|
//
|
|
// We had a PDO, but now we don't detect any device
|
|
//
|
|
ParDump2(PARPNP1, ("rescan::ParRescan1284_3DaisyChain - DEVICE GONE - idx = %d\n", idx) );
|
|
changeDetected = TRUE;
|
|
break;
|
|
|
|
} else {
|
|
|
|
//
|
|
// We had a PDO, but the device we detect differs from what we expected
|
|
//
|
|
if( 0 == strcmp( ext->DeviceIdString, dot3InfString ) ) {
|
|
ParDump2(PARPNP1, ("rescan::ParRescan1284_3DaisyChain - DEVICE STILL THERE - idx = %d\n", idx) );
|
|
} else {
|
|
ParDump2(PARPNP1, ("rescan::ParRescan1284_3DaisyChain - DEVICE CHANGED - idx = %d\n", idx) );
|
|
changeDetected = TRUE;
|
|
}
|
|
|
|
ExFreePool( dot3InfString );
|
|
|
|
if( changeDetected ) {
|
|
break;
|
|
}
|
|
|
|
}
|
|
|
|
} // if( NULL != oldDevObj[idx] ...
|
|
|
|
} // for( idx=0 ; ...
|
|
|
|
} // if( oldDeviceCount != newDeviceCount ) {...} else {...}
|
|
|
|
|
|
if( changeDetected ) {
|
|
|
|
//
|
|
// Mark all existing .3 PDOs for devices connected to the port as "hardware gone"
|
|
//
|
|
ParDump2(PARPNP1, ("rescan::ParRescan1284_3DaisyChain - CHANGE DETECTED\n") );
|
|
|
|
for( idx=0 ; idx <= IEEE_1284_3_DAISY_CHAIN_MAX_ID ; ++idx ) {
|
|
if( NULL != oldDevObj[idx] ) {
|
|
ParDump2(PARPNP1, ("rescan::ParRescan1284_3DaisyChain - marking PDO %p as HARDWARE GONE\n", oldDevObj[idx]) );
|
|
ParMarkPdoHardwareGone( oldDevObj[idx]->DeviceExtension );
|
|
}
|
|
}
|
|
|
|
//
|
|
// Create a new PDO for each .3 device.
|
|
//
|
|
for( idx = 0 ; idx < newDeviceCount ; ++idx ) {
|
|
|
|
PDEVICE_OBJECT newDevObj;
|
|
BOOLEAN bBuildStlDeviceId;
|
|
|
|
bBuildStlDeviceId = ParStlCheckIfStl(legacyPodo->DeviceExtension, idx ) ;
|
|
|
|
//
|
|
// Select Device
|
|
//
|
|
status = ParSelect1284_3Device(portDeviceObject, idx);
|
|
if( !NT_SUCCESS( status ) ) {
|
|
ParDump2(PARPNP1, ("rescan::ParRescan1284_3DaisyChain - creating of new PDO for idx=%d FAILED\n", idx) );
|
|
continue;
|
|
}
|
|
|
|
//
|
|
// Create new PDO
|
|
//
|
|
newDevObj = ParDetectCreatePdo( legacyPodo, idx, bBuildStlDeviceId );
|
|
|
|
//
|
|
// Deselect Device
|
|
//
|
|
status = ParDeselect1284_3Device(portDeviceObject, idx);
|
|
if( !NT_SUCCESS( status ) ) {
|
|
ASSERTMSG("Unable to Deselect? - ParPort probably blocked now - this should never happen \n", FALSE);
|
|
if( NULL != newDevObj ) {
|
|
ParKillDeviceObject( newDevObj );
|
|
newDevObj = NULL;
|
|
}
|
|
}
|
|
|
|
//
|
|
// Add new PDO to FDO's list of children
|
|
//
|
|
if( NULL != newDevObj ) {
|
|
ParDump2(PARPNP1, ("rescan::ParRescan1284_3DaisyChain - adding new PDO %p - idx=%d to FDO list\n", newDevObj, idx) );
|
|
ParAddDevObjToFdoList(newDevObj);
|
|
} else {
|
|
ParDump2(PARPNP1, ("rescan::ParRescan1284_3DaisyChain - creating of new PDO for idx=%d FAILED\n", idx) );
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
VOID
|
|
ParCreateDot3DeviceIdList(
|
|
IN OUT PCHAR deviceIdArray[],
|
|
IN PDEVICE_EXTENSION legacyExt,
|
|
IN UCHAR dot3DeviceCount
|
|
)
|
|
{
|
|
PDEVICE_OBJECT portDeviceObject = legacyExt->PortDeviceObject;
|
|
NTSTATUS status;
|
|
UCHAR idx=0;
|
|
ULONG deviceIdSize;
|
|
BOOLEAN bBuildStlDeviceId;
|
|
|
|
ParDump2(PARPNP1, ("ParCreateDot3DeviceIdList() - Enter\n") );
|
|
while( idx < dot3DeviceCount ) {
|
|
bBuildStlDeviceId = ParStlCheckIfStl (legacyExt, idx) ;
|
|
status = ParSelect1284_3Device(portDeviceObject, idx);
|
|
if( NT_SUCCESS( status ) ) {
|
|
ParDump2(PARPNP1, ("rescan::ParCreateDot3DeviceIdList: - select SUCCESS - idx=%d\n", idx) );
|
|
deviceIdArray[idx] = Par3QueryDeviceId(legacyExt, NULL, 0, &deviceIdSize, FALSE, bBuildStlDeviceId);
|
|
if(deviceIdArray[idx]) {
|
|
ParDump2(PARPNP1, ("rescan::ParCreateDot3DeviceIdList: - id=<%s>\n", deviceIdArray[idx]) );
|
|
} else {
|
|
ParDump2(PARPNP1, ("rescan::ParCreateDot3DeviceIdList: - Par3QueryDeviceId FAILED\n") );
|
|
}
|
|
ParDeselect1284_3Device(portDeviceObject, idx);
|
|
} else {
|
|
ParDump2(PARPNP1, ("rescan::ParCreateDot3DeviceIdList: - select FAILED - idx=%d\n", idx) );
|
|
deviceIdArray[idx] = NULL;
|
|
}
|
|
++idx;
|
|
}
|
|
}
|
|
|
|
NTSTATUS
|
|
ParPnpFdoQueryDeviceRelationsBusRelations(
|
|
IN PDEVICE_OBJECT Fdo,
|
|
IN PIRP Irp
|
|
)
|
|
{
|
|
NTSTATUS status;
|
|
PDEVICE_EXTENSION fdoExt = Fdo->DeviceExtension;
|
|
PPAR_DEVOBJ_STRUCT devObjStructHead = NULL;
|
|
ULONG DeviceRelationsSize = 0;
|
|
ULONG Idx = 0;
|
|
PDEVICE_RELATIONS DeviceRelations = NULL;
|
|
PDEVICE_OBJECT pNextDeviceObject; // used for walking the ParClass DO list
|
|
PDEVICE_EXTENSION pExtension; // used for walking the ParClass DO list
|
|
|
|
ParDump2(PARPNP1, ("ParFdoQueryDeviceRelationsBusRelations - Enter\n") );
|
|
|
|
//
|
|
// Build a list of PAR_DEVOBJ_STRUCTs, one per ParPort device,
|
|
// from the FDO's list of device objects that were found connected
|
|
// to the ports the last time we checked.
|
|
//
|
|
// Create FILE against each ParPort Device to prevent it from being
|
|
// deleted out from under us.
|
|
//
|
|
ExAcquireFastMutex(&fdoExt->DevObjListMutex);
|
|
devObjStructHead = ParBuildDevObjStructList(Fdo);
|
|
devObjStructHead = ParLockPortDeviceObjects( devObjStructHead );
|
|
ExReleaseFastMutex(&fdoExt->DevObjListMutex);
|
|
|
|
if( !devObjStructHead ) {
|
|
// something went wrong, likely either no parallel ports, or unable to alloc pool
|
|
DDPnP1(("## ParPnpFdoQueryDeviceRelationsBusRelations - empty devObjStructHead - goto rescanComplete\n"));
|
|
goto rescanComplete;
|
|
}
|
|
|
|
//
|
|
// Dump the list of device objects that we have before rescan (debug only)
|
|
//
|
|
#if DBG
|
|
ParDumpDevObjStructList(devObjStructHead);
|
|
#endif
|
|
|
|
//
|
|
// Rescan all ports for changes in attached devices and
|
|
// update the ParClass FDO's list of device objects accordingly.
|
|
// (side effects - big time!!!)
|
|
//
|
|
ParDoParallelBusRescan(devObjStructHead);
|
|
|
|
//
|
|
// Close FDO FILEs against ParPort Devices (release FDO locks)
|
|
//
|
|
ParUnlockPortDeviceObjects(devObjStructHead);
|
|
|
|
//
|
|
// Delete the previous PAR_DEVOBJ_STRUCT list and create a
|
|
// new list from the FDO's list of devices after the rescan.
|
|
//
|
|
ParDestroyDevObjStructList(devObjStructHead);
|
|
|
|
ExAcquireFastMutex(&fdoExt->DevObjListMutex);
|
|
devObjStructHead = ParBuildDevObjStructList(Fdo);
|
|
ExReleaseFastMutex(&fdoExt->DevObjListMutex);
|
|
|
|
if( !devObjStructHead ) {
|
|
// something went wrong, likely either no parallel ports, or unable to alloc pool
|
|
goto rescanComplete;
|
|
}
|
|
|
|
//
|
|
// Dump the list of device objects that we have after rescan (debug only)
|
|
//
|
|
#if DBG
|
|
ParDumpDevObjStructList(devObjStructHead);
|
|
#endif
|
|
|
|
//
|
|
// Delete the PAR_DEVOBJ_STRUCT list, we no longer need it
|
|
//
|
|
ParDestroyDevObjStructList(devObjStructHead);
|
|
|
|
rescanComplete:
|
|
|
|
//
|
|
// The rescan is now complete, report the current set of attached devices to PnP
|
|
//
|
|
|
|
//
|
|
// Lock list while we scan it twice
|
|
//
|
|
ExAcquireFastMutex(&fdoExt->DevObjListMutex);
|
|
|
|
//
|
|
// Get list head
|
|
//
|
|
pNextDeviceObject = fdoExt->ParClassPdo;
|
|
|
|
//
|
|
// Walk list and count number of PDOs
|
|
//
|
|
while( pNextDeviceObject ) {
|
|
pExtension = pNextDeviceObject->DeviceExtension;
|
|
if ( pExtension->DeviceIdString[0] != 0 ) {
|
|
Idx++;
|
|
ParDump2(PARPNP1, ("found PDO %wZ - Extension: %x\n", &pExtension->SymbolicLinkName, pExtension) );
|
|
ParDump2(PARPNP1, (" - %s\n", pExtension->DeviceIdString) );
|
|
} else if ( pExtension->DeviceStateFlags & PAR_DEVICE_HARDWARE_GONE ) {
|
|
ParDump2(PARPNP1, ("found PDO %wZ - marked HARDWARE_GONE - Extension: %x\n", &pExtension->SymbolicLinkName, pExtension) );
|
|
ParDump2(PARPNP1, (" - %s\n", pExtension->DeviceIdString) );
|
|
} else {
|
|
ParDump2(PARPNP1, ("found PODO %wZ - Extension: %x\n", &pExtension->SymbolicLinkName, pExtension) );
|
|
}
|
|
pNextDeviceObject = pExtension->Next;
|
|
}
|
|
|
|
//
|
|
// allocate and initialize pool to hold DeviceRelations
|
|
//
|
|
DeviceRelationsSize = sizeof(DEVICE_RELATIONS) + (Idx * sizeof(PDEVICE_OBJECT));
|
|
DeviceRelations = ExAllocatePool(PagedPool, DeviceRelationsSize);
|
|
if( !DeviceRelations ) {
|
|
Irp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES;
|
|
ExReleaseFastMutex(&fdoExt->DevObjListMutex);
|
|
IoCompleteRequest(Irp, IO_NO_INCREMENT);
|
|
ParReleaseRemoveLock(&fdoExt->RemoveLock, Irp);
|
|
return STATUS_INSUFFICIENT_RESOURCES;
|
|
}
|
|
RtlZeroMemory(DeviceRelations, DeviceRelationsSize);
|
|
|
|
//
|
|
// Walk the list again to construct DeviceRelations
|
|
//
|
|
Idx = 0;
|
|
pNextDeviceObject = fdoExt->ParClassPdo;
|
|
|
|
while( pNextDeviceObject ) {
|
|
pExtension = pNextDeviceObject->DeviceExtension;
|
|
ParDump2(PARPNP1, ("rescan::ParPnpFdoQDR/BusRelations - Examining DO= %x , Ext= %x\n", pNextDeviceObject, pExtension));
|
|
if( (pExtension->DeviceIdString[0] != 0) &&
|
|
!(pExtension->DeviceStateFlags & PAR_DEVICE_HARDWARE_GONE) &&
|
|
(pExtension->SymbolicLinkName.Length > 0) ) {
|
|
// If this is a PDO, that is not marked "hardware gone", and has a SymbolicLink
|
|
DeviceRelations->Objects[Idx++] = pNextDeviceObject;
|
|
DeviceRelations->Count++;
|
|
ParDump2(PARPNP1, ("adding PDO %x <%wZ> to DeviceRelations, new PDO count=%d\n",
|
|
pNextDeviceObject, &pExtension->SymbolicLinkName,DeviceRelations->Count) );
|
|
ASSERT( ( pExtension->SymbolicLinkName.Length > 0 ) );
|
|
status = ObReferenceObjectByPointer(pNextDeviceObject, 0, NULL, KernelMode);
|
|
if(!NT_SUCCESS(status)) {
|
|
ParDumpP( ("Error Referencing PDO\n") );
|
|
ExFreePool(DeviceRelations);
|
|
Irp->IoStatus.Status = status;
|
|
ExReleaseFastMutex(&fdoExt->DevObjListMutex); // error - release Mutex
|
|
IoCompleteRequest(Irp, IO_NO_INCREMENT);
|
|
ParReleaseRemoveLock(&fdoExt->RemoveLock, Irp);
|
|
return status;
|
|
}
|
|
} else {
|
|
ParDump2(PARPNP1, (" - skipping DO= %x\n", pNextDeviceObject));
|
|
if( pExtension->DeviceStateFlags & PAR_DEVICE_HARDWARE_GONE ) {
|
|
ParDump2(PARPNP1, (" - because PAR_DEVICE_HARDWARE_GONE\n"));
|
|
} else if( pExtension->DeviceIdString[0] == 0 ) {
|
|
ParDump2(PARPNP1, (" - because DeviceIdString[0] == 0 - may be a PODO\n"));
|
|
} else if( pExtension->SymbolicLinkName.Length == 0 ) {
|
|
ParDump2(PARPNP1, (" - because pExtension->SymbolicLinkName.Length == 0\n"));
|
|
} else {
|
|
ParDump2(PARPNP1, (" - WHY are we skipping this?\n"));
|
|
ASSERT(FALSE);
|
|
}
|
|
}
|
|
pNextDeviceObject = pExtension->Next;
|
|
}
|
|
|
|
ParDump2(PARPNP1, ("rescan::ParPnpFdoQDR/BusRelations - DeviceRelations->Count = %d\n", DeviceRelations->Count));
|
|
|
|
//
|
|
// SUCCESS - set IRP fields and pass the IRP down the stack
|
|
//
|
|
Irp->IoStatus.Information = (ULONG_PTR)DeviceRelations;
|
|
Irp->IoStatus.Status = STATUS_SUCCESS;
|
|
ExReleaseFastMutex(&fdoExt->DevObjListMutex); // done - release Mutex
|
|
IoSkipCurrentIrpStackLocation(Irp);
|
|
ParReleaseRemoveLock(&fdoExt->RemoveLock, Irp);
|
|
ParDump2(PARPNP1, ("ParFdoQueryDeviceRelationsBusRelations - Leave\n") );
|
|
return ParCallDriver(fdoExt->ParentDeviceObject, Irp);
|
|
}
|
|
|
|
PPAR_DEVOBJ_STRUCT
|
|
ParBuildDevObjStructList(
|
|
IN PDEVICE_OBJECT Fdo
|
|
)
|
|
/*++dvdf - code complete
|
|
|
|
Routine Description:
|
|
|
|
This routine creates a list of PAR_DEVOBJ_STRUCT structures and returns
|
|
a pointer to the first structure. Each PAR_DEVOBJ_STRUCT describes
|
|
all ParClass devices associated with a single PortPort device.
|
|
|
|
|
|
Arguments:
|
|
|
|
Fdo - points to the ParClass FDO
|
|
|
|
Return Value:
|
|
|
|
PPAR_DEVOBJ_STRUCT - on success, points to the first structure created.
|
|
|
|
NULL - otherwise
|
|
|
|
--*/
|
|
{
|
|
PPAR_DEVOBJ_STRUCT devObjStructHead = NULL;
|
|
PDEVICE_EXTENSION fdoExt = Fdo->DeviceExtension;
|
|
PDEVICE_OBJECT currentDo;
|
|
PDEVICE_EXTENSION currentExt;
|
|
|
|
ParDump2(PARPNP1, ("Enter ParBuildDevObjStructList()\n") );
|
|
|
|
//
|
|
// do a quick exit if there are no ParClass Created PODOs or PDOs
|
|
//
|
|
currentDo = fdoExt->ParClassPdo;
|
|
if( !currentDo ) {
|
|
ParDump2(PARPNP1, ("No ParClass PODOs or PDOs exist\n") );
|
|
return NULL;
|
|
}
|
|
|
|
//
|
|
// create an initial PAR_DEVOBJ_STRUCT
|
|
//
|
|
currentExt = currentDo->DeviceExtension;
|
|
devObjStructHead = ParFindCreateDevObjStruct(NULL, currentExt->Controller);
|
|
if( !devObjStructHead ) {
|
|
return NULL;
|
|
}
|
|
|
|
//
|
|
// walk linear list of ParClass created PODOs and PDOs and
|
|
// create structured list of PAR_DEVOBJ_STRUCTs based on
|
|
// Controller address and DevObj type
|
|
//
|
|
ParDump2(PARPNP1, ("walking FDO's list of created PODOs and PDOs\n") );
|
|
while( currentDo ) {
|
|
currentExt = currentDo->DeviceExtension;
|
|
if( currentExt->DeviceStateFlags & PAR_DEVICE_HARDWARE_GONE ) {
|
|
// this is a PDO that is waiting for PnP to send it a REMOVE, skip it
|
|
ParDump2(PARPNP1, ("found PDO waiting to be REMOVEd - skipping - DO= %x , Ext= %x\n",
|
|
currentDo, currentExt) );
|
|
} else if( currentExt->DeviceIdString[0] == 0 ) {
|
|
// this is a Legacy PODO
|
|
ParDump2(PARPNP1, ("found PODO - DO= %x , Ext= %x , Controller=%x\n",
|
|
currentDo, currentExt, currentExt->Controller) );
|
|
ParAddPodoToDevObjStruct(devObjStructHead, currentDo);
|
|
} else if( currentExt->EndOfChain ) {
|
|
// this is an End-Of-Chain PDO
|
|
ParDump2(PARPNP1, ("found EOC PDO - DO= %x , Ext= %x , Controller=%x\n",
|
|
currentDo, currentExt, currentExt->Controller) );
|
|
ParAddEndOfChainPdoToDevObjStruct(devObjStructHead, currentDo);
|
|
} else if( currentExt->Ieee1284_3DeviceId == DOT3_LEGACY_ZIP_ID ) {
|
|
// this is a Legacy Zip PDO
|
|
ParDump2(PARPNP1, ("found LGZIP PDO - DO= %x , Ext= %x , Controller=%x\n",
|
|
currentDo, currentExt, currentExt->Controller) );
|
|
ParAddLegacyZipPdoToDevObjStruct(devObjStructHead, currentDo);
|
|
} else {
|
|
// this is a 1284.3 Daisy Chain PDO
|
|
ParDump2(PARPNP1, ("found Dot3 DC PDO - DO= %x , Ext= %x , Controller=%x , Dot3ID=%d\n",
|
|
currentDo, currentExt, currentExt->Controller, currentExt->Ieee1284_3DeviceId) );
|
|
ParAddDot3PdoToDevObjStruct(devObjStructHead, currentDo);
|
|
}
|
|
currentDo = currentExt->Next;
|
|
}
|
|
|
|
|
|
//
|
|
// It is possible for this function to construct a node with
|
|
// a NULL LegacyPodo if the parport goes away while we still have a PDO
|
|
// marked PAR_DEVICE_HARDWARE_GONE that is waiting to be cleaned up.
|
|
//
|
|
// Discard any such nodes that don't have a LegacyPodo since the lack of a
|
|
// LegacyPodo indicates that the parport device is gone, and attempting to
|
|
// communicate with the parport will likely bugcheck.
|
|
//
|
|
{
|
|
PPAR_DEVOBJ_STRUCT currentNode = devObjStructHead;
|
|
PPAR_DEVOBJ_STRUCT prevNode = NULL;
|
|
|
|
while( currentNode ) {
|
|
|
|
if( currentNode->LegacyPodo ) {
|
|
|
|
// keep this node - advance pointers
|
|
prevNode = currentNode;
|
|
currentNode = currentNode->Next;
|
|
|
|
} else {
|
|
|
|
// no PODO? - remove this node
|
|
PPAR_DEVOBJ_STRUCT delNode = currentNode;
|
|
currentNode = currentNode->Next;
|
|
|
|
if( prevNode ) {
|
|
// node to be removed is not first node - link around node to be deleted
|
|
prevNode->Next = currentNode;
|
|
} else {
|
|
// node to be removed was head of list - update list head
|
|
devObjStructHead = currentNode;
|
|
}
|
|
|
|
ExFreePool( delNode );
|
|
|
|
} // end if/else currentNode->LegacyPodo
|
|
|
|
} // end while currentNode
|
|
|
|
} // end localblock
|
|
|
|
return devObjStructHead;
|
|
}
|
|
|
|
VOID
|
|
ParAddPodoToDevObjStruct(
|
|
IN PPAR_DEVOBJ_STRUCT DevObjStructHead,
|
|
IN PDEVICE_OBJECT CurrentDo
|
|
)
|
|
{
|
|
PDEVICE_EXTENSION ext = CurrentDo->DeviceExtension;
|
|
PPAR_DEVOBJ_STRUCT node = ParFindCreateDevObjStruct(DevObjStructHead, ext->Controller);
|
|
if( node ) {
|
|
node->LegacyPodo = CurrentDo;
|
|
}
|
|
return;
|
|
}
|
|
|
|
VOID
|
|
ParAddEndOfChainPdoToDevObjStruct(
|
|
IN PPAR_DEVOBJ_STRUCT DevObjStructHead,
|
|
IN PDEVICE_OBJECT CurrentDo
|
|
)
|
|
{
|
|
PDEVICE_EXTENSION ext = CurrentDo->DeviceExtension;
|
|
PPAR_DEVOBJ_STRUCT node = ParFindCreateDevObjStruct(DevObjStructHead, ext->Controller);
|
|
if( node ) {
|
|
node->EndOfChainPdo = CurrentDo;
|
|
}
|
|
return;
|
|
}
|
|
|
|
VOID
|
|
ParAddLegacyZipPdoToDevObjStruct(
|
|
IN PPAR_DEVOBJ_STRUCT DevObjStructHead,
|
|
IN PDEVICE_OBJECT CurrentDo
|
|
)
|
|
{
|
|
PDEVICE_EXTENSION ext = CurrentDo->DeviceExtension;
|
|
PPAR_DEVOBJ_STRUCT node = ParFindCreateDevObjStruct(DevObjStructHead, ext->Controller);
|
|
if( node ) {
|
|
ParDump2(PARPNP1, ("rescan::ParAddLegacyZipPdoToDevObjStruct - Controller=%x\n", ext->Controller) );
|
|
node->LegacyZipPdo = CurrentDo;
|
|
}
|
|
return;
|
|
}
|
|
|
|
VOID
|
|
ParAddDot3PdoToDevObjStruct(
|
|
IN PPAR_DEVOBJ_STRUCT DevObjStructHead,
|
|
IN PDEVICE_OBJECT CurrentDo
|
|
)
|
|
{
|
|
PDEVICE_EXTENSION ext = CurrentDo->DeviceExtension;
|
|
PPAR_DEVOBJ_STRUCT node = ParFindCreateDevObjStruct(DevObjStructHead, ext->Controller);
|
|
if( node ) {
|
|
*( (&node->Dot3Id0Pdo) + (ext->Ieee1284_3DeviceId) ) = CurrentDo;
|
|
}
|
|
return;
|
|
}
|
|
|
|
PPAR_DEVOBJ_STRUCT ParFindCreateDevObjStruct(
|
|
IN PPAR_DEVOBJ_STRUCT DevObjStructHead,
|
|
IN PUCHAR Controller
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This function searches a list of PAR_DEVOBJ_STRUCTs for a
|
|
PAR_DEVOBJ_STRUCT whose Controller field matches the Controller
|
|
parameter.
|
|
|
|
If no match is found, then a new PAR_DEVOBJ_STRUCT that matches
|
|
is created, initialized (Controller field set, other fields
|
|
initialized to NULL), and appended to the end of the list.
|
|
|
|
Arguments:
|
|
|
|
DevObjStructHead - points to the head of the list to be searched
|
|
- NULL indicates that we should create an initial
|
|
element for the list
|
|
|
|
Controller - specifies the Controller that we should try to match
|
|
|
|
Return Value:
|
|
|
|
PPAR_DEVOBJ_STRUCT - on success, points to a PAR_DEVOBJ_STRUCT whose
|
|
Controller field matches the Controller parameter
|
|
|
|
NULL - insufficient resources failure (ExAllocatePool failed)
|
|
|
|
--*/
|
|
{
|
|
PPAR_DEVOBJ_STRUCT current;
|
|
PPAR_DEVOBJ_STRUCT previous;
|
|
|
|
ParDump2(PARPNP1, ("rescan::ParFindCreateDevObjStruct - Enter\n"));
|
|
|
|
//
|
|
// If list is empty, create the initial element and return a pointer to it.
|
|
//
|
|
if( !DevObjStructHead ) {
|
|
ParDump2(PARPNP1, ("rescan::ParFindCreateDevObjStruct - Empty List - Creating Initial Element - %x\n", Controller));
|
|
current = ExAllocatePool(PagedPool, sizeof(PAR_DEVOBJ_STRUCT));
|
|
if( !current ) {
|
|
return NULL; // insufficient resources
|
|
}
|
|
RtlZeroMemory(current, sizeof(PAR_DEVOBJ_STRUCT));
|
|
current->Controller = Controller;
|
|
return current;
|
|
}
|
|
|
|
//
|
|
// list is not empty - scan for a matching Controller
|
|
//
|
|
current = DevObjStructHead;
|
|
while( current ) {
|
|
if( current->Controller == Controller ) {
|
|
break; // found match, break out of loop
|
|
}
|
|
previous = current; // not found, advance pointers to next element
|
|
current = current->Next;
|
|
}
|
|
|
|
//
|
|
// did we find a match?
|
|
//
|
|
if( current ) {
|
|
ParDump2(PARPNP1, ("rescan::ParFindCreateDevObjStruct - Found Match - %x\n", Controller));
|
|
return current; // we found a match, return pointer to it
|
|
}
|
|
|
|
//
|
|
// we didn't find a match, create a new list item, append it to the list,
|
|
// and return a pointer to it
|
|
//
|
|
current = ExAllocatePool(PagedPool, sizeof(PAR_DEVOBJ_STRUCT));
|
|
if( !current ) {
|
|
return NULL; // insufficient resources
|
|
}
|
|
RtlZeroMemory(current, sizeof(PAR_DEVOBJ_STRUCT));
|
|
current->Controller = Controller;
|
|
previous->Next = current;
|
|
ParDump2(PARPNP1, ("rescan::ParFindCreateDevObjStruct - Match not found - Creating New - %x\n", Controller));
|
|
return current;
|
|
}
|
|
|
|
VOID
|
|
ParDestroyDevObjStructList(
|
|
IN PPAR_DEVOBJ_STRUCT DevObjStructHead
|
|
)
|
|
{
|
|
PPAR_DEVOBJ_STRUCT current = DevObjStructHead;
|
|
PPAR_DEVOBJ_STRUCT next;
|
|
|
|
while( current ) {
|
|
next = current->Next;
|
|
ExFreePool( current );
|
|
current = next;
|
|
}
|
|
}
|
|
|
|
VOID
|
|
ParDoParallelBusRescan(
|
|
IN PPAR_DEVOBJ_STRUCT DevObjStructHead
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine rescans the parallel port "buses" for
|
|
changes in the PnP devices connected to each parallel port.
|
|
|
|
Arguments:
|
|
|
|
DevObjStructHead - points to a list of structures where each structure
|
|
contains info about a single parallel port
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
{
|
|
PPAR_DEVOBJ_STRUCT currentNode = DevObjStructHead;
|
|
PDEVICE_OBJECT legacyPodo;
|
|
PDEVICE_EXTENSION legacyExt;
|
|
NTSTATUS status;
|
|
LARGE_INTEGER acquirePortTimeout;
|
|
|
|
//
|
|
// Process each parallel port (controller)
|
|
//
|
|
while( currentNode ) {
|
|
|
|
legacyPodo = currentNode->LegacyPodo;
|
|
if( NULL == legacyPodo ) {
|
|
//
|
|
// associated ParPort device object has been removed, so skip
|
|
// processing of this PAR_DEVOBJ_STRUCT
|
|
//
|
|
ParDump2(PARPNP1, ("ParDoParallelBusRescan - NULL legacyPodo for Controller=%x"
|
|
" - skipping rescan of this port\n",
|
|
currentNode->Controller) );
|
|
currentNode = currentNode->Next;
|
|
continue;
|
|
}
|
|
|
|
legacyExt = legacyPodo->DeviceExtension;
|
|
|
|
//
|
|
// Acquire the port from ParPort
|
|
//
|
|
|
|
// timeout is in 100 ns units
|
|
acquirePortTimeout.QuadPart = -(10 * 1000 * 1000 * 2); // 2 seconds
|
|
|
|
status = ParAcquirePort(legacyExt->PortDeviceObject, &acquirePortTimeout);
|
|
if( !NT_SUCCESS(status) ) {
|
|
ParDump2(PARPNP1, ("ParDoParallelBusRescan - Unable to acquire port/"
|
|
"Controller=%x - skipping rescan of this port\n",
|
|
currentNode->Controller) );
|
|
currentNode = currentNode->Next;
|
|
continue;
|
|
}
|
|
|
|
//
|
|
// Port is acquired
|
|
//
|
|
|
|
//
|
|
// Rescan for change in End-Of-Chain Device
|
|
//
|
|
ParRescanEndOfChain( currentNode );
|
|
|
|
//
|
|
// Rescan for changes in 1284.3 Daisy Chain Devices
|
|
//
|
|
// ParRescan1284_3DaisyChain(currentNode);
|
|
dot3rescan( currentNode );
|
|
|
|
//
|
|
// Rescan for change in Legacy Zip Drive
|
|
//
|
|
{
|
|
ULONG OldParEnableLegacyZipFlag = ParEnableLegacyZip;
|
|
ParCheckEnableLegacyZipFlag();
|
|
if( (OldParEnableLegacyZipFlag == 1) && (ParEnableLegacyZip == 0) ) {
|
|
// We can handle enable ( 0 -> 1 ) without a reboot, but not disable ( 1 -> 0 )
|
|
ParEnableLegacyZip = OldParEnableLegacyZipFlag;
|
|
}
|
|
ParRescanLegacyZip( currentNode );
|
|
}
|
|
|
|
//
|
|
// Release the port back to ParPort
|
|
//
|
|
status = ParReleasePort( legacyExt->PortDeviceObject );
|
|
if( !NT_SUCCESS(status) ) {
|
|
ASSERTMSG("Unable to free port??? - this should never happen ", FALSE);
|
|
}
|
|
|
|
//
|
|
// Advance pointer to next PAR_DEVOBJ_STRUCT
|
|
//
|
|
currentNode = currentNode->Next;
|
|
|
|
} // end while
|
|
}
|
|
|
|
VOID
|
|
ParRescanEndOfChain(
|
|
IN PPAR_DEVOBJ_STRUCT CurrentNode
|
|
)
|
|
{
|
|
PDEVICE_OBJECT legacyPodo = CurrentNode->LegacyPodo;
|
|
PDEVICE_EXTENSION legacyExt = legacyPodo->DeviceExtension;
|
|
PUCHAR deviceId;
|
|
ULONG deviceIdLength;
|
|
UCHAR resultString[MAX_ID_SIZE];
|
|
NTSTATUS status;
|
|
ULONG deviceIdTryCount = 1;
|
|
ULONG maxIdTries = 3;
|
|
|
|
|
|
// Query for an End-Of-Chain 1284 device ID
|
|
|
|
retryDeviceIdQuery:
|
|
|
|
deviceId = Par3QueryDeviceId(legacyExt, NULL, 0, &deviceIdLength, FALSE, FALSE);
|
|
|
|
if( ( deviceId == NULL ) && ( deviceIdTryCount < maxIdTries ) ) {
|
|
|
|
//
|
|
// we didn't find a device - give any device that might be connected
|
|
// another chance to tell us that it is there
|
|
//
|
|
ParDump2(PARRESCAN, ("rescan::ParRescanEndOfChain - no EOC detected on "
|
|
"try %d - retrying 1284 id query\n", deviceIdTryCount) );
|
|
++deviceIdTryCount;
|
|
KeStallExecutionProcessor(1); // allow the signals on the wires to stabilize
|
|
goto retryDeviceIdQuery;
|
|
|
|
}
|
|
|
|
//
|
|
// Done with retries, we either found a device or we did not.
|
|
//
|
|
|
|
if( !deviceId ) {
|
|
|
|
//
|
|
// We didn't find an EOC device
|
|
//
|
|
if( CurrentNode->EndOfChainPdo ) {
|
|
//
|
|
// we had a device but now it is gone - mark extension as "hardware gone"
|
|
//
|
|
ParDump2(PARRESCAN, ("rescan::ParRescanEndOfChain - EOC device went away\n"));
|
|
ParMarkPdoHardwareGone(CurrentNode->EndOfChainPdo->DeviceExtension);
|
|
} else {
|
|
ParDump2(PARRESCAN, ("rescan::ParRescanEndOfChain - No end of chain device detected\n"));
|
|
}
|
|
|
|
} else {
|
|
|
|
//
|
|
// we found an EOC device
|
|
//
|
|
ParDump2(PARRESCAN, ("rescan::ParRescanEndOfChain - EOC device detected - tries required == %d\n",deviceIdTryCount));
|
|
ParDump2(PARRESCAN, ("\"RAW\" ID string = <%s>\n", deviceId) );
|
|
|
|
//
|
|
// did we already have an EOC device?
|
|
//
|
|
if( CurrentNode->EndOfChainPdo ) {
|
|
//
|
|
// we already had an EOC device - compare its ID from its extension
|
|
// with the ID we just read from the hardware
|
|
//
|
|
PDEVICE_EXTENSION endOfChainExt = CurrentNode->EndOfChainPdo->DeviceExtension;
|
|
|
|
//
|
|
// massage the ID read from the hardware into the form needed for compare
|
|
//
|
|
RtlZeroMemory(resultString, MAX_ID_SIZE);
|
|
status = ParPnpGetId(deviceId, BusQueryDeviceID, resultString, NULL);
|
|
if( NT_SUCCESS(status) ) {
|
|
//
|
|
// massage succeeded - do compare
|
|
//
|
|
if(0 == strcmp(endOfChainExt->DeviceIdString, resultString)) {
|
|
//
|
|
// id matches - we found the same device we previously found
|
|
//
|
|
} else {
|
|
//
|
|
// id differs - we have different device that we previously had
|
|
//
|
|
// mark previous device extension as "hardware gone"
|
|
//
|
|
ParMarkPdoHardwareGone(CurrentNode->EndOfChainPdo->DeviceExtension);
|
|
|
|
//
|
|
// create device object for new device and add it to FDO's list
|
|
//
|
|
ParDetectCreateEndOfChainPdo(legacyPodo);
|
|
}
|
|
} else {
|
|
// massage failed - unable to extract valid ID
|
|
|
|
// mark previous extension as "hardware gone"
|
|
ParMarkPdoHardwareGone(CurrentNode->EndOfChainPdo->DeviceExtension);
|
|
}
|
|
} else {
|
|
// we didn't have an EOC device on previous scan, but ID detected on this scan
|
|
|
|
// create device object for new device and add it to FDO's list
|
|
ParDetectCreateEndOfChainPdo(legacyPodo);
|
|
}
|
|
ExFreePool( deviceId );
|
|
|
|
} // end if/else ( !deviceId ) - end of chain device rescan complete for this port
|
|
}
|
|
|
|
#if 0
|
|
VOID
|
|
ParRescan1284_3DaisyChain(
|
|
IN PPAR_DEVOBJ_STRUCT CurrentNode
|
|
)
|
|
{
|
|
PDEVICE_OBJECT legacyPodo = CurrentNode->LegacyPodo;
|
|
PDEVICE_EXTENSION legacyExt = legacyPodo->DeviceExtension;
|
|
PDEVICE_OBJECT portDeviceObject = legacyExt->PortDeviceObject;
|
|
PDEVICE_OBJECT currentDeviceObject;
|
|
UCHAR newDot3DeviceCount;
|
|
NTSTATUS status;
|
|
UCHAR idx;
|
|
UCHAR oldDot3DeviceCount;
|
|
PUCHAR deviceId;
|
|
ULONG deviceIdLength;
|
|
UCHAR tempIdBuffer[MAX_ID_SIZE];
|
|
PCHAR deviceIdArray[IEEE_1284_3_DAISY_CHAIN_MAX_ID+1] = {NULL,NULL,NULL,NULL};
|
|
BOOLEAN chainWasBroken;
|
|
UCHAR firstDeviceGone;
|
|
|
|
ParDump2(PARPNP1, ("rescan::ParRescan1284_3DaisyChain - Enter\n") );
|
|
|
|
//
|
|
// Count the number of .3 daisy chain devices we had on last scan
|
|
// of this port
|
|
//
|
|
idx = 0;
|
|
while( NULL != *( (&CurrentNode->Dot3Id0Pdo) + idx ) ) {
|
|
++idx;
|
|
}
|
|
oldDot3DeviceCount = idx;
|
|
ParDump2(PARPNP1, ("rescan::ParRescan1284_3DaisyChain - Dot3 DeviceCount Before Rescan = %d\n", idx) );
|
|
|
|
|
|
//
|
|
// Walk the daisy chain and verify that each device is still here
|
|
//
|
|
chainWasBroken = FALSE;
|
|
idx=0;
|
|
while( idx < oldDot3DeviceCount ) {
|
|
PDEVICE_OBJECT curDevObj = *( (&CurrentNode->Dot3Id0Pdo) + idx );
|
|
PDEVICE_EXTENSION curDevExt = curDevObj->DeviceExtension;
|
|
if( ParDeviceExists( curDevExt, HAVE_PORT_KEEP_PORT ) ) {
|
|
ParDump2(PARPNP1, ("rescan::ParRescan1284_3DaisyChain - Dot3 device %d still there\n", idx) );
|
|
++idx;
|
|
} else {
|
|
ParDump2(PARPNP1, ("rescan::ParRescan1284_3DaisyChain - Dot3 device %d GONE - chain broken\n", idx) );
|
|
chainWasBroken=TRUE;
|
|
firstDeviceGone = idx;
|
|
break;
|
|
}
|
|
}
|
|
|
|
//
|
|
// If chain was broken, nuke PDO for missing device and for all
|
|
// .3 daisy chain devices connected beyond that device in
|
|
// the daisy chain.
|
|
//
|
|
if( chainWasBroken ) {
|
|
for( idx = firstDeviceGone ; idx < oldDot3DeviceCount ; ++idx ) {
|
|
PDEVICE_OBJECT curDevObj = *( (&CurrentNode->Dot3Id0Pdo) + idx );
|
|
PDEVICE_EXTENSION curDevExt = curDevObj->DeviceExtension;
|
|
ParDump2(PARPNP1, ("rescan::ParRescan1284_3DaisyChain - Nuking DevObj= %x , idx=%d\n", curDevObj, idx) );
|
|
ParMarkPdoHardwareGone( curDevExt );
|
|
*( (&CurrentNode->Dot3Id0Pdo) + idx ) = NULL;
|
|
--oldDot3DeviceCount;
|
|
}
|
|
ParDump2(PARPNP1, ("rescan::ParRescan1284_3DaisyChain - Dot3 DeviceCount - post-Nuking= %d\n", oldDot3DeviceCount) );
|
|
}
|
|
|
|
//
|
|
// Step through the list of Dot3 device objects associated with
|
|
// this port, read the device ID from the corresponding device and
|
|
// compare with the ID stored in the device extension. Mark any
|
|
// device extension whose device doesn't answer the query or
|
|
// answers the query with a different ID than the one in the
|
|
// extension as "hardware gone".
|
|
//
|
|
|
|
|
|
//
|
|
// Reinitialize 1284.3 daisy chain device IDs
|
|
//
|
|
ParDump2(PARPNP1, ("rescan::ParRescan1284_3DaisyChain - reinitializing Dot3 bus\n") );
|
|
status = ParInit1284_3Bus(portDeviceObject);
|
|
if( !NT_SUCCESS(status) ) {
|
|
ASSERT(FALSE); // this should never happen
|
|
return;
|
|
}
|
|
|
|
|
|
//
|
|
// Get count of 1284.3 daisy chain devices connected to port
|
|
//
|
|
newDot3DeviceCount = ParGet1284_3DeviceCount(legacyExt->PortDeviceObject);
|
|
ParDump2(PARPNP1, ("rescan::ParRescan1284_3DaisyChain - newDot3DeviceCount = %d\n", newDot3DeviceCount) );
|
|
|
|
|
|
//
|
|
// scan for 1284.3 daisy chain changes
|
|
//
|
|
for(idx = 0 ; idx <= IEEE_1284_3_DAISY_CHAIN_MAX_ID ; ++idx) {
|
|
// get a pointer to the existing 1284.3 dc device object, if any
|
|
PDEVICE_OBJECT devObj = *( (&CurrentNode->Dot3Id0Pdo) + idx );
|
|
PDEVICE_EXTENSION devExt;
|
|
|
|
if( (devObj == NULL) && ( idx >= newDot3DeviceCount ) ) {
|
|
|
|
// no device object, no device, done, exit loop early
|
|
ParDump2(PARPNP2, ("rescan::ParRescan1284_3DaisyChain - idx = %d, no DO - no device - exit loop early\n",idx) );
|
|
break;
|
|
|
|
} else if( (devObj == NULL) && ( idx < newDot3DeviceCount ) ) {
|
|
|
|
//
|
|
// no device object, but we have a device
|
|
// - create new device object
|
|
//
|
|
ParDump2(PARPNP2, ("rescan::ParRescan1284_3DaisyChain - idx = %d, no DO - have device - create device\n",idx) );
|
|
{
|
|
PDEVICE_OBJECT newPdo;
|
|
|
|
ParDump2(PARPNP2, ("rescan::ParRescan1284_3DaisyChain - selecting idx = %d\n",idx) );
|
|
status = ParSelect1284_3Device(legacyExt->PortDeviceObject, idx);
|
|
|
|
if( NT_SUCCESS( status ) ) {
|
|
ParDump2(PARPNP2, ("rescan::ParRescan1284_3DaisyChain - select succeeded on idx=%d\n",idx) );
|
|
ParDump2(PARPNP2, ("rescan::ParRescan1284_3DaisyChain - creating PDO for idx=%d\n",idx) );
|
|
newPdo = ParDetectCreatePdo(legacyPodo, idx);
|
|
// add to FDO list
|
|
if( newPdo ) {
|
|
ParDump2(PARPNP2, ("rescan::ParRescan1284_3DaisyChain - PDO %x created for idx=%d\n", newPdo, idx) );
|
|
ParDump2(PARPNP2, ("rescan::ParRescan1284_3DaisyChain - adding new Dot3 PDO to FDO list\n") );
|
|
ParAddDevObjToFdoList(newPdo);
|
|
} else {
|
|
ParDump2(PARPNP2, ("rescan::ParRescan1284_3DaisyChain - create of PDO for idx=%d FAILED\n", idx) );
|
|
}
|
|
ParDump2(PARPNP2, ("rescan::ParRescan1284_3DaisyChain - deselecting idx = %d\n",idx) );
|
|
status = ParDeselect1284_3Device(legacyExt->PortDeviceObject, idx);
|
|
if( !NT_SUCCESS( status ) ) {
|
|
ASSERTMSG("DESELECT FAILED??? - This should never happen ", FALSE);
|
|
}
|
|
} else {
|
|
ParDump2(PARPNP2, ("rescan::ParRescan1284_3DaisyChain - select FAILED on idx=%d\n",idx) );
|
|
}
|
|
}
|
|
|
|
} else if( (devObj != NULL) && ( idx >= newDot3DeviceCount ) ) {
|
|
|
|
//
|
|
// have a device object, but no device - this should not happen
|
|
// because we should have cleaned up in the code above
|
|
//
|
|
ASSERT(FALSE);
|
|
|
|
} else if( (devObj != NULL) && ( idx < newDot3DeviceCount ) ) {
|
|
|
|
// have a device object and a device
|
|
devExt = devObj->DeviceExtension;
|
|
|
|
// - compare ID's between device object and device
|
|
ParDump2(PARPNP2, ("rescan::ParRescan1284_3DaisyChain - idx = %d, have DO - have device - compare id's\n",idx) );
|
|
|
|
// do 1284.3 selection to select the device
|
|
status = ParSelect1284_3Device(portDeviceObject, idx);
|
|
if( NT_SUCCESS( status ) ) {
|
|
|
|
// device selected
|
|
|
|
// query ID from device
|
|
deviceId = Par3QueryDeviceId(legacyExt, NULL, 0, &deviceIdLength, FALSE);
|
|
|
|
// deselect the 1284.3 dc device
|
|
status = ParDeselect1284_3Device(portDeviceObject, idx);
|
|
if( !NT_SUCCESS(status) ) {
|
|
// deselect should not fail, however not much we can do except complain if it does
|
|
ParDump2(PARERRORS, ("rescan::ParRescan1284_3DaisyChain - call to ParDeselect1284_3Device() FAILED\n") );
|
|
}
|
|
|
|
// did we get a device id from the hardware?
|
|
if( deviceId ) {
|
|
|
|
// massage deviceId into format saved in extension
|
|
RtlZeroMemory(tempIdBuffer, sizeof(tempIdBuffer));
|
|
|
|
status = ParPnpGetId(deviceId, BusQueryDeviceID, tempIdBuffer, NULL);
|
|
if( !NT_SUCCESS(status) ) {
|
|
// RMT - don't bother to compare
|
|
sprintf(tempIdBuffer, "rescan::ParRescan1284_3DaisyChain - ParPnpGetId Failed - don't compare\0");
|
|
}
|
|
|
|
// got a device id from hardware - do compare
|
|
ParDump2(PARPNP2, ("rescan::ParRescan1284_3DaisyChain - device id = <%s>\n", tempIdBuffer) );
|
|
ParDump2(PARPNP2, ("rescan::ParRescan1284_3DaisyChain - ext id = <%s>\n", devExt->DeviceIdString) );
|
|
|
|
devExt = devObj->DeviceExtension;
|
|
if( strcmp(tempIdBuffer, devExt->DeviceIdString) == 0 ) {
|
|
// match - do nothing - device is same that was there before rescan
|
|
ParDump2(PARPNP2, ("rescan::ParRescan1284_3DaisyChain - MATCH - KEEP device, idx=%d\n", idx) );
|
|
} else {
|
|
PDEVICE_OBJECT newPdo;
|
|
// no match
|
|
ParDump2(PARPNP2, ("rescan::ParRescan1284_3DaisyChain - "
|
|
"NO MATCH - mark hardware gone and create new device, idx = %d\n", idx) );
|
|
// - mark device object as hardware gone
|
|
devExt = devObj->DeviceExtension;
|
|
ParMarkPdoHardwareGone( devExt );
|
|
|
|
// - create device object for new device
|
|
newPdo = ParDetectCreatePdo(legacyPodo, idx);
|
|
|
|
// add to FDO list
|
|
if( newPdo ) {
|
|
ParDump2(PARPNP2, ("rescan::ParRescan1284_3DaisyChain - adding new Dot3 PDO to FDO list\n") );
|
|
ParAddDevObjToFdoList(newPdo);
|
|
}
|
|
}
|
|
// done with temp ID string
|
|
ExFreePool( deviceId );
|
|
|
|
} else {
|
|
|
|
// unable to read device id
|
|
ParDump2(PARPNP2, ("rescan::ParRescan1284_3DaisyChain - didn't get device id, idx=%d\n", idx) );
|
|
|
|
// - mark device object as hardware gone
|
|
devExt = devObj->DeviceExtension;
|
|
ParMarkPdoHardwareGone( devExt );
|
|
}
|
|
|
|
} else {
|
|
|
|
// unable to select device
|
|
ParDump2(PARPNP2, ("rescan::ParRescan1284_3DaisyChain - unable to select device, idx=%d\n", idx) );
|
|
|
|
// - mark device object as hardware gone
|
|
devExt = devObj->DeviceExtension;
|
|
ParMarkPdoHardwareGone( devExt );
|
|
|
|
}
|
|
|
|
} // end if have a device object and a device
|
|
|
|
} // end for(idx = 0 ; ...)
|
|
|
|
}
|
|
#endif // 0
|