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.

1112 lines
35 KiB

  1. /*++
  2. Copyright (c) 1990-1995 Microsoft Corporation
  3. Module Name:
  4. Ndispnp.c
  5. Abstract:
  6. Author:
  7. Kyle Brandon (KyleB)
  8. Alireza Dabagh (AliD)
  9. Environment:
  10. Kernel mode
  11. Revision History:
  12. 12/20/96 KyleB Added support for IRP_MN_QUERY_CAPABILITIES.
  13. --*/
  14. #include <precomp.h>
  15. #pragma hdrstop
  16. //
  17. // Define the module number for debug code.
  18. //
  19. #define MODULE_NUMBER MODULE_NDIS_PNP
  20. VOID
  21. NdisCompletePnPEvent(
  22. IN NDIS_STATUS Status,
  23. IN NDIS_HANDLE NdisBindingHandle,
  24. IN PNET_PNP_EVENT NetPnPEvent
  25. )
  26. /*++
  27. Routine Description:
  28. This routine is called by a transport when it wants to complete a PnP/PM
  29. event indication on a given binding.
  30. Arguments:
  31. Status - Status of the PnP/PM event indication.
  32. NdisBindingHandle - Binding that the event was for.
  33. NetPnPEvent - Structure describing the PnP/PM event.
  34. Return Value:
  35. None.
  36. --*/
  37. {
  38. PNDIS_PNP_EVENT_RESERVED EventReserved;
  39. #if !DBG
  40. UNREFERENCED_PARAMETER(NdisBindingHandle);
  41. #endif
  42. DBGPRINT_RAW(DBG_COMP_PNP, DBG_LEVEL_INFO,
  43. ("==>NdisCompletePnPEvent: Open %p\n", NdisBindingHandle));
  44. ASSERT(Status != NDIS_STATUS_PENDING);
  45. //
  46. // Get a pointer to the NDIS reserved area in the event.
  47. //
  48. EventReserved = PNDIS_PNP_EVENT_RESERVED_FROM_NET_PNP_EVENT(NetPnPEvent);
  49. //
  50. // Save the status with the net event.
  51. //
  52. EventReserved->Status = Status;
  53. //
  54. // Signal the event.
  55. //
  56. SET_EVENT(EventReserved->pEvent);
  57. DBGPRINT_RAW(DBG_COMP_PNP, DBG_LEVEL_INFO,
  58. ("<==NdisCompletePnPEvent: Open %p\n", NdisBindingHandle));
  59. }
  60. NTSTATUS
  61. ndisMIrpCompletion(
  62. IN PDEVICE_OBJECT DeviceObject,
  63. IN PIRP Irp,
  64. IN PVOID Context
  65. )
  66. /*++
  67. Routine Description:
  68. This routine will get called after the next device object in the stack
  69. processes the IRP_MN_QUERY_CAPABILITIES IRP this needs to be merged with
  70. the miniport's capabilites and completed.
  71. Arguments:
  72. DeviceObject
  73. Irp
  74. Context
  75. Return Value:
  76. --*/
  77. {
  78. UNREFERENCED_PARAMETER(DeviceObject);
  79. UNREFERENCED_PARAMETER(Irp);
  80. SET_EVENT(Context);
  81. return(STATUS_MORE_PROCESSING_REQUIRED);
  82. }
  83. NTSTATUS
  84. ndisPassIrpDownTheStack(
  85. IN PIRP pIrp,
  86. IN PDEVICE_OBJECT pNextDeviceObject
  87. )
  88. /*++
  89. Routine Description:
  90. This routine will simply pass the IRP down to the next device object to
  91. process.
  92. Arguments:
  93. pIrp - Pointer to the IRP to process.
  94. pNextDeviceObject - Pointer to the next device object that wants
  95. the IRP.
  96. Return Value:
  97. --*/
  98. {
  99. KEVENT Event;
  100. NTSTATUS Status = STATUS_SUCCESS;
  101. //
  102. // Initialize the event structure.
  103. //
  104. INITIALIZE_EVENT(&Event);
  105. //
  106. // Set the completion routine so that we can process the IRP when
  107. // our PDO is done.
  108. //
  109. IoSetCompletionRoutine(pIrp,
  110. (PIO_COMPLETION_ROUTINE)ndisMIrpCompletion,
  111. &Event,
  112. TRUE,
  113. TRUE,
  114. TRUE);
  115. //
  116. // Pass the IRP down to the PDO.
  117. //
  118. Status = IoCallDriver(pNextDeviceObject, pIrp);
  119. if (Status == STATUS_PENDING)
  120. {
  121. //
  122. // Wait for completion.
  123. //
  124. WAIT_FOR_OBJECT(&Event, NULL);
  125. Status = pIrp->IoStatus.Status;
  126. }
  127. return(Status);
  128. }
  129. NDIS_STATUS
  130. ndisPnPNotifyAllTransports(
  131. IN PNDIS_MINIPORT_BLOCK Miniport,
  132. IN NET_PNP_EVENT_CODE PnpEvent,
  133. IN PVOID Buffer,
  134. IN ULONG BufferLength
  135. )
  136. /*++
  137. Routine Description:
  138. This routine will notify the transports bound to the miniport about
  139. the PnP event. When all of the bound transports have completed the
  140. PnP event it will then call the completion routine.
  141. Arguments:
  142. Miniport - Pointer to the miniport block.
  143. PnpEvent - PnP event to notify the transports of.
  144. Return Value:
  145. --*/
  146. {
  147. PNDIS_OPEN_BLOCK Open = NULL;
  148. NET_PNP_EVENT NetPnpEvent;
  149. NDIS_STATUS NdisStatus = NDIS_STATUS_SUCCESS;
  150. KIRQL OldIrql;
  151. DBGPRINT_RAW(DBG_COMP_PNP, DBG_LEVEL_INFO,
  152. ("==>ndisPnPNotifyAllTransports: Miniport %p\n", Miniport));
  153. PnPReferencePackage();
  154. //
  155. // Initialize the PnP event structure.
  156. //
  157. NdisZeroMemory(&NetPnpEvent, sizeof(NetPnpEvent));
  158. NetPnpEvent.NetEvent = PnpEvent;
  159. NetPnpEvent.Buffer = Buffer;
  160. NetPnpEvent.BufferLength = BufferLength;
  161. //
  162. // Indicate this event to the opens.
  163. //
  164. do
  165. {
  166. Open = ndisReferenceNextUnprocessedOpen(Miniport);
  167. if (Open == NULL)
  168. break;
  169. NdisStatus = ndisPnPNotifyBinding(Open, &NetPnpEvent);
  170. //
  171. // Is the status OK?
  172. //
  173. if (NdisStatus != NDIS_STATUS_SUCCESS)
  174. {
  175. DBGPRINT_RAW(DBG_COMP_PNP, DBG_LEVEL_INFO,
  176. ("ndisPnPNotifyAllTransports: Transport "));
  177. DBGPRINT_UNICODE(DBG_COMP_INIT, DBG_LEVEL_INFO,
  178. &Open->ProtocolHandle->ProtocolCharacteristics.Name);
  179. DBGPRINT_RAW(DBG_COMP_INIT, DBG_LEVEL_INFO,
  180. (" failed the pnp event: %lx for Miniport %p with Status %lx\n", PnpEvent, Miniport, NdisStatus));
  181. if ((PnpEvent == NetEventQueryPower) ||
  182. (PnpEvent == NetEventQueryRemoveDevice) ||
  183. ((PnpEvent == NetEventSetPower) && (*((PDEVICE_POWER_STATE)Buffer) > PowerDeviceD0)))
  184. {
  185. break;
  186. }
  187. else
  188. {
  189. NdisStatus = NDIS_STATUS_SUCCESS;
  190. }
  191. }
  192. } while (TRUE);
  193. //
  194. // check for any open that we skipped because they were in the
  195. // process of being closed
  196. //
  197. next:
  198. NDIS_ACQUIRE_MINIPORT_SPIN_LOCK(Miniport, &OldIrql);
  199. for (Open = Miniport->OpenQueue;
  200. Open != NULL;
  201. Open = Open->MiniportNextOpen)
  202. {
  203. ACQUIRE_SPIN_LOCK_DPC(&Open->SpinLock);
  204. if (OPEN_TEST_FLAG(Open, (fMINIPORT_OPEN_CLOSING | fMINIPORT_OPEN_UNBINDING)))
  205. {
  206. RELEASE_SPIN_LOCK_DPC(&Open->SpinLock);
  207. break;
  208. }
  209. RELEASE_SPIN_LOCK_DPC(&Open->SpinLock);
  210. }
  211. NDIS_RELEASE_MINIPORT_SPIN_LOCK(Miniport, OldIrql);
  212. if (Open != NULL)
  213. {
  214. NdisMSleep(50000); // Sleep to yield the CPU to other worker threads
  215. goto next;
  216. }
  217. ndisUnprocessAllOpens(Miniport);
  218. PnPDereferencePackage();
  219. DBGPRINT_RAW(DBG_COMP_PNP, DBG_LEVEL_INFO,
  220. ("<==ndisPnPNotifyAllTransports: Miniport %p\n", Miniport));
  221. return(NdisStatus);
  222. }
  223. /*
  224. PNDIS_OPEN_BLOCK
  225. FASTCALL
  226. ndisReferenceNextUnprocessedOpen(
  227. IN PNDIS_MINIPORT_BLOCK Miniport
  228. )
  229. Routine Description:
  230. This routine is used during PnP notification to protocols. it walks through
  231. the Open queue on the miniport and finds the first Open that is not being unbound
  232. and it has not been already notified of the PnP even. it then sets the
  233. fMINIPORT_OPEN_PROCESSING flag so we do not try to unbind the open and
  234. fMINIPORT_OPEN_NOTIFY_PROCESSING flag so we know which opens to "unprocess"
  235. when we are done
  236. Arguments:
  237. Miniport: the Miniport block whose open blocks we are going to process.
  238. Return Value:
  239. the first unprocessed open or null.
  240. */
  241. PNDIS_OPEN_BLOCK
  242. FASTCALL
  243. ndisReferenceNextUnprocessedOpen(
  244. IN PNDIS_MINIPORT_BLOCK Miniport
  245. )
  246. {
  247. PNDIS_OPEN_BLOCK Open;
  248. KIRQL OldIrql;
  249. DBGPRINT_RAW(DBG_COMP_PNP, DBG_LEVEL_INFO,
  250. ("==>ndisReferenceNextUnprocessedOpen: Miniport %p\n", Miniport));
  251. NDIS_ACQUIRE_MINIPORT_SPIN_LOCK(Miniport, &OldIrql);
  252. for (Open = Miniport->OpenQueue;
  253. Open != NULL;
  254. Open = Open->MiniportNextOpen)
  255. {
  256. ACQUIRE_SPIN_LOCK_DPC(&Open->SpinLock);
  257. if (!OPEN_TEST_FLAG(Open, (fMINIPORT_OPEN_CLOSING |
  258. fMINIPORT_OPEN_PROCESSING |
  259. fMINIPORT_OPEN_UNBINDING)))
  260. {
  261. //
  262. // this will stop Ndis to Unbind this open for the time being
  263. //
  264. OPEN_SET_FLAG(Open, fMINIPORT_OPEN_PROCESSING |
  265. fMINIPORT_OPEN_NOTIFY_PROCESSING);
  266. RELEASE_SPIN_LOCK_DPC(&Open->SpinLock);
  267. break;
  268. }
  269. RELEASE_SPIN_LOCK_DPC(&Open->SpinLock);
  270. }
  271. NDIS_RELEASE_MINIPORT_SPIN_LOCK(Miniport, OldIrql);
  272. DBGPRINT_RAW(DBG_COMP_PNP, DBG_LEVEL_INFO,
  273. ("<==ndisReferenceNextUnprocessedOpen: Miniport %p\n", Miniport));
  274. return(Open);
  275. }
  276. /*
  277. VOID
  278. ndisUnprocessAllOpens(
  279. IN PNDIS_MINIPORT_BLOCK Miniport
  280. )
  281. Routine Description:
  282. Clears the fMINIPORT_OPEN_PROCESSING flag on all the open blocks that have been
  283. processed during a PnP Notification.
  284. Arguments:
  285. Miniport: the Miniport block whose open blocks we are going to unprocess.
  286. Return Value:
  287. None
  288. */
  289. VOID
  290. ndisUnprocessAllOpens(
  291. IN PNDIS_MINIPORT_BLOCK Miniport
  292. )
  293. {
  294. PNDIS_OPEN_BLOCK Open, NextOpen;
  295. KIRQL OldIrql;
  296. DBGPRINT_RAW(DBG_COMP_PNP, DBG_LEVEL_INFO,
  297. ("==>ndisUnprocessAllOpens: Miniport %p\n", Miniport));
  298. NDIS_ACQUIRE_MINIPORT_SPIN_LOCK(Miniport, &OldIrql);
  299. for (Open = Miniport->OpenQueue;
  300. Open != NULL;
  301. Open = NextOpen)
  302. {
  303. NextOpen = Open->MiniportNextOpen;
  304. ACQUIRE_SPIN_LOCK_DPC(&Open->SpinLock);
  305. if (OPEN_TEST_FLAGS(Open, fMINIPORT_OPEN_NOTIFY_PROCESSING |
  306. fMINIPORT_OPEN_PROCESSING))
  307. {
  308. OPEN_CLEAR_FLAG(Open, fMINIPORT_OPEN_PROCESSING |
  309. fMINIPORT_OPEN_NOTIFY_PROCESSING);
  310. }
  311. RELEASE_SPIN_LOCK_DPC(&Open->SpinLock);
  312. Open = NextOpen;
  313. }
  314. NDIS_RELEASE_MINIPORT_SPIN_LOCK(Miniport, OldIrql);
  315. DBGPRINT_RAW(DBG_COMP_PNP, DBG_LEVEL_INFO,
  316. ("<==ndisUnprocessAllOpens: Miniport %p\n", Miniport));
  317. }
  318. NDIS_STATUS
  319. FASTCALL
  320. ndisPnPNotifyBinding(
  321. IN PNDIS_OPEN_BLOCK Open,
  322. IN PNET_PNP_EVENT NetPnpEvent
  323. )
  324. {
  325. PNDIS_PROTOCOL_BLOCK Protocol;
  326. NDIS_HANDLE ProtocolBindingContext;
  327. KEVENT Event;
  328. NDIS_STATUS NdisStatus = NDIS_STATUS_NOT_SUPPORTED;
  329. PNDIS_PNP_EVENT_RESERVED EventReserved;
  330. DEVICE_POWER_STATE DeviceState;
  331. KIRQL OldIrql;
  332. DBGPRINT_RAW(DBG_COMP_PNP, DBG_LEVEL_INFO,
  333. ("==>ndisPnPNotifyBinding: Open %p\n", Open));
  334. do
  335. {
  336. Protocol = Open->ProtocolHandle;
  337. ProtocolBindingContext = Open->ProtocolBindingContext;
  338. //
  339. // Does the transport have a PnP Event handler?
  340. //
  341. if (Protocol->ProtocolCharacteristics.PnPEventHandler != NULL)
  342. {
  343. //
  344. // Get a pointer to the NDIS reserved in PnP event.
  345. //
  346. EventReserved = PNDIS_PNP_EVENT_RESERVED_FROM_NET_PNP_EVENT(NetPnpEvent);
  347. //
  348. // Initialize and save the local event with the PnP event.
  349. //
  350. INITIALIZE_EVENT(&Event);
  351. EventReserved->pEvent = &Event;
  352. //
  353. // Indicate the event to the protocol.
  354. //
  355. NdisStatus = (Protocol->ProtocolCharacteristics.PnPEventHandler)(
  356. ProtocolBindingContext,
  357. NetPnpEvent);
  358. if (NDIS_STATUS_PENDING == NdisStatus)
  359. {
  360. //
  361. // Wait for completion.
  362. //
  363. WAIT_FOR_PROTOCOL(Protocol, &Event);
  364. //
  365. // Get the completion status.
  366. //
  367. NdisStatus = EventReserved->Status;
  368. }
  369. if ((NetPnpEvent->NetEvent == NetEventQueryPower) &&
  370. (NDIS_STATUS_SUCCESS != NdisStatus) &&
  371. (NDIS_STATUS_NOT_SUPPORTED != NdisStatus))
  372. {
  373. DbgPrint("***NDIS***: Protocol %Z failed QueryPower %lx\n",
  374. &Protocol->ProtocolCharacteristics.Name, NdisStatus);
  375. }
  376. #if DBG
  377. if ((NetPnpEvent->NetEvent == NetEventSetPower) &&
  378. (*((PDEVICE_POWER_STATE)NetPnpEvent->Buffer) > PowerDeviceD0) &&
  379. (OPEN_TEST_FLAG(Open->MiniportHandle, fMINIPORT_RESET_IN_PROGRESS)) &&
  380. (Open->MiniportHandle->ResetOpen == Open))
  381. {
  382. DbgPrint("ndisPnPNotifyBinding: Protocol %p returned from SetPower with outstanding Reset.\n", Protocol);
  383. DbgBreakPoint();
  384. }
  385. #endif
  386. }
  387. else
  388. {
  389. if ((NetPnpEvent->NetEvent == NetEventQueryRemoveDevice) ||
  390. (NetPnpEvent->NetEvent == NetEventQueryPower) ||
  391. (NetPnpEvent->NetEvent == NetEventCancelRemoveDevice)
  392. )
  393. {
  394. //
  395. // since protocol at least has an UnbindHandler, we can unbind
  396. // it from the adapter if necessary
  397. //
  398. NdisStatus = NDIS_STATUS_SUCCESS;
  399. break;
  400. }
  401. }
  402. //
  403. // if the protocol does not have a PnPEventHandler or
  404. // we tried to suspend a protocol and protocol returned NDIS_STATUS_NOT_SUPPORTED,
  405. // unbind the protocol
  406. //
  407. if ((NdisStatus == NDIS_STATUS_NOT_SUPPORTED) &&
  408. (NetPnpEvent->NetEvent == NetEventSetPower))
  409. {
  410. DeviceState = *((PDEVICE_POWER_STATE)NetPnpEvent->Buffer);
  411. switch (DeviceState)
  412. {
  413. case PowerDeviceD1:
  414. case PowerDeviceD2:
  415. case PowerDeviceD3:
  416. ACQUIRE_SPIN_LOCK(&Open->SpinLock, &OldIrql);
  417. if (!OPEN_TEST_FLAG(Open, (fMINIPORT_OPEN_UNBINDING |
  418. fMINIPORT_OPEN_CLOSING)))
  419. {
  420. OPEN_SET_FLAG(Open, fMINIPORT_OPEN_UNBINDING |
  421. fMINIPORT_OPEN_DONT_FREE);
  422. RELEASE_SPIN_LOCK(&Open->SpinLock, OldIrql);
  423. ndisUnbindProtocol(Open, Protocol, Open->MiniportHandle, FALSE);
  424. }
  425. else
  426. {
  427. RELEASE_SPIN_LOCK(&Open->SpinLock, OldIrql);
  428. }
  429. NdisStatus = NDIS_STATUS_SUCCESS;
  430. break;
  431. default:
  432. break;
  433. }
  434. }
  435. } while (FALSE);
  436. DBGPRINT_RAW(DBG_COMP_PNP, DBG_LEVEL_INFO,
  437. ("<==ndisPnPNotifyBinding: Open %p\n", Open));
  438. return NdisStatus;
  439. }
  440. NTSTATUS
  441. ndisPnPDispatch(
  442. IN PDEVICE_OBJECT DeviceObject,
  443. IN PIRP Irp
  444. )
  445. /*++
  446. Routine Description:
  447. The handler for IRP_MJ_PNP_POWER.
  448. Arguments:
  449. DeviceObject - The adapter's functional device object.
  450. Irp - The IRP.
  451. Return Value:
  452. --*/
  453. {
  454. PIO_STACK_LOCATION IrpSp;
  455. NTSTATUS Status = STATUS_SUCCESS;
  456. PDEVICE_OBJECT NextDeviceObject = NULL;
  457. PNDIS_MINIPORT_BLOCK Miniport = NULL;
  458. KEVENT RemoveReadyEvent;
  459. ULONG PnPDeviceState;
  460. PNDIS_MINIPORT_BLOCK* ppMB;
  461. KIRQL OldIrql;
  462. BOOLEAN fSendIrpDown = TRUE;
  463. BOOLEAN fCompleteIrp = TRUE;
  464. DBGPRINT_RAW(DBG_COMP_PNP, DBG_LEVEL_INFO,
  465. ("==>ndisPnPDispatch: DeviceObject %p, Irp %p\n", DeviceObject, Irp));
  466. PnPReferencePackage();
  467. //
  468. // Get a pointer to the miniport block
  469. //
  470. Miniport = (PNDIS_MINIPORT_BLOCK)((PNDIS_WRAPPER_CONTEXT)DeviceObject->DeviceExtension + 1);
  471. ASSERT(Miniport->Signature == (PVOID)MINIPORT_DEVICE_MAGIC_VALUE);
  472. if (Miniport->Signature != (PVOID)MINIPORT_DEVICE_MAGIC_VALUE)
  473. {
  474. DBGPRINT_RAW(DBG_COMP_PNP, DBG_LEVEL_INFO,
  475. ("ndisPnPDispatch: DeviceObject %p, Irp %p, Device extension is not a miniport.\n",
  476. DeviceObject, Irp));
  477. Status = STATUS_INVALID_DEVICE_REQUEST;
  478. fSendIrpDown = FALSE;
  479. goto Done;
  480. }
  481. //
  482. // Get a pointer to the next miniport.
  483. //
  484. NextDeviceObject = Miniport->NextDeviceObject;
  485. IrpSp = IoGetCurrentIrpStackLocation (Irp);
  486. DBGPRINT_RAW(DBG_COMP_PNP, DBG_LEVEL_INFO,
  487. ("ndisPnPDispatch: Miniport %p, IrpSp->MinorFunction: %lx\n", Miniport, IrpSp->MinorFunction));
  488. switch(IrpSp->MinorFunction)
  489. {
  490. //
  491. // for Memphis the following IRPs are handled by handling the corresponding
  492. // Config Manager message:
  493. //
  494. // IRP_MN_START_DEVICE CONFIG_START
  495. // IRP_MN_QUERY_REMOVE_DEVICE CONFIG_TEST/CONFIG_TEST_CAN_REMOVE
  496. // IRP_MN_CANCEL_REMOVE_DEVICE CONFIG_TEST_FAILED/CONFIG_TEST_CAN_REMOVE
  497. // IRP_MN_REMOVE_DEVICE CONFIG_REMOVE
  498. // IRP_MN_QUERY_STOP_DEVICE CONFIG_TEST/CONFIG_TEST_CAN_STOP
  499. // IRP_MN_CANCEL_STOP_DEVICE CONFIG_TEST_FAILED/CONFIG_TEST_CAN_STOP
  500. // IRP_MN_STOP_DEVICE CONFIG_STOP
  501. // IRP_MN_SURPRISE_REMOVAL
  502. //
  503. case IRP_MN_START_DEVICE:
  504. DBGPRINT_RAW(DBG_COMP_PNP, DBG_LEVEL_INFO,
  505. ("ndisPnPDispatch: Miniport %p, IRP_MN_START_DEVICE\n", Miniport));
  506. MINIPORT_PNP_CLEAR_FLAG(Miniport, fMINIPORT_REMOVE_IN_PROGRESS);
  507. MINIPORT_PNP_SET_FLAG(Miniport, fMINIPORT_RECEIVED_START);
  508. IoCopyCurrentIrpStackLocationToNext(Irp);
  509. Status = ndisPassIrpDownTheStack(Irp, NextDeviceObject);
  510. //
  511. // If the bus driver succeeded the start irp then proceed.
  512. //
  513. if (NT_SUCCESS(Status))
  514. {
  515. if (Miniport->DriverHandle->Flags & fMINIBLOCK_INTERMEDIATE_DRIVER)
  516. {
  517. NDIS_HANDLE DeviceContext;
  518. //
  519. // for layered miniport drivers, have to check to see
  520. // if we got InitializeDeviceInstance
  521. //
  522. MINIPORT_SET_FLAG(Miniport, fMINIPORT_INTERMEDIATE_DRIVER);
  523. if (ndisIMCheckDeviceInstance(Miniport->DriverHandle,
  524. &Miniport->MiniportName,
  525. &DeviceContext))
  526. {
  527. WAIT_FOR_OBJECT(&Miniport->DriverHandle->IMStartRemoveMutex, NULL);
  528. Status = ndisIMInitializeDeviceInstance(Miniport, DeviceContext, TRUE);
  529. RELEASE_MUTEX(&Miniport->DriverHandle->IMStartRemoveMutex);
  530. }
  531. }
  532. else
  533. {
  534. Status = ndisPnPStartDevice(DeviceObject, Irp);
  535. if (Status == NDIS_STATUS_SUCCESS)
  536. {
  537. if (MINIPORT_TEST_FLAG(Miniport, fMINIPORT_IS_CO) &&
  538. !ndisMediaTypeCl[Miniport->MediaType] &&
  539. (Miniport->MediaType != NdisMediumWan))
  540. {
  541. UNICODE_STRING NDProxy;
  542. RtlInitUnicodeString(&NDProxy, NDIS_PROXY_SERVICE);
  543. ZwLoadDriver(&NDProxy);
  544. }
  545. if (ndisProtocolList != NULL)
  546. {
  547. ndisQueueBindWorkitem(Miniport);
  548. }
  549. }
  550. else
  551. {
  552. Status = STATUS_UNSUCCESSFUL;
  553. }
  554. }
  555. }
  556. Irp->IoStatus.Status = Status;
  557. fSendIrpDown = FALSE; // we already did send the IRP down
  558. break;
  559. case IRP_MN_QUERY_REMOVE_DEVICE:
  560. DBGPRINT_RAW(DBG_COMP_PNP, DBG_LEVEL_INFO,
  561. ("ndisPnPDispatch: Miniport %p, IRP_MN_QUERY_REMOVE_DEVICE\n", Miniport));
  562. Miniport->OldPnPDeviceState = Miniport->PnPDeviceState;
  563. Miniport->PnPDeviceState = NdisPnPDeviceQueryRemoved;
  564. Status = ndisPnPQueryRemoveDevice(DeviceObject, Irp);
  565. Irp->IoStatus.Status = Status;
  566. //
  567. // if we failed query_remove, no point sending this irp down
  568. //
  569. fSendIrpDown = NT_SUCCESS(Status) ? TRUE : FALSE;
  570. break;
  571. case IRP_MN_CANCEL_REMOVE_DEVICE:
  572. DBGPRINT_RAW(DBG_COMP_PNP, DBG_LEVEL_INFO,
  573. ("ndisPnPDispatch: Miniport %p, IRP_MN_CANCEL_REMOVE_DEVICE\n", Miniport));
  574. Status = ndisPnPCancelRemoveDevice(DeviceObject,Irp);
  575. if (NT_SUCCESS(Status))
  576. {
  577. Miniport->PnPDeviceState = Miniport->OldPnPDeviceState;
  578. }
  579. Irp->IoStatus.Status = Status;
  580. fSendIrpDown = NT_SUCCESS(Status) ? TRUE : FALSE;
  581. break;
  582. case IRP_MN_REMOVE_DEVICE:
  583. DBGPRINT_RAW(DBG_COMP_PNP, DBG_LEVEL_INFO,
  584. ("ndisPnPDispatch: Miniport %p, IRP_MN_REMOVE_DEVICE\n", Miniport));
  585. ASSERT(KeGetCurrentIrql() == PASSIVE_LEVEL);
  586. PnPDeviceState = Miniport->PnPDeviceState;
  587. if (PnPDeviceState != NdisPnPDeviceSurpriseRemoved)
  588. {
  589. Miniport->PnPDeviceState = NdisPnPDeviceRemoved;
  590. MINIPORT_PNP_SET_FLAG(Miniport, fMINIPORT_REMOVE_IN_PROGRESS);
  591. MINIPORT_PNP_CLEAR_FLAG(Miniport, fMINIPORT_RECEIVED_START);
  592. //
  593. // initialize an event and signal when all the wotrkitems have fired.
  594. //
  595. if (MINIPORT_INCREMENT_REF(Miniport))
  596. {
  597. INITIALIZE_EVENT(&RemoveReadyEvent);
  598. Miniport->RemoveReadyEvent = &RemoveReadyEvent;
  599. }
  600. else
  601. {
  602. Miniport->RemoveReadyEvent = NULL;
  603. }
  604. Status = ndisPnPRemoveDevice(DeviceObject, Irp);
  605. if (Miniport->RemoveReadyEvent != NULL)
  606. {
  607. MINIPORT_DECREMENT_REF(Miniport);
  608. WAIT_FOR_OBJECT(&RemoveReadyEvent, NULL);
  609. }
  610. ASSERT(Miniport->Ref.ReferenceCount == 0);
  611. Irp->IoStatus.Status = Status;
  612. }
  613. else
  614. {
  615. Irp->IoStatus.Status = STATUS_SUCCESS;
  616. }
  617. //
  618. // when we are done, send the Irp down here
  619. // we have some post-processing to do
  620. //
  621. IoSkipCurrentIrpStackLocation(Irp);
  622. Status = IoCallDriver(NextDeviceObject, Irp);
  623. if (Miniport->pAdapterInstanceName != NULL)
  624. {
  625. FREE_POOL(Miniport->pAdapterInstanceName);
  626. Miniport->pAdapterInstanceName = NULL;
  627. }
  628. if (Miniport->SecurityDescriptor)
  629. {
  630. FREE_POOL(Miniport->SecurityDescriptor);
  631. Miniport->SecurityDescriptor = NULL;
  632. }
  633. //
  634. // remove miniport from global miniport list
  635. //
  636. ACQUIRE_SPIN_LOCK(&ndisMiniportListLock, &OldIrql);
  637. for (ppMB = &ndisMiniportList; *ppMB != NULL; ppMB = &(*ppMB)->NextGlobalMiniport)
  638. {
  639. if (*ppMB == Miniport)
  640. {
  641. *ppMB = Miniport->NextGlobalMiniport;
  642. break;
  643. }
  644. }
  645. RELEASE_SPIN_LOCK(&ndisMiniportListLock, OldIrql);
  646. if (Miniport->BindPaths != NULL)
  647. {
  648. FREE_POOL(Miniport->BindPaths);
  649. }
  650. if (Miniport->BusInterface != NULL)
  651. {
  652. FREE_POOL(Miniport->BusInterface);
  653. }
  654. ASSERT(Miniport->SystemAdapterObject == NULL);
  655. IoDetachDevice(Miniport->NextDeviceObject);
  656. IoDeleteDevice(Miniport->DeviceObject);
  657. fSendIrpDown = FALSE;
  658. fCompleteIrp = FALSE;
  659. break;
  660. case IRP_MN_SURPRISE_REMOVAL:
  661. DBGPRINT_RAW(DBG_COMP_PNP, DBG_LEVEL_INFO,
  662. ("ndisPnPDispatch: Miniport %p, IRP_MN_SURPRISE_REMOVAL\n", Miniport));
  663. ASSERT(KeGetCurrentIrql() == PASSIVE_LEVEL);
  664. //
  665. // let the miniport know the hardware is gone asap
  666. //
  667. if (ndisIsMiniportStarted(Miniport) &&
  668. (Miniport->PnPDeviceState == NdisPnPDeviceStarted) &&
  669. (!MINIPORT_PNP_TEST_FLAG(Miniport, fMINIPORT_PM_HALTED)) &&
  670. (Miniport->DriverHandle->MiniportCharacteristics.PnPEventNotifyHandler != NULL))
  671. {
  672. Miniport->DriverHandle->MiniportCharacteristics.PnPEventNotifyHandler(Miniport->MiniportAdapterContext,
  673. NdisDevicePnPEventSurpriseRemoved,
  674. NULL,
  675. 0);
  676. }
  677. Miniport->PnPDeviceState = NdisPnPDeviceSurpriseRemoved;
  678. MINIPORT_PNP_SET_FLAG(Miniport, fMINIPORT_REMOVE_IN_PROGRESS);
  679. MINIPORT_PNP_CLEAR_FLAG(Miniport, fMINIPORT_RECEIVED_START);
  680. //
  681. // initialize an event and signal when all the wotrkitems have fired.
  682. //
  683. if (MINIPORT_INCREMENT_REF(Miniport))
  684. {
  685. INITIALIZE_EVENT(&RemoveReadyEvent);
  686. Miniport->RemoveReadyEvent = &RemoveReadyEvent;
  687. }
  688. else
  689. {
  690. Miniport->RemoveReadyEvent = NULL;
  691. }
  692. Status = ndisPnPRemoveDevice(DeviceObject, Irp);
  693. if (Miniport->RemoveReadyEvent != NULL)
  694. {
  695. MINIPORT_DECREMENT_REF(Miniport);
  696. WAIT_FOR_OBJECT(&RemoveReadyEvent, NULL);
  697. }
  698. ASSERT(Miniport->Ref.ReferenceCount == 0);
  699. Irp->IoStatus.Status = Status;
  700. //
  701. // when we are done, send the Irp down here
  702. // we have some post-processing to do
  703. //
  704. IoSkipCurrentIrpStackLocation(Irp);
  705. Status = IoCallDriver(NextDeviceObject, Irp);
  706. fSendIrpDown = FALSE;
  707. fCompleteIrp = FALSE;
  708. break;
  709. case IRP_MN_QUERY_STOP_DEVICE:
  710. DBGPRINT_RAW(DBG_COMP_PNP, DBG_LEVEL_INFO,
  711. ("ndisPnPDispatch: Miniport %p, IRP_MN_QUERY_STOP_DEVICE\n", Miniport));
  712. Miniport->OldPnPDeviceState = Miniport->PnPDeviceState;
  713. Miniport->PnPDeviceState = NdisPnPDeviceQueryStopped;
  714. Status = ndisPnPQueryStopDevice(DeviceObject, Irp);
  715. Irp->IoStatus.Status = Status;
  716. fSendIrpDown = NT_SUCCESS(Status) ? TRUE : FALSE;
  717. break;
  718. case IRP_MN_CANCEL_STOP_DEVICE:
  719. DBGPRINT_RAW(DBG_COMP_PNP, DBG_LEVEL_INFO,
  720. ("ndisPnPDispatch: Adapter %p, IRP_MN_CANCEL_STOP_DEVICE\n", Miniport));
  721. Status = ndisPnPCancelStopDevice(DeviceObject,Irp);
  722. if (NT_SUCCESS(Status))
  723. {
  724. Miniport->PnPDeviceState = Miniport->OldPnPDeviceState;
  725. }
  726. Irp->IoStatus.Status = Status;
  727. fSendIrpDown = NT_SUCCESS(Status) ? TRUE : FALSE;
  728. break;
  729. case IRP_MN_STOP_DEVICE:
  730. DBGPRINT_RAW(DBG_COMP_PNP, DBG_LEVEL_INFO,
  731. ("ndisPnPDispatch: Miniport %p, IRP_MN_STOP_DEVICE\n", Miniport));
  732. Miniport->PnPDeviceState = NdisPnPDeviceStopped;
  733. MINIPORT_PNP_CLEAR_FLAG(Miniport, fMINIPORT_RECEIVED_START);
  734. //
  735. // initialize an event and signal when
  736. // all the wotrkitems have fired.
  737. //
  738. if (MINIPORT_INCREMENT_REF(Miniport))
  739. {
  740. INITIALIZE_EVENT(&RemoveReadyEvent);
  741. Miniport->RemoveReadyEvent = &RemoveReadyEvent;
  742. Miniport->PnPDeviceState = NdisPnPDeviceStopped;
  743. MINIPORT_PNP_SET_FLAG(Miniport, fMINIPORT_REMOVE_IN_PROGRESS);
  744. }
  745. else
  746. {
  747. Miniport->RemoveReadyEvent = NULL;
  748. }
  749. Status = ndisPnPStopDevice(DeviceObject, Irp);
  750. if (Miniport->RemoveReadyEvent != NULL)
  751. {
  752. MINIPORT_DECREMENT_REF(Miniport);
  753. WAIT_FOR_OBJECT(&RemoveReadyEvent, NULL);
  754. }
  755. ASSERT(Miniport->Ref.ReferenceCount == 0);
  756. Irp->IoStatus.Status = Status;
  757. fSendIrpDown = NT_SUCCESS(Status) ? TRUE : FALSE;
  758. break;
  759. case IRP_MN_QUERY_CAPABILITIES:
  760. DBGPRINT_RAW(DBG_COMP_PNP, DBG_LEVEL_INFO,
  761. ("ndisPnPDispatch: Miniport, IRP_MN_QUERY_CAPABILITIES\n", Miniport));
  762. if (MINIPORT_PNP_TEST_FLAG(Miniport, fMINIPORT_SWENUM) ||
  763. (Miniport->MiniportAttributes & NDIS_ATTRIBUTE_SURPRISE_REMOVE_OK))
  764. {
  765. IrpSp->Parameters.DeviceCapabilities.Capabilities->SurpriseRemovalOK = 1;
  766. }
  767. IoCopyCurrentIrpStackLocationToNext(Irp);
  768. Status = ndisPassIrpDownTheStack(Irp, NextDeviceObject);
  769. //
  770. // If the bus driver succeeded the start irp then proceed.
  771. //
  772. if (NT_SUCCESS(Status) &&
  773. !MINIPORT_PNP_TEST_FLAG(Miniport, fMINIPORT_SWENUM) &&
  774. !(Miniport->MiniportAttributes & NDIS_ATTRIBUTE_SURPRISE_REMOVE_OK))
  775. {
  776. DBGPRINT_RAW(DBG_COMP_PNP, DBG_LEVEL_INFO,
  777. ("ndisPnPDispatch: Miniport %p, Clearing the SupriseRemovalOk bit.\n", Miniport));
  778. //
  779. // Modify the capabilities so that the device is not suprise removable.
  780. //
  781. IrpSp->Parameters.DeviceCapabilities.Capabilities->SurpriseRemovalOK = 0;
  782. }
  783. fSendIrpDown = FALSE;
  784. break;
  785. case IRP_MN_QUERY_PNP_DEVICE_STATE:
  786. if (MINIPORT_PNP_TEST_FLAG(Miniport, fMINIPORT_HIDDEN))
  787. {
  788. Irp->IoStatus.Information |= PNP_DEVICE_DONT_DISPLAY_IN_UI;
  789. }
  790. //
  791. // Check to see if a power up failed.
  792. //
  793. if (MINIPORT_PNP_TEST_FLAG(Miniport, fMINIPORT_DEVICE_FAILED))
  794. {
  795. DBGPRINT_RAW(DBG_COMP_PNP, DBG_LEVEL_ERR,
  796. ("ndisPnPDispatch: Miniport %p, IRP_MN_QUERY_PNP_DEVICE_STATE device failed\n", Miniport));
  797. //
  798. // Mark the device as having failed so that pnp will remove it.
  799. //
  800. Irp->IoStatus.Information |= PNP_DEVICE_FAILED;
  801. }
  802. Irp->IoStatus.Status = Status;
  803. fSendIrpDown = TRUE ;
  804. break;
  805. case IRP_MN_QUERY_DEVICE_RELATIONS:
  806. case IRP_MN_QUERY_INTERFACE:
  807. case IRP_MN_QUERY_RESOURCES:
  808. case IRP_MN_QUERY_RESOURCE_REQUIREMENTS:
  809. case IRP_MN_READ_CONFIG:
  810. case IRP_MN_WRITE_CONFIG:
  811. case IRP_MN_EJECT:
  812. case IRP_MN_SET_LOCK:
  813. case IRP_MN_QUERY_ID:
  814. default:
  815. DBGPRINT_RAW(DBG_COMP_PNP, DBG_LEVEL_INFO,
  816. ("ndisPnPDispatch: Miniport %p, MinorFunction 0x%x\n", Miniport, IrpSp->MinorFunction));
  817. //
  818. // We don't handle the irp so pass it down.
  819. //
  820. fSendIrpDown = TRUE;
  821. break;
  822. }
  823. Done:
  824. //
  825. // First check to see if we need to send the irp down.
  826. // If we don't pass the irp on then check to see if we need to complete it.
  827. //
  828. if (fSendIrpDown && NextDeviceObject)
  829. {
  830. IoSkipCurrentIrpStackLocation(Irp);
  831. Status = IoCallDriver(NextDeviceObject, Irp);
  832. }
  833. else if (fCompleteIrp)
  834. {
  835. Irp->IoStatus.Status = Status;
  836. IoCompleteRequest(Irp, IO_NO_INCREMENT);
  837. }
  838. PnPDereferencePackage();
  839. DBGPRINT_RAW(DBG_COMP_PNP, DBG_LEVEL_INFO,
  840. ("<==ndisPnPDispatch: Miniport %p\n", Miniport));
  841. return(Status);
  842. }
  843. NDIS_STATUS
  844. NdisIMNotifyPnPEvent(
  845. IN NDIS_HANDLE MiniportAdapterHandle,
  846. IN PNET_PNP_EVENT NetPnPEvent
  847. )
  848. {
  849. PNDIS_MINIPORT_BLOCK Miniport = (PNDIS_MINIPORT_BLOCK)MiniportAdapterHandle;
  850. NET_PNP_EVENT_CODE NetEvent = NetPnPEvent->NetEvent;
  851. NDIS_STATUS Status = NDIS_STATUS_SUCCESS;
  852. DBGPRINT_RAW(DBG_COMP_PNP, DBG_LEVEL_INFO,
  853. ("==>NdisIMNotifyPnPEvent: Miniport %p, NetEvent %lx\n", Miniport, NetEvent));
  854. switch (NetEvent)
  855. {
  856. case NetEventQueryPower:
  857. case NetEventQueryRemoveDevice:
  858. case NetEventCancelRemoveDevice:
  859. case NetEventPnPCapabilities:
  860. //
  861. // indicate up to the protocols
  862. //
  863. Status = ndisPnPNotifyAllTransports(
  864. Miniport,
  865. NetPnPEvent->NetEvent,
  866. NetPnPEvent->Buffer,
  867. NetPnPEvent->BufferLength);
  868. break;
  869. case NetEventSetPower:
  870. case NetEventReconfigure:
  871. case NetEventBindList:
  872. case NetEventBindsComplete:
  873. default:
  874. //
  875. // ignore
  876. //
  877. break;
  878. }
  879. DBGPRINT_RAW(DBG_COMP_PNP, DBG_LEVEL_INFO,
  880. ("<==NdisIMNotifyPnPEvent: Miniport %p, NetEvent %lx, Status %lx\n", Miniport, NetEvent, Status));
  881. return (Status);
  882. }