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.

1479 lines
42 KiB

  1. /*++
  2. Copyright (c) 1990-1995 Microsoft Corporation
  3. Module Name:
  4. timerm.c
  5. Abstract:
  6. NDIS wrapper functions for miniport isr/timer
  7. Author:
  8. Sean Selitrennikoff (SeanSe) 05-Oct-93
  9. Environment:
  10. Kernel mode, FSD
  11. Revision History:
  12. Jameel Hyder (JameelH) Re-organization 01-Jun-95
  13. --*/
  14. #include <precomp.h>
  15. #pragma hdrstop
  16. //
  17. // Define the module number for debug code.
  18. //
  19. #define MODULE_NUMBER MODULE_TIMERM
  20. //
  21. // Timers
  22. //
  23. VOID
  24. NdisMInitializeTimer(
  25. IN OUT PNDIS_MINIPORT_TIMER MiniportTimer,
  26. IN NDIS_HANDLE MiniportAdapterHandle,
  27. IN PNDIS_TIMER_FUNCTION TimerFunction,
  28. IN PVOID FunctionContext
  29. )
  30. /*++
  31. Routine Description:
  32. Sets up an Miniport Timer object, initializing the DPC in the timer to
  33. the function and context.
  34. Arguments:
  35. MiniportTimer - the timer object.
  36. MiniportAdapterHandle - pointer to the mini-port block;
  37. TimerFunction - Routine to start.
  38. FunctionContext - Context of TimerFunction.
  39. Return Value:
  40. None.
  41. --*/
  42. {
  43. INITIALIZE_TIMER(&MiniportTimer->Timer);
  44. MiniportTimer->Miniport = (PNDIS_MINIPORT_BLOCK)MiniportAdapterHandle;
  45. MiniportTimer->MiniportTimerFunction = TimerFunction;
  46. MiniportTimer->MiniportTimerContext = FunctionContext;
  47. //
  48. // Initialize our dpc. If Dpc was previously initialized, this will
  49. // reinitialize it.
  50. //
  51. INITIALIZE_DPC(&MiniportTimer->Dpc,
  52. MINIPORT_TEST_FLAG(MiniportTimer->Miniport, fMINIPORT_DESERIALIZE) ?
  53. (PKDEFERRED_ROUTINE)ndisMTimerDpcX : (PKDEFERRED_ROUTINE)ndisMTimerDpc,
  54. (PVOID)MiniportTimer);
  55. SET_PROCESSOR_DPC(&MiniportTimer->Dpc,
  56. MiniportTimer->Miniport->AssignedProcessor);
  57. }
  58. VOID
  59. NdisMSetTimer(
  60. IN PNDIS_MINIPORT_TIMER MiniportTimer,
  61. IN UINT MillisecondsToDelay
  62. )
  63. /*++
  64. Routine Description:
  65. Sets up TimerFunction to fire after MillisecondsToDelay.
  66. Arguments:
  67. MiniportTimer - the timer object.
  68. MillisecondsToDelay - Amount of time before TimerFunction is started.
  69. Return Value:
  70. None.
  71. --*/
  72. {
  73. LARGE_INTEGER FireUpTime;
  74. FireUpTime.QuadPart = Int32x32To64((LONG)MillisecondsToDelay, -10000);
  75. #if CHECK_TIMER
  76. if (MiniportTimer->Miniport->DriverHandle->Flags & fMINIBLOCK_VERIFYING)
  77. {
  78. KIRQL OldIrql;
  79. PNDIS_MINIPORT_TIMER pTimer;
  80. ACQUIRE_SPIN_LOCK(&MiniportTimer->Miniport->TimerQueueLock, &OldIrql);
  81. //
  82. // check to see if the timer is already set
  83. //
  84. for (pTimer = MiniportTimer->Miniport->TimerQueue;
  85. pTimer != NULL;
  86. pTimer = pTimer->NextTimer)
  87. {
  88. if (pTimer == MiniportTimer)
  89. break;
  90. }
  91. if (pTimer == NULL)
  92. {
  93. MiniportTimer->NextTimer = MiniportTimer->Miniport->TimerQueue;
  94. MiniportTimer->Miniport->TimerQueue = MiniportTimer;
  95. }
  96. RELEASE_SPIN_LOCK(&MiniportTimer->Miniport->TimerQueueLock, OldIrql);
  97. }
  98. #endif
  99. //
  100. // Set the timer
  101. //
  102. SET_TIMER(&MiniportTimer->Timer, FireUpTime, &MiniportTimer->Dpc);
  103. }
  104. VOID
  105. NdisMCancelTimer(
  106. IN PNDIS_MINIPORT_TIMER Timer,
  107. OUT PBOOLEAN TimerCancelled
  108. )
  109. /*++
  110. Routine Description:
  111. Cancels a timer.
  112. Arguments:
  113. Timer - The timer to cancel.
  114. TimerCancelled - TRUE if the timer was canceled, else FALSE.
  115. Return Value:
  116. None
  117. --*/
  118. {
  119. if (MINIPORT_VERIFY_TEST_FLAG(Timer->Miniport, fMINIPORT_VERIFY_FAIL_CANCEL_TIMER))
  120. {
  121. *TimerCancelled = FALSE;
  122. #if DBG
  123. DbgPrint("NdisMCancelTimer for Timer %p failed to verify miniport %p\n",
  124. Timer, Timer->Miniport);
  125. #endif
  126. return;
  127. }
  128. *TimerCancelled = CANCEL_TIMER(&((PNDIS_TIMER)Timer)->Timer);
  129. #if CHECK_TIMER
  130. if (Timer->Miniport->DriverHandle->Flags & fMINIBLOCK_VERIFYING)
  131. {
  132. if (*TimerCancelled)
  133. {
  134. PNDIS_MINIPORT_TIMER *pTimer;
  135. KIRQL OldIrql;
  136. BOOLEAN Dequeued = FALSE;
  137. ACQUIRE_SPIN_LOCK(&Timer->Miniport->TimerQueueLock, &OldIrql);
  138. for (pTimer = &Timer->Miniport->TimerQueue;
  139. *pTimer != NULL;
  140. pTimer = &(*pTimer)->NextTimer)
  141. {
  142. if (*pTimer == Timer)
  143. {
  144. *pTimer = Timer->NextTimer;
  145. Dequeued = TRUE;
  146. break;
  147. }
  148. }
  149. RELEASE_SPIN_LOCK(&Timer->Miniport->TimerQueueLock, OldIrql);
  150. }
  151. }
  152. #endif
  153. }
  154. VOID
  155. ndisMTimerDpc(
  156. IN PKDPC Dpc,
  157. IN PVOID Context,
  158. IN PVOID SystemContext1,
  159. IN PVOID SystemContext2
  160. )
  161. /*++
  162. Routine Description:
  163. This function services all mini-port timer interrupts. It then calls the
  164. appropriate function that mini-port consumers have registered in the
  165. call to NdisMInitializeTimer.
  166. Arguments:
  167. Dpc - Not used.
  168. Context - A pointer to the NDIS_MINIPORT_TIMER which is bound to this DPC.
  169. SystemContext1,2 - not used.
  170. Return Value:
  171. None.
  172. Note:
  173. by virtue of having either the local lock or miniport spinlock, the driver's
  174. timer function is protected against getting unloaded .
  175. --*/
  176. {
  177. PNDIS_MINIPORT_TIMER MiniportTimer = (PNDIS_MINIPORT_TIMER)(Context);
  178. PNDIS_MINIPORT_BLOCK Miniport = MiniportTimer->Miniport;
  179. PNDIS_TIMER_FUNCTION TimerFunction;
  180. UNREFERENCED_PARAMETER(Dpc);
  181. UNREFERENCED_PARAMETER(SystemContext1);
  182. UNREFERENCED_PARAMETER(SystemContext2);
  183. NDIS_ACQUIRE_MINIPORT_SPIN_LOCK_DPC(Miniport);
  184. do
  185. {
  186. BLOCK_LOCK_MINIPORT_DPC_L(Miniport);
  187. #if CHECK_TIMER
  188. if (Miniport->DriverHandle->Flags & fMINIBLOCK_VERIFYING)
  189. {
  190. PNDIS_MINIPORT_TIMER *pTimer;
  191. BOOLEAN Dequeued = FALSE;
  192. ACQUIRE_SPIN_LOCK_DPC(&Miniport->TimerQueueLock);
  193. for (pTimer = &Miniport->TimerQueue;
  194. *pTimer != NULL;
  195. pTimer = &(*pTimer)->NextTimer)
  196. {
  197. if (*pTimer == MiniportTimer)
  198. {
  199. //
  200. // don't dequeue periodic timers when they fire
  201. //
  202. if (MiniportTimer->Timer.Period == 0)
  203. {
  204. *pTimer = MiniportTimer->NextTimer;
  205. }
  206. Dequeued = TRUE;
  207. break;
  208. }
  209. }
  210. RELEASE_SPIN_LOCK_DPC(&Miniport->TimerQueueLock);
  211. }
  212. #endif
  213. if (MINIPORT_TEST_FLAG(Miniport, fMINIPORT_IN_INITIALIZE))
  214. {
  215. //
  216. // Queue the timer as we cannot call the miniport
  217. //
  218. NdisMSetTimer(MiniportTimer, 10);
  219. //
  220. // Unlock the miniport
  221. //
  222. UNLOCK_MINIPORT_L(Miniport);
  223. break;
  224. }
  225. //
  226. // if the miniport is shut down (no, I don't mean halted)
  227. // then don't send the timer down.
  228. //
  229. if (MINIPORT_PNP_TEST_FLAG(Miniport, fMINIPORT_SHUTTING_DOWN))
  230. {
  231. UNLOCK_MINIPORT_L(Miniport);
  232. break;
  233. }
  234. //
  235. // Call Miniport timer function
  236. //
  237. TimerFunction = MiniportTimer->MiniportTimerFunction;
  238. NDIS_RELEASE_MINIPORT_SPIN_LOCK_DPC(Miniport);
  239. (*TimerFunction)(NULL, MiniportTimer->MiniportTimerContext, NULL, NULL);
  240. NDIS_ACQUIRE_MINIPORT_SPIN_LOCK_DPC(Miniport);
  241. NDISM_PROCESS_DEFERRED(Miniport);
  242. UNLOCK_MINIPORT_L(Miniport);
  243. } while (FALSE);
  244. NDIS_RELEASE_MINIPORT_SPIN_LOCK_DPC(Miniport);
  245. }
  246. VOID
  247. ndisMTimerDpcX(
  248. IN PKDPC Dpc,
  249. IN PVOID Context,
  250. IN PVOID SystemContext1,
  251. IN PVOID SystemContext2
  252. )
  253. /*++
  254. Routine Description:
  255. This function services all mini-port timer DPCs. It then calls the
  256. appropriate function that mini-port consumers have registered in the
  257. call to NdisMInitializeTimer.
  258. Arguments:
  259. Dpc - Not used.
  260. Context - A pointer to the NDIS_MINIPORT_TIMER which is bound to this DPC.
  261. SystemContext1,2 - not used.
  262. Return Value:
  263. None.
  264. Note:
  265. we have to make sure the driver does not go away while the driver's timer function
  266. is running. this can happen for example if the timer function was to signal an event
  267. to let the Halthandler and Halt proceed.
  268. No need to protect the miniport here becasue we do not touch the miniport after the
  269. timer function returns.
  270. --*/
  271. {
  272. PNDIS_MINIPORT_TIMER MiniportTimer = (PNDIS_MINIPORT_TIMER)(Context);
  273. PNDIS_MINIPORT_BLOCK Miniport = MiniportTimer->Miniport;
  274. PNDIS_M_DRIVER_BLOCK MiniDriver = Miniport->DriverHandle;
  275. UNREFERENCED_PARAMETER(Dpc);
  276. UNREFERENCED_PARAMETER(SystemContext1);
  277. UNREFERENCED_PARAMETER(SystemContext2);
  278. //
  279. // make sure the driver does not go away while the timer function
  280. // is running
  281. ndisReferenceDriver(MiniDriver);
  282. #if CHECK_TIMER
  283. if (MiniportTimer->Miniport->DriverHandle->Flags & fMINIBLOCK_VERIFYING)
  284. {
  285. PNDIS_MINIPORT_TIMER *pTimer;
  286. KIRQL OldIrql;
  287. BOOLEAN Dequeued = FALSE;
  288. ACQUIRE_SPIN_LOCK_DPC(&MiniportTimer->Miniport->TimerQueueLock);
  289. for (pTimer = &Miniport->TimerQueue;
  290. *pTimer != NULL;
  291. pTimer = &(*pTimer)->NextTimer)
  292. {
  293. if (*pTimer == MiniportTimer)
  294. {
  295. //
  296. // don't dequeue periodic timers when they fire
  297. //
  298. if (MiniportTimer->Timer.Period == 0)
  299. {
  300. *pTimer = MiniportTimer->NextTimer;
  301. }
  302. Dequeued = TRUE;
  303. break;
  304. }
  305. }
  306. RELEASE_SPIN_LOCK_DPC(&MiniportTimer->Miniport->TimerQueueLock);
  307. }
  308. #endif
  309. //
  310. // if the miniport is shut down (no, I don't mean halted)
  311. // then don't send the timer down.
  312. //
  313. if (!MINIPORT_PNP_TEST_FLAG(Miniport, fMINIPORT_SHUTTING_DOWN))
  314. {
  315. (*MiniportTimer->MiniportTimerFunction)(NULL, MiniportTimer->MiniportTimerContext, NULL, NULL);
  316. }
  317. //
  318. // this can be called at DPC
  319. //
  320. ndisDereferenceDriver(MiniDriver, FALSE);
  321. }
  322. NDIS_STATUS
  323. NdisMRegisterInterrupt(
  324. OUT PNDIS_MINIPORT_INTERRUPT Interrupt,
  325. IN NDIS_HANDLE MiniportAdapterHandle,
  326. IN UINT InterruptVector,
  327. IN UINT InterruptLevel,
  328. IN BOOLEAN RequestIsr,
  329. IN BOOLEAN SharedInterrupt,
  330. IN NDIS_INTERRUPT_MODE InterruptMode
  331. )
  332. {
  333. PNDIS_MINIPORT_BLOCK Miniport = (PNDIS_MINIPORT_BLOCK)MiniportAdapterHandle;
  334. NDIS_STATUS Status;
  335. Interrupt->Reserved = (PVOID)Miniport->MiniportAdapterContext;
  336. Miniport->Interrupt = (PNDIS_MINIPORT_INTERRUPT)Interrupt;
  337. Status = ndisMRegisterInterruptCommon(
  338. Interrupt,
  339. MiniportAdapterHandle,
  340. InterruptVector,
  341. InterruptLevel,
  342. RequestIsr,
  343. SharedInterrupt,
  344. InterruptMode);
  345. if (Status != NDIS_STATUS_SUCCESS)
  346. {
  347. Miniport->Interrupt = NULL;
  348. }
  349. return Status;
  350. }
  351. VOID
  352. NdisMDeregisterInterrupt(
  353. IN PNDIS_MINIPORT_INTERRUPT MiniportInterrupt
  354. )
  355. {
  356. DBGPRINT(DBG_COMP_INIT, DBG_LEVEL_INFO,
  357. ("==>NdisMDeregisterInterrupt: Miniport %p\n", MiniportInterrupt->Miniport));
  358. do
  359. {
  360. if (MiniportInterrupt->InterruptObject == NULL)
  361. break;
  362. ndisMDeregisterInterruptCommon(MiniportInterrupt);
  363. MiniportInterrupt->Miniport->Interrupt = NULL;
  364. } while (FALSE);
  365. DBGPRINT(DBG_COMP_INIT, DBG_LEVEL_INFO,
  366. ("<==NdisMDeregisterInterrupt: Miniport %p\n", MiniportInterrupt->Miniport));
  367. }
  368. BOOLEAN
  369. NdisMSynchronizeWithInterrupt(
  370. IN PNDIS_MINIPORT_INTERRUPT Interrupt,
  371. IN PVOID SynchronizeFunction,
  372. IN PVOID SynchronizeContext
  373. )
  374. {
  375. return (SYNC_WITH_ISR((Interrupt)->InterruptObject,
  376. SynchronizeFunction,
  377. SynchronizeContext));
  378. }
  379. VOID
  380. ndisMWakeUpDpcX(
  381. IN PKDPC Dpc,
  382. IN PVOID Context,
  383. IN PVOID SystemContext1,
  384. IN PVOID SystemContext2
  385. )
  386. /*++
  387. Routine Description:
  388. Arguments:
  389. Return Value:
  390. --*/
  391. {
  392. PNDIS_MINIPORT_BLOCK Miniport = (PNDIS_MINIPORT_BLOCK)(Context);
  393. BOOLEAN Hung = FALSE;
  394. PNDIS_MINIPORT_WORK_ITEM WorkItem;
  395. NDIS_STATUS Status;
  396. BOOLEAN AddressingReset = FALSE;
  397. BOOLEAN fDontReset = FALSE;
  398. UNREFERENCED_PARAMETER(Dpc);
  399. UNREFERENCED_PARAMETER(SystemContext1);
  400. UNREFERENCED_PARAMETER(SystemContext2);
  401. do
  402. {
  403. //
  404. // If the miniport is halting then do nothing.
  405. //
  406. if (MINIPORT_TEST_FLAG(Miniport, fMINIPORT_PM_HALTING))
  407. {
  408. break;
  409. }
  410. Miniport->CFHangCurrentTick--;
  411. if (Miniport->CFHangCurrentTick == 0)
  412. {
  413. Miniport->CFHangCurrentTick = Miniport->CFHangTicks;
  414. //
  415. // Call Miniport stall checker.
  416. //
  417. if (Miniport->DriverHandle->MiniportCharacteristics.CheckForHangHandler != NULL)
  418. {
  419. Hung = (Miniport->DriverHandle->MiniportCharacteristics.CheckForHangHandler)(Miniport->MiniportAdapterContext);
  420. }
  421. //
  422. // Was there a request to reset the device?
  423. //
  424. if (MINIPORT_TEST_FLAG(Miniport, fMINIPORT_RESTORING_FILTERS))
  425. {
  426. Hung = FALSE;
  427. break;
  428. }
  429. NDIS_ACQUIRE_MINIPORT_SPIN_LOCK_DPC(Miniport);
  430. //
  431. // Check the internal wrapper states for the miniport and
  432. // see if we think the miniport should be reset.
  433. //
  434. if (!Hung)
  435. {
  436. //
  437. // Should we check the request queue?
  438. // Did a request pend too long?
  439. //
  440. if (!MINIPORT_TEST_FLAG(Miniport, fMINIPORT_IGNORE_REQUEST_QUEUE) &&
  441. MINIPORT_TEST_FLAG(Miniport, fMINIPORT_PROCESSING_REQUEST))
  442. {
  443. if (MINIPORT_TEST_FLAG(Miniport, fMINIPORT_REQUEST_TIMEOUT))
  444. {
  445. Miniport->InternalResetCount ++;
  446. Hung = TRUE;
  447. }
  448. else
  449. {
  450. if (Miniport->CFHangXTicks == 0)
  451. {
  452. MINIPORT_SET_FLAG(Miniport, fMINIPORT_REQUEST_TIMEOUT);
  453. }
  454. else
  455. {
  456. Miniport->CFHangXTicks--;
  457. }
  458. }
  459. }
  460. }
  461. else
  462. {
  463. Miniport->MiniportResetCount ++;
  464. }
  465. if (Hung)
  466. {
  467. if (NULL != Miniport->DriverHandle->MiniportCharacteristics.ResetHandler)
  468. {
  469. if ((MINIPORT_TEST_FLAG(Miniport, fMINIPORT_RESET_IN_PROGRESS)) ||
  470. (MINIPORT_PNP_TEST_FLAG(Miniport, fMINIPORT_HALTING)))
  471. {
  472. fDontReset = TRUE;
  473. }
  474. else
  475. {
  476. MINIPORT_SET_FLAG(Miniport, fMINIPORT_RESET_IN_PROGRESS);
  477. Miniport->ResetOpen = NULL;
  478. }
  479. ndisMSwapOpenHandlers(Miniport,
  480. NDIS_STATUS_RESET_IN_PROGRESS,
  481. fMINIPORT_STATE_RESETTING);
  482. }
  483. else Hung = FALSE;
  484. }
  485. if (Hung && !fDontReset)
  486. {
  487. MINIPORT_SET_FLAG(Miniport, fMINIPORT_CALLING_RESET);
  488. //
  489. // wait for all the requests to come back.
  490. // note: this is not the same as waiting for all requests to complete
  491. // we just make sure the original request call has come back
  492. //
  493. do
  494. {
  495. if (Miniport->RequestCount == 0)
  496. {
  497. break;
  498. }
  499. else
  500. {
  501. NDIS_RELEASE_MINIPORT_SPIN_LOCK_DPC(Miniport);
  502. NDIS_INTERNAL_STALL(50);
  503. NDIS_ACQUIRE_MINIPORT_SPIN_LOCK_DPC(Miniport);
  504. }
  505. } while (TRUE);
  506. NDIS_RELEASE_MINIPORT_SPIN_LOCK_DPC(Miniport);
  507. NdisMIndicateStatus(Miniport, NDIS_STATUS_RESET_START, NULL, 0);
  508. NdisMIndicateStatusComplete(Miniport);
  509. DBGPRINT(DBG_COMP_WORK_ITEM, DBG_LEVEL_INFO,
  510. ("Calling miniport reset\n"));
  511. //
  512. // Call the miniport's reset handler.
  513. //
  514. Status = (Miniport->DriverHandle->MiniportCharacteristics.ResetHandler)(
  515. &AddressingReset,
  516. Miniport->MiniportAdapterContext);
  517. if (NDIS_STATUS_PENDING != Status)
  518. {
  519. NdisMResetComplete(Miniport, Status, AddressingReset);
  520. }
  521. }
  522. else
  523. {
  524. NDIS_RELEASE_MINIPORT_SPIN_LOCK_DPC(Miniport);
  525. }
  526. }
  527. if (!Hung)
  528. {
  529. if (MINIPORT_TEST_FLAG(Miniport, fMINIPORT_REQUIRES_MEDIA_POLLING) == TRUE)
  530. {
  531. NDIS_ACQUIRE_MINIPORT_SPIN_LOCK_DPC(Miniport);
  532. ndisMPollMediaState(Miniport);
  533. NDIS_RELEASE_MINIPORT_SPIN_LOCK_DPC(Miniport);
  534. }
  535. }
  536. } while (FALSE);
  537. }
  538. VOID
  539. ndisMWakeUpDpc(
  540. IN PKDPC Dpc,
  541. IN PVOID Context,
  542. IN PVOID SystemContext1,
  543. IN PVOID SystemContext2
  544. )
  545. /*++
  546. Routine Description:
  547. This function services all mini-port. It checks to see if a mini-port is
  548. ever stalled.
  549. Arguments:
  550. Dpc - Not used.
  551. Context - A pointer to the NDIS_TIMER which is bound to this DPC.
  552. SystemContext1,2 - not used.
  553. Return Value:
  554. None.
  555. --*/
  556. {
  557. PNDIS_MINIPORT_BLOCK Miniport = (PNDIS_MINIPORT_BLOCK)(Context);
  558. BOOLEAN Hung = FALSE;
  559. BOOLEAN LocalLock;
  560. PNDIS_MINIPORT_WORK_ITEM WorkItem;
  561. UNREFERENCED_PARAMETER(Dpc);
  562. UNREFERENCED_PARAMETER(SystemContext1);
  563. UNREFERENCED_PARAMETER(SystemContext2);
  564. NDIS_ACQUIRE_MINIPORT_SPIN_LOCK_DPC(Miniport);
  565. do
  566. {
  567. //
  568. // If the miniport is halting then do nothing.
  569. //
  570. if (MINIPORT_TEST_FLAG(Miniport, fMINIPORT_PM_HALTING))
  571. {
  572. break;
  573. }
  574. //
  575. // Can we get the miniport lock. If not then quit. This is not time-critical
  576. // and we can try again next tick
  577. //
  578. LOCK_MINIPORT(Miniport, LocalLock);
  579. if (!LocalLock ||
  580. MINIPORT_TEST_FLAG(Miniport, (fMINIPORT_RESET_IN_PROGRESS | fMINIPORT_RESET_REQUESTED)))
  581. {
  582. UNLOCK_MINIPORT(Miniport, LocalLock);
  583. break;
  584. }
  585. Miniport->CFHangCurrentTick--;
  586. if (Miniport->CFHangCurrentTick == 0)
  587. {
  588. Miniport->CFHangCurrentTick = Miniport->CFHangTicks;
  589. //
  590. // Call Miniport stall checker.
  591. //
  592. if (Miniport->DriverHandle->MiniportCharacteristics.CheckForHangHandler != NULL)
  593. {
  594. NDIS_RELEASE_MINIPORT_SPIN_LOCK_DPC(Miniport);
  595. Hung = (Miniport->DriverHandle->MiniportCharacteristics.CheckForHangHandler)(Miniport->MiniportAdapterContext);
  596. NDIS_ACQUIRE_MINIPORT_SPIN_LOCK_DPC(Miniport);
  597. }
  598. if (MINIPORT_TEST_FLAG(Miniport, fMINIPORT_RESTORING_FILTERS))
  599. {
  600. //
  601. // We are restoring filters post reset. Don't pre-empt again
  602. //
  603. Hung = FALSE;
  604. UNLOCK_MINIPORT(Miniport, LocalLock);
  605. break;
  606. }
  607. //
  608. // Check the internal wrapper states for the miniport and
  609. // see if we think the miniport should be reset.
  610. //
  611. if (Hung)
  612. {
  613. Miniport->MiniportResetCount ++;
  614. }
  615. else do
  616. {
  617. //
  618. // Should we check the request queue ? Did a request pend too long ?
  619. //
  620. if ((Miniport->Flags & (fMINIPORT_IGNORE_REQUEST_QUEUE|fMINIPORT_PROCESSING_REQUEST)) == fMINIPORT_PROCESSING_REQUEST)
  621. {
  622. if (MINIPORT_TEST_FLAG(Miniport, fMINIPORT_REQUEST_TIMEOUT))
  623. {
  624. Miniport->InternalResetCount ++;
  625. Hung = TRUE;
  626. break;
  627. }
  628. else
  629. {
  630. if (Miniport->CFHangXTicks == 0)
  631. {
  632. MINIPORT_SET_FLAG(Miniport, fMINIPORT_REQUEST_TIMEOUT);
  633. }
  634. else
  635. {
  636. Miniport->CFHangXTicks--;
  637. }
  638. }
  639. }
  640. //
  641. // Should we check the packet queue ? Did a packet pend too long ?
  642. //
  643. if (!MINIPORT_TEST_FLAG(Miniport, fMINIPORT_IGNORE_PACKET_QUEUE))
  644. {
  645. PNDIS_PACKET Packet;
  646. GET_FIRST_MINIPORT_PACKET(Miniport, &Packet);
  647. //
  648. // Does the miniport have possession of any packets?
  649. //
  650. if ((Packet != NULL) &&
  651. MINIPORT_TEST_PACKET_FLAG(Packet, fPACKET_PENDING))
  652. {
  653. //
  654. // Has the packet timed out?
  655. //
  656. if (MINIPORT_TEST_PACKET_FLAG(Packet, fPACKET_HAS_TIMED_OUT))
  657. {
  658. //
  659. // Reset the miniport.
  660. //
  661. Miniport->InternalResetCount ++;
  662. Hung = TRUE;
  663. }
  664. else
  665. {
  666. //
  667. // Set the packet flag and wait to see if it is still
  668. // there next time in.
  669. //
  670. MINIPORT_SET_PACKET_FLAG(Packet, fPACKET_HAS_TIMED_OUT);
  671. }
  672. }
  673. else
  674. {
  675. break;
  676. }
  677. //
  678. // If we are hung then we don't need to check for token ring errors.
  679. //
  680. if (Hung)
  681. {
  682. break;
  683. }
  684. }
  685. //
  686. // Are we ignoring token ring errors?
  687. //
  688. if (!MINIPORT_TEST_FLAG(Miniport, fMINIPORT_IGNORE_TOKEN_RING_ERRORS))
  689. {
  690. //
  691. // Token Ring reset...
  692. //
  693. if (Miniport->TrResetRing == 1)
  694. {
  695. Miniport->InternalResetCount ++;
  696. Hung = TRUE;
  697. break;
  698. }
  699. else if (Miniport->TrResetRing > 1)
  700. {
  701. Miniport->TrResetRing--;
  702. }
  703. }
  704. } while (FALSE);
  705. //
  706. // If the miniport is hung then queue a workitem to reset it.
  707. //
  708. if (Hung)
  709. {
  710. if (!MINIPORT_TEST_FLAG(Miniport, fMINIPORT_RESTORING_FILTERS))
  711. {
  712. if (NULL != Miniport->DriverHandle->MiniportCharacteristics.ResetHandler)
  713. {
  714. NDISM_QUEUE_WORK_ITEM(Miniport, NdisWorkItemResetRequested, NULL);
  715. }
  716. }
  717. }
  718. }
  719. if (!Hung)
  720. {
  721. if (MINIPORT_TEST_FLAG(Miniport, fMINIPORT_REQUIRES_MEDIA_POLLING) == TRUE)
  722. {
  723. ndisMPollMediaState(Miniport);
  724. }
  725. }
  726. //
  727. // Process any changes that have occurred.
  728. //
  729. NDISM_PROCESS_DEFERRED(Miniport);
  730. UNLOCK_MINIPORT_L(Miniport);
  731. } while (FALSE);
  732. NDIS_RELEASE_MINIPORT_SPIN_LOCK_DPC(Miniport);
  733. }
  734. BOOLEAN
  735. ndisMIsr(
  736. IN PKINTERRUPT KInterrupt,
  737. IN PVOID Context
  738. )
  739. /*++
  740. Routine Description:
  741. Handles ALL Miniport interrupts, calling the appropriate Miniport ISR and DPC
  742. depending on the context.
  743. Arguments:
  744. Interrupt - Interrupt object for the Mac.
  745. Context - Really a pointer to the interrupt.
  746. Return Value:
  747. None.
  748. --*/
  749. {
  750. PNDIS_MINIPORT_INTERRUPT Interrupt = (PNDIS_MINIPORT_INTERRUPT)Context;
  751. PNDIS_MINIPORT_BLOCK Miniport = Interrupt->Miniport;
  752. BOOLEAN InterruptRecognized;
  753. BOOLEAN IsrCalled = FALSE, QueueDpc = FALSE;
  754. do
  755. {
  756. if (MINIPORT_TEST_FLAG(Miniport, fMINIPORT_NORMAL_INTERRUPTS))
  757. {
  758. MINIPORT_DISABLE_INTERRUPT_EX(Miniport, Interrupt);
  759. InterruptRecognized = QueueDpc = TRUE;
  760. }
  761. else
  762. {
  763. IsrCalled = TRUE;
  764. // Interrupt->MiniportIsr(&InterruptRecognized,
  765. // &QueueDpc,
  766. // Miniport->MiniportAdapterContext);
  767. Interrupt->MiniportIsr(&InterruptRecognized,
  768. &QueueDpc,
  769. Interrupt->Reserved);
  770. }
  771. if (QueueDpc)
  772. {
  773. InterlockedIncrement((PLONG)&Interrupt->DpcCount);
  774. if (QUEUE_DPC(&Interrupt->InterruptDpc))
  775. {
  776. break;
  777. }
  778. //
  779. // The DPC was already queued, so we have an extra reference (we
  780. // do it this way to ensure that the reference is added *before*
  781. // the DPC is queued).
  782. InterlockedDecrement((PLONG)&Interrupt->DpcCount);
  783. break;
  784. }
  785. if (!IsrCalled)
  786. {
  787. if (!Interrupt->SharedInterrupt &&
  788. !Interrupt->IsrRequested &&
  789. !MINIPORT_TEST_FLAG(Miniport, fMINIPORT_IN_INITIALIZE))
  790. {
  791. ASSERT(Miniport->DisableInterruptHandler != NULL);
  792. MINIPORT_DISABLE_INTERRUPT_EX(Miniport, Interrupt);
  793. InterruptRecognized = TRUE;
  794. break;
  795. }
  796. //
  797. // Call MiniportIsr, but don't queue a DPC.
  798. //
  799. // Interrupt->MiniportIsr(&InterruptRecognized,
  800. // &QueueDpc,
  801. // Miniport->MiniportAdapterContext);
  802. Interrupt->MiniportIsr(&InterruptRecognized,
  803. &QueueDpc,
  804. Interrupt->Reserved);
  805. }
  806. } while (FALSE);
  807. return(InterruptRecognized);
  808. }
  809. VOID
  810. ndisMDpc(
  811. IN PVOID SystemSpecific1,
  812. IN PVOID InterruptContext,
  813. IN PVOID SystemSpecific2,
  814. IN PVOID SystemSpecific3
  815. )
  816. /*++
  817. Routine Description:
  818. Handles ALL Miniport interrupt DPCs, calling the appropriate Miniport DPC
  819. depending on the context.
  820. Arguments:
  821. Interrupt - Interrupt object for the Mac.
  822. Context - Really a pointer to the Interrupt.
  823. Return Value:
  824. None.
  825. --*/
  826. {
  827. PNDIS_MINIPORT_INTERRUPT Interrupt = (PNDIS_MINIPORT_INTERRUPT)(InterruptContext);
  828. PNDIS_MINIPORT_BLOCK Miniport = Interrupt->Miniport;
  829. W_HANDLE_INTERRUPT_HANDLER MiniportDpc = Interrupt->MiniportDpc;
  830. NDIS_ACQUIRE_MINIPORT_SPIN_LOCK_DPC(Miniport);
  831. do
  832. {
  833. if (MINIPORT_TEST_FLAG(Miniport, (fMINIPORT_PM_HALTING)) ||
  834. Interrupt->DpcCountLock)
  835. {
  836. InterlockedDecrement((PLONG)&Interrupt->DpcCount);
  837. if (Interrupt->DpcCount==0)
  838. {
  839. SET_EVENT(&Interrupt->DpcsCompletedEvent);
  840. }
  841. break;
  842. }
  843. BLOCK_LOCK_MINIPORT_DPC_L(Miniport);
  844. NDIS_RELEASE_MINIPORT_SPIN_LOCK_DPC(Miniport);
  845. // (*MiniportDpc)(Miniport->MiniportAdapterContext);
  846. (*MiniportDpc)(Interrupt->Reserved);
  847. NDIS_ACQUIRE_MINIPORT_SPIN_LOCK_DPC(Miniport);
  848. InterlockedDecrement((PLONG)&Interrupt->DpcCount);
  849. MINIPORT_SYNC_ENABLE_INTERRUPT_EX(Miniport, Interrupt);
  850. NDISM_PROCESS_DEFERRED(Miniport);
  851. UNLOCK_MINIPORT(Miniport, TRUE);
  852. } while (FALSE);
  853. NDIS_RELEASE_MINIPORT_SPIN_LOCK_DPC(Miniport);
  854. }
  855. VOID
  856. ndisMDpcX(
  857. IN PVOID SystemSpecific1,
  858. IN PVOID InterruptContext,
  859. IN PVOID SystemSpecific2,
  860. IN PVOID SystemSpecific3
  861. )
  862. /*++
  863. Routine Description:
  864. Handles ALL Miniport interrupt DPCs, calling the appropriate Miniport DPC
  865. depending on the context.
  866. Arguments:
  867. Interrupt - Interrupt object for the Mac.
  868. Context - Really a pointer to the Interrupt.
  869. Return Value:
  870. None.
  871. --*/
  872. {
  873. PNDIS_MINIPORT_INTERRUPT Interrupt = (PNDIS_MINIPORT_INTERRUPT)(InterruptContext);
  874. PNDIS_MINIPORT_BLOCK Miniport = Interrupt->Miniport;
  875. W_HANDLE_INTERRUPT_HANDLER MiniportDpc = Interrupt->MiniportDpc;
  876. if (MINIPORT_TEST_FLAG(Miniport, (fMINIPORT_PM_HALTING)) ||
  877. Interrupt->DpcCountLock)
  878. {
  879. InterlockedDecrement((PLONG)&Interrupt->DpcCount);
  880. if (Interrupt->DpcCount==0)
  881. {
  882. SET_EVENT(&Interrupt->DpcsCompletedEvent);
  883. }
  884. }
  885. else
  886. {
  887. //(*MiniportDpc)(Miniport->MiniportAdapterContext);
  888. (*MiniportDpc)(Interrupt->Reserved);
  889. InterlockedDecrement((PLONG)&Interrupt->DpcCount);
  890. MINIPORT_SYNC_ENABLE_INTERRUPT_EX(Miniport, Interrupt);
  891. }
  892. }
  893. VOID
  894. ndisMDeferredDpc(
  895. IN PKDPC Dpc,
  896. IN PVOID Context,
  897. IN PVOID SystemContext1,
  898. IN PVOID SystemContext2
  899. )
  900. /*++
  901. Routine Description:
  902. This is a DPC routine that is queue'd by some of the [full-duplex] routines
  903. in order to get ndisMProcessDeferred to run outside of their
  904. context.
  905. Arguments:
  906. Return Value:
  907. None.
  908. --*/
  909. {
  910. PNDIS_MINIPORT_BLOCK Miniport = Context;
  911. UNREFERENCED_PARAMETER(Dpc);
  912. UNREFERENCED_PARAMETER(SystemContext1);
  913. UNREFERENCED_PARAMETER(SystemContext2);
  914. NDIS_ACQUIRE_MINIPORT_SPIN_LOCK_DPC(Miniport);
  915. BLOCK_LOCK_MINIPORT_DPC_L(Miniport);
  916. NDISM_PROCESS_DEFERRED(Miniport);
  917. UNLOCK_MINIPORT(Miniport, TRUE);
  918. NDIS_RELEASE_MINIPORT_SPIN_LOCK_DPC(Miniport);
  919. }
  920. NDIS_STATUS
  921. NdisMRegisterInterruptEx(
  922. OUT PNDIS_MINIPORT_INTERRUPT_EX Interrupt,
  923. IN NDIS_HANDLE MiniportAdapterHandle,
  924. IN UINT InterruptVector,
  925. IN UINT InterruptLevel,
  926. IN BOOLEAN RequestIsr,
  927. IN BOOLEAN SharedInterrupt,
  928. IN NDIS_INTERRUPT_MODE InterruptMode
  929. )
  930. {
  931. PNDIS_MINIPORT_BLOCK Miniport = (PNDIS_MINIPORT_BLOCK)MiniportAdapterHandle;
  932. NDIS_STATUS Status;
  933. KIRQL OldIrql;
  934. Interrupt->InterruptContext = (PVOID)Interrupt;
  935. NDIS_ACQUIRE_MINIPORT_SPIN_LOCK(Miniport, &OldIrql);
  936. Interrupt->NextInterrupt = (PNDIS_MINIPORT_INTERRUPT_EX)Miniport->Interrupt;
  937. Miniport->Interrupt = (PNDIS_MINIPORT_INTERRUPT)Interrupt;
  938. NDIS_RELEASE_MINIPORT_SPIN_LOCK(Miniport, OldIrql);
  939. Status = ndisMRegisterInterruptCommon(
  940. (PNDIS_MINIPORT_INTERRUPT)Interrupt,
  941. MiniportAdapterHandle,
  942. InterruptVector,
  943. InterruptLevel,
  944. RequestIsr,
  945. SharedInterrupt,
  946. InterruptMode);
  947. if (Status != NDIS_STATUS_SUCCESS)
  948. {
  949. PNDIS_MINIPORT_INTERRUPT_EX *ppQ;
  950. PnPReferencePackage();
  951. NDIS_ACQUIRE_MINIPORT_SPIN_LOCK(Miniport, &OldIrql);
  952. for (ppQ = (PNDIS_MINIPORT_INTERRUPT_EX *)&Miniport->Interrupt;
  953. *ppQ != NULL;
  954. ppQ = &(*ppQ)->NextInterrupt)
  955. {
  956. if (*ppQ == Interrupt)
  957. {
  958. *ppQ = Interrupt->NextInterrupt;
  959. break;
  960. }
  961. }
  962. PnPDereferencePackage();
  963. NDIS_RELEASE_MINIPORT_SPIN_LOCK(Miniport, OldIrql);
  964. }
  965. return Status;
  966. }
  967. VOID
  968. NdisMDeregisterInterruptEx(
  969. IN PNDIS_MINIPORT_INTERRUPT_EX MiniportInterrupt
  970. )
  971. {
  972. PNDIS_MINIPORT_BLOCK Miniport = MiniportInterrupt->Miniport;
  973. PNDIS_MINIPORT_INTERRUPT_EX *ppQ;
  974. KIRQL OldIrql;
  975. DBGPRINT(DBG_COMP_INIT, DBG_LEVEL_INFO,
  976. ("==>NdisMDeregisterInterruptEx: Miniport %p\n", MiniportInterrupt->Miniport));
  977. ndisMDeregisterInterruptCommon((PNDIS_MINIPORT_INTERRUPT)MiniportInterrupt);
  978. PnPReferencePackage();
  979. NDIS_ACQUIRE_MINIPORT_SPIN_LOCK(Miniport, &OldIrql);
  980. for (ppQ = (PNDIS_MINIPORT_INTERRUPT_EX *)&Miniport->Interrupt;
  981. *ppQ != NULL;
  982. ppQ = &(*ppQ)->NextInterrupt)
  983. {
  984. if (*ppQ == MiniportInterrupt)
  985. {
  986. *ppQ = MiniportInterrupt->NextInterrupt;
  987. break;
  988. }
  989. }
  990. NDIS_RELEASE_MINIPORT_SPIN_LOCK(Miniport, OldIrql);
  991. PnPDereferencePackage();
  992. DBGPRINT(DBG_COMP_INIT, DBG_LEVEL_INFO,
  993. ("<==NdisMDeregisterInterruptEx: Miniport %p\n", MiniportInterrupt->Miniport));
  994. }
  995. NDIS_STATUS
  996. ndisMRegisterInterruptCommon(
  997. OUT PNDIS_MINIPORT_INTERRUPT Interrupt,
  998. IN NDIS_HANDLE MiniportAdapterHandle,
  999. IN UINT InterruptVector,
  1000. IN UINT InterruptLevel,
  1001. IN BOOLEAN RequestIsr,
  1002. IN BOOLEAN SharedInterrupt,
  1003. IN NDIS_INTERRUPT_MODE InterruptMode
  1004. )
  1005. {
  1006. PNDIS_MINIPORT_BLOCK Miniport = (PNDIS_MINIPORT_BLOCK)MiniportAdapterHandle;
  1007. ULONG Vector;
  1008. NDIS_STATUS Status;
  1009. NTSTATUS NtStatus;
  1010. KIRQL Irql;
  1011. KAFFINITY InterruptAffinity;
  1012. PCM_PARTIAL_RESOURCE_DESCRIPTOR pResourceDescriptor;
  1013. PHYSICAL_ADDRESS NonTranslatedInterrupt, TranslatedIrql;
  1014. DBGPRINT(DBG_COMP_INIT, DBG_LEVEL_INFO,
  1015. ("==>ndisMRegisterInterruptCommon: Miniport %p\n", MiniportAdapterHandle));
  1016. if (MINIPORT_VERIFY_TEST_FLAG((PNDIS_MINIPORT_BLOCK)MiniportAdapterHandle, fMINIPORT_VERIFY_FAIL_INTERRUPT_REGISTER))
  1017. {
  1018. #if DBG
  1019. DbgPrint("NdisMRegisterInterrupt failed to verify miniport %p\n", MiniportAdapterHandle);
  1020. #endif
  1021. return NDIS_STATUS_RESOURCES;
  1022. }
  1023. do
  1024. {
  1025. Status = NDIS_STATUS_SUCCESS;
  1026. InterlockedIncrement(&Miniport->RegisteredInterrupts);
  1027. //
  1028. // We must do this stuff first because if we connect the
  1029. // interrupt first then an interrupt could occur before
  1030. // the ISR is recorded in the Ndis interrupt structure.
  1031. //
  1032. Interrupt->DpcCount = 0;
  1033. Interrupt->DpcCountLock = 0;
  1034. Interrupt->Miniport = Miniport;
  1035. Interrupt->MiniportIsr = Miniport->DriverHandle->MiniportCharacteristics.ISRHandler;
  1036. Interrupt->MiniportDpc = Miniport->HandleInterruptHandler;
  1037. Interrupt->SharedInterrupt = SharedInterrupt;
  1038. Interrupt->IsrRequested = RequestIsr;
  1039. //
  1040. // This is used to tell when all Dpcs are completed after the
  1041. // interrupt has been removed.
  1042. //
  1043. INITIALIZE_EVENT(&Interrupt->DpcsCompletedEvent);
  1044. INITIALIZE_DPC(&Interrupt->InterruptDpc,
  1045. MINIPORT_TEST_FLAG(Miniport, fMINIPORT_DESERIALIZE) ?
  1046. ndisMDpcX : ndisMDpc,
  1047. Interrupt);
  1048. SET_DPC_IMPORTANCE(&Interrupt->InterruptDpc);
  1049. SET_PROCESSOR_DPC(&Interrupt->InterruptDpc,
  1050. Miniport->AssignedProcessor);
  1051. NonTranslatedInterrupt.QuadPart = InterruptLevel;
  1052. Status = ndisTranslateResources(Miniport,
  1053. CmResourceTypeInterrupt,
  1054. NonTranslatedInterrupt,
  1055. &TranslatedIrql,
  1056. &pResourceDescriptor);
  1057. if (NDIS_STATUS_SUCCESS != Status)
  1058. {
  1059. DBGPRINT_RAW(DBG_COMP_INIT, DBG_LEVEL_INFO,
  1060. ((" NdisMRegisterInterrupt: trying to register interrupt %p which is not allocated to device\n"),
  1061. InterruptLevel));
  1062. Status = NDIS_STATUS_FAILURE;
  1063. break;
  1064. }
  1065. Irql = (KIRQL)pResourceDescriptor->u.Interrupt.Level;
  1066. Vector = pResourceDescriptor->u.Interrupt.Vector;
  1067. InterruptAffinity = pResourceDescriptor->u.Interrupt.Affinity;
  1068. if (pResourceDescriptor->Flags == CM_RESOURCE_INTERRUPT_LEVEL_SENSITIVE)
  1069. {
  1070. InterruptMode = LevelSensitive;
  1071. }
  1072. else
  1073. {
  1074. InterruptMode = Latched;
  1075. }
  1076. //
  1077. // just in case this is not the first time we try to get an interrupt
  1078. // for this miniport (suspend/resume or if the miniport has decided to
  1079. // let go of interrupt and hook it again
  1080. //
  1081. MINIPORT_CLEAR_FLAG(Miniport, fMINIPORT_DEREGISTERED_INTERRUPT);
  1082. NtStatus = IoConnectInterrupt(&Interrupt->InterruptObject,
  1083. (PKSERVICE_ROUTINE)ndisMIsr,
  1084. Interrupt,
  1085. NULL,
  1086. Vector,
  1087. Irql,
  1088. Irql,
  1089. (KINTERRUPT_MODE)InterruptMode,
  1090. SharedInterrupt,
  1091. InterruptAffinity,
  1092. FALSE);
  1093. if (!NT_SUCCESS(NtStatus))
  1094. {
  1095. Status = NDIS_STATUS_FAILURE;
  1096. DBGPRINT_RAW(DBG_COMP_INIT, DBG_LEVEL_INFO,
  1097. ((" NdisMRegisterInterrupt: IoConnectInterrupt failed on Interrupt Level:%lx, Vector: %lx\n"),
  1098. Irql, Vector));
  1099. //
  1100. // zero out the interrupt object just in case driver tries to remove the interrupt
  1101. // they are aligned in both structures
  1102. //
  1103. Interrupt->InterruptObject = NULL;
  1104. }
  1105. } while (FALSE);
  1106. if (Status != NDIS_STATUS_SUCCESS)
  1107. {
  1108. InterlockedDecrement(&Miniport->RegisteredInterrupts);
  1109. }
  1110. DBGPRINT(DBG_COMP_INIT, DBG_LEVEL_INFO,
  1111. ("<==ndisMRegisterInterruptCommon: Miniport %p, Status %lx\n", MiniportAdapterHandle, Status));
  1112. return Status;
  1113. }
  1114. VOID
  1115. ndisMDeregisterInterruptCommon(
  1116. IN PNDIS_MINIPORT_INTERRUPT MiniportInterrupt
  1117. )
  1118. {
  1119. LARGE_INTEGER TimeoutValue;
  1120. PNDIS_MINIPORT_BLOCK Miniport = MiniportInterrupt->Miniport;
  1121. DBGPRINT(DBG_COMP_INIT, DBG_LEVEL_INFO,
  1122. ("==>ndisMDeregisterInterruptCommon: Miniport %p\n", MiniportInterrupt->Miniport));
  1123. do
  1124. {
  1125. //
  1126. // drivers can register interrupts only during initialization
  1127. // and deregister them only during halt
  1128. // so here we can safely set the flag after the ref count
  1129. // goes to zero.
  1130. //
  1131. if (InterlockedDecrement(&Miniport->RegisteredInterrupts) == 0)
  1132. {
  1133. MINIPORT_SET_FLAG(MiniportInterrupt->Miniport, fMINIPORT_DEREGISTERED_INTERRUPT);
  1134. }
  1135. //
  1136. // overloading the DpcCountLock to say that interrupt is
  1137. // deregistered
  1138. //
  1139. (ULONG)MiniportInterrupt->DpcCountLock = 1;
  1140. //
  1141. // Now we disconnect the interrupt.
  1142. // NOTE: they are aligned in both structures
  1143. //
  1144. IoDisconnectInterrupt(MiniportInterrupt->InterruptObject);
  1145. //
  1146. // Right now we know that any Dpcs that may fire are counted.
  1147. // We don't have to guard this with a spin lock because the
  1148. // Dpc will set the event it completes first, or we may
  1149. // wait for a little while for it to complete.
  1150. //
  1151. TimeoutValue.QuadPart = Int32x32To64(1000, -10000); // Make it 1 second
  1152. if (MiniportInterrupt->DpcCount > 0)
  1153. {
  1154. //
  1155. // Now we wait for all dpcs to complete.
  1156. //
  1157. WAIT_FOR_OBJECT(&MiniportInterrupt->DpcsCompletedEvent, &TimeoutValue);
  1158. RESET_EVENT(&MiniportInterrupt->DpcsCompletedEvent);
  1159. }
  1160. } while (FALSE);
  1161. DBGPRINT(DBG_COMP_INIT, DBG_LEVEL_INFO,
  1162. ("<==ndisMDeregisterInterruptCommon: Miniport %p\n", MiniportInterrupt->Miniport));
  1163. }