Leaked source code of windows server 2003
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.

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