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.

1633 lines
41 KiB

  1. /*++
  2. Copyright (c) 1990-1995 Microsoft Corporation
  3. Module Name:
  4. miniport.c
  5. Abstract:
  6. NDIS miniport wrapper functions
  7. Author:
  8. Sean Selitrennikoff (SeanSe) 05-Oct-93
  9. Jameel Hyder (JameelH) Re-organization 01-Jun-95
  10. Environment:
  11. Kernel mode, FSD
  12. Revision History:
  13. --*/
  14. #include <precomp.h>
  15. #pragma hdrstop
  16. //
  17. // Define the module number for debug code.
  18. //
  19. #define MODULE_NUMBER MODULE_MININT
  20. /////////////////////////////////////////////////////////////////////
  21. //
  22. // HALT / CLOSE CODE
  23. //
  24. /////////////////////////////////////////////////////////////////////
  25. BOOLEAN
  26. FASTCALL
  27. ndisMKillOpen(
  28. IN PNDIS_OPEN_BLOCK Open
  29. )
  30. /*++
  31. Routine Description:
  32. Closes an open. Used when NdisCloseAdapter is called.
  33. Arguments:
  34. Open - The open to be closed.
  35. Return Value:
  36. TRUE if the open finished, FALSE if it pended.
  37. Comments:
  38. called at passive level -without- miniport's lock held.
  39. --*/
  40. {
  41. PNDIS_MINIPORT_BLOCK Miniport = Open->MiniportHandle;
  42. PNDIS_OPEN_BLOCK tmpOpen;
  43. ULONG newWakeUpEnable;
  44. BOOLEAN rc = TRUE;
  45. NDIS_STATUS Status;
  46. UINT OpenRef;
  47. KIRQL OldIrql;
  48. DBGPRINT_RAW(DBG_COMP_INIT, DBG_LEVEL_INFO,
  49. ("==>ndisMKillOpen: Open %p\n", Open));
  50. ASSERT(ndisPkgs[NPNP_PKG].ReferenceCount > 0);
  51. PnPReferencePackage();
  52. KeRaiseIrql(DISPATCH_LEVEL, &OldIrql);
  53. NDIS_ACQUIRE_MINIPORT_SPIN_LOCK_DPC(Miniport);
  54. //
  55. // Find the Miniport open block
  56. //
  57. for (tmpOpen = Miniport->OpenQueue;
  58. tmpOpen != NULL;
  59. tmpOpen = tmpOpen->MiniportNextOpen)
  60. {
  61. if (tmpOpen == Open)
  62. {
  63. break;
  64. }
  65. }
  66. NDIS_RELEASE_MINIPORT_SPIN_LOCK_DPC(Miniport);
  67. do
  68. {
  69. ASSERT(tmpOpen != NULL);
  70. if (tmpOpen == NULL)
  71. break;
  72. //
  73. // See if this open is already closing.
  74. //
  75. ACQUIRE_SPIN_LOCK_DPC(&Open->SpinLock);
  76. if (MINIPORT_TEST_FLAG(Open, fMINIPORT_OPEN_CLOSING))
  77. {
  78. RELEASE_SPIN_LOCK_DPC(&Open->SpinLock);
  79. break;
  80. }
  81. //
  82. // Indicate to others that this open is closing.
  83. //
  84. MINIPORT_SET_FLAG(Open, fMINIPORT_OPEN_CLOSING);
  85. RELEASE_SPIN_LOCK_DPC(&Open->SpinLock);
  86. NDIS_ACQUIRE_MINIPORT_SPIN_LOCK_DPC(Miniport);
  87. BLOCK_LOCK_MINIPORT_DPC_L(Miniport);
  88. //
  89. // Remove us from the filter package
  90. //
  91. switch (Miniport->MediaType)
  92. {
  93. #if ARCNET
  94. case NdisMediumArcnet878_2:
  95. if (!MINIPORT_TEST_FLAG(Open,
  96. fMINIPORT_OPEN_USING_ETH_ENCAPSULATION))
  97. {
  98. Status = ArcDeleteFilterOpenAdapter(Miniport->ArcDB,
  99. Open->FilterHandle,
  100. NULL);
  101. break;
  102. }
  103. //
  104. // If we're using encapsulation then we
  105. // didn't open an arcnet filter but rather
  106. // an ethernet filter.
  107. //
  108. #endif
  109. case NdisMedium802_3:
  110. Status = EthDeleteFilterOpenAdapter(Miniport->EthDB,
  111. Open->FilterHandle);
  112. break;
  113. case NdisMedium802_5:
  114. Status = TrDeleteFilterOpenAdapter(Miniport->TrDB,
  115. Open->FilterHandle);
  116. break;
  117. case NdisMediumFddi:
  118. Status = FddiDeleteFilterOpenAdapter(Miniport->FddiDB,
  119. Open->FilterHandle);
  120. break;
  121. default:
  122. Status = nullDeleteFilterOpenAdapter(Miniport->NullDB,
  123. Open->FilterHandle);
  124. break;
  125. }
  126. //
  127. // Fix up flags that are dependant on all opens.
  128. //
  129. //
  130. // preserve the state of NDIS_PNP_WAKE_UP_MAGIC_PACKET and NDIS_PNP_WAKE_UP_LINK_CHANGE flag
  131. //
  132. newWakeUpEnable = Miniport->WakeUpEnable & (NDIS_PNP_WAKE_UP_MAGIC_PACKET | NDIS_PNP_WAKE_UP_LINK_CHANGE);
  133. for (tmpOpen = Miniport->OpenQueue;
  134. tmpOpen != NULL;
  135. tmpOpen = tmpOpen->MiniportNextOpen)
  136. {
  137. //
  138. // We don't want to include the open that is closing.
  139. //
  140. if (tmpOpen != Open)
  141. {
  142. newWakeUpEnable |= tmpOpen->WakeUpEnable;
  143. }
  144. }
  145. //
  146. // Reset the filter settings. Just to be sure that we remove the
  147. // opens settings at the adapter.
  148. //
  149. switch (Miniport->MediaType)
  150. {
  151. case NdisMedium802_3:
  152. case NdisMedium802_5:
  153. case NdisMediumFddi:
  154. #if ARCNET
  155. case NdisMediumArcnet878_2:
  156. #endif
  157. if (!MINIPORT_PNP_TEST_FLAG(Miniport, fMINIPORT_REMOVE_IN_PROGRESS | fMINIPORT_PM_HALTED))
  158. {
  159. ndisMRestoreFilterSettings(Miniport, Open, FALSE);
  160. }
  161. break;
  162. }
  163. DBGPRINT_RAW(DBG_COMP_BIND, DBG_LEVEL_INFO,
  164. ("!=0 Open 0x%x References 0x%x\n", Open, Open->References));
  165. if (Status != NDIS_STATUS_CLOSING_INDICATING)
  166. {
  167. //
  168. // Otherwise the close action routine will fix this up.
  169. //
  170. DBGPRINT_RAW(DBG_COMP_BIND, DBG_LEVEL_INFO,
  171. ("- Open 0x%x Reference 0x%x\n", Open, Open->References));
  172. M_OPEN_DECREMENT_REF_INTERLOCKED(Open, OpenRef);
  173. }
  174. rc = FALSE;
  175. if (OpenRef != 0)
  176. {
  177. ndisMDoRequests(Miniport);
  178. UNLOCK_MINIPORT_L(Miniport);
  179. }
  180. else
  181. {
  182. UNLOCK_MINIPORT_L(Miniport);
  183. ndisMFinishClose(Open);
  184. }
  185. NDIS_RELEASE_MINIPORT_SPIN_LOCK_DPC(Miniport);
  186. } while (FALSE);
  187. DBGPRINT_RAW(DBG_COMP_INIT, DBG_LEVEL_INFO,
  188. ("<==ndisMKillOpen: Open %p, rc %ld\n", Open, rc));
  189. KeLowerIrql(OldIrql);
  190. PnPDereferencePackage();
  191. return rc;
  192. }
  193. VOID
  194. FASTCALL
  195. ndisMFinishClose(
  196. IN PNDIS_OPEN_BLOCK Open
  197. )
  198. /*++
  199. Routine Description:
  200. Finishes off a close adapter call. it is called when the ref count on the open
  201. drops to zero.
  202. CALLED WITH LOCK HELD!!
  203. Arguments:
  204. Miniport - The mini-port the open is queued on.
  205. Open - The open to close
  206. Return Value:
  207. None.
  208. Comments:
  209. Called at DPC with Miniport's SpinLock held
  210. --*/
  211. {
  212. PNDIS_MINIPORT_BLOCK Miniport = Open->MiniportHandle;
  213. PKEVENT pAllOpensClosedEvent;
  214. KIRQL OldIrql;
  215. DBGPRINT_RAW(DBG_COMP_INIT, DBG_LEVEL_INFO,
  216. ("==>ndisMFinishClose: MOpen %p\n", Open));
  217. ASSERT(MINIPORT_TEST_FLAG(Open, fMINIPORT_OPEN_CLOSING));
  218. MINIPORT_INCREMENT_REF(Miniport);
  219. //
  220. // free any memory allocated to Vcs
  221. //
  222. if (MINIPORT_TEST_FLAG(Miniport, fMINIPORT_IS_CO))
  223. {
  224. ndisMCoFreeResources(Open);
  225. }
  226. ndisDeQueueOpenOnProtocol(Open, Open->ProtocolHandle);
  227. if (Open->Flags & fMINIPORT_OPEN_PMODE)
  228. {
  229. Miniport->PmodeOpens --;
  230. Open->Flags &= ~fMINIPORT_OPEN_PMODE;
  231. NDIS_CHECK_PMODE_OPEN_REF(Miniport);
  232. ndisUpdateCheckForLoopbackFlag(Miniport);
  233. }
  234. ndisDeQueueOpenOnMiniport(Open, Miniport);
  235. Open->QC.Status = NDIS_STATUS_SUCCESS;
  236. INITIALIZE_WORK_ITEM(&Open->QC.WorkItem,
  237. ndisMQueuedFinishClose,
  238. Open);
  239. QUEUE_WORK_ITEM(&Open->QC.WorkItem, DelayedWorkQueue);
  240. MINIPORT_DECREMENT_REF(Miniport);
  241. DBGPRINT_RAW(DBG_COMP_INIT, DBG_LEVEL_INFO,
  242. ("<==ndisMFinishClose: Mopen %p\n", Open));
  243. }
  244. VOID
  245. ndisMQueuedFinishClose(
  246. IN PNDIS_OPEN_BLOCK Open
  247. )
  248. /*++
  249. Routine Description:
  250. Finishes off a close adapter call.
  251. Arguments:
  252. Miniport - The mini-port the open is queued on.
  253. Open - The open to close
  254. Return Value:
  255. None.
  256. --*/
  257. {
  258. PNDIS_MINIPORT_BLOCK Miniport = Open->MiniportHandle;
  259. PKEVENT pAllOpensClosedEvent;
  260. KIRQL OldIrql;
  261. BOOLEAN FreeOpen;
  262. DBGPRINT_RAW(DBG_COMP_INIT, DBG_LEVEL_INFO,
  263. ("==>ndisMQueuedFinishClose: Open %p, Miniport %p\n", Open, Miniport));
  264. ASSERT(ndisPkgs[NPNP_PKG].ReferenceCount > 0);
  265. MINIPORT_INCREMENT_REF(Miniport);
  266. (Open->ProtocolHandle->ProtocolCharacteristics.CloseAdapterCompleteHandler) (
  267. Open->ProtocolBindingContext,
  268. NDIS_STATUS_SUCCESS);
  269. MINIPORT_DECREMENT_REF(Miniport);
  270. ndisDereferenceProtocol(Open->ProtocolHandle);
  271. if (Open->CloseCompleteEvent != NULL)
  272. {
  273. SET_EVENT(Open->CloseCompleteEvent);
  274. }
  275. NDIS_ACQUIRE_MINIPORT_SPIN_LOCK(Miniport, &OldIrql);
  276. if ((Miniport->AllOpensClosedEvent != NULL) &&
  277. (Miniport->OpenQueue == NULL))
  278. {
  279. pAllOpensClosedEvent = Miniport->AllOpensClosedEvent;
  280. Miniport->AllOpensClosedEvent = NULL;
  281. SET_EVENT(pAllOpensClosedEvent);
  282. }
  283. ACQUIRE_SPIN_LOCK_DPC(&Open->SpinLock);
  284. if (MINIPORT_TEST_FLAG(Open, fMINIPORT_OPEN_DONT_FREE))
  285. {
  286. //
  287. // there is an unbind attempt in progress
  288. // do not free the Open block and let unbind know that
  289. // you've seen its message
  290. //
  291. MINIPORT_SET_FLAG(Open, fMINIPORT_OPEN_CLOSE_COMPLETE);
  292. FreeOpen = FALSE;
  293. }
  294. else
  295. {
  296. FreeOpen = TRUE;
  297. }
  298. RELEASE_SPIN_LOCK_DPC(&Open->SpinLock);
  299. NDIS_RELEASE_MINIPORT_SPIN_LOCK(Miniport, OldIrql);
  300. if (FreeOpen)
  301. {
  302. ndisRemoveOpenFromGlobalList(Open);
  303. FREE_POOL(Open);
  304. }
  305. //
  306. // finaly decrement the ref count we added for miniport
  307. //
  308. MINIPORT_DECREMENT_REF(Miniport);
  309. //
  310. // decrement the ref count for PnP package that we added when noticed
  311. // close is going to pend.
  312. //
  313. PnPDereferencePackage();
  314. DBGPRINT_RAW(DBG_COMP_INIT, DBG_LEVEL_INFO,
  315. ("<==ndisMQueuedFinishClose: Open %p, Miniport %p\n", Open, Miniport));
  316. }
  317. VOID
  318. FASTCALL
  319. ndisDeQueueOpenOnMiniport(
  320. IN PNDIS_OPEN_BLOCK OpenP,
  321. IN PNDIS_MINIPORT_BLOCK Miniport
  322. )
  323. /*++
  324. Routine Description:
  325. Arguments:
  326. Return Value:
  327. Note: Called with Miniport lock held.
  328. --*/
  329. {
  330. KIRQL OldIrql;
  331. DBGPRINT_RAW(DBG_COMP_INIT, DBG_LEVEL_INFO,
  332. ("==>ndisDeQueueOpenOnMiniport: MOpen %p, Miniport %p\n", OpenP, Miniport));
  333. //
  334. // we can not reference the package here because this routine can
  335. // be called at raised IRQL.
  336. // make sure the PNP package has been referenced already
  337. //
  338. ASSERT(ndisPkgs[NPNP_PKG].ReferenceCount > 0);
  339. //
  340. // Find the open on the queue, and remove it.
  341. //
  342. if (Miniport->OpenQueue == OpenP)
  343. {
  344. Miniport->OpenQueue = OpenP->MiniportNextOpen;
  345. Miniport->NumOpens--;
  346. }
  347. else
  348. {
  349. PNDIS_OPEN_BLOCK PP = Miniport->OpenQueue;
  350. while ((PP != NULL) && (PP->MiniportNextOpen != OpenP))
  351. {
  352. PP = PP->MiniportNextOpen;
  353. }
  354. if (PP == NULL)
  355. {
  356. #if TRACK_MOPEN_REFCOUNTS
  357. DbgPrint("Ndis:ndisDeQueueOpenOnMiniport Open %p is -not- on Miniport %p\n", OpenP, Miniport);
  358. DbgBreakPoint();
  359. #endif
  360. }
  361. else
  362. {
  363. PP->MiniportNextOpen = PP->MiniportNextOpen->MiniportNextOpen;
  364. Miniport->NumOpens--;
  365. }
  366. }
  367. ndisUpdateCheckForLoopbackFlag(Miniport);
  368. DBGPRINT_RAW(DBG_COMP_INIT, DBG_LEVEL_INFO,
  369. ("<==ndisDeQueueOpenOnMiniport: MOpen %p, Miniport %p\n", OpenP, Miniport));
  370. }
  371. BOOLEAN
  372. FASTCALL
  373. ndisQueueMiniportOnDriver(
  374. IN PNDIS_MINIPORT_BLOCK Miniport,
  375. IN PNDIS_M_DRIVER_BLOCK MiniBlock
  376. )
  377. /*++
  378. Routine Description:
  379. Adds an mini-port to a list of mini-port for a driver.
  380. Arguments:
  381. Miniport - The mini-port block to queue.
  382. MiniBlock - The driver block to queue it to.
  383. Return Value:
  384. FALSE if the driver is closing.
  385. TRUE otherwise.
  386. --*/
  387. {
  388. KIRQL OldIrql;
  389. BOOLEAN rc = TRUE;
  390. DBGPRINT_RAW(DBG_COMP_INIT, DBG_LEVEL_INFO,
  391. ("==>ndisQueueMiniportOnDriver: Miniport %p, MiniBlock %p\n", Miniport, MiniBlock));
  392. PnPReferencePackage();
  393. do
  394. {
  395. ACQUIRE_SPIN_LOCK(&MiniBlock->Ref.SpinLock, &OldIrql);
  396. //
  397. // Make sure the driver is not closing.
  398. //
  399. if (MiniBlock->Ref.Closing)
  400. {
  401. RELEASE_SPIN_LOCK(&MiniBlock->Ref.SpinLock, OldIrql);
  402. rc = FALSE;
  403. break;
  404. }
  405. //
  406. // Add this adapter at the head of the queue
  407. //
  408. Miniport->NextMiniport = MiniBlock->MiniportQueue;
  409. MiniBlock->MiniportQueue = Miniport;
  410. RELEASE_SPIN_LOCK(&MiniBlock->Ref.SpinLock, OldIrql);
  411. } while (FALSE);
  412. PnPDereferencePackage();
  413. DBGPRINT_RAW(DBG_COMP_INIT, DBG_LEVEL_INFO,
  414. ("<==ndisQueueMiniportOnDriver: Miniport %p, MiniBlock %p, rc %ld\n", Miniport, MiniBlock, rc));
  415. return rc;
  416. }
  417. VOID FASTCALL
  418. FASTCALL
  419. ndisDeQueueMiniportOnDriver(
  420. IN PNDIS_MINIPORT_BLOCK Miniport,
  421. IN PNDIS_M_DRIVER_BLOCK MiniBlock
  422. )
  423. /*++
  424. Routine Description:
  425. Removes an mini-port from a list of mini-port for a driver.
  426. Arguments:
  427. Miniport - The mini-port block to dequeue.
  428. MiniBlock - The driver block to dequeue it from.
  429. Return Value:
  430. None.
  431. --*/
  432. {
  433. PNDIS_MINIPORT_BLOCK *ppQ;
  434. KIRQL OldIrql;
  435. DBGPRINT_RAW(DBG_COMP_INIT, DBG_LEVEL_INFO,
  436. ("==>ndisDeQueueMiniportOnDriver, Miniport %p, MiniBlock %p\n", Miniport, MiniBlock));
  437. PnPReferencePackage();
  438. ACQUIRE_SPIN_LOCK(&MiniBlock->Ref.SpinLock, &OldIrql);
  439. //
  440. // Find the driver on the queue, and remove it.
  441. //
  442. for (ppQ = &MiniBlock->MiniportQueue;
  443. *ppQ != NULL;
  444. ppQ = &(*ppQ)->NextMiniport)
  445. {
  446. if (*ppQ == Miniport)
  447. {
  448. *ppQ = Miniport->NextMiniport;
  449. break;
  450. }
  451. }
  452. ASSERT(*ppQ == Miniport->NextMiniport);
  453. //
  454. // the same miniport can be queued on the driver again without all the fields
  455. // getting re-initialized so zero out the linkage
  456. //
  457. Miniport->NextMiniport = NULL;
  458. RELEASE_SPIN_LOCK(&MiniBlock->Ref.SpinLock, OldIrql);
  459. PnPDereferencePackage();
  460. DBGPRINT_RAW(DBG_COMP_INIT, DBG_LEVEL_INFO,
  461. ("<==ndisDeQueueMiniportOnDriver: Miniport %p, MiniBlock %p\n", Miniport, MiniBlock));
  462. }
  463. VOID
  464. FASTCALL
  465. ndisDereferenceDriver(
  466. IN PNDIS_M_DRIVER_BLOCK MiniBlock,
  467. IN BOOLEAN fGlobalLockHeld
  468. )
  469. /*++
  470. Routine Description:
  471. Removes a reference from the mini-port driver, deleting it if the count goes to 0.
  472. Arguments:
  473. Miniport - The mini-port block to dereference.
  474. Return Value:
  475. None.
  476. --*/
  477. {
  478. KIRQL OldIrql;
  479. DBGPRINT_RAW(DBG_COMP_REF, DBG_LEVEL_INFO,
  480. ("==>ndisDereferenceDriver: MiniBlock %p\n", MiniBlock));
  481. if (ndisDereferenceRef(&(MiniBlock)->Ref))
  482. {
  483. PNDIS_M_DRIVER_BLOCK *ppMB;
  484. PNDIS_PENDING_IM_INSTANCE ImInstance, NextImInstance;
  485. //
  486. // Remove it from the global list.
  487. //
  488. ASSERT (IsListEmpty(&MiniBlock->DeviceList));
  489. if (!fGlobalLockHeld)
  490. {
  491. ACQUIRE_SPIN_LOCK(&ndisMiniDriverListLock, &OldIrql);
  492. }
  493. for (ppMB = &ndisMiniDriverList; *ppMB != NULL; ppMB = &(*ppMB)->NextDriver)
  494. {
  495. if (*ppMB == MiniBlock)
  496. {
  497. *ppMB = MiniBlock->NextDriver;
  498. DEREF_NDIS_DRIVER_OBJECT();
  499. break;
  500. }
  501. }
  502. if (!fGlobalLockHeld)
  503. {
  504. RELEASE_SPIN_LOCK(&ndisMiniDriverListLock, OldIrql);
  505. }
  506. //
  507. // Free the wrapper handle allocated during NdisInitializeWrapper
  508. //
  509. if (MiniBlock->NdisDriverInfo != NULL)
  510. {
  511. FREE_POOL(MiniBlock->NdisDriverInfo);
  512. MiniBlock->NdisDriverInfo = NULL;
  513. }
  514. //
  515. // Free any queued device-instance blocks
  516. //
  517. for (ImInstance = MiniBlock->PendingDeviceList;
  518. ImInstance != NULL;
  519. ImInstance = NextImInstance)
  520. {
  521. NextImInstance = ImInstance->Next;
  522. FREE_POOL(ImInstance);
  523. }
  524. //
  525. // set the event holding unload to go through
  526. //
  527. SET_EVENT(&MiniBlock->MiniportsRemovedEvent);
  528. }
  529. DBGPRINT_RAW(DBG_COMP_REF, DBG_LEVEL_INFO,
  530. ("<==ndisDereferenceDriver: MiniBlock %p\n", MiniBlock));
  531. }
  532. #if DBG
  533. BOOLEAN
  534. FASTCALL
  535. ndisReferenceMiniport(
  536. IN PNDIS_MINIPORT_BLOCK Miniport
  537. )
  538. {
  539. BOOLEAN rc;
  540. DBGPRINT(DBG_COMP_REF, DBG_LEVEL_INFO,("==>ndisReferenceMiniport: Miniport %p\n", Miniport));
  541. rc = ndisReferenceULongRef(&(Miniport->Ref));
  542. DBGPRINT_RAW(DBG_COMP_REF, DBG_LEVEL_INFO,
  543. (" ndisReferenceMiniport: Miniport %p, Ref = %lx\n", Miniport, Miniport->Ref.ReferenceCount));
  544. DBGPRINT(DBG_COMP_REF, DBG_LEVEL_INFO,("<==ndisReferenceMiniport: Miniport %p\n", Miniport));
  545. return(rc);
  546. }
  547. #endif
  548. #ifdef TRACK_MINIPORT_REFCOUNTS
  549. BOOLEAN
  550. ndisReferenceMiniportAndLog(
  551. IN PNDIS_MINIPORT_BLOCK Miniport,
  552. IN UINT Line,
  553. IN UINT Module
  554. )
  555. {
  556. BOOLEAN rc;
  557. rc = ndisReferenceMiniport(Miniport);
  558. M_LOG_MINIPORT_INCREMENT_REF(Miniport, Line, Module);
  559. return rc;
  560. }
  561. BOOLEAN
  562. ndisReferenceMiniportAndLogCreate(
  563. IN PNDIS_MINIPORT_BLOCK Miniport,
  564. IN UINT Line,
  565. IN UINT Module,
  566. IN PIRP Irp
  567. )
  568. {
  569. BOOLEAN rc;
  570. rc = ndisReferenceMiniport(Miniport);
  571. M_LOG_MINIPORT_INCREMENT_REF_CREATE(Miniport, Line, Module);
  572. return rc;
  573. }
  574. #endif
  575. VOID
  576. FASTCALL
  577. ndisDereferenceMiniport(
  578. IN PNDIS_MINIPORT_BLOCK Miniport
  579. )
  580. /*++
  581. Routine Description:
  582. Removes a reference from the mini-port driver, deleting it if the count goes to 0.
  583. Arguments:
  584. Miniport - The mini-port block to dereference.
  585. Return Value:
  586. None.
  587. --*/
  588. {
  589. PSINGLE_LIST_ENTRY Link;
  590. PNDIS_MINIPORT_WORK_ITEM WorkItem;
  591. UINT c;
  592. PKEVENT RemoveReadyEvent = NULL;
  593. KEVENT RequestsCompletedEvent;
  594. KIRQL OldIrql;
  595. BOOLEAN fTimerCancelled;
  596. BOOLEAN rc;
  597. DBGPRINT_RAW(DBG_COMP_REF, DBG_LEVEL_INFO,
  598. ("==>ndisDereferenceMiniport: Miniport %p\n", Miniport));
  599. rc = ndisDereferenceULongRef(&(Miniport)->Ref);
  600. DBGPRINT_RAW(DBG_COMP_REF, DBG_LEVEL_INFO,
  601. (" ndisDereferenceMiniport:Miniport %p, Ref = %lx\n", Miniport, Miniport->Ref.ReferenceCount));
  602. if (rc)
  603. {
  604. DBGPRINT_RAW(DBG_COMP_INIT, DBG_LEVEL_INFO,
  605. (" ndisDereferenceMiniport:Miniport %p, Ref = %lx\n", Miniport, Miniport->Ref.ReferenceCount));
  606. RemoveReadyEvent = Miniport->RemoveReadyEvent;
  607. if (ndisIsMiniportStarted(Miniport) && (Miniport->Ref.ReferenceCount == 0))
  608. {
  609. ASSERT (Miniport->Interrupt == NULL);
  610. if (Miniport->EthDB)
  611. {
  612. EthDeleteFilter(Miniport->EthDB);
  613. Miniport->EthDB = NULL;
  614. }
  615. if (Miniport->TrDB)
  616. {
  617. TrDeleteFilter(Miniport->TrDB);
  618. Miniport->TrDB = NULL;
  619. }
  620. if (Miniport->FddiDB)
  621. {
  622. FddiDeleteFilter(Miniport->FddiDB);
  623. Miniport->FddiDB = NULL;
  624. }
  625. #if ARCNET
  626. if (Miniport->ArcDB)
  627. {
  628. ArcDeleteFilter(Miniport->ArcDB);
  629. Miniport->ArcDB = NULL;
  630. }
  631. #endif
  632. if (Miniport->AllocatedResources)
  633. {
  634. FREE_POOL(Miniport->AllocatedResources);
  635. }
  636. //
  637. // Free the work items that are currently on the work queue that are
  638. // allocated outside of the miniport block
  639. //
  640. for (c = NUMBER_OF_SINGLE_WORK_ITEMS; c < NUMBER_OF_WORK_ITEM_TYPES; c++)
  641. {
  642. //
  643. // Free all work items on the current queue.
  644. //
  645. while (Miniport->WorkQueue[c].Next != NULL)
  646. {
  647. Link = PopEntryList(&Miniport->WorkQueue[c]);
  648. WorkItem = CONTAINING_RECORD(Link, NDIS_MINIPORT_WORK_ITEM, Link);
  649. FREE_POOL(WorkItem);
  650. }
  651. }
  652. if (Miniport->OidList != NULL)
  653. {
  654. FREE_POOL(Miniport->OidList);
  655. Miniport->OidList = NULL;
  656. }
  657. //
  658. // Did we set a timer for the link change power down?
  659. //
  660. if (MINIPORT_PNP_TEST_FLAG(Miniport, fMINIPORT_MEDIA_DISCONNECT_WAIT))
  661. {
  662. MINIPORT_PNP_CLEAR_FLAG(Miniport, fMINIPORT_MEDIA_DISCONNECT_WAIT);
  663. MINIPORT_PNP_SET_FLAG(Miniport, fMINIPORT_MEDIA_DISCONNECT_CANCELLED);
  664. NdisCancelTimer(&Miniport->MediaDisconnectTimer, &fTimerCancelled);
  665. if (!fTimerCancelled)
  666. {
  667. NdisStallExecution(Miniport->MediaDisconnectTimeOut * 1000000);
  668. }
  669. }
  670. #if ARCNET
  671. //
  672. // Is there an arcnet lookahead buffer allocated?
  673. //
  674. if ((Miniport->MediaType == NdisMediumArcnet878_2) &&
  675. (Miniport->ArcBuf != NULL))
  676. {
  677. if (Miniport->ArcBuf->ArcnetLookaheadBuffer != NULL)
  678. {
  679. FREE_POOL(Miniport->ArcBuf->ArcnetLookaheadBuffer);
  680. }
  681. FREE_POOL(Miniport->ArcBuf);
  682. Miniport->ArcBuf = NULL;
  683. }
  684. #endif
  685. //
  686. // if the adapter uses SG DMA, we have to dereference the DMA adapter
  687. // to get it freed
  688. //
  689. if (MINIPORT_TEST_FLAG(Miniport, fMINIPORT_SG_LIST))
  690. {
  691. ndisDereferenceDmaAdapter(Miniport);
  692. }
  693. INITIALIZE_EVENT(&RequestsCompletedEvent);
  694. NDIS_ACQUIRE_MINIPORT_SPIN_LOCK(Miniport, &OldIrql);
  695. Miniport->DmaResourcesReleasedEvent = &RequestsCompletedEvent;
  696. if (Miniport->SystemAdapterObject != NULL)
  697. {
  698. LARGE_INTEGER TimeoutValue;
  699. TimeoutValue.QuadPart = Int32x32To64(30000, -10000); // Make it 30 second
  700. NDIS_RELEASE_MINIPORT_SPIN_LOCK(Miniport, OldIrql);
  701. if (!NT_SUCCESS(WAIT_FOR_OBJECT(&RequestsCompletedEvent, &TimeoutValue)))
  702. {
  703. #if DBG
  704. ASSERTMSG("Ndis: Miniport is going away without releasing all resources.\n", (Miniport->DmaAdapterRefCount == 0));
  705. #endif
  706. }
  707. }
  708. else
  709. {
  710. NDIS_RELEASE_MINIPORT_SPIN_LOCK(Miniport, OldIrql);
  711. }
  712. Miniport->DmaResourcesReleasedEvent = NULL;
  713. //
  714. // Free the map of custom GUIDs to OIDs.
  715. //
  716. if (NULL != Miniport->pNdisGuidMap)
  717. {
  718. FREE_POOL(Miniport->pNdisGuidMap);
  719. Miniport->pNdisGuidMap = NULL;
  720. }
  721. if (Miniport->FakeMac != NULL)
  722. {
  723. FREE_POOL(Miniport->FakeMac);
  724. Miniport->FakeMac = NULL;
  725. }
  726. if (MINIPORT_TEST_FLAG(Miniport, fMINIPORT_IS_CO))
  727. {
  728. CoDereferencePackage();
  729. }
  730. ndisDeQueueMiniportOnDriver(Miniport, Miniport->DriverHandle);
  731. ndisDereferenceDriver(Miniport->DriverHandle, FALSE);
  732. NdisMDeregisterAdapterShutdownHandler(Miniport);
  733. IoUnregisterShutdownNotification(Miniport->DeviceObject);
  734. if (Miniport->SymbolicLinkName.Buffer != NULL)
  735. {
  736. RtlFreeUnicodeString(&Miniport->SymbolicLinkName);
  737. Miniport->SymbolicLinkName.Buffer = NULL;
  738. }
  739. MiniportDereferencePackage();
  740. }
  741. if (RemoveReadyEvent)
  742. {
  743. SET_EVENT(RemoveReadyEvent);
  744. }
  745. }
  746. DBGPRINT_RAW(DBG_COMP_REF, DBG_LEVEL_INFO,
  747. ("<==ndisDereferenceMiniport: Miniport %p\n", Miniport));
  748. }
  749. VOID
  750. FASTCALL
  751. ndisMCommonHaltMiniport(
  752. IN PNDIS_MINIPORT_BLOCK Miniport
  753. )
  754. /*++
  755. Routine Description:
  756. This is common code for halting a miniport. There are two different paths
  757. that will call this routine: 1) from a normal unload. 2) from an adapter
  758. being transitioned to a low power state.
  759. Arguments:
  760. Return Value:
  761. --*/
  762. {
  763. KIRQL OldIrql;
  764. BOOLEAN Canceled;
  765. PNDIS_AF_LIST MiniportAfList, pNext;
  766. KEVENT RequestsCompletedEvent;
  767. FILTER_PACKET_INDICATION_HANDLER PacketIndicateHandler;
  768. DBGPRINT_RAW(DBG_COMP_INIT, DBG_LEVEL_INFO,
  769. ("==>ndisMCommonHaltMiniport: Miniport %p\n", Miniport));
  770. PnPReferencePackage();
  771. //
  772. // wait for outstanding resets to complete
  773. //
  774. BLOCK_LOCK_MINIPORT_LOCKED(Miniport, OldIrql);
  775. MINIPORT_PNP_SET_FLAG(Miniport, fMINIPORT_HALTING | fMINIPORT_REJECT_REQUESTS);
  776. if (MINIPORT_TEST_FLAG(Miniport, fMINIPORT_RESET_IN_PROGRESS))
  777. {
  778. INITIALIZE_EVENT(&RequestsCompletedEvent);
  779. Miniport->ResetCompletedEvent = &RequestsCompletedEvent;
  780. }
  781. UNLOCK_MINIPORT_L(Miniport);
  782. NDIS_RELEASE_MINIPORT_SPIN_LOCK(Miniport, OldIrql);
  783. if (Miniport->ResetCompletedEvent)
  784. WAIT_FOR_OBJECT(&RequestsCompletedEvent, NULL);
  785. Miniport->ResetCompletedEvent = NULL;
  786. //
  787. // if we have an outstanding queued workitem to initialize the bindings
  788. // wait for it to fire
  789. //
  790. BLOCK_LOCK_MINIPORT_LOCKED(Miniport, OldIrql);
  791. if (MINIPORT_PNP_TEST_FLAG(Miniport, fMINIPORT_QUEUED_BIND_WORKITEM))
  792. {
  793. INITIALIZE_EVENT(&RequestsCompletedEvent);
  794. Miniport->QueuedBindingCompletedEvent = &RequestsCompletedEvent;
  795. }
  796. UNLOCK_MINIPORT_L(Miniport);
  797. NDIS_RELEASE_MINIPORT_SPIN_LOCK(Miniport, OldIrql);
  798. if (Miniport->QueuedBindingCompletedEvent)
  799. WAIT_FOR_OBJECT(&RequestsCompletedEvent, NULL);
  800. Miniport->QueuedBindingCompletedEvent = NULL;
  801. IoSetDeviceInterfaceState(&Miniport->SymbolicLinkName, FALSE);
  802. //
  803. // Deregister with WMI
  804. //
  805. IoWMIRegistrationControl(Miniport->DeviceObject, WMIREG_ACTION_DEREGISTER);
  806. NdisCancelTimer(&Miniport->WakeUpDpcTimer, &Canceled);
  807. if (!Canceled)
  808. {
  809. NdisStallExecution(NDIS_MINIPORT_WAKEUP_TIMEOUT * 1000);
  810. }
  811. BLOCK_LOCK_MINIPORT_LOCKED(Miniport, OldIrql);
  812. if (Miniport->PendingRequest != NULL)
  813. {
  814. INITIALIZE_EVENT(&RequestsCompletedEvent);
  815. Miniport->AllRequestsCompletedEvent = &RequestsCompletedEvent;
  816. }
  817. UNLOCK_MINIPORT_L(Miniport);
  818. NDIS_RELEASE_MINIPORT_SPIN_LOCK(Miniport, OldIrql);
  819. if (Miniport->AllRequestsCompletedEvent)
  820. WAIT_FOR_OBJECT(&RequestsCompletedEvent, NULL);
  821. Miniport->AllRequestsCompletedEvent = NULL;
  822. if (MINIPORT_TEST_FLAG(Miniport, fMINIPORT_INTERMEDIATE_DRIVER))
  823. {
  824. PacketIndicateHandler = Miniport->PacketIndicateHandler;
  825. Miniport->PacketIndicateHandler = ndisMDummyIndicatePacket;
  826. while (Miniport->IndicatedPacketsCount != 0)
  827. {
  828. NdisMSleep(1000);
  829. }
  830. }
  831. (Miniport->DriverHandle->MiniportCharacteristics.HaltHandler)(Miniport->MiniportAdapterContext);
  832. if (MINIPORT_TEST_FLAG(Miniport, fMINIPORT_INTERMEDIATE_DRIVER))
  833. {
  834. Miniport->PacketIndicateHandler = PacketIndicateHandler;
  835. }
  836. MINIPORT_PNP_CLEAR_FLAG(Miniport, fMINIPORT_HALTING);
  837. ASSERT(Miniport->TimerQueue == NULL);
  838. ASSERT (Miniport->Interrupt == NULL);
  839. ASSERT(Miniport->MapRegisters == NULL);
  840. //
  841. // check for memory leak
  842. //
  843. if (Miniport == ndisMiniportTrackAlloc)
  844. {
  845. ASSERT(IsListEmpty(&ndisMiniportTrackAllocList));
  846. ndisMiniportTrackAlloc = NULL;
  847. }
  848. //
  849. // zero out statistics
  850. //
  851. ZeroMemory(&Miniport->NdisStats, sizeof(Miniport->NdisStats));
  852. if ((Miniport->TimerQueue != NULL) || (Miniport->Interrupt != NULL))
  853. {
  854. if (Miniport->Interrupt != NULL)
  855. {
  856. BAD_MINIPORT(Miniport, "Unloading without deregistering interrupt");
  857. }
  858. else
  859. {
  860. BAD_MINIPORT(Miniport, "Unloading without deregistering timer");
  861. }
  862. KeBugCheckEx(BUGCODE_ID_DRIVER,
  863. (ULONG_PTR)Miniport,
  864. (ULONG_PTR)Miniport->TimerQueue,
  865. (ULONG_PTR)Miniport->Interrupt,
  866. 0);
  867. }
  868. BLOCK_LOCK_MINIPORT_LOCKED(Miniport, OldIrql);
  869. ndisMAbortPackets(Miniport, NULL, NULL);
  870. //
  871. // Dequeue any request work items that are queued
  872. //
  873. NDISM_DEQUEUE_WORK_ITEM(Miniport, NdisWorkItemRequest, NULL);
  874. ndisMAbortRequests(Miniport);
  875. //
  876. // Free up any AFs registered by this miniport
  877. //
  878. for (MiniportAfList = Miniport->CallMgrAfList, Miniport->CallMgrAfList = NULL;
  879. MiniportAfList != NULL;
  880. MiniportAfList = pNext)
  881. {
  882. pNext = MiniportAfList->NextAf;
  883. FREE_POOL(MiniportAfList);
  884. }
  885. UNLOCK_MINIPORT_L(Miniport);
  886. NDIS_RELEASE_MINIPORT_SPIN_LOCK(Miniport, OldIrql);
  887. PnPDereferencePackage();
  888. DBGPRINT_RAW(DBG_COMP_INIT, DBG_LEVEL_INFO,
  889. ("<==ndisMCommonHaltMiniport: Miniport %p\n", Miniport));
  890. }
  891. VOID
  892. FASTCALL
  893. ndisMHaltMiniport(
  894. IN PNDIS_MINIPORT_BLOCK Miniport
  895. )
  896. /*++
  897. Routine Description:
  898. Does all the clean up for a mini-port.
  899. Arguments:
  900. Miniport - pointer to the mini-port to halt
  901. Return Value:
  902. None.
  903. --*/
  904. {
  905. DBGPRINT_RAW(DBG_COMP_INIT, DBG_LEVEL_INFO,
  906. ("==>ndisMHaltMiniport: Miniport %p\n", Miniport));
  907. do
  908. {
  909. //
  910. // If the Miniport is already closing, return.
  911. //
  912. if (!ndisCloseULongRef(&Miniport->Ref))
  913. {
  914. break;
  915. }
  916. //
  917. // if the miniport is not already halted becuase of a PM event
  918. // halt it here
  919. //
  920. if (!MINIPORT_PNP_TEST_FLAG(Miniport, fMINIPORT_PM_HALTED))
  921. {
  922. //
  923. // Common halt code.
  924. //
  925. ndisMCommonHaltMiniport(Miniport);
  926. //
  927. // If a shutdown handler was registered then deregister it.
  928. //
  929. NdisMDeregisterAdapterShutdownHandler(Miniport);
  930. }
  931. MINIPORT_DECREMENT_REF(Miniport);
  932. } while (FALSE);
  933. DBGPRINT_RAW(DBG_COMP_INIT, DBG_LEVEL_INFO,
  934. ("<==ndisMHaltMiniport: Miniport %p\n", Miniport));
  935. }
  936. VOID
  937. ndisMUnload(
  938. IN PDRIVER_OBJECT DriverObject
  939. )
  940. /*++
  941. Routine Description:
  942. This routine is called when a driver is supposed to unload.
  943. Arguments:
  944. DriverObject - the driver object for the mac that is to unload.
  945. Return Value:
  946. None.
  947. --*/
  948. {
  949. PNDIS_M_DRIVER_BLOCK MiniBlock, Tmp, IoMiniBlock;
  950. PNDIS_MINIPORT_BLOCK Miniport, NextMiniport;
  951. KIRQL OldIrql;
  952. #if TRACK_UNLOAD
  953. DbgPrint("ndisMUnload: DriverObject %p\n", DriverObject);
  954. #endif
  955. DBGPRINT_RAW(DBG_COMP_INIT, DBG_LEVEL_INFO,
  956. ("==>ndisMUnload: DriverObject %p\n", DriverObject));
  957. PnPReferencePackage();
  958. do
  959. {
  960. //
  961. // Search for the driver
  962. //
  963. IoMiniBlock = (PNDIS_M_DRIVER_BLOCK)IoGetDriverObjectExtension(DriverObject,
  964. (PVOID)NDIS_PNP_MINIPORT_DRIVER_ID);
  965. if (IoMiniBlock && !(IoMiniBlock->Flags & fMINIBLOCK_TERMINATE_WRAPPER_UNLOAD))
  966. {
  967. IoMiniBlock->Flags |= fMINIBLOCK_IO_UNLOAD;
  968. }
  969. ACQUIRE_SPIN_LOCK(&ndisMiniDriverListLock, &OldIrql);
  970. MiniBlock = ndisMiniDriverList;
  971. while (MiniBlock != (PNDIS_M_DRIVER_BLOCK)NULL)
  972. {
  973. if (MiniBlock->NdisDriverInfo->DriverObject == DriverObject)
  974. {
  975. break;
  976. }
  977. MiniBlock = MiniBlock->NextDriver;
  978. }
  979. RELEASE_SPIN_LOCK(&ndisMiniDriverListLock, OldIrql);
  980. #if TRACK_UNLOAD
  981. DbgPrint("ndisMUnload: MiniBlock %p\n", MiniBlock);
  982. #endif
  983. if (MiniBlock == (PNDIS_M_DRIVER_BLOCK)NULL)
  984. {
  985. //
  986. // It is already gone. Just return.
  987. //
  988. break;
  989. }
  990. ASSERT(MiniBlock == IoMiniBlock);
  991. DBGPRINT_RAW(DBG_COMP_INIT, DBG_LEVEL_INFO,
  992. (" ndisMUnload: MiniBlock %p\n", MiniBlock));
  993. MiniBlock->Flags |= fMINIBLOCK_UNLOADING;
  994. //
  995. // Now remove the last reference (this will remove it from the list)
  996. //
  997. // ASSERT(MiniBlock->Ref.ReferenceCount == 1);
  998. //
  999. // If this is an intermediate driver and wants to be called to do unload handling, allow him
  1000. //
  1001. if (MiniBlock->UnloadHandler != NULL)
  1002. {
  1003. (*MiniBlock->UnloadHandler)(DriverObject);
  1004. }
  1005. if (MiniBlock->AssociatedProtocol != NULL)
  1006. {
  1007. MiniBlock->AssociatedProtocol->AssociatedMiniDriver = NULL;
  1008. MiniBlock->AssociatedProtocol = NULL;
  1009. }
  1010. ndisDereferenceDriver(MiniBlock, FALSE);
  1011. //
  1012. // Wait for all adapters to be gonzo.
  1013. //
  1014. WAIT_FOR_OBJECT(&MiniBlock->MiniportsRemovedEvent, NULL);
  1015. RESET_EVENT(&MiniBlock->MiniportsRemovedEvent);
  1016. #if TRACK_UNLOAD
  1017. ACQUIRE_SPIN_LOCK(&ndisMiniDriverListLock, &OldIrql);
  1018. for (Tmp = ndisMiniDriverList; Tmp != NULL; Tmp = Tmp->NextDriver)
  1019. {
  1020. ASSERT (Tmp != MiniBlock);
  1021. if (Tmp == MiniBlock)
  1022. {
  1023. DbgPrint("NdisMUnload: MiniBlock %p is getting unloaded but it is still on ndisMiniDriverList\n",
  1024. MiniBlock);
  1025. KeBugCheckEx(BUGCODE_ID_DRIVER,
  1026. (ULONG_PTR)MiniBlock,
  1027. (ULONG_PTR)MiniBlock->Ref.ReferenceCount,
  1028. 0,
  1029. 0);
  1030. }
  1031. }
  1032. RELEASE_SPIN_LOCK(&ndisMiniDriverListLock, OldIrql);
  1033. #endif
  1034. //
  1035. // check to make sure that the driver has freed all the memory it allocated
  1036. //
  1037. if (MiniBlock == ndisDriverTrackAlloc)
  1038. {
  1039. ASSERT(IsListEmpty(&ndisDriverTrackAllocList));
  1040. ndisDriverTrackAlloc = NULL;
  1041. }
  1042. } while (FALSE);
  1043. PnPDereferencePackage();
  1044. DBGPRINT_RAW(DBG_COMP_INIT, DBG_LEVEL_INFO,
  1045. ("<==ndisMUnload: DriverObject %p, MiniBlock %p\n", DriverObject, MiniBlock));
  1046. }
  1047. /////////////////////////////////////////////////////////////////////
  1048. //
  1049. // PLUG-N-PLAY CODE
  1050. //
  1051. /////////////////////////////////////////////////////////////////////
  1052. NDIS_STATUS
  1053. FASTCALL
  1054. ndisCloseMiniportBindings(
  1055. IN PNDIS_MINIPORT_BLOCK Miniport
  1056. )
  1057. /*++
  1058. Routine Description:
  1059. Unbind all protocols from this miniport and finally unload it.
  1060. Arguments:
  1061. Miniport - The Miniport to unload.
  1062. Return Value:
  1063. None.
  1064. --*/
  1065. {
  1066. KIRQL OldIrql;
  1067. PNDIS_OPEN_BLOCK Open, TmpOpen;
  1068. NDIS_BIND_CONTEXT UnbindContext;
  1069. NDIS_STATUS UnbindStatus;
  1070. KEVENT CloseCompleteEvent;
  1071. KEVENT AllOpensClosedEvent;
  1072. PKEVENT pAllOpensClosedEvent;
  1073. DBGPRINT_RAW(DBG_COMP_INIT, DBG_LEVEL_INFO,
  1074. ("==>ndisCloseMiniportBindings, Miniport %p\n", Miniport));
  1075. PnPReferencePackage();
  1076. //
  1077. // if we have an outstanding queued workitem to initialize the bindings
  1078. // wait for it to fire
  1079. //
  1080. BLOCK_LOCK_MINIPORT_LOCKED(Miniport, OldIrql);
  1081. if (MINIPORT_PNP_TEST_FLAG(Miniport, fMINIPORT_QUEUED_BIND_WORKITEM))
  1082. {
  1083. INITIALIZE_EVENT(&AllOpensClosedEvent);
  1084. Miniport->QueuedBindingCompletedEvent = &AllOpensClosedEvent;
  1085. }
  1086. UNLOCK_MINIPORT_L(Miniport);
  1087. NDIS_RELEASE_MINIPORT_SPIN_LOCK(Miniport, OldIrql);
  1088. if (Miniport->QueuedBindingCompletedEvent)
  1089. WAIT_FOR_OBJECT(&AllOpensClosedEvent, NULL);
  1090. Miniport->QueuedBindingCompletedEvent = NULL;
  1091. INITIALIZE_EVENT(&AllOpensClosedEvent);
  1092. INITIALIZE_EVENT(&CloseCompleteEvent);
  1093. NDIS_ACQUIRE_MINIPORT_SPIN_LOCK(Miniport, &OldIrql);
  1094. if ((Miniport->OpenQueue != NULL) && (Miniport->AllOpensClosedEvent == NULL))
  1095. {
  1096. Miniport->AllOpensClosedEvent = &AllOpensClosedEvent;
  1097. }
  1098. pAllOpensClosedEvent = Miniport->AllOpensClosedEvent;
  1099. next:
  1100. //
  1101. // Walk the list of open bindings on this miniport and ask the protocols to
  1102. // unbind from them.
  1103. //
  1104. for (Open = Miniport->OpenQueue;
  1105. Open != NULL;
  1106. Open = Open->MiniportNextOpen)
  1107. {
  1108. ACQUIRE_SPIN_LOCK_DPC(&Open->SpinLock);
  1109. if (!MINIPORT_TEST_FLAG(Open, (fMINIPORT_OPEN_CLOSING | fMINIPORT_OPEN_PROCESSING)))
  1110. {
  1111. MINIPORT_SET_FLAG(Open, fMINIPORT_OPEN_PROCESSING);
  1112. if (!MINIPORT_TEST_FLAG(Open, fMINIPORT_OPEN_UNBINDING))
  1113. {
  1114. MINIPORT_SET_FLAG(Open, fMINIPORT_OPEN_UNBINDING | fMINIPORT_OPEN_DONT_FREE);
  1115. Open->CloseCompleteEvent = &CloseCompleteEvent;
  1116. RELEASE_SPIN_LOCK_DPC(&Open->SpinLock);
  1117. break;
  1118. }
  1119. #if DBG
  1120. else
  1121. {
  1122. DBGPRINT(DBG_COMP_INIT, DBG_LEVEL_INFO,
  1123. ("ndisCloseMiniportBindings: Open %p is already Closing, Flags %lx\n",
  1124. Open, Open->Flags));
  1125. }
  1126. #endif
  1127. }
  1128. RELEASE_SPIN_LOCK_DPC(&Open->SpinLock);
  1129. }
  1130. if (Open != NULL)
  1131. {
  1132. NDIS_RELEASE_MINIPORT_SPIN_LOCK(Miniport, OldIrql);
  1133. ndisUnbindProtocol(Open, FALSE);
  1134. NDIS_ACQUIRE_MINIPORT_SPIN_LOCK(Miniport, &OldIrql);
  1135. goto next;
  1136. }
  1137. //
  1138. // if we reached the end of the list but there are still some opens
  1139. // that are not marked for closing (can happen if we skip an open only because of
  1140. // processign flag being set) release the spinlocks, give whoever set the
  1141. // processing flag time to release the open. then go back and try again
  1142. // ultimately, all opens should either be marked for Unbinding or be gone
  1143. // by themselves
  1144. //
  1145. for (TmpOpen = Miniport->OpenQueue;
  1146. TmpOpen != NULL;
  1147. TmpOpen = TmpOpen->MiniportNextOpen)
  1148. {
  1149. if (!MINIPORT_TEST_FLAG(TmpOpen, fMINIPORT_OPEN_UNBINDING))
  1150. break;
  1151. }
  1152. if (TmpOpen != NULL)
  1153. {
  1154. NDIS_RELEASE_MINIPORT_SPIN_LOCK(Miniport, OldIrql);
  1155. NDIS_INTERNAL_STALL(50);
  1156. NDIS_ACQUIRE_MINIPORT_SPIN_LOCK(Miniport, &OldIrql);
  1157. goto next;
  1158. }
  1159. NDIS_RELEASE_MINIPORT_SPIN_LOCK(Miniport, OldIrql);
  1160. if (pAllOpensClosedEvent)
  1161. {
  1162. WAIT_FOR_OBJECT(pAllOpensClosedEvent, NULL);
  1163. }
  1164. DBGPRINT_RAW(DBG_COMP_INIT, DBG_LEVEL_INFO,
  1165. ("<==ndisCloseMiniportBindings, Miniport %p\n", Miniport));
  1166. PnPDereferencePackage();
  1167. return NDIS_STATUS_SUCCESS;
  1168. }
  1169. VOID
  1170. NdisMSetPeriodicTimer(
  1171. IN PNDIS_MINIPORT_TIMER Timer,
  1172. IN UINT MillisecondsPeriod
  1173. )
  1174. /*++
  1175. Routine Description:
  1176. Sets up a periodic timer.
  1177. Arguments:
  1178. Timer - The timer to Set.
  1179. MillisecondsPeriod - The timer will fire once every so often.
  1180. Return Value:
  1181. --*/
  1182. {
  1183. LARGE_INTEGER FireUpTime;
  1184. FireUpTime.QuadPart = Int32x32To64((LONG)MillisecondsPeriod, -10000);
  1185. #if CHECK_TIMER
  1186. if ((Timer->Dpc.DeferredRoutine != ndisMWakeUpDpc) &&
  1187. (Timer->Dpc.DeferredRoutine != ndisMWakeUpDpcX) &&
  1188. (Timer->Miniport->DriverHandle->Flags & fMINIBLOCK_VERIFYING))
  1189. {
  1190. KIRQL OldIrql;
  1191. PNDIS_MINIPORT_TIMER pTimer;
  1192. ACQUIRE_SPIN_LOCK(&Timer->Miniport->TimerQueueLock, &OldIrql);
  1193. //
  1194. // check to see if the timer is already set
  1195. //
  1196. for (pTimer = Timer->Miniport->TimerQueue;
  1197. pTimer != NULL;
  1198. pTimer = pTimer->NextTimer)
  1199. {
  1200. if (pTimer == Timer)
  1201. break;
  1202. }
  1203. if (pTimer == NULL)
  1204. {
  1205. Timer->NextTimer = Timer->Miniport->TimerQueue;
  1206. Timer->Miniport->TimerQueue = Timer;
  1207. }
  1208. RELEASE_SPIN_LOCK(&Timer->Miniport->TimerQueueLock, OldIrql);
  1209. }
  1210. #endif
  1211. //
  1212. // Set the timer
  1213. //
  1214. SET_PERIODIC_TIMER(&Timer->Timer, FireUpTime, MillisecondsPeriod, &Timer->Dpc);
  1215. }
  1216. VOID
  1217. NdisMSleep(
  1218. IN ULONG MicrosecondsToSleep
  1219. )
  1220. /*++
  1221. Routine Description:
  1222. Blocks the caller for specified duration of time. Callable at Irql < DISPATCH_LEVEL.
  1223. Arguments:
  1224. MicrosecondsToSleep - The caller will be blocked for this much time.
  1225. Return Value:
  1226. NONE
  1227. --*/
  1228. {
  1229. KTIMER SleepTimer;
  1230. LARGE_INTEGER TimerValue;
  1231. ASSERT (KeGetCurrentIrql() == LOW_LEVEL);
  1232. INITIALIZE_TIMER_EX(&SleepTimer, SynchronizationTimer);
  1233. TimerValue.QuadPart = Int32x32To64(MicrosecondsToSleep, -10);
  1234. SET_TIMER(&SleepTimer, TimerValue, NULL);
  1235. WAIT_FOR_OBJECT(&SleepTimer, NULL);
  1236. }