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.

583 lines
18 KiB

  1. /*++
  2. Copyright (c) 2000 Microsoft Corporation
  3. Module Name:
  4. pnp.c
  5. Abstract: This module contains code to handle PnP and Power IRPs.
  6. Environment:
  7. Kernel mode
  8. Author:
  9. Michael Tsang (MikeTs) 13-Apr-2000
  10. Revision History:
  11. --*/
  12. #include "pch.h"
  13. #ifdef ALLOC_PRAGMA
  14. #pragma alloc_text(PAGE, HbutPnp)
  15. #pragma alloc_text(PAGE, HbutPower)
  16. #pragma alloc_text(PAGE, StartDevice)
  17. #pragma alloc_text(PAGE, RemoveDevice)
  18. #pragma alloc_text(PAGE, SendSyncIrp)
  19. #endif
  20. /*****************************************************************************
  21. *
  22. * @doc EXTERNAL
  23. *
  24. * @func NTSTATUS | HbutPnp |
  25. * Plug and Play dispatch routine for this driver.
  26. *
  27. * @parm IN PDEVICE_OBJECT | DevObj | Pointer to the device object.
  28. * @parm IN PIRP | Irp | Pointer to an I/O request packet.
  29. *
  30. * @rvalue SUCCESS | returns STATUS_SUCCESS
  31. * @rvalue FAILURE | returns NT status code
  32. *
  33. *****************************************************************************/
  34. NTSTATUS EXTERNAL
  35. HbutPnp(
  36. IN PDEVICE_OBJECT DevObj,
  37. IN PIRP Irp
  38. )
  39. {
  40. PROCNAME("HbutPnp")
  41. NTSTATUS status;
  42. PIO_STACK_LOCATION irpsp;
  43. PDEVICE_EXTENSION devext;
  44. PAGED_CODE();
  45. irpsp = IoGetCurrentIrpStackLocation(Irp);
  46. ENTER(1, ("(DevObj=%p,Irp=%p,IrpSp=%p,Minor=%s)\n",
  47. DevObj, Irp, irpsp,
  48. LookupName(irpsp->MinorFunction, PnPMinorFnNames)));
  49. devext = GET_MINIDRIVER_DEVICE_EXTENSION(DevObj);
  50. status = IoAcquireRemoveLock(&devext->RemoveLock, Irp);
  51. if (!NT_SUCCESS(status))
  52. {
  53. //
  54. // Someone sent us another plug and play IRP after removed
  55. //
  56. ERRPRINT(("received PnP IRP after device was removed\n"));
  57. Irp->IoStatus.Information = 0;
  58. Irp->IoStatus.Status = status;
  59. IoCompleteRequest(Irp, IO_NO_INCREMENT);
  60. }
  61. else
  62. {
  63. BOOLEAN fSkipIt = FALSE;
  64. switch (irpsp->MinorFunction)
  65. {
  66. case IRP_MN_START_DEVICE:
  67. ASSERT(!(devext->dwfHBut & HBUTF_DEVICE_STARTED));
  68. //
  69. // Forward the IRP down the stack
  70. //
  71. status = SendSyncIrp(GET_NEXT_DEVICE_OBJECT(DevObj), Irp, TRUE);
  72. if (NT_SUCCESS(status))
  73. {
  74. status = StartDevice(DevObj, Irp);
  75. if (NT_SUCCESS(status))
  76. {
  77. devext->dwfHBut |= HBUTF_DEVICE_STARTED;
  78. }
  79. }
  80. else
  81. {
  82. ERRPRINT(("failed to forward start IRP (status=%x)\n",
  83. status));
  84. }
  85. Irp->IoStatus.Information = 0;
  86. Irp->IoStatus.Status = status;
  87. IoCompleteRequest(Irp, IO_NO_INCREMENT);
  88. break;
  89. case IRP_MN_STOP_DEVICE:
  90. //
  91. // After the start IRP has been sent to the lower driver
  92. // object, the bus may NOT send any more IRPS down ``touch''
  93. // until another START has occured. Whatever access is
  94. // required must be done before Irp passed on.
  95. //
  96. if (devext->dwfHBut & HBUTF_DEVICE_STARTED)
  97. {
  98. devext->dwfHBut &= ~HBUTF_DEVICE_STARTED;
  99. if (devext->dwfHBut & HBUTF_INTERRUPT_CONNECTED)
  100. {
  101. IoDisconnectInterrupt(devext->InterruptObject);
  102. devext->dwfHBut &= ~HBUTF_INTERRUPT_CONNECTED;
  103. }
  104. }
  105. //
  106. // We don't need a completion routine so fire and forget.
  107. // Set the current stack location to the next stack location and
  108. // call the next device object.
  109. //
  110. fSkipIt = TRUE;
  111. Irp->IoStatus.Status = STATUS_SUCCESS;
  112. break;
  113. case IRP_MN_REMOVE_DEVICE:
  114. case IRP_MN_SURPRISE_REMOVAL:
  115. //
  116. // The PlugPlay system has detected the removal of this device.
  117. // We have no choice but to detach and delete the device object.
  118. // (If we wanted to express an interest in preventing this
  119. // removal, we should have filtered the query remove and query
  120. // stop routines.)
  121. // Note: we might receive a remove WITHOUT first receiving a
  122. // stop.
  123. //
  124. //
  125. // Make sure we do not allow more IRPs to start touching the
  126. // device.
  127. //
  128. devext->dwfHBut &= ~HBUTF_DEVICE_STARTED;
  129. devext->dwfHBut |= HBUTF_DEVICE_REMOVED;
  130. RemoveDevice(DevObj, Irp);
  131. //
  132. // Send on the remove IRP
  133. //
  134. fSkipIt = TRUE;
  135. Irp->IoStatus.Status = STATUS_SUCCESS;
  136. break;
  137. case IRP_MN_QUERY_CAPABILITIES:
  138. status = SendSyncIrp(GET_NEXT_DEVICE_OBJECT(DevObj), Irp, TRUE);
  139. if (NT_SUCCESS(status))
  140. {
  141. PDEVICE_CAPABILITIES devcaps;
  142. devcaps = irpsp->Parameters.DeviceCapabilities.Capabilities;
  143. if (devcaps != NULL)
  144. {
  145. SYSTEM_POWER_STATE i;
  146. //
  147. // This device is built-in to the system, so it should
  148. // be impossible to surprise remove this device, but
  149. // we will handle it anyway.
  150. //
  151. devcaps->SurpriseRemovalOK = TRUE;
  152. //
  153. // While the underlying serial bus might be able to
  154. // wake the machine from low power (via wake on ring),
  155. // the tablet cannot.
  156. //
  157. devcaps->SystemWake = PowerSystemUnspecified;
  158. devcaps->DeviceWake = PowerDeviceUnspecified;
  159. devcaps->WakeFromD0 =
  160. devcaps->WakeFromD1 =
  161. devcaps->WakeFromD2 =
  162. devcaps->WakeFromD3 = FALSE;
  163. devcaps->DeviceState[PowerSystemWorking] =
  164. PowerDeviceD0;
  165. for (i = PowerSystemSleeping1;
  166. i < PowerSystemMaximum;
  167. i++)
  168. {
  169. devcaps->DeviceState[i] = PowerDeviceD3;
  170. }
  171. }
  172. }
  173. IoCompleteRequest(Irp, IO_NO_INCREMENT);
  174. break;
  175. default:
  176. fSkipIt = TRUE;
  177. break;
  178. }
  179. if (fSkipIt)
  180. {
  181. IoSkipCurrentIrpStackLocation(Irp);
  182. ENTER(2, (".IoCallDriver(DevObj=%p,Irp=%p)\n",
  183. GET_NEXT_DEVICE_OBJECT(DevObj), Irp));
  184. status = IoCallDriver(GET_NEXT_DEVICE_OBJECT(DevObj), Irp);
  185. EXIT(2, (".IoCallDriver=%x\n", status));
  186. }
  187. if (irpsp->MinorFunction == IRP_MN_REMOVE_DEVICE)
  188. {
  189. //
  190. // Wait for the remove lock to free.
  191. //
  192. IoReleaseRemoveLockAndWait(&devext->RemoveLock, Irp);
  193. }
  194. else
  195. {
  196. IoReleaseRemoveLock(&devext->RemoveLock, Irp);
  197. }
  198. }
  199. EXIT(1, ("=%x\n", status));
  200. return status;
  201. } //HbutPnp
  202. /*****************************************************************************
  203. *
  204. * @doc EXTERNAL
  205. *
  206. * @func NTSTATUS | HbutPower | The power dispatch routine for this driver.
  207. *
  208. * @parm IN PDEVICE_OBJECT | DevObj | Points to the device object.
  209. * @parm IN PIRP | Irp | Points to an I/O request packet.
  210. *
  211. * @rvalue SUCCESS | returns STATUS_SUCCESS
  212. * @rvalue FAILURE | returns NT status code
  213. *
  214. *****************************************************************************/
  215. NTSTATUS EXTERNAL
  216. HbutPower(
  217. IN PDEVICE_OBJECT DevObj,
  218. IN PIRP Irp
  219. )
  220. {
  221. PROCNAME("HbutPower")
  222. NTSTATUS status;
  223. PDEVICE_EXTENSION devext;
  224. PAGED_CODE();
  225. ENTER(1, ("(DevObj=%p,Irp=%p,Minor=%s)\n",
  226. DevObj, Irp,
  227. LookupName(IoGetCurrentIrpStackLocation(Irp)->MinorFunction,
  228. PowerMinorFnNames)));
  229. devext = GET_MINIDRIVER_DEVICE_EXTENSION(DevObj);
  230. status = IoAcquireRemoveLock(&devext->RemoveLock, Irp);
  231. if (!NT_SUCCESS(status))
  232. {
  233. //
  234. // Someone sent us another power IRP after removed
  235. //
  236. ERRPRINT(("received Power IRP after device was removed\n"));
  237. Irp->IoStatus.Status = status;
  238. IoCompleteRequest(Irp, IO_NO_INCREMENT);
  239. }
  240. else
  241. {
  242. IoSkipCurrentIrpStackLocation(Irp);
  243. ENTER(2, (".PoCallDriver(DevObj=%p,Irp=%p)\n",
  244. GET_NEXT_DEVICE_OBJECT(DevObj), Irp));
  245. status = PoCallDriver(GET_NEXT_DEVICE_OBJECT(DevObj), Irp);
  246. EXIT(2, (".PoCallDriver=%x\n", status));
  247. IoReleaseRemoveLock(&devext->RemoveLock, Irp);
  248. }
  249. EXIT(1, ("=%x\n", status));
  250. return status;
  251. } //HbutPower
  252. /*****************************************************************************
  253. *
  254. * @doc INTERNAL
  255. *
  256. * @func NTSTATUS | StartDevice |
  257. * Get the device information and attempt to initialize a
  258. * configuration for a device. If we cannot identify this as a
  259. * valid HID device or configure the device, our start device
  260. * function is failed.
  261. *
  262. * @parm IN PDEVICE_OBJECT | DevObj | Points to the device object.
  263. * @parm IN PIRP | Irp | Points to an I/O request packet.
  264. *
  265. * @rvalue SUCCESS | returns STATUS_SUCCESS
  266. * @rvalue FAILURE | returns NT status code
  267. *
  268. *****************************************************************************/
  269. NTSTATUS INTERNAL
  270. StartDevice(
  271. IN PDEVICE_OBJECT DevObj,
  272. IN PIRP Irp
  273. )
  274. {
  275. PROCNAME("StartDevice")
  276. NTSTATUS status = STATUS_SUCCESS;
  277. PIO_STACK_LOCATION irpsp;
  278. PDEVICE_EXTENSION devext;
  279. PAGED_CODE();
  280. ENTER(2, ("(DevObj=%p,Irp=%p)\n", DevObj, Irp));
  281. irpsp = IoGetCurrentIrpStackLocation(Irp);
  282. devext = GET_MINIDRIVER_DEVICE_EXTENSION(DevObj);
  283. if (irpsp->Parameters.StartDevice.AllocatedResourcesTranslated == NULL)
  284. {
  285. ERRPRINT(("no resources is allocated to the button device!\n"));
  286. status = STATUS_INSUFFICIENT_RESOURCES;
  287. }
  288. else
  289. {
  290. ULONG Count;
  291. PCM_PARTIAL_RESOURCE_DESCRIPTOR pDesc;
  292. Count = 0;
  293. pDesc = RtlUnpackPartialDesc(
  294. CmResourceTypePort,
  295. irpsp->Parameters.StartDevice.AllocatedResourcesTranslated,
  296. &Count);
  297. if (pDesc == NULL)
  298. {
  299. ERRPRINT(("no allocated port resources!\n"));
  300. status = STATUS_INSUFFICIENT_RESOURCES;
  301. }
  302. else
  303. {
  304. devext->IORes = *pDesc;
  305. Count = 0;
  306. pDesc = RtlUnpackPartialDesc(
  307. CmResourceTypeInterrupt,
  308. irpsp->Parameters.StartDevice.AllocatedResourcesTranslated,
  309. &Count);
  310. if (pDesc == NULL)
  311. {
  312. ERRPRINT(("no allocated IRQ resources!\n"));
  313. status = STATUS_INSUFFICIENT_RESOURCES;
  314. }
  315. else
  316. {
  317. int i;
  318. UCHAR Buttons;
  319. ASSERT(!(devext->dwfHBut & HBUTF_INTERRUPT_CONNECTED));
  320. devext->IRQRes = *pDesc;
  321. //
  322. // To determine potential stuck buttons, read the buttons
  323. // up to 5 times for any button down bits without an interrupt.
  324. //
  325. for (i = 0; i < STUCK_DETECTION_RETRIES; ++i)
  326. {
  327. Buttons = READBUTTONSTATE(devext);
  328. if (!(Buttons & BUTTON_INTERRUPT_MASK))
  329. {
  330. devext->StuckButtonsMask |= Buttons &
  331. BUTTON_STATUS_MASK;
  332. }
  333. }
  334. devext->StuckButtonsMask = Buttons & BUTTON_STATUS_MASK;
  335. DBGPRINT(1, ("StuckButtonsMask=%x\n",
  336. devext->StuckButtonsMask));
  337. status = IoConnectInterrupt(
  338. &devext->InterruptObject,
  339. OemInterruptServiceRoutine,
  340. devext,
  341. NULL,
  342. devext->IRQRes.u.Interrupt.Vector,
  343. (KIRQL)devext->IRQRes.u.Interrupt.Level,
  344. (KIRQL)devext->IRQRes.u.Interrupt.Level,
  345. (devext->IRQRes.Flags & CM_RESOURCE_INTERRUPT_LATCHED)?
  346. Latched: LevelSensitive,
  347. devext->IRQRes.ShareDisposition == CmResourceShareShared,
  348. devext->IRQRes.u.Interrupt.Affinity,
  349. FALSE);
  350. if (NT_SUCCESS(status))
  351. {
  352. devext->dwfHBut |= HBUTF_INTERRUPT_CONNECTED;
  353. DBGPRINT(3, ("IO(Start=0x%x%x,Len=0x%x), IRQ(Level=%d,Vector=0x%x,Affinity=%d)\n",
  354. devext->IORes.u.Port.Start.HighPart,
  355. devext->IORes.u.Port.Start.LowPart,
  356. devext->IORes.u.Port.Length,
  357. devext->IRQRes.u.Interrupt.Level,
  358. devext->IRQRes.u.Interrupt.Vector,
  359. devext->IRQRes.u.Interrupt.Affinity));
  360. }
  361. }
  362. }
  363. }
  364. EXIT(2, ("=%x\n", status));
  365. return status;
  366. } //StartDevice
  367. /*****************************************************************************
  368. *
  369. * @doc INTERNAL
  370. *
  371. * @func VOID | RemoveDevice | FDO Remove routine
  372. *
  373. * @parm IN PDEVICE_OBJECT | DevObj | Points to the device object.
  374. * @parm IN PIRP | Irp | Points to an I/O request packet.
  375. *
  376. *****************************************************************************/
  377. VOID INTERNAL
  378. RemoveDevice(
  379. PDEVICE_OBJECT DevObj,
  380. PIRP Irp
  381. )
  382. {
  383. PROCNAME("RemoveDevice")
  384. PDEVICE_EXTENSION devext;
  385. PAGED_CODE();
  386. ENTER(2, ("(DevObj=%p,Irp=%p)\n", DevObj, Irp));
  387. devext = GET_MINIDRIVER_DEVICE_EXTENSION(DevObj);
  388. ASSERT(devext->dwfHBut & HBUTF_DEVICE_REMOVED);
  389. if (devext->dwfHBut & HBUTF_INTERRUPT_CONNECTED)
  390. {
  391. IoDisconnectInterrupt(devext->InterruptObject);
  392. devext->dwfHBut &= ~HBUTF_INTERRUPT_CONNECTED;
  393. }
  394. if (devext->dwfHBut & HBUTF_DEBOUNCE_TIMER_SET)
  395. {
  396. KeCancelTimer(&devext->DebounceTimer);
  397. }
  398. #ifdef DEBUG
  399. ExAcquireFastMutex(&gmutexDevExtList);
  400. RemoveEntryList(&devext->List);
  401. ExReleaseFastMutex (&gmutexDevExtList);
  402. #endif
  403. EXIT(2, ("!\n"));
  404. return;
  405. } //RemoveDevice
  406. /*****************************************************************************
  407. *
  408. * @doc INTERNAL
  409. *
  410. * @func NTSTATUS | SendSyncIrp |
  411. * Send an IRP synchronously down the stack.
  412. *
  413. * @parm IN PDEVICE_OBJECT | DevObj | Points to the device object.
  414. * @parm IN PIRP | Irp | Points to the IRP.
  415. * @parm IN BOOLEAN | fCopyToNext | if TRUE, copy the irpsp to next location.
  416. *
  417. * @rvalue SUCCESS | returns STATUS_SUCCESS
  418. * @rvalue FAILURE | returns NT status code
  419. *
  420. *****************************************************************************/
  421. NTSTATUS INTERNAL
  422. SendSyncIrp(
  423. IN PDEVICE_OBJECT DevObj,
  424. IN PIRP Irp,
  425. IN BOOLEAN fCopyToNext
  426. )
  427. {
  428. PROCNAME("SendSyncIrp")
  429. NTSTATUS status;
  430. PIO_STACK_LOCATION irpsp = IoGetCurrentIrpStackLocation(Irp);
  431. KEVENT event;
  432. PAGED_CODE();
  433. ENTER(2, ("(DevObj=%p,Irp=%p,fCopyToNext=%x,MajorFunc=%s)\n",
  434. DevObj, Irp, fCopyToNext,
  435. LookupName(irpsp->MajorFunction, MajorFnNames)));
  436. KeInitializeEvent(&event, SynchronizationEvent, FALSE);
  437. if (fCopyToNext)
  438. {
  439. IoCopyCurrentIrpStackLocationToNext(Irp);
  440. }
  441. IoSetCompletionRoutine(Irp, IrpCompletion, &event, TRUE, TRUE, TRUE);
  442. if (irpsp->MajorFunction == IRP_MJ_POWER)
  443. {
  444. ENTER(2, (".PoCallDriver(DevObj=%p,Irp=%p)\n", DevObj, Irp));
  445. status = PoCallDriver(DevObj, Irp);
  446. EXIT(2, (".IoCallDriver=%x\n", status));
  447. }
  448. else
  449. {
  450. ENTER(2, (".IoCallDriver(DevObj=%p,Irp=%p)\n", DevObj, Irp));
  451. status = IoCallDriver(DevObj, Irp);
  452. EXIT(2, (".IoCallDriver=%x\n", status));
  453. }
  454. if (status == STATUS_PENDING)
  455. {
  456. status = KeWaitForSingleObject(&event,
  457. Executive,
  458. KernelMode,
  459. FALSE,
  460. NULL);
  461. }
  462. if (NT_SUCCESS(status))
  463. {
  464. status = Irp->IoStatus.Status;
  465. }
  466. EXIT(2, ("=%x\n", status));
  467. return status;
  468. } //SendSyncIrp
  469. /*****************************************************************************
  470. *
  471. * @doc INTERNAL
  472. *
  473. * @func NTSTATUS | IrpCompletion | Completion routine for all IRPs.
  474. *
  475. * @parm IN PDEVICE_OBJECT | DevObj | Points to the device object.
  476. * @parm IN PIRP | Irp | Points to an I/O request packet.
  477. * @parm IN PKEVENT | Event | Points to the event to notify.
  478. *
  479. * @rvalue STATUS_MORE_PROCESSING_REQUIRED | We want the IRP back
  480. *
  481. *****************************************************************************/
  482. NTSTATUS INTERNAL
  483. IrpCompletion(
  484. IN PDEVICE_OBJECT DevObj,
  485. IN PIRP Irp,
  486. IN PKEVENT Event
  487. )
  488. {
  489. PROCNAME("IrpCompletion")
  490. ENTER(2, ("(DevObj=%p,Irp=%p,Event=%p)\n", DevObj, Irp, Event));
  491. UNREFERENCED_PARAMETER(DevObj);
  492. KeSetEvent(Event, 0, FALSE);
  493. /*
  494. * If the lower driver returned PENDING, mark our stack location as
  495. * pending also. This prevents the IRP's thread from being freed if
  496. * the client's call returns pending.
  497. */
  498. if (Irp->PendingReturned)
  499. {
  500. IoMarkIrpPending(Irp);
  501. }
  502. EXIT(2, ("=%x\n", STATUS_MORE_PROCESSING_REQUIRED));
  503. return STATUS_MORE_PROCESSING_REQUIRED;
  504. } //IrpCompletion