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.

1256 lines
37 KiB

  1. /*++
  2. Copyright (c) Microsoft Corporation. All rights reserved.
  3. THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY
  4. KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
  5. IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR
  6. PURPOSE.
  7. Module Name:
  8. Miniport.C
  9. Abstract:
  10. The purpose of this sample is to illustrate functionality of a deserialized
  11. NDIS miniport driver without requiring a physical network adapter. This
  12. sample is based on E100BEX sample present in the DDK. It is basically a
  13. simplified version of E100bex driver. The driver can be installed either
  14. manually using Add Hardware wizard as a root enumerated virtual miniport
  15. driver or on a virtual bus (like toaster bus). Since the driver does not
  16. interact with any hardware, it makes it very easy to understand the miniport
  17. interface and the usage of various NDIS functions without the clutter of
  18. hardware specific code normally found in a fully functional driver.
  19. This sample provides an example of minimal driver intended for education
  20. purposes. Neither the driver or it's sample test programs are intended
  21. for use in a production environment.
  22. Author: Eliyas Yakub (Nov 20th 2002)
  23. Revision History:
  24. Notes:
  25. --*/
  26. #include "miniport.h"
  27. #pragma NDIS_INIT_FUNCTION(DriverEntry)
  28. #pragma NDIS_PAGEABLE_FUNCTION(MPInitialize)
  29. #pragma NDIS_PAGEABLE_FUNCTION(MPHalt)
  30. #pragma NDIS_PAGEABLE_FUNCTION(MPUnload)
  31. #ifdef NDIS51_MINIPORT
  32. #pragma NDIS_PAGEABLE_FUNCTION(MPPnPEventNotify)
  33. #endif
  34. MP_GLOBAL_DATA GlobalData;
  35. INT MPDebugLevel = MP_INFO;
  36. NDIS_HANDLE NdisWrapperHandle;
  37. NDIS_STATUS
  38. DriverEntry(
  39. PVOID DriverObject,
  40. PVOID RegistryPath)
  41. /*++
  42. Routine Description:
  43. In the context of its DriverEntry function, a miniport driver associates
  44. itself with NDIS, specifies the NDIS version that it is using, and
  45. registers its entry points.
  46. Arguments:
  47. PVOID DriverObject - pointer to the driver object.
  48. PVOID RegistryPath - pointer to the driver registry path.
  49. Return Value:
  50. NDIS_STATUS_xxx code
  51. --*/
  52. {
  53. NDIS_STATUS Status;
  54. NDIS_MINIPORT_CHARACTERISTICS MPChar;
  55. DEBUGP(MP_TRACE, ("---> DriverEntry built on "__DATE__" at "__TIME__ "\n"));
  56. //
  57. // Associate the miniport driver with NDIS by calling the
  58. // NdisMInitializeWrapper. This function allocates a structure
  59. // to represent this association, stores the miniport driver-
  60. // specific information that the NDIS Library needs in this
  61. // structure, and returns NdisWrapperHandle. The driver must retain and
  62. // pass this handle to NdisMRegisterMiniport when it registers its entry
  63. // points. NDIS will use NdisWrapperHandle to identify the miniport driver.
  64. // The miniport driver must retain this handle but it should never attempt
  65. // to access or interpret this handle.
  66. //
  67. NdisMInitializeWrapper(
  68. &NdisWrapperHandle,
  69. DriverObject,
  70. RegistryPath,
  71. NULL
  72. );
  73. //
  74. // Fill in the Miniport characteristics structure with the version numbers
  75. // and the entry points for driver-supplied MiniportXxx
  76. //
  77. NdisZeroMemory(&MPChar, sizeof(MPChar));
  78. //
  79. // The NDIS version number, in addition to being included in
  80. // NDIS_MINIPORT_CHARACTERISTICS, must also be specified when the
  81. // miniport driver source code is compiled.
  82. //
  83. MPChar.MajorNdisVersion = MP_NDIS_MAJOR_VERSION;
  84. MPChar.MinorNdisVersion = MP_NDIS_MINOR_VERSION;
  85. MPChar.InitializeHandler = MPInitialize;
  86. MPChar.HaltHandler = MPHalt;
  87. MPChar.SetInformationHandler = MPSetInformation;
  88. MPChar.QueryInformationHandler = MPQueryInformation;
  89. MPChar.SendPacketsHandler = MPSendPackets;
  90. MPChar.ReturnPacketHandler = MPReturnPacket;
  91. MPChar.ResetHandler = MPReset;
  92. MPChar.CheckForHangHandler = MPCheckForHang; //optional
  93. MPChar.AllocateCompleteHandler = MPAllocateComplete;//optional
  94. MPChar.DisableInterruptHandler = MPDisableInterrupt; //optional
  95. MPChar.EnableInterruptHandler = MPEnableInterrupt; //optional
  96. MPChar.HandleInterruptHandler = MPHandleInterrupt;
  97. MPChar.ISRHandler = MPIsr;
  98. #ifdef NDIS51_MINIPORT
  99. MPChar.CancelSendPacketsHandler = MPCancelSendPackets;
  100. MPChar.PnPEventNotifyHandler = MPPnPEventNotify;
  101. MPChar.AdapterShutdownHandler = MPShutdown;
  102. #endif
  103. DEBUGP(MP_LOUD, ("Calling NdisMRegisterMiniport...\n"));
  104. //
  105. // Registers miniport's entry points with the NDIS library as the first
  106. // step in NIC driver initialization. The NDIS will call the
  107. // MiniportInitialize when the device is actually started by the PNP
  108. // manager.
  109. //
  110. Status = NdisMRegisterMiniport(
  111. NdisWrapperHandle,
  112. &MPChar,
  113. sizeof(NDIS_MINIPORT_CHARACTERISTICS));
  114. if (Status != NDIS_STATUS_SUCCESS) {
  115. DEBUGP(MP_ERROR, ("Status = 0x%08x\n", Status));
  116. NdisTerminateWrapper(NdisWrapperHandle, NULL);
  117. } else {
  118. //
  119. // Initialize the global variables. The ApaterList in the
  120. // GloablData structure is used to track the multiple instances
  121. // of the same adapter. Make sure you do that before registering
  122. // the unload handler.
  123. //
  124. NdisAllocateSpinLock(&GlobalData.Lock);
  125. NdisInitializeListHead(&GlobalData.AdapterList);
  126. //
  127. // Register an Unload handler for global data cleanup. The unload handler
  128. // has a more global scope, whereas the scope of the MiniportHalt function
  129. // is restricted to a particular miniport instance.
  130. //
  131. NdisMRegisterUnloadHandler(NdisWrapperHandle, MPUnload);
  132. }
  133. DEBUGP(MP_TRACE, ("<--- DriverEntry\n"));
  134. return Status;
  135. }
  136. NDIS_STATUS
  137. MPInitialize(
  138. OUT PNDIS_STATUS OpenErrorStatus,
  139. OUT PUINT SelectedMediumIndex,
  140. IN PNDIS_MEDIUM MediumArray,
  141. IN UINT MediumArraySize,
  142. IN NDIS_HANDLE MiniportAdapterHandle,
  143. IN NDIS_HANDLE WrapperConfigurationContext)
  144. /*++
  145. Routine Description:
  146. The MiniportInitialize function is a required function that sets up a
  147. NIC (or virtual NIC) for network I/O operations, claims all hardware
  148. resources necessary to the NIC in the registry, and allocates resources
  149. the driver needs to carry out network I/O operations.
  150. MiniportInitialize runs at IRQL = PASSIVE_LEVEL.
  151. Arguments:
  152. Return Value:
  153. NDIS_STATUS_xxx code
  154. --*/
  155. {
  156. NDIS_STATUS Status = NDIS_STATUS_SUCCESS;
  157. PMP_ADAPTER Adapter=NULL;
  158. NDIS_HANDLE ConfigurationHandle;
  159. UINT index;
  160. DEBUGP(MP_TRACE, ("---> MPInitialize\n"));
  161. do {
  162. //
  163. // Check to see if our media type exists in an array of supported
  164. // media types provided by NDIS.
  165. //
  166. for(index = 0; index < MediumArraySize; ++index)
  167. {
  168. if(MediumArray[index] == NIC_MEDIA_TYPE) {
  169. break;
  170. }
  171. }
  172. if(index == MediumArraySize)
  173. {
  174. DEBUGP(MP_ERROR, ("Expected media is not in MediumArray.\n"));
  175. Status = NDIS_STATUS_UNSUPPORTED_MEDIA;
  176. break;
  177. }
  178. //
  179. // Set the index value as the selected medium for our device.
  180. //
  181. *SelectedMediumIndex = index;
  182. //
  183. // Allocate adapter context structure and initialize all the
  184. // memory resources for sending and receiving packets.
  185. //
  186. Status = NICAllocAdapter(&Adapter);
  187. if(Status != NDIS_STATUS_SUCCESS)
  188. {
  189. break;
  190. }
  191. MP_INC_REF(Adapter);
  192. //
  193. // NdisMGetDeviceProperty function enables us to get the:
  194. // PDO - created by the bus driver to represent our device.
  195. // FDO - created by NDIS to represent our miniport as a function driver.
  196. // NextDeviceObject - deviceobject of another driver (filter)
  197. // attached to us at the bottom.
  198. // In a pure NDIS miniport driver, there is no use for this
  199. // information, but a NDISWDM driver would need to know this so that it
  200. // can transfer packets to the lower WDM stack using IRPs.
  201. //
  202. NdisMGetDeviceProperty(MiniportAdapterHandle,
  203. &Adapter->Pdo,
  204. &Adapter->Fdo,
  205. &Adapter->NextDeviceObject,
  206. NULL,
  207. NULL);
  208. Adapter->AdapterHandle = MiniportAdapterHandle;
  209. //
  210. // Read Advanced configuration information from the registry
  211. //
  212. Status = NICReadRegParameters(Adapter, WrapperConfigurationContext);
  213. if(Status != NDIS_STATUS_SUCCESS)
  214. {
  215. break;
  216. }
  217. //
  218. // Inform NDIS about significant features of the NIC. A
  219. // MiniportInitialize function must call NdisMSetAttributesEx
  220. // (or NdisMSetAttributes) before calling any other NdisMRegisterXxx
  221. // or NdisXxx function that claims hardware resources. If your
  222. // hardware supports busmaster DMA, you must specify NDIS_ATTRIBUTE_BUS_MASTER.
  223. // If this is NDIS51 miniport, it should use safe APIs. But if this
  224. // is NDIS 5.0, the driver claim to use safe APIs by setting
  225. // NDIS_ATTRIBUTE_USES_SAFE_BUFFER_APIS
  226. //
  227. NdisMSetAttributesEx(
  228. MiniportAdapterHandle,
  229. (NDIS_HANDLE) Adapter,
  230. 0,
  231. #ifdef NDIS51_MINIPORT
  232. NDIS_ATTRIBUTE_DESERIALIZE, // NDIS does not maintain a send-packet queue
  233. #else
  234. NDIS_ATTRIBUTE_DESERIALIZE|
  235. NDIS_ATTRIBUTE_USES_SAFE_BUFFER_APIS,
  236. #endif
  237. NIC_INTERFACE_TYPE);
  238. //
  239. // Get the Adapter Resources & Initialize the hardware.
  240. //
  241. Status = NICInitializeAdapter(Adapter, WrapperConfigurationContext);
  242. if(Status != NDIS_STATUS_SUCCESS) {
  243. Status = NDIS_STATUS_FAILURE;
  244. break;
  245. }
  246. //
  247. // Setup a timer function for Receive Indication
  248. //
  249. NdisInitializeTimer(
  250. &Adapter->RecvTimer,
  251. (PNDIS_TIMER_FUNCTION)NICIndicateReceiveTimerDpc,
  252. (PVOID)Adapter);
  253. //
  254. // Setup a timer function for use with our MPReset routine.
  255. //
  256. NdisInitializeTimer(
  257. &Adapter->ResetTimer,
  258. (PNDIS_TIMER_FUNCTION) NICResetCompleteTimerDpc,
  259. (PVOID) Adapter);
  260. NdisInitializeEvent(&Adapter->RemoveEvent);
  261. } while(FALSE);
  262. if(Status == NDIS_STATUS_SUCCESS) {
  263. //
  264. // Attach this Adapter to the global list of adapters managed by
  265. // this driver.
  266. //
  267. NICAttachAdapter(Adapter);
  268. //
  269. // Create an IOCTL interface
  270. //
  271. NICRegisterDevice();
  272. }
  273. else {
  274. if(Adapter){
  275. MP_DEC_REF(Adapter);
  276. NICFreeAdapter(Adapter);
  277. }
  278. }
  279. DEBUGP(MP_TRACE, ("<--- MPInitialize Status = 0x%08x%\n", Status));
  280. return Status;
  281. }
  282. VOID
  283. MPHalt(
  284. IN NDIS_HANDLE MiniportAdapterContext
  285. )
  286. /*++
  287. Routine Description:
  288. Halt handler is called when NDIS receives IRP_MN_STOP_DEVICE,
  289. IRP_MN_SUPRISE_REMOVE or IRP_MN_REMOVE_DEVICE requests from the
  290. PNP manager. Here, the driver should free all the resources acquired
  291. in MiniportInitialize and stop access to the hardware. NDIS will
  292. not submit any further request once this handler is invoked.
  293. 1) Free and unmap all I/O resources.
  294. 2) Disable interrupt and deregister interrupt handler.
  295. 3) Deregister shutdown handler regsitered by
  296. NdisMRegisterAdapterShutdownHandler .
  297. 4) Cancel all queued up timer callbacks.
  298. 5) Finally wait indefinitely for all the outstanding receive
  299. packets indicated to the protocol to return.
  300. MiniportHalt runs at IRQL = PASSIVE_LEVEL.
  301. Arguments:
  302. MiniportAdapterContext Pointer to the Adapter
  303. Return Value:
  304. None.
  305. --*/
  306. {
  307. PMP_ADAPTER Adapter = (PMP_ADAPTER) MiniportAdapterContext;
  308. BOOLEAN bDone=TRUE;
  309. BOOLEAN bCancelled;
  310. LONG nHaltCount = 0, Count;
  311. MP_SET_FLAG(Adapter, fMP_ADAPTER_HALT_IN_PROGRESS);
  312. DEBUGP(MP_TRACE, ("---> MPHalt\n"));
  313. //
  314. // Call Shutdown handler to disable interrupt and turn the hardware off
  315. // by issuing a full reset
  316. //
  317. #if defined(NDIS50_MINIPORT)
  318. MPShutdown(MiniportAdapterContext);
  319. #elif defined(NDIS51_MINIPORT)
  320. //
  321. // On XP and later, NDIS notifies our PNP event handler the
  322. // reason for calling Halt. So before accessing the device, check to see
  323. // if the device is surprise removed, if so don't bother calling
  324. // the shutdown handler to stop the hardware because it doesn't exist.
  325. //
  326. if(!MP_TEST_FLAG(Adapter, fMP_ADAPTER_SURPRISE_REMOVED)) {
  327. MPShutdown(MiniportAdapterContext);
  328. }
  329. #endif
  330. //
  331. // Free the packets on SendWaitList
  332. //
  333. NICFreeQueuedSendPackets(Adapter);
  334. //
  335. // Cancel the ResetTimer.
  336. //
  337. NdisCancelTimer(&Adapter->ResetTimer, &bCancelled);
  338. //
  339. // Cancel the ReceiveIndication Timer.
  340. //
  341. NdisCancelTimer(&Adapter->RecvTimer, &bCancelled);
  342. if(bCancelled) {
  343. //
  344. // We are able to cancel a queued Timer. So there is a
  345. // possibility for the packets to be waiting in the
  346. // RecvWaitList. So let us free them by calling..
  347. //
  348. NICFreeQueuedRecvPackets(Adapter);
  349. }
  350. //
  351. // Decrement the ref count which was incremented in MPInitialize
  352. //
  353. MP_DEC_REF(Adapter);
  354. //
  355. // Possible non-zero ref counts mean one or more of the following conditions:
  356. // 1) Reset DPC is still running.
  357. // 2) Receive Indication DPC is still running.
  358. //
  359. DEBUGP(MP_INFO, ("RefCount=%d --- waiting!\n", MP_GET_REF(Adapter)));
  360. NdisWaitEvent(&Adapter->RemoveEvent, 0);
  361. while(TRUE)
  362. {
  363. bDone = TRUE;
  364. //
  365. // Are all the packets indicated up returned?
  366. //
  367. if(Adapter->nBusyRecv)
  368. {
  369. DEBUGP(MP_INFO, ("nBusyRecv = %d\n", Adapter->nBusyRecv));
  370. bDone = FALSE;
  371. }
  372. //
  373. // Are there any outstanding send packets?
  374. //
  375. if(Adapter->nBusySend)
  376. {
  377. DEBUGP(MP_INFO, ("nBusySend = %d\n", Adapter->nBusySend));
  378. bDone = FALSE;
  379. }
  380. if(bDone)
  381. {
  382. break;
  383. }
  384. if(++nHaltCount % 100)
  385. {
  386. DEBUGP(MP_ERROR, ("Halt timed out!!!\n"));
  387. DEBUGP(MP_ERROR, ("RecvWaitList = %p\n", &Adapter->RecvWaitList));
  388. ASSERT(FALSE);
  389. }
  390. DEBUGP(MP_INFO, ("MPHalt - waiting ...\n"));
  391. NdisMSleep(1000);
  392. }
  393. ASSERT(bDone);
  394. #ifdef NDIS50_MINIPORT
  395. //
  396. // Deregister shutdown handler as it's being halted
  397. //
  398. NdisMDeregisterAdapterShutdownHandler(Adapter->AdapterHandle);
  399. #endif
  400. //
  401. // Unregister the ioctl interface.
  402. //
  403. NICDeregisterDevice();
  404. NICDetachAdapter(Adapter);
  405. NICFreeAdapter(Adapter);
  406. DEBUGP(MP_TRACE, ("<--- MPHalt\n"));
  407. }
  408. NDIS_STATUS
  409. MPReset(
  410. OUT PBOOLEAN AddressingReset,
  411. IN NDIS_HANDLE MiniportAdapterContext
  412. )
  413. /*++
  414. Routine Description:
  415. MiniportReset is a required to issue a hardware reset to the NIC
  416. and/or to reset the driver's software state.
  417. 1) The miniport driver can optionally complete any pending
  418. OID requests. NDIS will submit no further OID requests
  419. to the miniport driver for the NIC being reset until
  420. the reset operation has finished. After the reset,
  421. NDIS will resubmit to the miniport driver any OID requests
  422. that were pending but not completed by the miniport driver
  423. before the reset.
  424. 2) A deserialized miniport driver must complete any pending send
  425. operations. NDIS will not requeue pending send packets for
  426. a deserialized driver since NDIS does not maintain the send
  427. queue for such a driver.
  428. 3) If MiniportReset returns NDIS_STATUS_PENDING, the driver must
  429. complete the original request subsequently with a call to
  430. NdisMResetComplete.
  431. MiniportReset runs at IRQL = DISPATCH_LEVEL.
  432. Arguments:
  433. AddressingReset - If multicast or functional addressing information
  434. or the lookahead size, is changed by a reset,
  435. MiniportReset must set the variable at AddressingReset
  436. to TRUE before it returns control. This causes NDIS to
  437. call the MiniportSetInformation function to restore
  438. the information.
  439. MiniportAdapterContext - Pointer to our adapter
  440. Return Value:
  441. NDIS_STATUS
  442. --*/
  443. {
  444. NDIS_STATUS Status;
  445. PMP_ADAPTER Adapter = (PMP_ADAPTER) MiniportAdapterContext;
  446. BOOLEAN bDone = TRUE;
  447. DEBUGP(MP_TRACE, ("---> MPReset\n"));
  448. do
  449. {
  450. ASSERT(!MP_TEST_FLAG(Adapter, fMP_ADAPTER_HALT_IN_PROGRESS));
  451. if(MP_TEST_FLAG(Adapter, fMP_RESET_IN_PROGRESS))
  452. {
  453. Status = NDIS_STATUS_RESET_IN_PROGRESS;
  454. break;
  455. }
  456. MP_SET_FLAG(Adapter, fMP_RESET_IN_PROGRESS);
  457. //
  458. // Complete all the queued up send packets
  459. //
  460. NICFreeQueuedSendPackets(Adapter);
  461. //
  462. // Check to see if all the packets indicated up are returned.
  463. //
  464. if(Adapter->nBusyRecv)
  465. {
  466. DEBUGP(MP_INFO, ("nBusyRecv = %d\n", Adapter->nBusyRecv));
  467. bDone = FALSE;
  468. }
  469. //
  470. // Are there any send packets in the processes of being
  471. // transmitted?
  472. //
  473. if(Adapter->nBusySend)
  474. {
  475. DEBUGP(MP_INFO, ("nBusySend = %d\n", Adapter->nBusySend));
  476. bDone = FALSE;
  477. }
  478. if(!bDone)
  479. {
  480. Adapter->nResetTimerCount = 0;
  481. //
  482. // We can't complete the reset request now. So let us queue
  483. // a timer callback for 500ms and check again whether we can
  484. // successfully reset the hardware.
  485. //
  486. NdisSetTimer(&Adapter->ResetTimer, 500);
  487. //
  488. // By returning NDIS_STATUS_PENDING, we are promising NDIS that
  489. // we will complete the reset request by calling NdisMResetComplete.
  490. //
  491. Status = NDIS_STATUS_PENDING;
  492. break;
  493. }
  494. *AddressingReset = FALSE;
  495. MP_CLEAR_FLAG(Adapter, fMP_RESET_IN_PROGRESS);
  496. Status = NDIS_STATUS_SUCCESS;
  497. } while(FALSE);
  498. DEBUGP(MP_TRACE, ("<--- MPReset Status = 0x%08x\n", Status));
  499. return(Status);
  500. }
  501. VOID
  502. NICResetCompleteTimerDpc(
  503. IN PVOID SystemSpecific1,
  504. IN PVOID FunctionContext,
  505. IN PVOID SystemSpecific2,
  506. IN PVOID SystemSpecific3)
  507. /*++
  508. Routine Description:
  509. Timer callback function for Reset operation.
  510. Arguments:
  511. FunctionContext - Pointer to our adapter
  512. Return Value:
  513. VOID
  514. --*/
  515. {
  516. PMP_ADAPTER Adapter = (PMP_ADAPTER)FunctionContext;
  517. BOOLEAN bDone = TRUE;
  518. NDIS_STATUS Status = NDIS_STATUS_SUCCESS;
  519. DEBUGP(MP_TRACE, ("--> NICResetCompleteTimerDpc\n"));
  520. //
  521. // Increment the ref count on the adapter to prevent the driver from
  522. // unloding while the DPC is running. The Halt handler waits for the
  523. // ref count to drop to zero before returning.
  524. //
  525. MP_INC_REF(Adapter);
  526. //
  527. // Check to see if all the packets indicated up are returned.
  528. //
  529. if(Adapter->nBusyRecv)
  530. {
  531. DEBUGP(MP_INFO, ("nBusyRecv = %d\n", Adapter->nBusyRecv));
  532. bDone = FALSE;
  533. }
  534. //
  535. // Are there any send packets in the processes of being
  536. // transmitted?
  537. //
  538. if(Adapter->nBusySend)
  539. {
  540. DEBUGP(MP_INFO, ("nBusySend = %d\n", Adapter->nBusySend));
  541. bDone = FALSE;
  542. }
  543. if(!bDone && ++Adapter->nResetTimerCount <= 20)
  544. {
  545. //
  546. // Let us try one more time.
  547. //
  548. NdisSetTimer(&Adapter->ResetTimer, 500);
  549. }
  550. else
  551. {
  552. if(!bDone)
  553. {
  554. //
  555. // We have tried enough. Something is wrong. Let us
  556. // just complete the reset request with failure.
  557. //
  558. DEBUGP(MP_ERROR, ("Reset timed out!!!\n"));
  559. DEBUGP(MP_ERROR, ("nBusySend = %d\n", Adapter->nBusySend));
  560. DEBUGP(MP_ERROR, ("RecvWaitList = %p\n", &Adapter->RecvWaitList));
  561. DEBUGP(MP_ERROR, ("nBusyRecv = %d\n", Adapter->nBusyRecv));
  562. ASSERT(FALSE);
  563. Status = NDIS_STATUS_FAILURE;
  564. }
  565. DEBUGP(MP_INFO, ("Done - NdisMResetComplete\n"));
  566. MP_CLEAR_FLAG(Adapter, fMP_RESET_IN_PROGRESS);
  567. NdisMResetComplete(
  568. Adapter->AdapterHandle,
  569. Status,
  570. FALSE);
  571. }
  572. MP_DEC_REF(Adapter);
  573. DEBUGP(MP_TRACE, ("<-- NICResetCompleteTimerDpc Status = 0x%08x\n", Status));
  574. }
  575. VOID
  576. MPUnload(
  577. IN PDRIVER_OBJECT DriverObject
  578. )
  579. /*++
  580. Routine Description:
  581. The unload handler is called during driver unload to free up resources
  582. acquired in DriverEntry. This handler is registered through
  583. NdisMRegisterUnloadHandler. Note that an unload handler differs from
  584. a MiniportHalt function in that the unload handler has a more global
  585. scope, whereas the scope of the MiniportHalt function is restricted
  586. to a particular miniport driver instance.
  587. Runs at IRQL = PASSIVE_LEVEL.
  588. Arguments:
  589. DriverObject Not used
  590. Return Value:
  591. None
  592. --*/
  593. {
  594. DEBUGP(MP_TRACE, ("--> MPUnload\n"));
  595. ASSERT(IsListEmpty(&GlobalData.AdapterList));
  596. NdisFreeSpinLock(&GlobalData.Lock);
  597. DEBUGP(MP_TRACE, ("<--- MPUnload\n"));
  598. }
  599. VOID
  600. MPShutdown(
  601. IN NDIS_HANDLE MiniportAdapterContext
  602. )
  603. /*++
  604. Routine Description:
  605. The MiniportShutdown handler restores a NIC to its initial state when
  606. the system is shut down, whether by the user or because an unrecoverable
  607. system error occurred. This is to ensure that the NIC is in a known
  608. state and ready to be reinitialized when the machine is rebooted after
  609. a system shutdown occurs for any reason, including a crash dump.
  610. Here just disable the interrupt and stop the DMA engine.
  611. Do not free memory resources or wait for any packet transfers
  612. to complete.
  613. Runs at an arbitrary IRQL <= DIRQL. So do not call any passive-level
  614. function.
  615. Arguments:
  616. MiniportAdapterContext Pointer to our adapter
  617. Return Value:
  618. None
  619. --*/
  620. {
  621. PMP_ADAPTER Adapter = (PMP_ADAPTER) MiniportAdapterContext;
  622. DEBUGP(MP_TRACE, ("---> MPShutdown\n"));
  623. DEBUGP(MP_TRACE, ("<--- MPShutdown\n"));
  624. }
  625. BOOLEAN
  626. MPCheckForHang(
  627. IN NDIS_HANDLE MiniportAdapterContext
  628. )
  629. /*++
  630. Routine Description:
  631. The MiniportCheckForHang handler is called to report the state of the
  632. NIC, or to monitor the responsiveness of an underlying device driver.
  633. This is an optional function. If this handler is not specified, NDIS
  634. judges the driver unresponsive when the driver holds
  635. MiniportQueryInformation or MiniportSetInformation requests for a
  636. time-out interval (deafult 4 sec), and then calls the driver's
  637. MiniportReset function. A NIC driver's MiniportInitialize function can
  638. extend NDIS's time-out interval by calling NdisMSetAttributesEx to
  639. avoid unnecessary resets.
  640. Always runs at IRQL = DISPATCH_LEVEL.
  641. Arguments:
  642. MiniportAdapterContext Pointer to our adapter
  643. Return Value:
  644. TRUE NDIS calls the driver's MiniportReset function.
  645. FALSE Everything is fine
  646. Note:
  647. CheckForHang handler is called in the context of a timer DPC.
  648. take advantage of this fact when acquiring/releasing spinlocks
  649. --*/
  650. {
  651. DEBUGP(MP_LOUD, ("---> MPCheckForHang\n"));
  652. DEBUGP(MP_LOUD, ("<--- MPCheckForHang\n"));
  653. return(FALSE);
  654. }
  655. VOID
  656. MPHandleInterrupt(
  657. IN NDIS_HANDLE MiniportAdapterContext
  658. )
  659. /*++
  660. Routine Description:
  661. MiniportHandleInterrupt is a DPC function called to do deferred
  662. processing of all outstanding interrupt operations. When a NIC
  663. generates an interrupt, a miniport's MiniportISR or
  664. MiniportDisableInterrupt function dismisses the interrupt on the
  665. NIC, saves any necessary state about the operation, and returns
  666. control as quickly as possible, thereby deferring most
  667. interrupt-driven I/O operations to MiniportHandleInterrupt. This
  668. handler is called only if the MiniportISR function returned
  669. QueueMiniportHandleInterrupt set to TRUE.
  670. MiniportHandleInterrupt then re-enables interrupts on the NIC,
  671. either by letting NDIS call the miniport driver's
  672. MiniportEnableInterrupt function after MiniportHandleInterrupt
  673. returns control or by enabling the interrupt from within
  674. MiniportHandleInterrupt, which is faster.
  675. Note that more than one instance of this function can execute
  676. concurrently in SMP machines.
  677. Runs at IRQL = DISPATCH_LEVEL
  678. Arguments:
  679. MiniportAdapterContext Pointer to our adapter
  680. Return Value:
  681. None
  682. --*/
  683. {
  684. DEBUGP(MP_TRACE, ("---> MPHandleInterrupt\n"));
  685. DEBUGP(MP_TRACE, ("<--- MPHandleInterrupt\n"));
  686. }
  687. VOID
  688. MPIsr(
  689. OUT PBOOLEAN InterruptRecognized,
  690. OUT PBOOLEAN QueueMiniportHandleInterrupt,
  691. IN NDIS_HANDLE MiniportAdapterContext
  692. )
  693. /*++
  694. Routine Description:
  695. MiniportIsr handler is called to when the device asserts an interrupt.
  696. MiniportISR dismisses the interrupt on the NIC, saves whatever state
  697. it must about the interrupt, and defers as much of the I/O processing
  698. for each interrupt as possible to the MiniportHandleInterrupt function.
  699. MiniportISR is not re-entrant, although two instantiations of this
  700. function can execute concurrently in SMP machines, particularly if
  701. the miniport driver supports full-duplex sends and receives. A driver
  702. writer should not rely on a one-to-one correspondence between the
  703. execution of MiniportISR and MiniportHandleInterrupt.
  704. If the NIC shares an IRQ with other devices (check NdisMRegisterInterrupt),
  705. this function should determine whether the NIC generated the interrupt.
  706. If the NIC did not generated the interrupt, MiniportISR should return FALSE
  707. immediately so that the driver of the device that generated the interrupt
  708. is called quickly.
  709. Runs at IRQL = DIRQL assigned when the NIC driver's MiniportInitialize
  710. function called NdisMRegisterInterrupt.
  711. Arguments:
  712. InterruptRecognized TRUE on return if the interrupt comes
  713. from this NIC
  714. QueueMiniportHandleInterrupt TRUE on return if MiniportHandleInterrupt
  715. should be called
  716. MiniportAdapterContext Pointer to our adapter
  717. Return Value:
  718. None
  719. --*/
  720. {
  721. DEBUGP(MP_TRACE, ("---> MPIsr\n"));
  722. DEBUGP(MP_TRACE, ("<--- MPIsr\n"));
  723. }
  724. VOID
  725. MPDisableInterrupt(
  726. IN PVOID MiniportAdapterContext
  727. )
  728. /*++
  729. Routine Description:
  730. MiniportDisableInterrupt typically disables interrupts by writing
  731. a mask to the NIC. If a driver does not have this function, typically
  732. its MiniportISR disables interrupts on the NIC.
  733. This handler is required by drivers of NICs that support dynamic
  734. enabling and disabling of interrupts but do not share an IRQ.
  735. Runs at IRQL = DIRQL
  736. Arguments:
  737. MiniportAdapterContext Pointer to our adapter
  738. Return Value:
  739. None
  740. --*/
  741. {
  742. DEBUGP(MP_TRACE, ("---> MPDisableInterrupt\n"));
  743. DEBUGP(MP_TRACE, ("<--- MPDisableInterrupt\n"));
  744. }
  745. VOID
  746. MPEnableInterrupt(
  747. IN PVOID MiniportAdapterContext
  748. )
  749. /*++
  750. Routine Description:
  751. MiniportEnableInterrupt typically enables interrupts by writing a mask
  752. to the NIC. A NIC driver that exports a MiniportDisableInterrupt function
  753. need not have a reciprocal MiniportEnableInterrupt function.
  754. Such a driver's MiniportHandleInterrupt function is responsible for
  755. re-enabling interrupts on the NIC.
  756. Runs at IRQL = DIRQL
  757. Arguments:
  758. MiniportAdapterContext Pointer to our adapter
  759. Return Value:
  760. None
  761. --*/
  762. {
  763. DEBUGP(MP_TRACE, ("---> MPEnableInterrupt\n"));
  764. DEBUGP(MP_TRACE, ("<--- MPEnableInterrupt\n"));
  765. }
  766. VOID
  767. MPAllocateComplete(
  768. NDIS_HANDLE MiniportAdapterContext,
  769. IN PVOID VirtualAddress,
  770. IN PNDIS_PHYSICAL_ADDRESS PhysicalAddress,
  771. IN ULONG Length,
  772. IN PVOID Context
  773. )
  774. /*++
  775. Routine Description:
  776. This handler is needed if the driver makes calls to
  777. NdisMAllocateSharedMemoryAsync. Drivers of bus-master DMA NICs call
  778. NdisMAllocateSharedMemoryAsync to dynamically allocate shared memory
  779. for transfer operations when high network traffic places excessive
  780. demands on the shared memory space that the driver allocated during
  781. initialization.
  782. Runs at IRQL = DISPATCH_LEVEL.
  783. Arguments:
  784. MiniportAdapterContext Pointer to our adapter
  785. VirtualAddress Pointer to the allocated memory block
  786. PhysicalAddress Physical address of the memory block
  787. Length Length of the memory block
  788. Context Context in NdisMAllocateSharedMemoryAsync
  789. Return Value:
  790. None
  791. --*/
  792. {
  793. DEBUGP(MP_TRACE, ("---> MPAllocateComplete\n"));
  794. }
  795. #ifdef NDIS51_MINIPORT
  796. VOID
  797. MPCancelSendPackets(
  798. IN NDIS_HANDLE MiniportAdapterContext,
  799. IN PVOID CancelId
  800. )
  801. /*++
  802. Routine Description:
  803. MiniportCancelSendPackets cancels the transmission of all packets that
  804. are marked with a specified cancellation identifier. Miniport drivers
  805. that queue send packets for more than one second should export this
  806. handler. When a protocol driver or intermediate driver calls the
  807. NdisCancelSendPackets function, NDIS calls the MiniportCancelSendPackets
  808. function of the appropriate lower-level driver (miniport driver or
  809. intermediate driver) on the binding.
  810. Runs at IRQL <= DISPATCH_LEVEL.
  811. Available - NDIS5.1 (WinXP) and later.
  812. Arguments:
  813. MiniportAdapterContext Pointer to our adapter
  814. CancelId All the packets with this Id should be cancelled
  815. Return Value:
  816. None
  817. --*/
  818. {
  819. PNDIS_PACKET Packet;
  820. PVOID PacketId;
  821. PLIST_ENTRY thisEntry, nextEntry, listHead;
  822. SINGLE_LIST_ENTRY SendCancelList;
  823. PSINGLE_LIST_ENTRY entry;
  824. PMP_ADAPTER Adapter = (PMP_ADAPTER)MiniportAdapterContext;
  825. #define MP_GET_PACKET_MR(_p) (PSINGLE_LIST_ENTRY)(&(_p)->MiniportReserved[0])
  826. DEBUGP(MP_TRACE, ("---> MPCancelSendPackets\n"));
  827. SendCancelList.Next = NULL;
  828. NdisAcquireSpinLock(&Adapter->SendLock);
  829. //
  830. // Walk through the send wait queue and complete the sends with matching Id
  831. //
  832. listHead = &Adapter->SendWaitList;
  833. for(thisEntry = listHead->Flink,nextEntry = thisEntry->Flink;
  834. thisEntry != listHead;
  835. thisEntry = nextEntry,nextEntry = thisEntry->Flink) {
  836. Packet = CONTAINING_RECORD(thisEntry, NDIS_PACKET, MiniportReserved);
  837. PacketId = NdisGetPacketCancelId(Packet);
  838. if (PacketId == CancelId)
  839. {
  840. //
  841. // This packet has the right CancelId
  842. //
  843. RemoveEntryList(thisEntry);
  844. //
  845. // Put this packet on SendCancelList
  846. //
  847. PushEntryList(&SendCancelList, MP_GET_PACKET_MR(Packet));
  848. }
  849. }
  850. NdisReleaseSpinLock(&Adapter->SendLock);
  851. //
  852. // Get the packets from SendCancelList and complete them if any
  853. //
  854. entry = PopEntryList(&SendCancelList);
  855. while (entry)
  856. {
  857. Packet = CONTAINING_RECORD(entry, NDIS_PACKET, MiniportReserved);
  858. NdisMSendComplete(
  859. Adapter->AdapterHandle,
  860. Packet,
  861. NDIS_STATUS_REQUEST_ABORTED);
  862. entry = PopEntryList(&SendCancelList);
  863. }
  864. DEBUGP(MP_TRACE, ("<--- MPCancelSendPackets\n"));
  865. }
  866. VOID MPPnPEventNotify(
  867. IN NDIS_HANDLE MiniportAdapterContext,
  868. IN NDIS_DEVICE_PNP_EVENT PnPEvent,
  869. IN PVOID InformationBuffer,
  870. IN ULONG InformationBufferLength
  871. )
  872. /*++
  873. Routine Description:
  874. MiniportPnPEventNotify is to handle PnP notification messages.
  875. All NDIS 5.1 miniport drivers must export a MiniportPnPEventNotify
  876. function. Miniport drivers that have a WDM lower edge should export
  877. a MiniportPnPEventNotify function.
  878. Runs at IRQL = PASSIVE_LEVEL in the context of system thread.
  879. Available - NDIS5.1 (WinXP) and later.
  880. Arguments:
  881. MiniportAdapterContext Pointer to our adapter
  882. PnPEvent Self-explanatory
  883. InformationBuffer Self-explanatory
  884. InformationBufferLength Self-explanatory
  885. Return Value:
  886. None
  887. --*/
  888. {
  889. PMP_ADAPTER Adapter = (PMP_ADAPTER)MiniportAdapterContext;
  890. PNDIS_POWER_PROFILE NdisPowerProfile;
  891. //
  892. // Turn off the warings.
  893. //
  894. UNREFERENCED_PARAMETER(Adapter);
  895. DEBUGP(MP_TRACE, ("---> MPPnPEventNotify\n"));
  896. switch (PnPEvent)
  897. {
  898. case NdisDevicePnPEventQueryRemoved:
  899. //
  900. // Called when NDIS receives IRP_MN_QUERY_REMOVE_DEVICE.
  901. //
  902. DEBUGP(MP_INFO, ("MPPnPEventNotify: NdisDevicePnPEventQueryRemoved\n"));
  903. break;
  904. case NdisDevicePnPEventRemoved:
  905. //
  906. // Called when NDIS receives IRP_MN_REMOVE_DEVICE.
  907. // NDIS calls MiniportHalt function after this call returns.
  908. //
  909. DEBUGP(MP_INFO, ("MPPnPEventNotify: NdisDevicePnPEventRemoved\n"));
  910. break;
  911. case NdisDevicePnPEventSurpriseRemoved:
  912. //
  913. // Called when NDIS receives IRP_MN_SUPRISE_REMOVAL.
  914. // NDIS calls MiniportHalt function after this call returns.
  915. //
  916. MP_SET_FLAG(Adapter, fMP_ADAPTER_SURPRISE_REMOVED);
  917. DEBUGP(MP_INFO, ("MPPnPEventNotify: NdisDevicePnPEventSurpriseRemoved\n"));
  918. break;
  919. case NdisDevicePnPEventQueryStopped:
  920. //
  921. // Called when NDIS receives IRP_MN_QUERY_STOP_DEVICE. ??
  922. //
  923. DEBUGP(MP_INFO, ("MPPnPEventNotify: NdisDevicePnPEventQueryStopped\n"));
  924. break;
  925. case NdisDevicePnPEventStopped:
  926. //
  927. // Called when NDIS receives IRP_MN_STOP_DEVICE.
  928. // NDIS calls MiniportHalt function after this call returns.
  929. //
  930. //
  931. DEBUGP(MP_INFO, ("MPPnPEventNotify: NdisDevicePnPEventStopped\n"));
  932. break;
  933. case NdisDevicePnPEventPowerProfileChanged:
  934. //
  935. // After initializing a miniport driver and after miniport driver
  936. // receives an OID_PNP_SET_POWER notification that specifies
  937. // a device power state of NdisDeviceStateD0 (the powered-on state),
  938. // NDIS calls the miniport's MiniportPnPEventNotify function with
  939. // PnPEvent set to NdisDevicePnPEventPowerProfileChanged.
  940. //
  941. DEBUGP(MP_INFO, ("MPPnPEventNotify: NdisDevicePnPEventPowerProfileChanged\n"));
  942. if(InformationBufferLength == sizeof(NDIS_POWER_PROFILE)) {
  943. NdisPowerProfile = (PNDIS_POWER_PROFILE)InformationBuffer;
  944. if(*NdisPowerProfile == NdisPowerProfileBattery) {
  945. DEBUGP(MP_INFO,
  946. ("The host system is running on battery power\n"));
  947. }
  948. if(*NdisPowerProfile == NdisPowerProfileAcOnLine) {
  949. DEBUGP(MP_INFO,
  950. ("The host system is running on AC power\n"));
  951. }
  952. }
  953. break;
  954. default:
  955. DEBUGP(MP_ERROR, ("MPPnPEventNotify: unknown PnP event %x \n", PnPEvent));
  956. break;
  957. }
  958. DEBUGP(MP_TRACE, ("<--- MPPnPEventNotify\n"));
  959. }
  960. #endif