Source code of Windows XP (NT5)
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

  1. //+-------------------------------------------------------------------------
  2. //
  3. // Microsoft Windows
  4. //
  5. // Copyright (C) Microsoft Corporation, 1998 - 1999
  6. //
  7. // File: rescan.c
  8. //
  9. //--------------------------------------------------------------------------
  10. // rescan a parallel port for changes in the connected devices
  11. #include "pch.h"
  12. // typedef struct _PAR_DEVOBJ_STRUCT {
  13. // PUCHAR Controller; // host controller address for devices in this structure
  14. // PDEVICE_OBJECT LegacyPodo; // legacy or "raw" port device
  15. // PDEVICE_OBJECT EndOfChainPdo; // End-Of-Chain PnP device
  16. // PDEVICE_OBJECT Dot3Id0Pdo; // 1284.3 daisy chain device, 1284.3 deviceID == 0
  17. // PDEVICE_OBJECT Dot3Id1Pdo;
  18. // PDEVICE_OBJECT Dot3Id2Pdo;
  19. // PDEVICE_OBJECT Dot3Id3Pdo; // 1284.3 daisy chain device, 1284.3 deviceID == 3
  20. // PDEVICE_OBJECT LegacyZipPdo; // Legacy Zip Drive
  21. // PFILE_OBJECT pFileObject; // Need an open handle to ParPort device to prevent it
  22. // // from being removed out from under us
  23. // struct _PAR_DEVOBJ_STRUCT *Next;
  24. // } PAR_DEVOBJ_STRUCT, *PPAR_DEVOBJ_STRUCT;
  25. typedef struct _DEVOBJ_ID_PAIR {
  26. PDEVICE_OBJECT DevObj;
  27. PCHAR Id;
  28. } DEVOBJ_ID_PAIR, *PDEVOBJ_ID_PAIR;
  29. ULONG gsuc = 1;
  30. ULONG
  31. ParTst() {
  32. return gsuc;
  33. }
  34. PPAR_DEVOBJ_STRUCT
  35. ParLockPortDeviceObjects(
  36. IN PPAR_DEVOBJ_STRUCT DevObjStructHead
  37. )
  38. {
  39. NTSTATUS status;
  40. PPAR_DEVOBJ_STRUCT head = DevObjStructHead;
  41. PPAR_DEVOBJ_STRUCT currentNode = head;
  42. PPAR_DEVOBJ_STRUCT prevNode = NULL;
  43. PPAR_DEVOBJ_STRUCT delNode;
  44. DDPnP1(("## ParLockPortDeviceObjects - enter\n"));
  45. while( currentNode ) {
  46. PDEVICE_OBJECT currentDevObj;
  47. PDEVICE_EXTENSION currentDevExt;
  48. PUNICODE_STRING portDevName;
  49. PFILE_OBJECT portFileObj;
  50. PDEVICE_OBJECT portDevObj;
  51. currentDevObj = currentNode->LegacyPodo;
  52. currentDevExt = currentDevObj->DeviceExtension;
  53. portDevName = &currentDevExt->PortSymbolicLinkName;
  54. status = IoGetDeviceObjectPointer(portDevName,
  55. STANDARD_RIGHTS_ALL,
  56. &portFileObj,
  57. &portDevObj);
  58. if( NT_SUCCESS(status) && portFileObj && portDevObj ) {
  59. //
  60. // We have a FILE open against the ParPort Device to
  61. // lock the device into memory until we're done with the rescan.
  62. //
  63. // Save the pointer to the file object so we can unlock when we're done.
  64. //
  65. currentNode->pFileObject = portFileObj;
  66. DDPnP1(("## ParLockPortDeviceObjects - opened FILE - PFILE= %x , %x\n",portFileObj,currentNode->Controller));
  67. // advance pointers
  68. prevNode = currentNode;
  69. currentNode = currentNode->Next;
  70. } else {
  71. //
  72. // we couldn't open a FILE open against the ParPort Device so the
  73. // port must be gone. Remove this port from the list of ports to rescan.
  74. //
  75. DDPnP1(("## ParLockPortDeviceObjects - open FILE FAILED - %x\n",currentNode->Controller));
  76. delNode = currentNode; // this is the node to delete
  77. currentNode = currentNode->Next;
  78. if( head == delNode ) {
  79. // deleted node was list head - save updated current node as new list head
  80. head = currentNode;
  81. } else {
  82. // link around node to be deleted
  83. prevNode->Next = currentNode;
  84. }
  85. ExFreePool( delNode );
  86. }
  87. }
  88. DDPnP1(("## ParLockPortDeviceObjects - exit\n"));
  89. return head;
  90. }
  91. VOID
  92. ParUnlockPortDeviceObjects(
  93. IN PPAR_DEVOBJ_STRUCT DevObjStructHead
  94. )
  95. {
  96. PPAR_DEVOBJ_STRUCT currentNode = DevObjStructHead;
  97. DDPnP1(("## ParUnlockPortDeviceObjects - enter\n"));
  98. while( currentNode ) {
  99. if( currentNode->pFileObject ) {
  100. ObDereferenceObject( currentNode->pFileObject );
  101. DDPnP1(("## ParUnlockPortDeviceObjects - closed FILE - PFILE= %x , %x\n",currentNode->pFileObject,currentNode->Controller));
  102. currentNode->pFileObject = NULL;
  103. }
  104. currentNode = currentNode->Next;
  105. }
  106. DDPnP1(("## ParUnlockPortDeviceObjects - exit\n"));
  107. }
  108. PCHAR
  109. Par3Get1284InfString(PDEVICE_EXTENSION LegacyExt, UCHAR Dot3DeviceId)
  110. {
  111. NTSTATUS status;
  112. PCHAR devId = NULL;
  113. PCHAR infString = NULL;
  114. ULONG devIdSize;
  115. PDEVICE_OBJECT portDeviceObject = LegacyExt->PortDeviceObject;
  116. ULONG maxIdTries = 3;
  117. ULONG idTry = 1;
  118. BOOLEAN bBuildStlDeviceId = FALSE ;
  119. bBuildStlDeviceId = ParStlCheckIfStl (LegacyExt, Dot3DeviceId) ;
  120. //
  121. // Select the .3 daisy chain device, query for 1284 ID, and deselect device.
  122. //
  123. status = ParSelect1284_3Device(portDeviceObject, Dot3DeviceId);
  124. if( !NT_SUCCESS( status ) ) {
  125. // unable to select device, bail out
  126. ParDump2(PARPNP1, ("rescan::Par3Get1284InfString - SELECT FAILED\n") );
  127. goto targetExit;
  128. }
  129. while( (NULL==devId) && (idTry <= maxIdTries) ) {
  130. devId = Par3QueryDeviceId(LegacyExt, NULL, 0, &devIdSize, FALSE, bBuildStlDeviceId);
  131. if( NULL == devId ) {
  132. ParDump2(PARPNP1, ("rescan::Par3Get1284InfString - no 1284 ID on try %d\n", idTry) );
  133. KeStallExecutionProcessor(1);
  134. ++idTry;
  135. } else {
  136. ParDump2(PARPNP1, ("rescan::Par3Get1284InfString - <%s> on try %d\n", devId, idTry) );
  137. }
  138. }
  139. status = ParDeselect1284_3Device(portDeviceObject, Dot3DeviceId);
  140. if( !NT_SUCCESS( status ) ) {
  141. ASSERTMSG("Unable to Deselect? - ParPort probably blocked now - this should never happen \n", FALSE);
  142. goto targetExit;
  143. }
  144. if( NULL == devId ) {
  145. // we didn't get a 1284 ID, bail out
  146. ParDump2(PARPNP1, ("rescan::Par3Get1284InfString - didn't get a 1284 ID, bail out\n") );
  147. goto targetExit;
  148. }
  149. //
  150. // Massage the 1284 ID into the format used in the INF.
  151. //
  152. infString = ExAllocatePool( PagedPool, MAX_ID_SIZE + 1 );
  153. if( NULL == infString ) {
  154. ParDump2(PARPNP1, ("rescan::Par3Get1284InfString - no pool avail, bail out\n") );
  155. // no pool available, bail out
  156. goto targetExit;
  157. }
  158. RtlZeroMemory( infString, MAX_ID_SIZE + 1 );
  159. status = ParPnpGetId(devId, BusQueryDeviceID, infString, NULL);
  160. if( !NT_SUCCESS(status) ) {
  161. // massage failed, bail out
  162. ParDump2(PARPNP1, ("rescan::Par3Get1284InfString - ID massage failed, bail out\n") );
  163. ExFreePool( infString );
  164. infString = NULL;
  165. }
  166. targetExit:
  167. if( NULL != devId ) {
  168. ExFreePool( devId );
  169. }
  170. return infString;
  171. }
  172. VOID
  173. dot3rescan( IN PPAR_DEVOBJ_STRUCT CurrentNode )
  174. {
  175. NTSTATUS status;
  176. UCHAR oldDeviceCount;
  177. UCHAR newDeviceCount;
  178. UCHAR idx;
  179. PDEVICE_OBJECT *oldDevObj;
  180. DEVOBJ_ID_PAIR newDevObjIdPair[ IEEE_1284_3_DAISY_CHAIN_MAX_ID + 1 ];
  181. BOOLEAN changeDetected = FALSE;
  182. PDEVICE_OBJECT legacyPodo = CurrentNode->LegacyPodo;
  183. PDEVICE_EXTENSION legacyExtension = legacyPodo->DeviceExtension;
  184. PDEVICE_OBJECT portDeviceObject = legacyExtension->PortDeviceObject;
  185. ParDump2(PARPNP1, ("rescan::ParRescan1284_3DaisyChain - Enter\n") );
  186. //
  187. // Count the number of .3 daisy chain devices we had on last scan
  188. // of this port
  189. //
  190. idx = 0;
  191. oldDevObj = &CurrentNode->Dot3Id0Pdo;
  192. while( NULL != oldDevObj[idx] ) {
  193. ++idx;
  194. }
  195. oldDeviceCount = idx;
  196. ParDump2(PARPNP1, ("rescan::ParRescan1284_3DaisyChain - Dot3 DeviceCount Before Rescan = %d\n", idx) );
  197. //
  198. // Reinitialize the 1284.3 daisy chain (reassign .3 IDs)
  199. //
  200. ParDump2(PARPNP1, ("rescan::ParRescan1284_3DaisyChain - reinitializing Dot3 bus\n") );
  201. status = ParInit1284_3Bus( portDeviceObject );
  202. if( !NT_SUCCESS(status) ) {
  203. ASSERT(FALSE); // this should never happen
  204. return;
  205. }
  206. //
  207. // Ask ParPort how many .3 daisy chain devices were detected after
  208. // the .3 reinitialize. Does the number differ from the number that
  209. // we had prior to rescan?
  210. //
  211. newDeviceCount = ParGet1284_3DeviceCount( portDeviceObject );
  212. //
  213. // Did we detect a change in the .3 device daisy chain?
  214. //
  215. if( oldDeviceCount != newDeviceCount ) {
  216. ParDump2(PARPNP1, ("rescan::ParRescan1284_3DaisyChain - deviceCount changed - old=%d, new=%d\n", oldDeviceCount, newDeviceCount) );
  217. changeDetected=TRUE;
  218. } else {
  219. //
  220. // The number of .3 devices stayed the same. Compare 1284 IDs read from
  221. // the device with those saved in the PDOs from the previous rescan.
  222. //
  223. ParDump2(PARPNP1, ("rescan::ParRescan1284_3DaisyChain - deviceCount unchanged - old=new=%d - comparing IDs\n", newDeviceCount) );
  224. for( idx=0 ; idx < oldDeviceCount ; ++idx ) {
  225. ParDump2(PARPNP1, ("rescan::ParRescan1284_3DaisyChain - checking ID's - idx = %d\n", idx) );
  226. if( NULL != oldDevObj[idx] ) {
  227. //
  228. // We had a PDO, check if the device is still here
  229. //
  230. PDEVICE_EXTENSION ext = oldDevObj[idx]->DeviceExtension;
  231. PCHAR dot3InfString = Par3Get1284InfString( legacyExtension, idx );
  232. if( NULL == dot3InfString ) {
  233. //
  234. // We had a PDO, but now we don't detect any device
  235. //
  236. ParDump2(PARPNP1, ("rescan::ParRescan1284_3DaisyChain - DEVICE GONE - idx = %d\n", idx) );
  237. changeDetected = TRUE;
  238. break;
  239. } else {
  240. //
  241. // We had a PDO, but the device we detect differs from what we expected
  242. //
  243. if( 0 == strcmp( ext->DeviceIdString, dot3InfString ) ) {
  244. ParDump2(PARPNP1, ("rescan::ParRescan1284_3DaisyChain - DEVICE STILL THERE - idx = %d\n", idx) );
  245. } else {
  246. ParDump2(PARPNP1, ("rescan::ParRescan1284_3DaisyChain - DEVICE CHANGED - idx = %d\n", idx) );
  247. changeDetected = TRUE;
  248. }
  249. ExFreePool( dot3InfString );
  250. if( changeDetected ) {
  251. break;
  252. }
  253. }
  254. } // if( NULL != oldDevObj[idx] ...
  255. } // for( idx=0 ; ...
  256. } // if( oldDeviceCount != newDeviceCount ) {...} else {...}
  257. if( changeDetected ) {
  258. //
  259. // Mark all existing .3 PDOs for devices connected to the port as "hardware gone"
  260. //
  261. ParDump2(PARPNP1, ("rescan::ParRescan1284_3DaisyChain - CHANGE DETECTED\n") );
  262. for( idx=0 ; idx <= IEEE_1284_3_DAISY_CHAIN_MAX_ID ; ++idx ) {
  263. if( NULL != oldDevObj[idx] ) {
  264. ParDump2(PARPNP1, ("rescan::ParRescan1284_3DaisyChain - marking PDO %p as HARDWARE GONE\n", oldDevObj[idx]) );
  265. ParMarkPdoHardwareGone( oldDevObj[idx]->DeviceExtension );
  266. }
  267. }
  268. //
  269. // Create a new PDO for each .3 device.
  270. //
  271. for( idx = 0 ; idx < newDeviceCount ; ++idx ) {
  272. PDEVICE_OBJECT newDevObj;
  273. BOOLEAN bBuildStlDeviceId;
  274. bBuildStlDeviceId = ParStlCheckIfStl(legacyPodo->DeviceExtension, idx ) ;
  275. //
  276. // Select Device
  277. //
  278. status = ParSelect1284_3Device(portDeviceObject, idx);
  279. if( !NT_SUCCESS( status ) ) {
  280. ParDump2(PARPNP1, ("rescan::ParRescan1284_3DaisyChain - creating of new PDO for idx=%d FAILED\n", idx) );
  281. continue;
  282. }
  283. //
  284. // Create new PDO
  285. //
  286. newDevObj = ParDetectCreatePdo( legacyPodo, idx, bBuildStlDeviceId );
  287. //
  288. // Deselect Device
  289. //
  290. status = ParDeselect1284_3Device(portDeviceObject, idx);
  291. if( !NT_SUCCESS( status ) ) {
  292. ASSERTMSG("Unable to Deselect? - ParPort probably blocked now - this should never happen \n", FALSE);
  293. if( NULL != newDevObj ) {
  294. ParKillDeviceObject( newDevObj );
  295. newDevObj = NULL;
  296. }
  297. }
  298. //
  299. // Add new PDO to FDO's list of children
  300. //
  301. if( NULL != newDevObj ) {
  302. ParDump2(PARPNP1, ("rescan::ParRescan1284_3DaisyChain - adding new PDO %p - idx=%d to FDO list\n", newDevObj, idx) );
  303. ParAddDevObjToFdoList(newDevObj);
  304. } else {
  305. ParDump2(PARPNP1, ("rescan::ParRescan1284_3DaisyChain - creating of new PDO for idx=%d FAILED\n", idx) );
  306. }
  307. }
  308. }
  309. return;
  310. }
  311. VOID
  312. ParCreateDot3DeviceIdList(
  313. IN OUT PCHAR deviceIdArray[],
  314. IN PDEVICE_EXTENSION legacyExt,
  315. IN UCHAR dot3DeviceCount
  316. )
  317. {
  318. PDEVICE_OBJECT portDeviceObject = legacyExt->PortDeviceObject;
  319. NTSTATUS status;
  320. UCHAR idx=0;
  321. ULONG deviceIdSize;
  322. BOOLEAN bBuildStlDeviceId;
  323. ParDump2(PARPNP1, ("ParCreateDot3DeviceIdList() - Enter\n") );
  324. while( idx < dot3DeviceCount ) {
  325. bBuildStlDeviceId = ParStlCheckIfStl (legacyExt, idx) ;
  326. status = ParSelect1284_3Device(portDeviceObject, idx);
  327. if( NT_SUCCESS( status ) ) {
  328. ParDump2(PARPNP1, ("rescan::ParCreateDot3DeviceIdList: - select SUCCESS - idx=%d\n", idx) );
  329. deviceIdArray[idx] = Par3QueryDeviceId(legacyExt, NULL, 0, &deviceIdSize, FALSE, bBuildStlDeviceId);
  330. if(deviceIdArray[idx]) {
  331. ParDump2(PARPNP1, ("rescan::ParCreateDot3DeviceIdList: - id=<%s>\n", deviceIdArray[idx]) );
  332. } else {
  333. ParDump2(PARPNP1, ("rescan::ParCreateDot3DeviceIdList: - Par3QueryDeviceId FAILED\n") );
  334. }
  335. ParDeselect1284_3Device(portDeviceObject, idx);
  336. } else {
  337. ParDump2(PARPNP1, ("rescan::ParCreateDot3DeviceIdList: - select FAILED - idx=%d\n", idx) );
  338. deviceIdArray[idx] = NULL;
  339. }
  340. ++idx;
  341. }
  342. }
  343. NTSTATUS
  344. ParPnpFdoQueryDeviceRelationsBusRelations(
  345. IN PDEVICE_OBJECT Fdo,
  346. IN PIRP Irp
  347. )
  348. {
  349. NTSTATUS status;
  350. PDEVICE_EXTENSION fdoExt = Fdo->DeviceExtension;
  351. PPAR_DEVOBJ_STRUCT devObjStructHead = NULL;
  352. ULONG DeviceRelationsSize = 0;
  353. ULONG Idx = 0;
  354. PDEVICE_RELATIONS DeviceRelations = NULL;
  355. PDEVICE_OBJECT pNextDeviceObject; // used for walking the ParClass DO list
  356. PDEVICE_EXTENSION pExtension; // used for walking the ParClass DO list
  357. ParDump2(PARPNP1, ("ParFdoQueryDeviceRelationsBusRelations - Enter\n") );
  358. //
  359. // Build a list of PAR_DEVOBJ_STRUCTs, one per ParPort device,
  360. // from the FDO's list of device objects that were found connected
  361. // to the ports the last time we checked.
  362. //
  363. // Create FILE against each ParPort Device to prevent it from being
  364. // deleted out from under us.
  365. //
  366. ExAcquireFastMutex(&fdoExt->DevObjListMutex);
  367. devObjStructHead = ParBuildDevObjStructList(Fdo);
  368. devObjStructHead = ParLockPortDeviceObjects( devObjStructHead );
  369. ExReleaseFastMutex(&fdoExt->DevObjListMutex);
  370. if( !devObjStructHead ) {
  371. // something went wrong, likely either no parallel ports, or unable to alloc pool
  372. DDPnP1(("## ParPnpFdoQueryDeviceRelationsBusRelations - empty devObjStructHead - goto rescanComplete\n"));
  373. goto rescanComplete;
  374. }
  375. //
  376. // Dump the list of device objects that we have before rescan (debug only)
  377. //
  378. #if DBG
  379. ParDumpDevObjStructList(devObjStructHead);
  380. #endif
  381. //
  382. // Rescan all ports for changes in attached devices and
  383. // update the ParClass FDO's list of device objects accordingly.
  384. // (side effects - big time!!!)
  385. //
  386. ParDoParallelBusRescan(devObjStructHead);
  387. //
  388. // Close FDO FILEs against ParPort Devices (release FDO locks)
  389. //
  390. ParUnlockPortDeviceObjects(devObjStructHead);
  391. //
  392. // Delete the previous PAR_DEVOBJ_STRUCT list and create a
  393. // new list from the FDO's list of devices after the rescan.
  394. //
  395. ParDestroyDevObjStructList(devObjStructHead);
  396. ExAcquireFastMutex(&fdoExt->DevObjListMutex);
  397. devObjStructHead = ParBuildDevObjStructList(Fdo);
  398. ExReleaseFastMutex(&fdoExt->DevObjListMutex);
  399. if( !devObjStructHead ) {
  400. // something went wrong, likely either no parallel ports, or unable to alloc pool
  401. goto rescanComplete;
  402. }
  403. //
  404. // Dump the list of device objects that we have after rescan (debug only)
  405. //
  406. #if DBG
  407. ParDumpDevObjStructList(devObjStructHead);
  408. #endif
  409. //
  410. // Delete the PAR_DEVOBJ_STRUCT list, we no longer need it
  411. //
  412. ParDestroyDevObjStructList(devObjStructHead);
  413. rescanComplete:
  414. //
  415. // The rescan is now complete, report the current set of attached devices to PnP
  416. //
  417. //
  418. // Lock list while we scan it twice
  419. //
  420. ExAcquireFastMutex(&fdoExt->DevObjListMutex);
  421. //
  422. // Get list head
  423. //
  424. pNextDeviceObject = fdoExt->ParClassPdo;
  425. //
  426. // Walk list and count number of PDOs
  427. //
  428. while( pNextDeviceObject ) {
  429. pExtension = pNextDeviceObject->DeviceExtension;
  430. if ( pExtension->DeviceIdString[0] != 0 ) {
  431. Idx++;
  432. ParDump2(PARPNP1, ("found PDO %wZ - Extension: %x\n", &pExtension->SymbolicLinkName, pExtension) );
  433. ParDump2(PARPNP1, (" - %s\n", pExtension->DeviceIdString) );
  434. } else if ( pExtension->DeviceStateFlags & PAR_DEVICE_HARDWARE_GONE ) {
  435. ParDump2(PARPNP1, ("found PDO %wZ - marked HARDWARE_GONE - Extension: %x\n", &pExtension->SymbolicLinkName, pExtension) );
  436. ParDump2(PARPNP1, (" - %s\n", pExtension->DeviceIdString) );
  437. } else {
  438. ParDump2(PARPNP1, ("found PODO %wZ - Extension: %x\n", &pExtension->SymbolicLinkName, pExtension) );
  439. }
  440. pNextDeviceObject = pExtension->Next;
  441. }
  442. //
  443. // allocate and initialize pool to hold DeviceRelations
  444. //
  445. DeviceRelationsSize = sizeof(DEVICE_RELATIONS) + (Idx * sizeof(PDEVICE_OBJECT));
  446. DeviceRelations = ExAllocatePool(PagedPool, DeviceRelationsSize);
  447. if( !DeviceRelations ) {
  448. Irp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES;
  449. ExReleaseFastMutex(&fdoExt->DevObjListMutex);
  450. IoCompleteRequest(Irp, IO_NO_INCREMENT);
  451. ParReleaseRemoveLock(&fdoExt->RemoveLock, Irp);
  452. return STATUS_INSUFFICIENT_RESOURCES;
  453. }
  454. RtlZeroMemory(DeviceRelations, DeviceRelationsSize);
  455. //
  456. // Walk the list again to construct DeviceRelations
  457. //
  458. Idx = 0;
  459. pNextDeviceObject = fdoExt->ParClassPdo;
  460. while( pNextDeviceObject ) {
  461. pExtension = pNextDeviceObject->DeviceExtension;
  462. ParDump2(PARPNP1, ("rescan::ParPnpFdoQDR/BusRelations - Examining DO= %x , Ext= %x\n", pNextDeviceObject, pExtension));
  463. if( (pExtension->DeviceIdString[0] != 0) &&
  464. !(pExtension->DeviceStateFlags & PAR_DEVICE_HARDWARE_GONE) &&
  465. (pExtension->SymbolicLinkName.Length > 0) ) {
  466. // If this is a PDO, that is not marked "hardware gone", and has a SymbolicLink
  467. DeviceRelations->Objects[Idx++] = pNextDeviceObject;
  468. DeviceRelations->Count++;
  469. ParDump2(PARPNP1, ("adding PDO %x <%wZ> to DeviceRelations, new PDO count=%d\n",
  470. pNextDeviceObject, &pExtension->SymbolicLinkName,DeviceRelations->Count) );
  471. ASSERT( ( pExtension->SymbolicLinkName.Length > 0 ) );
  472. status = ObReferenceObjectByPointer(pNextDeviceObject, 0, NULL, KernelMode);
  473. if(!NT_SUCCESS(status)) {
  474. ParDumpP( ("Error Referencing PDO\n") );
  475. ExFreePool(DeviceRelations);
  476. Irp->IoStatus.Status = status;
  477. ExReleaseFastMutex(&fdoExt->DevObjListMutex); // error - release Mutex
  478. IoCompleteRequest(Irp, IO_NO_INCREMENT);
  479. ParReleaseRemoveLock(&fdoExt->RemoveLock, Irp);
  480. return status;
  481. }
  482. } else {
  483. ParDump2(PARPNP1, (" - skipping DO= %x\n", pNextDeviceObject));
  484. if( pExtension->DeviceStateFlags & PAR_DEVICE_HARDWARE_GONE ) {
  485. ParDump2(PARPNP1, (" - because PAR_DEVICE_HARDWARE_GONE\n"));
  486. } else if( pExtension->DeviceIdString[0] == 0 ) {
  487. ParDump2(PARPNP1, (" - because DeviceIdString[0] == 0 - may be a PODO\n"));
  488. } else if( pExtension->SymbolicLinkName.Length == 0 ) {
  489. ParDump2(PARPNP1, (" - because pExtension->SymbolicLinkName.Length == 0\n"));
  490. } else {
  491. ParDump2(PARPNP1, (" - WHY are we skipping this?\n"));
  492. ASSERT(FALSE);
  493. }
  494. }
  495. pNextDeviceObject = pExtension->Next;
  496. }
  497. ParDump2(PARPNP1, ("rescan::ParPnpFdoQDR/BusRelations - DeviceRelations->Count = %d\n", DeviceRelations->Count));
  498. //
  499. // SUCCESS - set IRP fields and pass the IRP down the stack
  500. //
  501. Irp->IoStatus.Information = (ULONG_PTR)DeviceRelations;
  502. Irp->IoStatus.Status = STATUS_SUCCESS;
  503. ExReleaseFastMutex(&fdoExt->DevObjListMutex); // done - release Mutex
  504. IoSkipCurrentIrpStackLocation(Irp);
  505. ParReleaseRemoveLock(&fdoExt->RemoveLock, Irp);
  506. ParDump2(PARPNP1, ("ParFdoQueryDeviceRelationsBusRelations - Leave\n") );
  507. return ParCallDriver(fdoExt->ParentDeviceObject, Irp);
  508. }
  509. PPAR_DEVOBJ_STRUCT
  510. ParBuildDevObjStructList(
  511. IN PDEVICE_OBJECT Fdo
  512. )
  513. /*++dvdf - code complete
  514. Routine Description:
  515. This routine creates a list of PAR_DEVOBJ_STRUCT structures and returns
  516. a pointer to the first structure. Each PAR_DEVOBJ_STRUCT describes
  517. all ParClass devices associated with a single PortPort device.
  518. Arguments:
  519. Fdo - points to the ParClass FDO
  520. Return Value:
  521. PPAR_DEVOBJ_STRUCT - on success, points to the first structure created.
  522. NULL - otherwise
  523. --*/
  524. {
  525. PPAR_DEVOBJ_STRUCT devObjStructHead = NULL;
  526. PDEVICE_EXTENSION fdoExt = Fdo->DeviceExtension;
  527. PDEVICE_OBJECT currentDo;
  528. PDEVICE_EXTENSION currentExt;
  529. ParDump2(PARPNP1, ("Enter ParBuildDevObjStructList()\n") );
  530. //
  531. // do a quick exit if there are no ParClass Created PODOs or PDOs
  532. //
  533. currentDo = fdoExt->ParClassPdo;
  534. if( !currentDo ) {
  535. ParDump2(PARPNP1, ("No ParClass PODOs or PDOs exist\n") );
  536. return NULL;
  537. }
  538. //
  539. // create an initial PAR_DEVOBJ_STRUCT
  540. //
  541. currentExt = currentDo->DeviceExtension;
  542. devObjStructHead = ParFindCreateDevObjStruct(NULL, currentExt->Controller);
  543. if( !devObjStructHead ) {
  544. return NULL;
  545. }
  546. //
  547. // walk linear list of ParClass created PODOs and PDOs and
  548. // create structured list of PAR_DEVOBJ_STRUCTs based on
  549. // Controller address and DevObj type
  550. //
  551. ParDump2(PARPNP1, ("walking FDO's list of created PODOs and PDOs\n") );
  552. while( currentDo ) {
  553. currentExt = currentDo->DeviceExtension;
  554. if( currentExt->DeviceStateFlags & PAR_DEVICE_HARDWARE_GONE ) {
  555. // this is a PDO that is waiting for PnP to send it a REMOVE, skip it
  556. ParDump2(PARPNP1, ("found PDO waiting to be REMOVEd - skipping - DO= %x , Ext= %x\n",
  557. currentDo, currentExt) );
  558. } else if( currentExt->DeviceIdString[0] == 0 ) {
  559. // this is a Legacy PODO
  560. ParDump2(PARPNP1, ("found PODO - DO= %x , Ext= %x , Controller=%x\n",
  561. currentDo, currentExt, currentExt->Controller) );
  562. ParAddPodoToDevObjStruct(devObjStructHead, currentDo);
  563. } else if( currentExt->EndOfChain ) {
  564. // this is an End-Of-Chain PDO
  565. ParDump2(PARPNP1, ("found EOC PDO - DO= %x , Ext= %x , Controller=%x\n",
  566. currentDo, currentExt, currentExt->Controller) );
  567. ParAddEndOfChainPdoToDevObjStruct(devObjStructHead, currentDo);
  568. } else if( currentExt->Ieee1284_3DeviceId == DOT3_LEGACY_ZIP_ID ) {
  569. // this is a Legacy Zip PDO
  570. ParDump2(PARPNP1, ("found LGZIP PDO - DO= %x , Ext= %x , Controller=%x\n",
  571. currentDo, currentExt, currentExt->Controller) );
  572. ParAddLegacyZipPdoToDevObjStruct(devObjStructHead, currentDo);
  573. } else {
  574. // this is a 1284.3 Daisy Chain PDO
  575. ParDump2(PARPNP1, ("found Dot3 DC PDO - DO= %x , Ext= %x , Controller=%x , Dot3ID=%d\n",
  576. currentDo, currentExt, currentExt->Controller, currentExt->Ieee1284_3DeviceId) );
  577. ParAddDot3PdoToDevObjStruct(devObjStructHead, currentDo);
  578. }
  579. currentDo = currentExt->Next;
  580. }
  581. //
  582. // It is possible for this function to construct a node with
  583. // a NULL LegacyPodo if the parport goes away while we still have a PDO
  584. // marked PAR_DEVICE_HARDWARE_GONE that is waiting to be cleaned up.
  585. //
  586. // Discard any such nodes that don't have a LegacyPodo since the lack of a
  587. // LegacyPodo indicates that the parport device is gone, and attempting to
  588. // communicate with the parport will likely bugcheck.
  589. //
  590. {
  591. PPAR_DEVOBJ_STRUCT currentNode = devObjStructHead;
  592. PPAR_DEVOBJ_STRUCT prevNode = NULL;
  593. while( currentNode ) {
  594. if( currentNode->LegacyPodo ) {
  595. // keep this node - advance pointers
  596. prevNode = currentNode;
  597. currentNode = currentNode->Next;
  598. } else {
  599. // no PODO? - remove this node
  600. PPAR_DEVOBJ_STRUCT delNode = currentNode;
  601. currentNode = currentNode->Next;
  602. if( prevNode ) {
  603. // node to be removed is not first node - link around node to be deleted
  604. prevNode->Next = currentNode;
  605. } else {
  606. // node to be removed was head of list - update list head
  607. devObjStructHead = currentNode;
  608. }
  609. ExFreePool( delNode );
  610. } // end if/else currentNode->LegacyPodo
  611. } // end while currentNode
  612. } // end localblock
  613. return devObjStructHead;
  614. }
  615. VOID
  616. ParAddPodoToDevObjStruct(
  617. IN PPAR_DEVOBJ_STRUCT DevObjStructHead,
  618. IN PDEVICE_OBJECT CurrentDo
  619. )
  620. {
  621. PDEVICE_EXTENSION ext = CurrentDo->DeviceExtension;
  622. PPAR_DEVOBJ_STRUCT node = ParFindCreateDevObjStruct(DevObjStructHead, ext->Controller);
  623. if( node ) {
  624. node->LegacyPodo = CurrentDo;
  625. }
  626. return;
  627. }
  628. VOID
  629. ParAddEndOfChainPdoToDevObjStruct(
  630. IN PPAR_DEVOBJ_STRUCT DevObjStructHead,
  631. IN PDEVICE_OBJECT CurrentDo
  632. )
  633. {
  634. PDEVICE_EXTENSION ext = CurrentDo->DeviceExtension;
  635. PPAR_DEVOBJ_STRUCT node = ParFindCreateDevObjStruct(DevObjStructHead, ext->Controller);
  636. if( node ) {
  637. node->EndOfChainPdo = CurrentDo;
  638. }
  639. return;
  640. }
  641. VOID
  642. ParAddLegacyZipPdoToDevObjStruct(
  643. IN PPAR_DEVOBJ_STRUCT DevObjStructHead,
  644. IN PDEVICE_OBJECT CurrentDo
  645. )
  646. {
  647. PDEVICE_EXTENSION ext = CurrentDo->DeviceExtension;
  648. PPAR_DEVOBJ_STRUCT node = ParFindCreateDevObjStruct(DevObjStructHead, ext->Controller);
  649. if( node ) {
  650. ParDump2(PARPNP1, ("rescan::ParAddLegacyZipPdoToDevObjStruct - Controller=%x\n", ext->Controller) );
  651. node->LegacyZipPdo = CurrentDo;
  652. }
  653. return;
  654. }
  655. VOID
  656. ParAddDot3PdoToDevObjStruct(
  657. IN PPAR_DEVOBJ_STRUCT DevObjStructHead,
  658. IN PDEVICE_OBJECT CurrentDo
  659. )
  660. {
  661. PDEVICE_EXTENSION ext = CurrentDo->DeviceExtension;
  662. PPAR_DEVOBJ_STRUCT node = ParFindCreateDevObjStruct(DevObjStructHead, ext->Controller);
  663. if( node ) {
  664. *( (&node->Dot3Id0Pdo) + (ext->Ieee1284_3DeviceId) ) = CurrentDo;
  665. }
  666. return;
  667. }
  668. PPAR_DEVOBJ_STRUCT ParFindCreateDevObjStruct(
  669. IN PPAR_DEVOBJ_STRUCT DevObjStructHead,
  670. IN PUCHAR Controller
  671. )
  672. /*++
  673. Routine Description:
  674. This function searches a list of PAR_DEVOBJ_STRUCTs for a
  675. PAR_DEVOBJ_STRUCT whose Controller field matches the Controller
  676. parameter.
  677. If no match is found, then a new PAR_DEVOBJ_STRUCT that matches
  678. is created, initialized (Controller field set, other fields
  679. initialized to NULL), and appended to the end of the list.
  680. Arguments:
  681. DevObjStructHead - points to the head of the list to be searched
  682. - NULL indicates that we should create an initial
  683. element for the list
  684. Controller - specifies the Controller that we should try to match
  685. Return Value:
  686. PPAR_DEVOBJ_STRUCT - on success, points to a PAR_DEVOBJ_STRUCT whose
  687. Controller field matches the Controller parameter
  688. NULL - insufficient resources failure (ExAllocatePool failed)
  689. --*/
  690. {
  691. PPAR_DEVOBJ_STRUCT current;
  692. PPAR_DEVOBJ_STRUCT previous;
  693. ParDump2(PARPNP1, ("rescan::ParFindCreateDevObjStruct - Enter\n"));
  694. //
  695. // If list is empty, create the initial element and return a pointer to it.
  696. //
  697. if( !DevObjStructHead ) {
  698. ParDump2(PARPNP1, ("rescan::ParFindCreateDevObjStruct - Empty List - Creating Initial Element - %x\n", Controller));
  699. current = ExAllocatePool(PagedPool, sizeof(PAR_DEVOBJ_STRUCT));
  700. if( !current ) {
  701. return NULL; // insufficient resources
  702. }
  703. RtlZeroMemory(current, sizeof(PAR_DEVOBJ_STRUCT));
  704. current->Controller = Controller;
  705. return current;
  706. }
  707. //
  708. // list is not empty - scan for a matching Controller
  709. //
  710. current = DevObjStructHead;
  711. while( current ) {
  712. if( current->Controller == Controller ) {
  713. break; // found match, break out of loop
  714. }
  715. previous = current; // not found, advance pointers to next element
  716. current = current->Next;
  717. }
  718. //
  719. // did we find a match?
  720. //
  721. if( current ) {
  722. ParDump2(PARPNP1, ("rescan::ParFindCreateDevObjStruct - Found Match - %x\n", Controller));
  723. return current; // we found a match, return pointer to it
  724. }
  725. //
  726. // we didn't find a match, create a new list item, append it to the list,
  727. // and return a pointer to it
  728. //
  729. current = ExAllocatePool(PagedPool, sizeof(PAR_DEVOBJ_STRUCT));
  730. if( !current ) {
  731. return NULL; // insufficient resources
  732. }
  733. RtlZeroMemory(current, sizeof(PAR_DEVOBJ_STRUCT));
  734. current->Controller = Controller;
  735. previous->Next = current;
  736. ParDump2(PARPNP1, ("rescan::ParFindCreateDevObjStruct - Match not found - Creating New - %x\n", Controller));
  737. return current;
  738. }
  739. VOID
  740. ParDestroyDevObjStructList(
  741. IN PPAR_DEVOBJ_STRUCT DevObjStructHead
  742. )
  743. {
  744. PPAR_DEVOBJ_STRUCT current = DevObjStructHead;
  745. PPAR_DEVOBJ_STRUCT next;
  746. while( current ) {
  747. next = current->Next;
  748. ExFreePool( current );
  749. current = next;
  750. }
  751. }
  752. VOID
  753. ParDoParallelBusRescan(
  754. IN PPAR_DEVOBJ_STRUCT DevObjStructHead
  755. )
  756. /*++
  757. Routine Description:
  758. This routine rescans the parallel port "buses" for
  759. changes in the PnP devices connected to each parallel port.
  760. Arguments:
  761. DevObjStructHead - points to a list of structures where each structure
  762. contains info about a single parallel port
  763. Return Value:
  764. None.
  765. --*/
  766. {
  767. PPAR_DEVOBJ_STRUCT currentNode = DevObjStructHead;
  768. PDEVICE_OBJECT legacyPodo;
  769. PDEVICE_EXTENSION legacyExt;
  770. NTSTATUS status;
  771. LARGE_INTEGER acquirePortTimeout;
  772. //
  773. // Process each parallel port (controller)
  774. //
  775. while( currentNode ) {
  776. legacyPodo = currentNode->LegacyPodo;
  777. if( NULL == legacyPodo ) {
  778. //
  779. // associated ParPort device object has been removed, so skip
  780. // processing of this PAR_DEVOBJ_STRUCT
  781. //
  782. ParDump2(PARPNP1, ("ParDoParallelBusRescan - NULL legacyPodo for Controller=%x"
  783. " - skipping rescan of this port\n",
  784. currentNode->Controller) );
  785. currentNode = currentNode->Next;
  786. continue;
  787. }
  788. legacyExt = legacyPodo->DeviceExtension;
  789. //
  790. // Acquire the port from ParPort
  791. //
  792. // timeout is in 100 ns units
  793. acquirePortTimeout.QuadPart = -(10 * 1000 * 1000 * 2); // 2 seconds
  794. status = ParAcquirePort(legacyExt->PortDeviceObject, &acquirePortTimeout);
  795. if( !NT_SUCCESS(status) ) {
  796. ParDump2(PARPNP1, ("ParDoParallelBusRescan - Unable to acquire port/"
  797. "Controller=%x - skipping rescan of this port\n",
  798. currentNode->Controller) );
  799. currentNode = currentNode->Next;
  800. continue;
  801. }
  802. //
  803. // Port is acquired
  804. //
  805. //
  806. // Rescan for change in End-Of-Chain Device
  807. //
  808. ParRescanEndOfChain( currentNode );
  809. //
  810. // Rescan for changes in 1284.3 Daisy Chain Devices
  811. //
  812. // ParRescan1284_3DaisyChain(currentNode);
  813. dot3rescan( currentNode );
  814. //
  815. // Rescan for change in Legacy Zip Drive
  816. //
  817. {
  818. ULONG OldParEnableLegacyZipFlag = ParEnableLegacyZip;
  819. ParCheckEnableLegacyZipFlag();
  820. if( (OldParEnableLegacyZipFlag == 1) && (ParEnableLegacyZip == 0) ) {
  821. // We can handle enable ( 0 -> 1 ) without a reboot, but not disable ( 1 -> 0 )
  822. ParEnableLegacyZip = OldParEnableLegacyZipFlag;
  823. }
  824. ParRescanLegacyZip( currentNode );
  825. }
  826. //
  827. // Release the port back to ParPort
  828. //
  829. status = ParReleasePort( legacyExt->PortDeviceObject );
  830. if( !NT_SUCCESS(status) ) {
  831. ASSERTMSG("Unable to free port??? - this should never happen ", FALSE);
  832. }
  833. //
  834. // Advance pointer to next PAR_DEVOBJ_STRUCT
  835. //
  836. currentNode = currentNode->Next;
  837. } // end while
  838. }
  839. VOID
  840. ParRescanEndOfChain(
  841. IN PPAR_DEVOBJ_STRUCT CurrentNode
  842. )
  843. {
  844. PDEVICE_OBJECT legacyPodo = CurrentNode->LegacyPodo;
  845. PDEVICE_EXTENSION legacyExt = legacyPodo->DeviceExtension;
  846. PUCHAR deviceId;
  847. ULONG deviceIdLength;
  848. UCHAR resultString[MAX_ID_SIZE];
  849. NTSTATUS status;
  850. ULONG deviceIdTryCount = 1;
  851. ULONG maxIdTries = 3;
  852. // Query for an End-Of-Chain 1284 device ID
  853. retryDeviceIdQuery:
  854. deviceId = Par3QueryDeviceId(legacyExt, NULL, 0, &deviceIdLength, FALSE, FALSE);
  855. if( ( deviceId == NULL ) && ( deviceIdTryCount < maxIdTries ) ) {
  856. //
  857. // we didn't find a device - give any device that might be connected
  858. // another chance to tell us that it is there
  859. //
  860. ParDump2(PARRESCAN, ("rescan::ParRescanEndOfChain - no EOC detected on "
  861. "try %d - retrying 1284 id query\n", deviceIdTryCount) );
  862. ++deviceIdTryCount;
  863. KeStallExecutionProcessor(1); // allow the signals on the wires to stabilize
  864. goto retryDeviceIdQuery;
  865. }
  866. //
  867. // Done with retries, we either found a device or we did not.
  868. //
  869. if( !deviceId ) {
  870. //
  871. // We didn't find an EOC device
  872. //
  873. if( CurrentNode->EndOfChainPdo ) {
  874. //
  875. // we had a device but now it is gone - mark extension as "hardware gone"
  876. //
  877. ParDump2(PARRESCAN, ("rescan::ParRescanEndOfChain - EOC device went away\n"));
  878. ParMarkPdoHardwareGone(CurrentNode->EndOfChainPdo->DeviceExtension);
  879. } else {
  880. ParDump2(PARRESCAN, ("rescan::ParRescanEndOfChain - No end of chain device detected\n"));
  881. }
  882. } else {
  883. //
  884. // we found an EOC device
  885. //
  886. ParDump2(PARRESCAN, ("rescan::ParRescanEndOfChain - EOC device detected - tries required == %d\n",deviceIdTryCount));
  887. ParDump2(PARRESCAN, ("\"RAW\" ID string = <%s>\n", deviceId) );
  888. //
  889. // did we already have an EOC device?
  890. //
  891. if( CurrentNode->EndOfChainPdo ) {
  892. //
  893. // we already had an EOC device - compare its ID from its extension
  894. // with the ID we just read from the hardware
  895. //
  896. PDEVICE_EXTENSION endOfChainExt = CurrentNode->EndOfChainPdo->DeviceExtension;
  897. //
  898. // massage the ID read from the hardware into the form needed for compare
  899. //
  900. RtlZeroMemory(resultString, MAX_ID_SIZE);
  901. status = ParPnpGetId(deviceId, BusQueryDeviceID, resultString, NULL);
  902. if( NT_SUCCESS(status) ) {
  903. //
  904. // massage succeeded - do compare
  905. //
  906. if(0 == strcmp(endOfChainExt->DeviceIdString, resultString)) {
  907. //
  908. // id matches - we found the same device we previously found
  909. //
  910. } else {
  911. //
  912. // id differs - we have different device that we previously had
  913. //
  914. // mark previous device extension as "hardware gone"
  915. //
  916. ParMarkPdoHardwareGone(CurrentNode->EndOfChainPdo->DeviceExtension);
  917. //
  918. // create device object for new device and add it to FDO's list
  919. //
  920. ParDetectCreateEndOfChainPdo(legacyPodo);
  921. }
  922. } else {
  923. // massage failed - unable to extract valid ID
  924. // mark previous extension as "hardware gone"
  925. ParMarkPdoHardwareGone(CurrentNode->EndOfChainPdo->DeviceExtension);
  926. }
  927. } else {
  928. // we didn't have an EOC device on previous scan, but ID detected on this scan
  929. // create device object for new device and add it to FDO's list
  930. ParDetectCreateEndOfChainPdo(legacyPodo);
  931. }
  932. ExFreePool( deviceId );
  933. } // end if/else ( !deviceId ) - end of chain device rescan complete for this port
  934. }
  935. #if 0
  936. VOID
  937. ParRescan1284_3DaisyChain(
  938. IN PPAR_DEVOBJ_STRUCT CurrentNode
  939. )
  940. {
  941. PDEVICE_OBJECT legacyPodo = CurrentNode->LegacyPodo;
  942. PDEVICE_EXTENSION legacyExt = legacyPodo->DeviceExtension;
  943. PDEVICE_OBJECT portDeviceObject = legacyExt->PortDeviceObject;
  944. PDEVICE_OBJECT currentDeviceObject;
  945. UCHAR newDot3DeviceCount;
  946. NTSTATUS status;
  947. UCHAR idx;
  948. UCHAR oldDot3DeviceCount;
  949. PUCHAR deviceId;
  950. ULONG deviceIdLength;
  951. UCHAR tempIdBuffer[MAX_ID_SIZE];
  952. PCHAR deviceIdArray[IEEE_1284_3_DAISY_CHAIN_MAX_ID+1] = {NULL,NULL,NULL,NULL};
  953. BOOLEAN chainWasBroken;
  954. UCHAR firstDeviceGone;
  955. ParDump2(PARPNP1, ("rescan::ParRescan1284_3DaisyChain - Enter\n") );
  956. //
  957. // Count the number of .3 daisy chain devices we had on last scan
  958. // of this port
  959. //
  960. idx = 0;
  961. while( NULL != *( (&CurrentNode->Dot3Id0Pdo) + idx ) ) {
  962. ++idx;
  963. }
  964. oldDot3DeviceCount = idx;
  965. ParDump2(PARPNP1, ("rescan::ParRescan1284_3DaisyChain - Dot3 DeviceCount Before Rescan = %d\n", idx) );
  966. //
  967. // Walk the daisy chain and verify that each device is still here
  968. //
  969. chainWasBroken = FALSE;
  970. idx=0;
  971. while( idx < oldDot3DeviceCount ) {
  972. PDEVICE_OBJECT curDevObj = *( (&CurrentNode->Dot3Id0Pdo) + idx );
  973. PDEVICE_EXTENSION curDevExt = curDevObj->DeviceExtension;
  974. if( ParDeviceExists( curDevExt, HAVE_PORT_KEEP_PORT ) ) {
  975. ParDump2(PARPNP1, ("rescan::ParRescan1284_3DaisyChain - Dot3 device %d still there\n", idx) );
  976. ++idx;
  977. } else {
  978. ParDump2(PARPNP1, ("rescan::ParRescan1284_3DaisyChain - Dot3 device %d GONE - chain broken\n", idx) );
  979. chainWasBroken=TRUE;
  980. firstDeviceGone = idx;
  981. break;
  982. }
  983. }
  984. //
  985. // If chain was broken, nuke PDO for missing device and for all
  986. // .3 daisy chain devices connected beyond that device in
  987. // the daisy chain.
  988. //
  989. if( chainWasBroken ) {
  990. for( idx = firstDeviceGone ; idx < oldDot3DeviceCount ; ++idx ) {
  991. PDEVICE_OBJECT curDevObj = *( (&CurrentNode->Dot3Id0Pdo) + idx );
  992. PDEVICE_EXTENSION curDevExt = curDevObj->DeviceExtension;
  993. ParDump2(PARPNP1, ("rescan::ParRescan1284_3DaisyChain - Nuking DevObj= %x , idx=%d\n", curDevObj, idx) );
  994. ParMarkPdoHardwareGone( curDevExt );
  995. *( (&CurrentNode->Dot3Id0Pdo) + idx ) = NULL;
  996. --oldDot3DeviceCount;
  997. }
  998. ParDump2(PARPNP1, ("rescan::ParRescan1284_3DaisyChain - Dot3 DeviceCount - post-Nuking= %d\n", oldDot3DeviceCount) );
  999. }
  1000. //
  1001. // Step through the list of Dot3 device objects associated with
  1002. // this port, read the device ID from the corresponding device and
  1003. // compare with the ID stored in the device extension. Mark any
  1004. // device extension whose device doesn't answer the query or
  1005. // answers the query with a different ID than the one in the
  1006. // extension as "hardware gone".
  1007. //
  1008. //
  1009. // Reinitialize 1284.3 daisy chain device IDs
  1010. //
  1011. ParDump2(PARPNP1, ("rescan::ParRescan1284_3DaisyChain - reinitializing Dot3 bus\n") );
  1012. status = ParInit1284_3Bus(portDeviceObject);
  1013. if( !NT_SUCCESS(status) ) {
  1014. ASSERT(FALSE); // this should never happen
  1015. return;
  1016. }
  1017. //
  1018. // Get count of 1284.3 daisy chain devices connected to port
  1019. //
  1020. newDot3DeviceCount = ParGet1284_3DeviceCount(legacyExt->PortDeviceObject);
  1021. ParDump2(PARPNP1, ("rescan::ParRescan1284_3DaisyChain - newDot3DeviceCount = %d\n", newDot3DeviceCount) );
  1022. //
  1023. // scan for 1284.3 daisy chain changes
  1024. //
  1025. for(idx = 0 ; idx <= IEEE_1284_3_DAISY_CHAIN_MAX_ID ; ++idx) {
  1026. // get a pointer to the existing 1284.3 dc device object, if any
  1027. PDEVICE_OBJECT devObj = *( (&CurrentNode->Dot3Id0Pdo) + idx );
  1028. PDEVICE_EXTENSION devExt;
  1029. if( (devObj == NULL) && ( idx >= newDot3DeviceCount ) ) {
  1030. // no device object, no device, done, exit loop early
  1031. ParDump2(PARPNP2, ("rescan::ParRescan1284_3DaisyChain - idx = %d, no DO - no device - exit loop early\n",idx) );
  1032. break;
  1033. } else if( (devObj == NULL) && ( idx < newDot3DeviceCount ) ) {
  1034. //
  1035. // no device object, but we have a device
  1036. // - create new device object
  1037. //
  1038. ParDump2(PARPNP2, ("rescan::ParRescan1284_3DaisyChain - idx = %d, no DO - have device - create device\n",idx) );
  1039. {
  1040. PDEVICE_OBJECT newPdo;
  1041. ParDump2(PARPNP2, ("rescan::ParRescan1284_3DaisyChain - selecting idx = %d\n",idx) );
  1042. status = ParSelect1284_3Device(legacyExt->PortDeviceObject, idx);
  1043. if( NT_SUCCESS( status ) ) {
  1044. ParDump2(PARPNP2, ("rescan::ParRescan1284_3DaisyChain - select succeeded on idx=%d\n",idx) );
  1045. ParDump2(PARPNP2, ("rescan::ParRescan1284_3DaisyChain - creating PDO for idx=%d\n",idx) );
  1046. newPdo = ParDetectCreatePdo(legacyPodo, idx);
  1047. // add to FDO list
  1048. if( newPdo ) {
  1049. ParDump2(PARPNP2, ("rescan::ParRescan1284_3DaisyChain - PDO %x created for idx=%d\n", newPdo, idx) );
  1050. ParDump2(PARPNP2, ("rescan::ParRescan1284_3DaisyChain - adding new Dot3 PDO to FDO list\n") );
  1051. ParAddDevObjToFdoList(newPdo);
  1052. } else {
  1053. ParDump2(PARPNP2, ("rescan::ParRescan1284_3DaisyChain - create of PDO for idx=%d FAILED\n", idx) );
  1054. }
  1055. ParDump2(PARPNP2, ("rescan::ParRescan1284_3DaisyChain - deselecting idx = %d\n",idx) );
  1056. status = ParDeselect1284_3Device(legacyExt->PortDeviceObject, idx);
  1057. if( !NT_SUCCESS( status ) ) {
  1058. ASSERTMSG("DESELECT FAILED??? - This should never happen ", FALSE);
  1059. }
  1060. } else {
  1061. ParDump2(PARPNP2, ("rescan::ParRescan1284_3DaisyChain - select FAILED on idx=%d\n",idx) );
  1062. }
  1063. }
  1064. } else if( (devObj != NULL) && ( idx >= newDot3DeviceCount ) ) {
  1065. //
  1066. // have a device object, but no device - this should not happen
  1067. // because we should have cleaned up in the code above
  1068. //
  1069. ASSERT(FALSE);
  1070. } else if( (devObj != NULL) && ( idx < newDot3DeviceCount ) ) {
  1071. // have a device object and a device
  1072. devExt = devObj->DeviceExtension;
  1073. // - compare ID's between device object and device
  1074. ParDump2(PARPNP2, ("rescan::ParRescan1284_3DaisyChain - idx = %d, have DO - have device - compare id's\n",idx) );
  1075. // do 1284.3 selection to select the device
  1076. status = ParSelect1284_3Device(portDeviceObject, idx);
  1077. if( NT_SUCCESS( status ) ) {
  1078. // device selected
  1079. // query ID from device
  1080. deviceId = Par3QueryDeviceId(legacyExt, NULL, 0, &deviceIdLength, FALSE);
  1081. // deselect the 1284.3 dc device
  1082. status = ParDeselect1284_3Device(portDeviceObject, idx);
  1083. if( !NT_SUCCESS(status) ) {
  1084. // deselect should not fail, however not much we can do except complain if it does
  1085. ParDump2(PARERRORS, ("rescan::ParRescan1284_3DaisyChain - call to ParDeselect1284_3Device() FAILED\n") );
  1086. }
  1087. // did we get a device id from the hardware?
  1088. if( deviceId ) {
  1089. // massage deviceId into format saved in extension
  1090. RtlZeroMemory(tempIdBuffer, sizeof(tempIdBuffer));
  1091. status = ParPnpGetId(deviceId, BusQueryDeviceID, tempIdBuffer, NULL);
  1092. if( !NT_SUCCESS(status) ) {
  1093. // RMT - don't bother to compare
  1094. sprintf(tempIdBuffer, "rescan::ParRescan1284_3DaisyChain - ParPnpGetId Failed - don't compare\0");
  1095. }
  1096. // got a device id from hardware - do compare
  1097. ParDump2(PARPNP2, ("rescan::ParRescan1284_3DaisyChain - device id = <%s>\n", tempIdBuffer) );
  1098. ParDump2(PARPNP2, ("rescan::ParRescan1284_3DaisyChain - ext id = <%s>\n", devExt->DeviceIdString) );
  1099. devExt = devObj->DeviceExtension;
  1100. if( strcmp(tempIdBuffer, devExt->DeviceIdString) == 0 ) {
  1101. // match - do nothing - device is same that was there before rescan
  1102. ParDump2(PARPNP2, ("rescan::ParRescan1284_3DaisyChain - MATCH - KEEP device, idx=%d\n", idx) );
  1103. } else {
  1104. PDEVICE_OBJECT newPdo;
  1105. // no match
  1106. ParDump2(PARPNP2, ("rescan::ParRescan1284_3DaisyChain - "
  1107. "NO MATCH - mark hardware gone and create new device, idx = %d\n", idx) );
  1108. // - mark device object as hardware gone
  1109. devExt = devObj->DeviceExtension;
  1110. ParMarkPdoHardwareGone( devExt );
  1111. // - create device object for new device
  1112. newPdo = ParDetectCreatePdo(legacyPodo, idx);
  1113. // add to FDO list
  1114. if( newPdo ) {
  1115. ParDump2(PARPNP2, ("rescan::ParRescan1284_3DaisyChain - adding new Dot3 PDO to FDO list\n") );
  1116. ParAddDevObjToFdoList(newPdo);
  1117. }
  1118. }
  1119. // done with temp ID string
  1120. ExFreePool( deviceId );
  1121. } else {
  1122. // unable to read device id
  1123. ParDump2(PARPNP2, ("rescan::ParRescan1284_3DaisyChain - didn't get device id, idx=%d\n", idx) );
  1124. // - mark device object as hardware gone
  1125. devExt = devObj->DeviceExtension;
  1126. ParMarkPdoHardwareGone( devExt );
  1127. }
  1128. } else {
  1129. // unable to select device
  1130. ParDump2(PARPNP2, ("rescan::ParRescan1284_3DaisyChain - unable to select device, idx=%d\n", idx) );
  1131. // - mark device object as hardware gone
  1132. devExt = devObj->DeviceExtension;
  1133. ParMarkPdoHardwareGone( devExt );
  1134. }
  1135. } // end if have a device object and a device
  1136. } // end for(idx = 0 ; ...)
  1137. }
  1138. #endif // 0