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.

2002 lines
60 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 (MiniportTimer->Miniport->DriverHandle->Flags & fMINIBLOCK_VERIFYING)
  76. {
  77. KIRQL OldIrql;
  78. PNDIS_MINIPORT_TIMER pTimer;
  79. ACQUIRE_SPIN_LOCK(&MiniportTimer->Miniport->TimerQueueLock, &OldIrql);
  80. //
  81. // check to see if the timer is already set
  82. //
  83. for (pTimer = MiniportTimer->Miniport->TimerQueue;
  84. pTimer != NULL;
  85. pTimer = pTimer->NextTimer)
  86. {
  87. if (pTimer == MiniportTimer)
  88. break;
  89. }
  90. if (pTimer == NULL)
  91. {
  92. MiniportTimer->NextTimer = MiniportTimer->Miniport->TimerQueue;
  93. MiniportTimer->Miniport->TimerQueue = MiniportTimer;
  94. }
  95. RELEASE_SPIN_LOCK(&MiniportTimer->Miniport->TimerQueueLock, OldIrql);
  96. }
  97. //
  98. // Set the timer
  99. //
  100. SET_TIMER(&MiniportTimer->Timer, FireUpTime, &MiniportTimer->Dpc);
  101. }
  102. VOID
  103. NdisMCancelTimer(
  104. IN PNDIS_MINIPORT_TIMER Timer,
  105. OUT PBOOLEAN TimerCancelled
  106. )
  107. /*++
  108. Routine Description:
  109. Cancels a timer.
  110. Arguments:
  111. Timer - The timer to cancel.
  112. TimerCancelled - TRUE if the timer was canceled, else FALSE.
  113. Return Value:
  114. None
  115. --*/
  116. {
  117. if (MINIPORT_VERIFY_TEST_FLAG(Timer->Miniport, fMINIPORT_VERIFY_FAIL_CANCEL_TIMER))
  118. {
  119. *TimerCancelled = FALSE;
  120. #if DBG
  121. DbgPrint("NdisMCancelTimer for Timer %p failed to verify miniport %p\n",
  122. Timer, Timer->Miniport);
  123. #endif
  124. return;
  125. }
  126. *TimerCancelled = CANCEL_TIMER(&((PNDIS_TIMER)Timer)->Timer);
  127. if (Timer->Miniport->DriverHandle->Flags & fMINIBLOCK_VERIFYING)
  128. {
  129. if (*TimerCancelled)
  130. {
  131. PNDIS_MINIPORT_TIMER *pTimer;
  132. KIRQL OldIrql;
  133. BOOLEAN Dequeued = FALSE;
  134. ACQUIRE_SPIN_LOCK(&Timer->Miniport->TimerQueueLock, &OldIrql);
  135. for (pTimer = &Timer->Miniport->TimerQueue;
  136. *pTimer != NULL;
  137. pTimer = &(*pTimer)->NextTimer)
  138. {
  139. if (*pTimer == Timer)
  140. {
  141. *pTimer = Timer->NextTimer;
  142. Dequeued = TRUE;
  143. break;
  144. }
  145. }
  146. RELEASE_SPIN_LOCK(&Timer->Miniport->TimerQueueLock, OldIrql);
  147. }
  148. }
  149. }
  150. VOID
  151. ndisMTimerDpc(
  152. IN PKDPC Dpc,
  153. IN PVOID Context,
  154. IN PVOID SystemContext1,
  155. IN PVOID SystemContext2
  156. )
  157. /*++
  158. Routine Description:
  159. This function services all mini-port timer interrupts. It then calls the
  160. appropriate function that mini-port consumers have registered in the
  161. call to NdisMInitializeTimer.
  162. Arguments:
  163. Dpc - Not used.
  164. Context - A pointer to the NDIS_MINIPORT_TIMER which is bound to this DPC.
  165. SystemContext1,2 - not used.
  166. Return Value:
  167. None.
  168. Note:
  169. by virtue of having either the local lock or miniport spinlock, the driver's
  170. timer function is protected against getting unloaded .
  171. --*/
  172. {
  173. PNDIS_MINIPORT_TIMER MiniportTimer = (PNDIS_MINIPORT_TIMER)(Context);
  174. PNDIS_MINIPORT_BLOCK Miniport = MiniportTimer->Miniport;
  175. PNDIS_TIMER_FUNCTION TimerFunction;
  176. UNREFERENCED_PARAMETER(Dpc);
  177. UNREFERENCED_PARAMETER(SystemContext1);
  178. UNREFERENCED_PARAMETER(SystemContext2);
  179. NDIS_ACQUIRE_MINIPORT_SPIN_LOCK_DPC(Miniport);
  180. do
  181. {
  182. BLOCK_LOCK_MINIPORT_DPC_L(Miniport);
  183. if (Miniport->DriverHandle->Flags & fMINIBLOCK_VERIFYING)
  184. {
  185. PNDIS_MINIPORT_TIMER *pTimer;
  186. BOOLEAN Dequeued = FALSE;
  187. ACQUIRE_SPIN_LOCK_DPC(&Miniport->TimerQueueLock);
  188. for (pTimer = &Miniport->TimerQueue;
  189. *pTimer != NULL;
  190. pTimer = &(*pTimer)->NextTimer)
  191. {
  192. if (*pTimer == MiniportTimer)
  193. {
  194. //
  195. // don't dequeue periodic timers when they fire
  196. //
  197. if (MiniportTimer->Timer.Period == 0)
  198. {
  199. *pTimer = MiniportTimer->NextTimer;
  200. }
  201. Dequeued = TRUE;
  202. break;
  203. }
  204. }
  205. RELEASE_SPIN_LOCK_DPC(&Miniport->TimerQueueLock);
  206. }
  207. if (MINIPORT_TEST_FLAG(Miniport, fMINIPORT_IN_INITIALIZE))
  208. {
  209. //
  210. // Queue the timer as we cannot call the miniport
  211. //
  212. NdisMSetTimer(MiniportTimer, 10);
  213. //
  214. // Unlock the miniport
  215. //
  216. UNLOCK_MINIPORT_L(Miniport);
  217. break;
  218. }
  219. //
  220. // if the miniport is shut down (no, I don't mean halted)
  221. // then don't send the timer down.
  222. //
  223. if (MINIPORT_PNP_TEST_FLAG(Miniport, fMINIPORT_SHUTTING_DOWN))
  224. {
  225. UNLOCK_MINIPORT_L(Miniport);
  226. break;
  227. }
  228. //
  229. // Call Miniport timer function
  230. //
  231. TimerFunction = MiniportTimer->MiniportTimerFunction;
  232. NDIS_RELEASE_MINIPORT_SPIN_LOCK_DPC(Miniport);
  233. (*TimerFunction)(NULL, MiniportTimer->MiniportTimerContext, NULL, NULL);
  234. NDIS_ACQUIRE_MINIPORT_SPIN_LOCK_DPC(Miniport);
  235. NDISM_PROCESS_DEFERRED(Miniport);
  236. UNLOCK_MINIPORT_L(Miniport);
  237. } while (FALSE);
  238. NDIS_RELEASE_MINIPORT_SPIN_LOCK_DPC(Miniport);
  239. }
  240. VOID
  241. ndisMTimerDpcX(
  242. IN PKDPC Dpc,
  243. IN PVOID Context,
  244. IN PVOID SystemContext1,
  245. IN PVOID SystemContext2
  246. )
  247. /*++
  248. Routine Description:
  249. This function services all mini-port timer DPCs. It then calls the
  250. appropriate function that mini-port consumers have registered in the
  251. call to NdisMInitializeTimer.
  252. Arguments:
  253. Dpc - Not used.
  254. Context - A pointer to the NDIS_MINIPORT_TIMER which is bound to this DPC.
  255. SystemContext1,2 - not used.
  256. Return Value:
  257. None.
  258. Note:
  259. we have to make sure the driver does not go away while the driver's timer function
  260. is running. this can happen for example if the timer function was to signal an event
  261. to let the Halthandler and Halt proceed.
  262. No need to protect the miniport here becasue we do not touch the miniport after the
  263. timer function returns.
  264. --*/
  265. {
  266. PNDIS_MINIPORT_TIMER MiniportTimer = (PNDIS_MINIPORT_TIMER)(Context);
  267. PNDIS_MINIPORT_BLOCK Miniport = MiniportTimer->Miniport;
  268. PNDIS_M_DRIVER_BLOCK MiniDriver = Miniport->DriverHandle;
  269. UNREFERENCED_PARAMETER(Dpc);
  270. UNREFERENCED_PARAMETER(SystemContext1);
  271. UNREFERENCED_PARAMETER(SystemContext2);
  272. //
  273. // make sure the driver does not go away while the timer function
  274. // is running
  275. ndisReferenceDriver(MiniDriver);
  276. if (MiniportTimer->Miniport->DriverHandle->Flags & fMINIBLOCK_VERIFYING)
  277. {
  278. PNDIS_MINIPORT_TIMER *pTimer;
  279. BOOLEAN Dequeued = FALSE;
  280. ACQUIRE_SPIN_LOCK_DPC(&MiniportTimer->Miniport->TimerQueueLock);
  281. for (pTimer = &Miniport->TimerQueue;
  282. *pTimer != NULL;
  283. pTimer = &(*pTimer)->NextTimer)
  284. {
  285. if (*pTimer == MiniportTimer)
  286. {
  287. //
  288. // don't dequeue periodic timers when they fire
  289. //
  290. if (MiniportTimer->Timer.Period == 0)
  291. {
  292. *pTimer = MiniportTimer->NextTimer;
  293. }
  294. Dequeued = TRUE;
  295. break;
  296. }
  297. }
  298. RELEASE_SPIN_LOCK_DPC(&MiniportTimer->Miniport->TimerQueueLock);
  299. }
  300. //
  301. // if the miniport is shut down (no, I don't mean halted)
  302. // then don't send the timer down.
  303. //
  304. if (!MINIPORT_PNP_TEST_FLAG(Miniport, fMINIPORT_SHUTTING_DOWN))
  305. {
  306. (*MiniportTimer->MiniportTimerFunction)(NULL, MiniportTimer->MiniportTimerContext, NULL, NULL);
  307. }
  308. //
  309. // this can be called at DPC
  310. //
  311. ndisDereferenceDriver(MiniDriver, FALSE);
  312. }
  313. NDIS_STATUS
  314. NdisMRegisterInterrupt(
  315. OUT PNDIS_MINIPORT_INTERRUPT Interrupt,
  316. IN NDIS_HANDLE MiniportAdapterHandle,
  317. IN UINT InterruptVector,
  318. IN UINT InterruptLevel,
  319. IN BOOLEAN RequestIsr,
  320. IN BOOLEAN SharedInterrupt,
  321. IN NDIS_INTERRUPT_MODE InterruptMode
  322. )
  323. {
  324. PNDIS_MINIPORT_BLOCK Miniport = (PNDIS_MINIPORT_BLOCK)MiniportAdapterHandle;
  325. NDIS_STATUS Status;
  326. Interrupt->Reserved = (PVOID)Miniport->MiniportAdapterContext;
  327. Miniport->Interrupt = (PNDIS_MINIPORT_INTERRUPT)Interrupt;
  328. INITIALIZE_DPC(&Interrupt->InterruptDpc,
  329. MINIPORT_TEST_FLAG(Miniport, fMINIPORT_DESERIALIZE) ?
  330. ndisMDpcX : ndisMDpc,
  331. Interrupt);
  332. SET_DPC_IMPORTANCE(&Interrupt->InterruptDpc);
  333. SET_PROCESSOR_DPC(&Interrupt->InterruptDpc,
  334. Miniport->AssignedProcessor);
  335. Status = ndisMRegisterInterruptCommon(
  336. Interrupt,
  337. MiniportAdapterHandle,
  338. InterruptVector,
  339. InterruptLevel,
  340. RequestIsr,
  341. SharedInterrupt,
  342. InterruptMode);
  343. if (Status != NDIS_STATUS_SUCCESS)
  344. {
  345. Miniport->Interrupt = NULL;
  346. }
  347. return Status;
  348. }
  349. VOID
  350. NdisMDeregisterInterrupt(
  351. IN PNDIS_MINIPORT_INTERRUPT MiniportInterrupt
  352. )
  353. {
  354. DBGPRINT(DBG_COMP_INIT, DBG_LEVEL_INFO,
  355. ("==>NdisMDeregisterInterrupt: Miniport %p\n", MiniportInterrupt->Miniport));
  356. do
  357. {
  358. if (MiniportInterrupt->InterruptObject == NULL)
  359. break;
  360. ndisMDeregisterInterruptCommon(MiniportInterrupt);
  361. MiniportInterrupt->Miniport->Interrupt = NULL;
  362. } while (FALSE);
  363. DBGPRINT(DBG_COMP_INIT, DBG_LEVEL_INFO,
  364. ("<==NdisMDeregisterInterrupt: Miniport %p\n", MiniportInterrupt->Miniport));
  365. }
  366. BOOLEAN
  367. NdisMSynchronizeWithInterrupt(
  368. IN PNDIS_MINIPORT_INTERRUPT Interrupt,
  369. IN PVOID SynchronizeFunction,
  370. IN PVOID SynchronizeContext
  371. )
  372. {
  373. return (SYNC_WITH_ISR((Interrupt)->InterruptObject,
  374. (PKSYNCHRONIZE_ROUTINE)SynchronizeFunction,
  375. SynchronizeContext));
  376. }
  377. VOID
  378. ndisMWakeUpDpcX(
  379. IN PKDPC Dpc,
  380. IN PVOID Context,
  381. IN PVOID SystemContext1,
  382. IN PVOID SystemContext2
  383. )
  384. /*++
  385. Routine Description:
  386. Arguments:
  387. Return Value:
  388. --*/
  389. {
  390. LARGE_INTEGER FireUpTime;
  391. PNDIS_MINIPORT_BLOCK Miniport = (PNDIS_MINIPORT_BLOCK)(Context);
  392. BOOLEAN Hung = FALSE;
  393. NDIS_STATUS Status;
  394. BOOLEAN AddressingReset = FALSE;
  395. BOOLEAN fDontReset = FALSE;
  396. BOOLEAN fSetTimer = TRUE;
  397. UNREFERENCED_PARAMETER(Dpc);
  398. UNREFERENCED_PARAMETER(SystemContext1);
  399. UNREFERENCED_PARAMETER(SystemContext2);
  400. do
  401. {
  402. //
  403. // If the miniport is halting then try to set the event that the halt routine
  404. // may be waiting on. if the event is not there, do nothing but let the timer
  405. // fire again so you can set the event next time.
  406. //
  407. if (MINIPORT_TEST_FLAG(Miniport, fMINIPORT_PM_HALTING) ||
  408. MINIPORT_PNP_TEST_FLAG(Miniport, fMINIPORT_HALTING | fMINIPORT_CANCEL_WAKE_UP_TIMER))
  409. {
  410. if (Miniport->WakeUpTimerEvent != NULL)
  411. {
  412. fSetTimer = FALSE;
  413. SET_EVENT(Miniport->WakeUpTimerEvent);
  414. }
  415. break;
  416. }
  417. Miniport->CFHangCurrentTick--;
  418. if (Miniport->CFHangCurrentTick == 0)
  419. {
  420. Miniport->CFHangCurrentTick = Miniport->CFHangTicks;
  421. //
  422. // Call Miniport stall checker.
  423. //
  424. if (Miniport->DriverHandle->MiniportCharacteristics.CheckForHangHandler != NULL)
  425. {
  426. Hung = (Miniport->DriverHandle->MiniportCharacteristics.CheckForHangHandler)(Miniport->MiniportAdapterContext);
  427. }
  428. //
  429. // Was there a request to reset the device?
  430. //
  431. if (MINIPORT_TEST_FLAG(Miniport, fMINIPORT_RESTORING_FILTERS))
  432. {
  433. Hung = FALSE;
  434. break;
  435. }
  436. NDIS_ACQUIRE_MINIPORT_SPIN_LOCK_DPC(Miniport);
  437. //
  438. // Check the internal wrapper states for the miniport and
  439. // see if we think the miniport should be reset.
  440. //
  441. if (!Hung)
  442. {
  443. //
  444. // Should we check the request queue?
  445. // Did a request pend too long?
  446. //
  447. if (!MINIPORT_TEST_FLAG(Miniport, fMINIPORT_IGNORE_REQUEST_QUEUE) &&
  448. MINIPORT_TEST_FLAG(Miniport, fMINIPORT_PROCESSING_REQUEST))
  449. {
  450. if (MINIPORT_TEST_FLAG(Miniport, fMINIPORT_REQUEST_TIMEOUT))
  451. {
  452. Miniport->InternalResetCount ++;
  453. Hung = TRUE;
  454. }
  455. else
  456. {
  457. if (Miniport->CFHangXTicks == 0)
  458. {
  459. MINIPORT_SET_FLAG(Miniport, fMINIPORT_REQUEST_TIMEOUT);
  460. }
  461. else
  462. {
  463. Miniport->CFHangXTicks--;
  464. }
  465. }
  466. }
  467. }
  468. else
  469. {
  470. Miniport->MiniportResetCount ++;
  471. }
  472. if (Hung)
  473. {
  474. if (NULL != Miniport->DriverHandle->MiniportCharacteristics.ResetHandler)
  475. {
  476. if ((MINIPORT_TEST_FLAG(Miniport, fMINIPORT_RESET_IN_PROGRESS)) ||
  477. (MINIPORT_PNP_TEST_FLAG(Miniport, fMINIPORT_HALTING)))
  478. {
  479. fDontReset = TRUE;
  480. }
  481. else
  482. {
  483. MINIPORT_SET_FLAG(Miniport, fMINIPORT_RESET_IN_PROGRESS);
  484. Miniport->ResetOpen = NULL;
  485. }
  486. ndisMSwapOpenHandlers(Miniport,
  487. NDIS_STATUS_RESET_IN_PROGRESS,
  488. fMINIPORT_STATE_RESETTING);
  489. }
  490. else Hung = FALSE;
  491. }
  492. if (Hung && !fDontReset)
  493. {
  494. MINIPORT_SET_FLAG(Miniport, fMINIPORT_CALLING_RESET);
  495. //
  496. // wait for all the requests to come back.
  497. // note: this is not the same as waiting for all requests to complete
  498. // we just make sure the original request call has come back
  499. //
  500. do
  501. {
  502. if (Miniport->RequestCount == 0)
  503. {
  504. break;
  505. }
  506. else
  507. {
  508. NDIS_RELEASE_MINIPORT_SPIN_LOCK_DPC(Miniport);
  509. NDIS_INTERNAL_STALL(50);
  510. NDIS_ACQUIRE_MINIPORT_SPIN_LOCK_DPC(Miniport);
  511. }
  512. } while (TRUE);
  513. NDIS_RELEASE_MINIPORT_SPIN_LOCK_DPC(Miniport);
  514. NdisMIndicateStatus(Miniport, NDIS_STATUS_RESET_START, NULL, 0);
  515. NdisMIndicateStatusComplete(Miniport);
  516. DBGPRINT(DBG_COMP_WORK_ITEM, DBG_LEVEL_INFO,
  517. ("Calling miniport reset\n"));
  518. //
  519. // Call the miniport's reset handler.
  520. //
  521. Status = (Miniport->DriverHandle->MiniportCharacteristics.ResetHandler)(
  522. &AddressingReset,
  523. Miniport->MiniportAdapterContext);
  524. if (NDIS_STATUS_PENDING != Status)
  525. {
  526. NdisMResetComplete(Miniport, Status, AddressingReset);
  527. }
  528. }
  529. else
  530. {
  531. NDIS_RELEASE_MINIPORT_SPIN_LOCK_DPC(Miniport);
  532. }
  533. }
  534. if (!Hung)
  535. {
  536. //
  537. //1 this may be unnecessary
  538. //
  539. if (MINIPORT_TEST_FLAG(Miniport, fMINIPORT_REQUIRES_MEDIA_POLLING) == TRUE)
  540. {
  541. NDIS_ACQUIRE_MINIPORT_SPIN_LOCK_DPC(Miniport);
  542. ndisMPollMediaState(Miniport);
  543. NDIS_RELEASE_MINIPORT_SPIN_LOCK_DPC(Miniport);
  544. }
  545. }
  546. } while (FALSE);
  547. if (fSetTimer)
  548. {
  549. //
  550. // If the miniport is halting then try to set the event that the halt routine
  551. // may be waiting on. if the event is not there, let the timer
  552. // fire again so you can set the event next time.
  553. //
  554. if (MINIPORT_TEST_FLAG(Miniport, fMINIPORT_PM_HALTING) ||
  555. MINIPORT_PNP_TEST_FLAG(Miniport, fMINIPORT_HALTING | fMINIPORT_CANCEL_WAKE_UP_TIMER))
  556. {
  557. if (Miniport->WakeUpTimerEvent != NULL)
  558. {
  559. fSetTimer = FALSE;
  560. SET_EVENT(Miniport->WakeUpTimerEvent);
  561. }
  562. }
  563. }
  564. if (fSetTimer)
  565. {
  566. FireUpTime.QuadPart = Int32x32To64((LONG)(Miniport->CheckForHangSeconds*1000), -10000);
  567. SET_TIMER(&Miniport->WakeUpDpcTimer.Timer, FireUpTime, &Miniport->WakeUpDpcTimer.Dpc);
  568. }
  569. }
  570. VOID
  571. ndisMWakeUpDpc(
  572. IN PKDPC Dpc,
  573. IN PVOID Context,
  574. IN PVOID SystemContext1,
  575. IN PVOID SystemContext2
  576. )
  577. /*++
  578. Routine Description:
  579. This function services all mini-port. It checks to see if a mini-port is
  580. ever stalled.
  581. Arguments:
  582. Dpc - Not used.
  583. Context - A pointer to the NDIS_TIMER which is bound to this DPC.
  584. SystemContext1,2 - not used.
  585. Return Value:
  586. None.
  587. --*/
  588. {
  589. LARGE_INTEGER FireUpTime;
  590. PNDIS_MINIPORT_BLOCK Miniport = (PNDIS_MINIPORT_BLOCK)(Context);
  591. BOOLEAN Hung = FALSE;
  592. BOOLEAN LocalLock;
  593. BOOLEAN fSetTimer = TRUE;
  594. UNREFERENCED_PARAMETER(Dpc);
  595. UNREFERENCED_PARAMETER(SystemContext1);
  596. UNREFERENCED_PARAMETER(SystemContext2);
  597. NDIS_ACQUIRE_MINIPORT_SPIN_LOCK_DPC(Miniport);
  598. do
  599. {
  600. //
  601. // If the miniport is halting then try to set the event that the halt routine
  602. // may be waiting on. if the event is not there, do nothing but let the timer
  603. // fire again so you can set the event next time.
  604. //
  605. if (MINIPORT_TEST_FLAG(Miniport, fMINIPORT_PM_HALTING) ||
  606. MINIPORT_PNP_TEST_FLAG(Miniport, fMINIPORT_HALTING | fMINIPORT_CANCEL_WAKE_UP_TIMER))
  607. {
  608. if (Miniport->WakeUpTimerEvent != NULL)
  609. {
  610. fSetTimer = FALSE;
  611. SET_EVENT(Miniport->WakeUpTimerEvent);
  612. }
  613. break;
  614. }
  615. //
  616. // Can we get the miniport lock. If not then quit. This is not time-critical
  617. // and we can try again next tick
  618. //
  619. LOCK_MINIPORT(Miniport, LocalLock);
  620. if (!LocalLock ||
  621. MINIPORT_TEST_FLAG(Miniport, (fMINIPORT_RESET_IN_PROGRESS | fMINIPORT_RESET_REQUESTED)))
  622. {
  623. UNLOCK_MINIPORT(Miniport, LocalLock);
  624. break;
  625. }
  626. Miniport->CFHangCurrentTick--;
  627. if (Miniport->CFHangCurrentTick == 0)
  628. {
  629. Miniport->CFHangCurrentTick = Miniport->CFHangTicks;
  630. //
  631. // Call Miniport stall checker.
  632. //
  633. if (Miniport->DriverHandle->MiniportCharacteristics.CheckForHangHandler != NULL)
  634. {
  635. NDIS_RELEASE_MINIPORT_SPIN_LOCK_DPC(Miniport);
  636. Hung = (Miniport->DriverHandle->MiniportCharacteristics.CheckForHangHandler)(Miniport->MiniportAdapterContext);
  637. NDIS_ACQUIRE_MINIPORT_SPIN_LOCK_DPC(Miniport);
  638. }
  639. if (MINIPORT_TEST_FLAG(Miniport, fMINIPORT_RESTORING_FILTERS))
  640. {
  641. //
  642. // We are restoring filters post reset. Don't pre-empt again
  643. //
  644. Hung = FALSE;
  645. UNLOCK_MINIPORT(Miniport, LocalLock);
  646. break;
  647. }
  648. //
  649. // Check the internal wrapper states for the miniport and
  650. // see if we think the miniport should be reset.
  651. //
  652. if (Hung)
  653. {
  654. Miniport->MiniportResetCount ++;
  655. }
  656. else do
  657. {
  658. //
  659. // Should we check the request queue ? Did a request pend too long ?
  660. //
  661. if ((Miniport->Flags & (fMINIPORT_IGNORE_REQUEST_QUEUE|fMINIPORT_PROCESSING_REQUEST)) == fMINIPORT_PROCESSING_REQUEST)
  662. {
  663. if (MINIPORT_TEST_FLAG(Miniport, fMINIPORT_REQUEST_TIMEOUT))
  664. {
  665. Miniport->InternalResetCount ++;
  666. Hung = TRUE;
  667. break;
  668. }
  669. else
  670. {
  671. if (Miniport->CFHangXTicks == 0)
  672. {
  673. MINIPORT_SET_FLAG(Miniport, fMINIPORT_REQUEST_TIMEOUT);
  674. }
  675. else
  676. {
  677. Miniport->CFHangXTicks--;
  678. }
  679. }
  680. }
  681. //
  682. // Should we check the packet queue ? Did a packet pend too long ?
  683. //
  684. if (!MINIPORT_TEST_FLAG(Miniport, fMINIPORT_IGNORE_PACKET_QUEUE))
  685. {
  686. PNDIS_PACKET Packet;
  687. GET_FIRST_MINIPORT_PACKET(Miniport, &Packet);
  688. //
  689. // Does the miniport have possession of any packets?
  690. //
  691. if ((Packet != NULL) &&
  692. MINIPORT_TEST_PACKET_FLAG(Packet, fPACKET_PENDING))
  693. {
  694. //
  695. // Has the packet timed out?
  696. //
  697. if (MINIPORT_TEST_PACKET_FLAG(Packet, fPACKET_HAS_TIMED_OUT))
  698. {
  699. //
  700. // Reset the miniport.
  701. //
  702. Miniport->InternalResetCount ++;
  703. Hung = TRUE;
  704. }
  705. else
  706. {
  707. //
  708. // Set the packet flag and wait to see if it is still
  709. // there next time in.
  710. //
  711. MINIPORT_SET_PACKET_FLAG(Packet, fPACKET_HAS_TIMED_OUT);
  712. }
  713. }
  714. else
  715. {
  716. break;
  717. }
  718. //
  719. // If we are hung then we don't need to check for token ring errors.
  720. //
  721. if (Hung)
  722. {
  723. break;
  724. }
  725. }
  726. //
  727. // Are we ignoring token ring errors?
  728. //
  729. if (!MINIPORT_TEST_FLAG(Miniport, fMINIPORT_IGNORE_TOKEN_RING_ERRORS))
  730. {
  731. //
  732. // Token Ring reset...
  733. //
  734. if (Miniport->TrResetRing == 1)
  735. {
  736. Miniport->InternalResetCount ++;
  737. Hung = TRUE;
  738. break;
  739. }
  740. else if (Miniport->TrResetRing > 1)
  741. {
  742. Miniport->TrResetRing--;
  743. }
  744. }
  745. } while (FALSE);
  746. //
  747. // If the miniport is hung then queue a workitem to reset it.
  748. //
  749. if (Hung)
  750. {
  751. if (!MINIPORT_TEST_FLAG(Miniport, fMINIPORT_RESTORING_FILTERS))
  752. {
  753. if (NULL != Miniport->DriverHandle->MiniportCharacteristics.ResetHandler)
  754. {
  755. NDISM_QUEUE_WORK_ITEM(Miniport, NdisWorkItemResetRequested, NULL);
  756. }
  757. }
  758. }
  759. }
  760. if (!Hung)
  761. {
  762. if (MINIPORT_TEST_FLAG(Miniport, fMINIPORT_REQUIRES_MEDIA_POLLING) == TRUE)
  763. {
  764. ndisMPollMediaState(Miniport);
  765. }
  766. }
  767. //
  768. // Process any changes that have occurred.
  769. //
  770. NDISM_PROCESS_DEFERRED(Miniport);
  771. UNLOCK_MINIPORT_L(Miniport);
  772. } while (FALSE);
  773. if (fSetTimer)
  774. {
  775. //
  776. // If the miniport is halting then try to set the event that the halt routine
  777. // may be waiting on. if the event is not there, let the timer
  778. // fire again so you can set the event next time.
  779. //
  780. if (MINIPORT_TEST_FLAG(Miniport, fMINIPORT_PM_HALTING) ||
  781. MINIPORT_PNP_TEST_FLAG(Miniport, fMINIPORT_HALTING | fMINIPORT_CANCEL_WAKE_UP_TIMER))
  782. {
  783. if (Miniport->WakeUpTimerEvent != NULL)
  784. {
  785. fSetTimer = FALSE;
  786. SET_EVENT(Miniport->WakeUpTimerEvent);
  787. }
  788. }
  789. }
  790. if (fSetTimer)
  791. {
  792. FireUpTime.QuadPart = Int32x32To64((LONG)(Miniport->CheckForHangSeconds*1000), -10000);
  793. SET_TIMER(&Miniport->WakeUpDpcTimer.Timer, FireUpTime, &Miniport->WakeUpDpcTimer.Dpc);
  794. }
  795. NDIS_RELEASE_MINIPORT_SPIN_LOCK_DPC(Miniport);
  796. }
  797. BOOLEAN
  798. ndisMIsr(
  799. IN PKINTERRUPT KInterrupt,
  800. IN PVOID Context
  801. )
  802. /*++
  803. Routine Description:
  804. Handles ALL Miniport interrupts, calling the appropriate Miniport ISR and DPC
  805. depending on the context.
  806. Arguments:
  807. Interrupt - Interrupt object for the Mac.
  808. Context - Really a pointer to the interrupt.
  809. Return Value:
  810. None.
  811. --*/
  812. {
  813. PNDIS_MINIPORT_INTERRUPT Interrupt = (PNDIS_MINIPORT_INTERRUPT)Context;
  814. PNDIS_MINIPORT_BLOCK Miniport = Interrupt->Miniport;
  815. BOOLEAN InterruptRecognized;
  816. BOOLEAN IsrCalled = FALSE, QueueDpc = FALSE;
  817. UNREFERENCED_PARAMETER(KInterrupt);
  818. do
  819. {
  820. if (MINIPORT_TEST_FLAG(Miniport, fMINIPORT_NORMAL_INTERRUPTS))
  821. {
  822. MINIPORT_DISABLE_INTERRUPT_EX(Miniport, Interrupt);
  823. InterruptRecognized = QueueDpc = TRUE;
  824. }
  825. else
  826. {
  827. IsrCalled = TRUE;
  828. // Interrupt->MiniportIsr(&InterruptRecognized,
  829. // &QueueDpc,
  830. // Miniport->MiniportAdapterContext);
  831. Interrupt->MiniportIsr(&InterruptRecognized,
  832. &QueueDpc,
  833. Interrupt->Reserved);
  834. }
  835. if (QueueDpc)
  836. {
  837. InterlockedIncrement((PLONG)&Interrupt->DpcCount);
  838. if (QUEUE_DPC(&Interrupt->InterruptDpc))
  839. {
  840. break;
  841. }
  842. //
  843. // The DPC was already queued, so we have an extra reference (we
  844. // do it this way to ensure that the reference is added *before*
  845. // the DPC is queued).
  846. InterlockedDecrement((PLONG)&Interrupt->DpcCount);
  847. break;
  848. }
  849. if (!IsrCalled)
  850. {
  851. if (!Interrupt->SharedInterrupt &&
  852. !Interrupt->IsrRequested &&
  853. !MINIPORT_TEST_FLAG(Miniport, fMINIPORT_IN_INITIALIZE))
  854. {
  855. ASSERT(Miniport->DisableInterruptHandler != NULL);
  856. MINIPORT_DISABLE_INTERRUPT_EX(Miniport, Interrupt);
  857. InterruptRecognized = TRUE;
  858. break;
  859. }
  860. //
  861. // Call MiniportIsr, but don't queue a DPC.
  862. //
  863. // Interrupt->MiniportIsr(&InterruptRecognized,
  864. // &QueueDpc,
  865. // Miniport->MiniportAdapterContext);
  866. Interrupt->MiniportIsr(&InterruptRecognized,
  867. &QueueDpc,
  868. Interrupt->Reserved);
  869. }
  870. } while (FALSE);
  871. return(InterruptRecognized);
  872. }
  873. VOID
  874. ndisMDpc(
  875. IN PVOID SystemSpecific1,
  876. IN PVOID InterruptContext,
  877. IN PVOID SystemSpecific2,
  878. IN PVOID SystemSpecific3
  879. )
  880. /*++
  881. Routine Description:
  882. Handles ALL Miniport interrupt DPCs, calling the appropriate Miniport DPC
  883. depending on the context.
  884. Arguments:
  885. Interrupt - Interrupt object for the Mac.
  886. Context - Really a pointer to the Interrupt.
  887. Return Value:
  888. None.
  889. --*/
  890. {
  891. PNDIS_MINIPORT_INTERRUPT Interrupt = (PNDIS_MINIPORT_INTERRUPT)(InterruptContext);
  892. PNDIS_MINIPORT_BLOCK Miniport = Interrupt->Miniport;
  893. W_HANDLE_INTERRUPT_HANDLER MiniportDpc = Interrupt->MiniportDpc;
  894. UNREFERENCED_PARAMETER(SystemSpecific1);
  895. UNREFERENCED_PARAMETER(SystemSpecific2);
  896. UNREFERENCED_PARAMETER(SystemSpecific3);
  897. NDIS_ACQUIRE_MINIPORT_SPIN_LOCK_DPC(Miniport);
  898. do
  899. {
  900. if (MINIPORT_TEST_FLAG(Miniport, (fMINIPORT_PM_HALTING)) ||
  901. Interrupt->DpcCountLock)
  902. {
  903. InterlockedDecrement((PLONG)&Interrupt->DpcCount);
  904. if (Interrupt->DpcCount==0)
  905. {
  906. SET_EVENT(&Interrupt->DpcsCompletedEvent);
  907. }
  908. break;
  909. }
  910. BLOCK_LOCK_MINIPORT_DPC_L(Miniport);
  911. #if DBG
  912. //
  913. // reset SendComplete and RcvIndication counters
  914. //
  915. Miniport->cDpcSendCompletes = 0;
  916. Miniport->cDpcRcvIndications = 0;
  917. Miniport->cDpcRcvIndicationCalls = 0;
  918. #endif
  919. NDIS_RELEASE_MINIPORT_SPIN_LOCK_DPC(Miniport);
  920. (*MiniportDpc)(Interrupt->Reserved);
  921. NDIS_ACQUIRE_MINIPORT_SPIN_LOCK_DPC(Miniport);
  922. InterlockedDecrement((PLONG)&Interrupt->DpcCount);
  923. MINIPORT_SYNC_ENABLE_INTERRUPT_EX(Miniport, Interrupt);
  924. NDISM_PROCESS_DEFERRED(Miniport);
  925. UNLOCK_MINIPORT(Miniport, TRUE);
  926. } while (FALSE);
  927. NDIS_RELEASE_MINIPORT_SPIN_LOCK_DPC(Miniport);
  928. }
  929. VOID
  930. ndisMDpcX(
  931. IN PVOID SystemSpecific1,
  932. IN PVOID InterruptContext,
  933. IN PVOID SystemSpecific2,
  934. IN PVOID SystemSpecific3
  935. )
  936. /*++
  937. Routine Description:
  938. Handles ALL Miniport interrupt DPCs, calling the appropriate Miniport DPC
  939. depending on the context.
  940. Arguments:
  941. Interrupt - Interrupt object for the Mac.
  942. Context - Really a pointer to the Interrupt.
  943. Return Value:
  944. None.
  945. --*/
  946. {
  947. PNDIS_MINIPORT_INTERRUPT Interrupt = (PNDIS_MINIPORT_INTERRUPT)(InterruptContext);
  948. PNDIS_MINIPORT_BLOCK Miniport = Interrupt->Miniport;
  949. W_HANDLE_INTERRUPT_HANDLER MiniportDpc = Interrupt->MiniportDpc;
  950. UNREFERENCED_PARAMETER(SystemSpecific1);
  951. UNREFERENCED_PARAMETER(SystemSpecific2);
  952. UNREFERENCED_PARAMETER(SystemSpecific3);
  953. if (MINIPORT_TEST_FLAG(Miniport, (fMINIPORT_PM_HALTING)) ||
  954. Interrupt->DpcCountLock)
  955. {
  956. InterlockedDecrement((PLONG)&Interrupt->DpcCount);
  957. if (Interrupt->DpcCount==0)
  958. {
  959. SET_EVENT(&Interrupt->DpcsCompletedEvent);
  960. }
  961. }
  962. else
  963. {
  964. #if DBG
  965. //
  966. // reset SendComplete and RcvIndication counters
  967. //
  968. Miniport->cDpcSendCompletes = 0;
  969. Miniport->cDpcRcvIndications = 0;
  970. Miniport->cDpcRcvIndicationCalls = 0;
  971. #endif
  972. (*MiniportDpc)(Interrupt->Reserved);
  973. InterlockedDecrement((PLONG)&Interrupt->DpcCount);
  974. MINIPORT_SYNC_ENABLE_INTERRUPT_EX(Miniport, Interrupt);
  975. }
  976. }
  977. VOID
  978. ndisMDeferredDpc(
  979. IN PKDPC Dpc,
  980. IN PVOID Context,
  981. IN PVOID SystemContext1,
  982. IN PVOID SystemContext2
  983. )
  984. /*++
  985. Routine Description:
  986. This is a DPC routine that is queue'd by some of the [full-duplex] routines
  987. in order to get ndisMProcessDeferred to run outside of their
  988. context.
  989. Arguments:
  990. Return Value:
  991. None.
  992. --*/
  993. {
  994. PNDIS_MINIPORT_BLOCK Miniport = Context;
  995. UNREFERENCED_PARAMETER(Dpc);
  996. UNREFERENCED_PARAMETER(SystemContext1);
  997. UNREFERENCED_PARAMETER(SystemContext2);
  998. NDIS_ACQUIRE_MINIPORT_SPIN_LOCK_DPC(Miniport);
  999. BLOCK_LOCK_MINIPORT_DPC_L(Miniport);
  1000. NDISM_PROCESS_DEFERRED(Miniport);
  1001. UNLOCK_MINIPORT(Miniport, TRUE);
  1002. NDIS_RELEASE_MINIPORT_SPIN_LOCK_DPC(Miniport);
  1003. }
  1004. #if NDIS_RECV_SCALE
  1005. NDIS_STATUS
  1006. NdisMRegisterInterruptEx(
  1007. OUT PNDIS_MINIPORT_INTERRUPT_EX Interrupt,
  1008. IN NDIS_HANDLE MiniportAdapterHandle,
  1009. IN UINT InterruptVector,
  1010. IN UINT InterruptLevel,
  1011. IN BOOLEAN RequestIsr,
  1012. IN BOOLEAN SharedInterrupt,
  1013. IN NDIS_INTERRUPT_MODE InterruptMode
  1014. )
  1015. {
  1016. PNDIS_MINIPORT_BLOCK Miniport = (PNDIS_MINIPORT_BLOCK)MiniportAdapterHandle;
  1017. ULONG Vector;
  1018. NDIS_STATUS Status;
  1019. NTSTATUS NtStatus;
  1020. KIRQL Irql;
  1021. KAFFINITY InterruptAffinity;
  1022. PCM_PARTIAL_RESOURCE_DESCRIPTOR pResourceDescriptor;
  1023. PHYSICAL_ADDRESS NonTranslatedInterrupt, TranslatedIrql;
  1024. CCHAR i;
  1025. KIRQL OldIrql;
  1026. DBGPRINT(DBG_COMP_INIT, DBG_LEVEL_INFO,
  1027. ("==>NdisMRegisterInterruptEx: Miniport %p\n", MiniportAdapterHandle));
  1028. if (MINIPORT_VERIFY_TEST_FLAG((PNDIS_MINIPORT_BLOCK)MiniportAdapterHandle, fMINIPORT_VERIFY_FAIL_INTERRUPT_REGISTER))
  1029. {
  1030. #if DBG
  1031. DbgPrint("NdisMRegisterInterrupt failed to verify miniport %p\n", MiniportAdapterHandle);
  1032. #endif
  1033. return NDIS_STATUS_RESOURCES;
  1034. }
  1035. Interrupt->InterruptContext = (PVOID)Interrupt;
  1036. NDIS_ACQUIRE_MINIPORT_SPIN_LOCK(Miniport, &OldIrql);
  1037. Interrupt->NextInterrupt = (PNDIS_MINIPORT_INTERRUPT_EX)Miniport->Interrupt;
  1038. Miniport->Interrupt = (PNDIS_MINIPORT_INTERRUPT)Interrupt;
  1039. NDIS_RELEASE_MINIPORT_SPIN_LOCK(Miniport, OldIrql);
  1040. do
  1041. {
  1042. Status = NDIS_STATUS_SUCCESS;
  1043. InterlockedIncrement(&Miniport->RegisteredInterrupts);
  1044. //
  1045. // We must do this stuff first because if we connect the
  1046. // interrupt first then an interrupt could occur before
  1047. // the ISR is recorded in the Ndis interrupt structure.
  1048. //
  1049. Interrupt->DpcCount = 0;
  1050. Interrupt->DpcCountLock = 0;
  1051. Interrupt->Miniport = Miniport;
  1052. Interrupt->MiniportIsr = Miniport->DriverHandle->MiniportCharacteristics.MiniportISRHandler;
  1053. Interrupt->MiniportDpc = Miniport->DriverHandle->MiniportCharacteristics.InterruptDpcHandler;
  1054. Interrupt->SharedInterrupt = SharedInterrupt;
  1055. Interrupt->IsrRequested = RequestIsr;
  1056. if (!SharedInterrupt)
  1057. {
  1058. Miniport->InfoFlags |= NDIS_MINIPORT_EXCLUSIVE_INTERRUPT;
  1059. }
  1060. //
  1061. // This is used to tell when all Dpcs are completed after the
  1062. // interrupt has been removed.
  1063. //
  1064. INITIALIZE_EVENT(&Interrupt->DpcsCompletedEvent);
  1065. Interrupt->DpcQueued = 0;
  1066. //
  1067. // set the the default DPC handler
  1068. //
  1069. INITIALIZE_DPC(&Interrupt->InterruptDpc,
  1070. ndisMiniportDpc, Interrupt);
  1071. SET_DPC_IMPORTANCE(&Interrupt->InterruptDpc);
  1072. SET_PROCESSOR_DPC(&Interrupt->InterruptDpc,
  1073. Miniport->AssignedProcessor);
  1074. //
  1075. // initialize one DPC for each processor
  1076. //
  1077. for (i = 0; i < ndisNumberOfProcessors; i++)
  1078. {
  1079. INITIALIZE_DPC(&Interrupt->Dpc[i],
  1080. ndisMiniportMultipleDpc, Interrupt);
  1081. SET_DPC_IMPORTANCE(&Interrupt->InterruptDpc);
  1082. KeSetTargetProcessorDpc(&Interrupt->Dpc[i],
  1083. i);
  1084. }
  1085. NonTranslatedInterrupt.QuadPart = InterruptLevel;
  1086. Status = ndisTranslateResources(Miniport,
  1087. CmResourceTypeInterrupt,
  1088. NonTranslatedInterrupt,
  1089. &TranslatedIrql,
  1090. &pResourceDescriptor);
  1091. if (NDIS_STATUS_SUCCESS != Status)
  1092. {
  1093. DBGPRINT_RAW(DBG_COMP_INIT, DBG_LEVEL_INFO,
  1094. ((" NdisMRegisterInterrupt: trying to register interrupt %p which is not allocated to device\n"),
  1095. InterruptLevel));
  1096. Status = NDIS_STATUS_FAILURE;
  1097. break;
  1098. }
  1099. Irql = (KIRQL)pResourceDescriptor->u.Interrupt.Level;
  1100. Vector = pResourceDescriptor->u.Interrupt.Vector;
  1101. InterruptAffinity = pResourceDescriptor->u.Interrupt.Affinity;
  1102. if (pResourceDescriptor->Flags == CM_RESOURCE_INTERRUPT_LEVEL_SENSITIVE)
  1103. {
  1104. InterruptMode = LevelSensitive;
  1105. }
  1106. else
  1107. {
  1108. InterruptMode = Latched;
  1109. }
  1110. //
  1111. // just in case this is not the first time we try to get an interrupt
  1112. // for this miniport (suspend/resume or if the miniport has decided to
  1113. // let go of interrupt and hook it again
  1114. //
  1115. MINIPORT_CLEAR_FLAG(Miniport, fMINIPORT_DEREGISTERED_INTERRUPT);
  1116. NtStatus = IoConnectInterrupt(&Interrupt->InterruptObject,
  1117. (PKSERVICE_ROUTINE)ndisMiniportIsr,
  1118. Interrupt,
  1119. NULL,
  1120. Vector,
  1121. Irql,
  1122. Irql,
  1123. (KINTERRUPT_MODE)InterruptMode,
  1124. SharedInterrupt,
  1125. InterruptAffinity,
  1126. FALSE);
  1127. if (!NT_SUCCESS(NtStatus))
  1128. {
  1129. Status = NDIS_STATUS_FAILURE;
  1130. DBGPRINT_RAW(DBG_COMP_INIT, DBG_LEVEL_INFO,
  1131. ((" NdisMRegisterInterrupt: IoConnectInterrupt failed on Interrupt Level:%lx, Vector: %lx\n"),
  1132. Irql, Vector));
  1133. //
  1134. // zero out the interrupt object just in case driver tries to remove the interrupt
  1135. // they are aligned in both structures
  1136. //
  1137. Interrupt->InterruptObject = NULL;
  1138. }
  1139. } while (FALSE);
  1140. if (Status != NDIS_STATUS_SUCCESS)
  1141. {
  1142. PNDIS_MINIPORT_INTERRUPT_EX *ppQ;
  1143. InterlockedDecrement(&Miniport->RegisteredInterrupts);
  1144. PnPReferencePackage();
  1145. NDIS_ACQUIRE_MINIPORT_SPIN_LOCK(Miniport, &OldIrql);
  1146. for (ppQ = (PNDIS_MINIPORT_INTERRUPT_EX *)&Miniport->Interrupt;
  1147. *ppQ != NULL;
  1148. ppQ = &(*ppQ)->NextInterrupt)
  1149. {
  1150. if (*ppQ == Interrupt)
  1151. {
  1152. *ppQ = Interrupt->NextInterrupt;
  1153. break;
  1154. }
  1155. }
  1156. PnPDereferencePackage();
  1157. NDIS_RELEASE_MINIPORT_SPIN_LOCK(Miniport, OldIrql);
  1158. }
  1159. DBGPRINT(DBG_COMP_INIT, DBG_LEVEL_INFO,
  1160. ("<==NdisMRegisterInterruptEx: Miniport %p, Status %lx\n", MiniportAdapterHandle, Status));
  1161. return Status;
  1162. }
  1163. BOOLEAN
  1164. ndisMiniportIsr(
  1165. IN PKINTERRUPT KInterrupt,
  1166. IN PVOID Context
  1167. )
  1168. /*++
  1169. Routine Description:
  1170. Handles ALL Miniport interrupts, calling the appropriate Miniport ISR and DPC
  1171. depending on the context.
  1172. Arguments:
  1173. Interrupt - Interrupt object for the Mac.
  1174. Context - Really a pointer to the interrupt.
  1175. Return Value:
  1176. None.
  1177. --*/
  1178. {
  1179. PNDIS_MINIPORT_INTERRUPT_EX Interrupt = (PNDIS_MINIPORT_INTERRUPT_EX)Context;
  1180. ULONG TargetProcessors = 0;
  1181. ULONG DpcProcessor;
  1182. ULONG TargetProcessor = 0;
  1183. BOOLEAN InterruptRecognized;
  1184. BOOLEAN QueueDpc = FALSE;
  1185. InterruptRecognized = Interrupt->MiniportIsr(Interrupt->Reserved,
  1186. &QueueDpc,
  1187. &TargetProcessors);
  1188. if (QueueDpc)
  1189. {
  1190. InterlockedIncrement((PLONG)&Interrupt->DpcCount);
  1191. if (!QUEUE_DPC(&Interrupt->InterruptDpc))
  1192. {
  1193. InterlockedDecrement((PLONG)&Interrupt->DpcCount);
  1194. }
  1195. }
  1196. else
  1197. {
  1198. DpcProcessor = 0;
  1199. while (TargetProcessor)
  1200. {
  1201. if (TargetProcessor & 0x00000001)
  1202. {
  1203. InterlockedIncrement((PLONG)&Interrupt->DpcCount);
  1204. if (!QUEUE_DPC(&Interrupt->Dpc[DpcProcessor]))
  1205. {
  1206. InterlockedDecrement((PLONG)&Interrupt->DpcCount);
  1207. }
  1208. }
  1209. TargetProcessor >>= 1;
  1210. DpcProcessor++;
  1211. }
  1212. }
  1213. return(InterruptRecognized);
  1214. }
  1215. VOID
  1216. ndisMiniportMultipleDpc(
  1217. IN PVOID SystemSpecific1,
  1218. IN PVOID InterruptContext,
  1219. IN PVOID SystemSpecific2,
  1220. IN PVOID SystemSpecific3
  1221. )
  1222. /*++
  1223. Routine Description:
  1224. Handles ALL Miniport interrupt DPCs, calling the appropriate Miniport DPC
  1225. depending on the context.
  1226. Arguments:
  1227. Interrupt - Interrupt object for the Mac.
  1228. Context - Really a pointer to the Interrupt.
  1229. Return Value:
  1230. None.
  1231. --*/
  1232. {
  1233. PNDIS_MINIPORT_INTERRUPT_EX Interrupt = (PNDIS_MINIPORT_INTERRUPT_EX)(InterruptContext);
  1234. PNDIS_MINIPORT_BLOCK Miniport = Interrupt->Miniport;
  1235. ULONG TargetProcessor;
  1236. ULONG DpcProcessor;
  1237. MINIPORT_INTERRUPT_DPC_HANDLER MiniportDpc = Interrupt->MiniportDpc;
  1238. if (MINIPORT_TEST_FLAG(Miniport, (fMINIPORT_PM_HALTING)) ||
  1239. Interrupt->DpcCountLock)
  1240. {
  1241. InterlockedDecrement((PLONG)&Interrupt->DpcCount);
  1242. if (Interrupt->DpcCount==0)
  1243. {
  1244. SET_EVENT(&Interrupt->DpcsCompletedEvent);
  1245. }
  1246. }
  1247. else
  1248. {
  1249. #if DBG
  1250. //
  1251. // reset SendComplete and RcvIndication counters
  1252. //
  1253. Miniport->cDpcSendCompletes = 0;
  1254. Miniport->cDpcRcvIndications = 0;
  1255. Miniport->cDpcRcvIndicationCalls = 0;
  1256. #endif
  1257. //
  1258. // call the interrupt DPC handler and check to see if miniport
  1259. // is interested in additional DPCs on other processors
  1260. //
  1261. TargetProcessor = 0;
  1262. (*MiniportDpc)(Interrupt->Reserved,
  1263. &TargetProcessor);
  1264. InterlockedDecrement((PLONG)&Interrupt->DpcCount);
  1265. DpcProcessor = 0;
  1266. while (TargetProcessor)
  1267. {
  1268. if (TargetProcessor & 0x00000001)
  1269. {
  1270. InterlockedIncrement((PLONG)&Interrupt->DpcCount);
  1271. if (!QUEUE_DPC(&Interrupt->Dpc[DpcProcessor]))
  1272. {
  1273. InterlockedDecrement((PLONG)&Interrupt->DpcCount);
  1274. }
  1275. }
  1276. TargetProcessor >>= 1;
  1277. DpcProcessor++;
  1278. }
  1279. }
  1280. }
  1281. VOID
  1282. ndisMiniportDpc(
  1283. IN PVOID SystemSpecific1,
  1284. IN PVOID InterruptContext,
  1285. IN PVOID SystemSpecific2,
  1286. IN PVOID SystemSpecific3
  1287. )
  1288. /*++
  1289. Routine Description:
  1290. Handles ALL Miniport interrupt DPCs, calling the appropriate Miniport DPC
  1291. depending on the context.
  1292. Arguments:
  1293. Interrupt - Interrupt object for the Mac.
  1294. Context - Really a pointer to the Interrupt.
  1295. Return Value:
  1296. None.
  1297. --*/
  1298. {
  1299. PNDIS_MINIPORT_INTERRUPT_EX Interrupt = (PNDIS_MINIPORT_INTERRUPT_EX)(InterruptContext);
  1300. PNDIS_MINIPORT_BLOCK Miniport = Interrupt->Miniport;
  1301. MINIPORT_INTERRUPT_DPC_HANDLER MiniportDpc = Interrupt->MiniportDpc;
  1302. if (MINIPORT_TEST_FLAG(Miniport, (fMINIPORT_PM_HALTING)) ||
  1303. Interrupt->DpcCountLock)
  1304. {
  1305. InterlockedDecrement((PLONG)&Interrupt->DpcCount);
  1306. if (Interrupt->DpcCount==0)
  1307. {
  1308. SET_EVENT(&Interrupt->DpcsCompletedEvent);
  1309. }
  1310. }
  1311. else
  1312. {
  1313. #if DBG
  1314. //
  1315. // reset SendComplete and RcvIndication counters
  1316. //
  1317. Miniport->cDpcSendCompletes = 0;
  1318. Miniport->cDpcRcvIndications = 0;
  1319. Miniport->cDpcRcvIndicationCalls = 0;
  1320. #endif
  1321. (*MiniportDpc)(Interrupt->Reserved,
  1322. NULL);
  1323. InterlockedDecrement((PLONG)&Interrupt->DpcCount);
  1324. MINIPORT_SYNC_ENABLE_INTERRUPT_EX(Miniport, Interrupt);
  1325. }
  1326. }
  1327. #else
  1328. NDIS_STATUS
  1329. NdisMRegisterInterruptEx(
  1330. OUT PNDIS_MINIPORT_INTERRUPT_EX Interrupt,
  1331. IN NDIS_HANDLE MiniportAdapterHandle,
  1332. IN UINT InterruptVector,
  1333. IN UINT InterruptLevel,
  1334. IN BOOLEAN RequestIsr,
  1335. IN BOOLEAN SharedInterrupt,
  1336. IN NDIS_INTERRUPT_MODE InterruptMode
  1337. )
  1338. {
  1339. PNDIS_MINIPORT_BLOCK Miniport = (PNDIS_MINIPORT_BLOCK)MiniportAdapterHandle;
  1340. NDIS_STATUS Status;
  1341. KIRQL OldIrql;
  1342. Interrupt->InterruptContext = (PVOID)Interrupt;
  1343. NDIS_ACQUIRE_MINIPORT_SPIN_LOCK(Miniport, &OldIrql);
  1344. Interrupt->NextInterrupt = (PNDIS_MINIPORT_INTERRUPT_EX)Miniport->Interrupt;
  1345. Miniport->Interrupt = (PNDIS_MINIPORT_INTERRUPT)Interrupt;
  1346. NDIS_RELEASE_MINIPORT_SPIN_LOCK(Miniport, OldIrql);
  1347. Status = ndisMRegisterInterruptCommon(
  1348. (PNDIS_MINIPORT_INTERRUPT)Interrupt,
  1349. MiniportAdapterHandle,
  1350. InterruptVector,
  1351. InterruptLevel,
  1352. RequestIsr,
  1353. SharedInterrupt,
  1354. InterruptMode);
  1355. if (Status != NDIS_STATUS_SUCCESS)
  1356. {
  1357. PNDIS_MINIPORT_INTERRUPT_EX *ppQ;
  1358. PnPReferencePackage();
  1359. NDIS_ACQUIRE_MINIPORT_SPIN_LOCK(Miniport, &OldIrql);
  1360. for (ppQ = (PNDIS_MINIPORT_INTERRUPT_EX *)&Miniport->Interrupt;
  1361. *ppQ != NULL;
  1362. ppQ = &(*ppQ)->NextInterrupt)
  1363. {
  1364. if (*ppQ == Interrupt)
  1365. {
  1366. *ppQ = Interrupt->NextInterrupt;
  1367. break;
  1368. }
  1369. }
  1370. PnPDereferencePackage();
  1371. NDIS_RELEASE_MINIPORT_SPIN_LOCK(Miniport, OldIrql);
  1372. }
  1373. return Status;
  1374. }
  1375. #endif
  1376. VOID
  1377. NdisMDeregisterInterruptEx(
  1378. IN PNDIS_MINIPORT_INTERRUPT_EX MiniportInterrupt
  1379. )
  1380. {
  1381. PNDIS_MINIPORT_BLOCK Miniport = MiniportInterrupt->Miniport;
  1382. PNDIS_MINIPORT_INTERRUPT_EX *ppQ;
  1383. KIRQL OldIrql;
  1384. DBGPRINT(DBG_COMP_INIT, DBG_LEVEL_INFO,
  1385. ("==>NdisMDeregisterInterruptEx: Miniport %p\n", MiniportInterrupt->Miniport));
  1386. ndisMDeregisterInterruptCommon((PNDIS_MINIPORT_INTERRUPT)MiniportInterrupt);
  1387. PnPReferencePackage();
  1388. NDIS_ACQUIRE_MINIPORT_SPIN_LOCK(Miniport, &OldIrql);
  1389. for (ppQ = (PNDIS_MINIPORT_INTERRUPT_EX *)&Miniport->Interrupt;
  1390. *ppQ != NULL;
  1391. ppQ = &(*ppQ)->NextInterrupt)
  1392. {
  1393. if (*ppQ == MiniportInterrupt)
  1394. {
  1395. *ppQ = MiniportInterrupt->NextInterrupt;
  1396. break;
  1397. }
  1398. }
  1399. NDIS_RELEASE_MINIPORT_SPIN_LOCK(Miniport, OldIrql);
  1400. PnPDereferencePackage();
  1401. DBGPRINT(DBG_COMP_INIT, DBG_LEVEL_INFO,
  1402. ("<==NdisMDeregisterInterruptEx: Miniport %p\n", MiniportInterrupt->Miniport));
  1403. }
  1404. NDIS_STATUS
  1405. ndisMRegisterInterruptCommon(
  1406. OUT PNDIS_MINIPORT_INTERRUPT Interrupt,
  1407. IN NDIS_HANDLE MiniportAdapterHandle,
  1408. IN UINT InterruptVector,
  1409. IN UINT InterruptLevel,
  1410. IN BOOLEAN RequestIsr,
  1411. IN BOOLEAN SharedInterrupt,
  1412. IN NDIS_INTERRUPT_MODE InterruptMode
  1413. )
  1414. {
  1415. PNDIS_MINIPORT_BLOCK Miniport = (PNDIS_MINIPORT_BLOCK)MiniportAdapterHandle;
  1416. ULONG Vector;
  1417. NDIS_STATUS Status;
  1418. NTSTATUS NtStatus;
  1419. KIRQL Irql;
  1420. KAFFINITY InterruptAffinity;
  1421. PCM_PARTIAL_RESOURCE_DESCRIPTOR pResourceDescriptor;
  1422. PHYSICAL_ADDRESS NonTranslatedInterrupt, TranslatedIrql;
  1423. UNREFERENCED_PARAMETER(InterruptVector);
  1424. DBGPRINT(DBG_COMP_INIT, DBG_LEVEL_INFO,
  1425. ("==>ndisMRegisterInterruptCommon: Miniport %p\n", MiniportAdapterHandle));
  1426. if (MINIPORT_VERIFY_TEST_FLAG((PNDIS_MINIPORT_BLOCK)MiniportAdapterHandle, fMINIPORT_VERIFY_FAIL_INTERRUPT_REGISTER))
  1427. {
  1428. #if DBG
  1429. DbgPrint("NdisMRegisterInterrupt failed to verify miniport %p\n", MiniportAdapterHandle);
  1430. #endif
  1431. return NDIS_STATUS_RESOURCES;
  1432. }
  1433. do
  1434. {
  1435. Status = NDIS_STATUS_SUCCESS;
  1436. InterlockedIncrement((PLONG)&Miniport->RegisteredInterrupts);
  1437. //
  1438. // We must do this stuff first because if we connect the
  1439. // interrupt first then an interrupt could occur before
  1440. // the ISR is recorded in the Ndis interrupt structure.
  1441. //
  1442. Interrupt->DpcCount = 0;
  1443. Interrupt->DpcCountLock = 0;
  1444. Interrupt->Miniport = Miniport;
  1445. Interrupt->MiniportIsr = Miniport->DriverHandle->MiniportCharacteristics.ISRHandler;
  1446. Interrupt->MiniportDpc = Miniport->HandleInterruptHandler;
  1447. Interrupt->SharedInterrupt = SharedInterrupt;
  1448. Interrupt->IsrRequested = RequestIsr;
  1449. if (!SharedInterrupt)
  1450. {
  1451. Miniport->InfoFlags |= NDIS_MINIPORT_EXCLUSIVE_INTERRUPT;
  1452. }
  1453. //
  1454. // This is used to tell when all Dpcs are completed after the
  1455. // interrupt has been removed.
  1456. //
  1457. INITIALIZE_EVENT(&Interrupt->DpcsCompletedEvent);
  1458. INITIALIZE_DPC(&Interrupt->InterruptDpc,
  1459. MINIPORT_TEST_FLAG(Miniport, fMINIPORT_DESERIALIZE) ?
  1460. ndisMDpcX : ndisMDpc,
  1461. Interrupt);
  1462. SET_DPC_IMPORTANCE(&Interrupt->InterruptDpc);
  1463. SET_PROCESSOR_DPC(&Interrupt->InterruptDpc,
  1464. Miniport->AssignedProcessor);
  1465. NonTranslatedInterrupt.QuadPart = InterruptLevel;
  1466. Status = ndisTranslateResources(Miniport,
  1467. CmResourceTypeInterrupt,
  1468. NonTranslatedInterrupt,
  1469. &TranslatedIrql,
  1470. &pResourceDescriptor);
  1471. if (NDIS_STATUS_SUCCESS != Status)
  1472. {
  1473. DBGPRINT_RAW(DBG_COMP_INIT, DBG_LEVEL_INFO,
  1474. ((" NdisMRegisterInterrupt: trying to register interrupt %p which is not allocated to device\n"),
  1475. InterruptLevel));
  1476. Status = NDIS_STATUS_FAILURE;
  1477. break;
  1478. }
  1479. Irql = (KIRQL)pResourceDescriptor->u.Interrupt.Level;
  1480. Vector = pResourceDescriptor->u.Interrupt.Vector;
  1481. InterruptAffinity = pResourceDescriptor->u.Interrupt.Affinity;
  1482. if (pResourceDescriptor->Flags == CM_RESOURCE_INTERRUPT_LEVEL_SENSITIVE)
  1483. {
  1484. InterruptMode = LevelSensitive;
  1485. }
  1486. else
  1487. {
  1488. InterruptMode = Latched;
  1489. }
  1490. //
  1491. // just in case this is not the first time we try to get an interrupt
  1492. // for this miniport (suspend/resume or if the miniport has decided to
  1493. // let go of interrupt and hook it again
  1494. //
  1495. MINIPORT_CLEAR_FLAG(Miniport, fMINIPORT_DEREGISTERED_INTERRUPT);
  1496. NtStatus = IoConnectInterrupt(&Interrupt->InterruptObject,
  1497. (PKSERVICE_ROUTINE)ndisMIsr,
  1498. Interrupt,
  1499. NULL,
  1500. Vector,
  1501. Irql,
  1502. Irql,
  1503. (KINTERRUPT_MODE)InterruptMode,
  1504. SharedInterrupt,
  1505. InterruptAffinity,
  1506. FALSE);
  1507. if (!NT_SUCCESS(NtStatus))
  1508. {
  1509. Status = NDIS_STATUS_FAILURE;
  1510. DBGPRINT_RAW(DBG_COMP_INIT, DBG_LEVEL_INFO,
  1511. ((" NdisMRegisterInterrupt: IoConnectInterrupt failed on Interrupt Level:%lx, Vector: %lx\n"),
  1512. Irql, Vector));
  1513. //
  1514. // zero out the interrupt object just in case driver tries to remove the interrupt
  1515. // they are aligned in both structures
  1516. //
  1517. Interrupt->InterruptObject = NULL;
  1518. }
  1519. } while (FALSE);
  1520. if (Status != NDIS_STATUS_SUCCESS)
  1521. {
  1522. InterlockedDecrement((PLONG)&Miniport->RegisteredInterrupts);
  1523. }
  1524. DBGPRINT(DBG_COMP_INIT, DBG_LEVEL_INFO,
  1525. ("<==ndisMRegisterInterruptCommon: Miniport %p, Status %lx\n", MiniportAdapterHandle, Status));
  1526. return Status;
  1527. }
  1528. VOID
  1529. ndisMDeregisterInterruptCommon(
  1530. IN PNDIS_MINIPORT_INTERRUPT MiniportInterrupt
  1531. )
  1532. {
  1533. PNDIS_MINIPORT_BLOCK Miniport = MiniportInterrupt->Miniport;
  1534. DBGPRINT(DBG_COMP_INIT, DBG_LEVEL_INFO,
  1535. ("==>ndisMDeregisterInterruptCommon: Miniport %p\n", MiniportInterrupt->Miniport));
  1536. do
  1537. {
  1538. //
  1539. // drivers can register interrupts only during initialization
  1540. // and deregister them only during halt
  1541. // so here we can safely set the flag after the ref count
  1542. // goes to zero.
  1543. //
  1544. if (InterlockedDecrement((PLONG)&Miniport->RegisteredInterrupts) == 0)
  1545. {
  1546. MINIPORT_SET_FLAG(MiniportInterrupt->Miniport, fMINIPORT_DEREGISTERED_INTERRUPT);
  1547. }
  1548. //
  1549. // overloading the DpcCountLock to say that interrupt is
  1550. // deregistered
  1551. //
  1552. (ULONG)MiniportInterrupt->DpcCountLock = 1;
  1553. //
  1554. // Now we disconnect the interrupt.
  1555. // NOTE: they are aligned in both structures
  1556. //
  1557. IoDisconnectInterrupt(MiniportInterrupt->InterruptObject);
  1558. //
  1559. // Right now we know that any Dpcs that may fire are counted.
  1560. // We don't have to guard this with a spin lock because the
  1561. // Dpc will set the event it completes first, or we may
  1562. // wait for it to complete.
  1563. //
  1564. if (MiniportInterrupt->DpcCount > 0)
  1565. {
  1566. //
  1567. // Now we wait for all dpcs to complete.
  1568. //
  1569. WAIT_FOR_OBJECT(&MiniportInterrupt->DpcsCompletedEvent, NULL);
  1570. RESET_EVENT(&MiniportInterrupt->DpcsCompletedEvent);
  1571. }
  1572. } while (FALSE);
  1573. DBGPRINT(DBG_COMP_INIT, DBG_LEVEL_INFO,
  1574. ("<==ndisMDeregisterInterruptCommon: Miniport %p\n", MiniportInterrupt->Miniport));
  1575. }