Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

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