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.

622 lines
20 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-Mar-2000
  10. Revision History:
  11. --*/
  12. #include "pch.h"
  13. #ifdef ALLOC_PRAGMA
  14. #pragma alloc_text(PAGE, HpenPnp)
  15. #pragma alloc_text(PAGE, HpenPower)
  16. #pragma alloc_text(PAGE, InitDevice)
  17. #pragma alloc_text(PAGE, RemoveDevice)
  18. #pragma alloc_text(PAGE, SendSyncIrp)
  19. #endif
  20. /*****************************************************************************
  21. *
  22. * @doc EXTERNAL
  23. *
  24. * @func NTSTATUS | HpenPnp |
  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. HpenPnp(
  36. IN PDEVICE_OBJECT DevObj,
  37. IN PIRP Irp
  38. )
  39. {
  40. PROCNAME("HpenPnp")
  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->dwfHPen & HPENF_DEVICE_STARTED));
  68. //
  69. // Forward the IRP down the stack
  70. //
  71. status = SendSyncIrp(devext->SerialDevObj, Irp, TRUE);
  72. if (NT_SUCCESS(status))
  73. {
  74. status = InitDevice(DevObj, Irp);
  75. if (NT_SUCCESS(status))
  76. {
  77. devext->dwfHPen |= HPENF_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->dwfHPen & HPENF_DEVICE_STARTED)
  97. {
  98. devext->dwfHPen &= ~HPENF_DEVICE_STARTED;
  99. //
  100. // I don't need to cancel any pending read IRPs since
  101. // those IRPs originated from hidclass and presumably
  102. // hidclass will cancel them.
  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->dwfHPen &= ~HPENF_DEVICE_STARTED;
  129. devext->dwfHPen |= HPENF_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. IoFreeWorkItem(devext->ReadWorkItem[0].WorkItem);
  194. IoFreeWorkItem(devext->ReadWorkItem[1].WorkItem);
  195. }
  196. else
  197. {
  198. IoReleaseRemoveLock(&devext->RemoveLock, Irp);
  199. }
  200. }
  201. EXIT(1, ("=%x\n", status));
  202. return status;
  203. } //HpenPnp
  204. /*****************************************************************************
  205. *
  206. * @doc EXTERNAL
  207. *
  208. * @func NTSTATUS | HpenPower | The power dispatch routine for this driver.
  209. *
  210. * @parm IN PDEVICE_OBJECT | DevObj | Points to the device object.
  211. * @parm IN PIRP | Irp | Points to an I/O request packet.
  212. *
  213. * @rvalue SUCCESS | returns STATUS_SUCCESS
  214. * @rvalue FAILURE | returns NT status code
  215. *
  216. *****************************************************************************/
  217. NTSTATUS EXTERNAL
  218. HpenPower(
  219. IN PDEVICE_OBJECT DevObj,
  220. IN PIRP Irp
  221. )
  222. {
  223. PROCNAME("HpenPower")
  224. NTSTATUS status;
  225. PDEVICE_EXTENSION devext;
  226. PAGED_CODE();
  227. ENTER(1, ("(DevObj=%p,Irp=%p,Minor=%s)\n",
  228. DevObj, Irp,
  229. LookupName(IoGetCurrentIrpStackLocation(Irp)->MinorFunction,
  230. PowerMinorFnNames)));
  231. devext = GET_MINIDRIVER_DEVICE_EXTENSION(DevObj);
  232. status = IoAcquireRemoveLock(&devext->RemoveLock, Irp);
  233. if (!NT_SUCCESS(status))
  234. {
  235. //
  236. // Someone sent us another power IRP after removed
  237. //
  238. ERRPRINT(("received Power IRP after device was removed\n"));
  239. Irp->IoStatus.Status = status;
  240. IoCompleteRequest(Irp, IO_NO_INCREMENT);
  241. }
  242. else
  243. {
  244. PIO_STACK_LOCATION irpsp = IoGetCurrentIrpStackLocation(Irp);
  245. POWER_STATE_TYPE PowerType = irpsp->Parameters.Power.Type;
  246. POWER_STATE NewPowerState = irpsp->Parameters.Power.State;
  247. BOOLEAN fSkipCalldown = FALSE;
  248. switch (irpsp->MinorFunction)
  249. {
  250. case IRP_MN_SET_POWER:
  251. //
  252. // We only handle DevicePowerState IRPs that change
  253. // power states.
  254. //
  255. if ((PowerType == DevicePowerState) &&
  256. (NewPowerState.DeviceState != devext->PowerState))
  257. {
  258. DBGPRINT(1, ("power state change (%s->%s)\n",
  259. LookupName(devext->PowerState,
  260. PowerStateNames),
  261. LookupName(NewPowerState.DeviceState,
  262. PowerStateNames)));
  263. switch (NewPowerState.DeviceState)
  264. {
  265. case PowerDeviceD0:
  266. //
  267. // Transitioning from a low D state to D0.
  268. //
  269. status = SendSyncIrp(GET_NEXT_DEVICE_OBJECT(DevObj),
  270. Irp,
  271. TRUE);
  272. if (NT_SUCCESS(status))
  273. {
  274. PoSetPowerState(DevObj,
  275. PowerType,
  276. NewPowerState);
  277. OemWakeupDevice(devext);
  278. devext->PowerState = NewPowerState.DeviceState;
  279. devext->dwfHPen &= ~HPENF_TABLET_STANDBY;
  280. }
  281. Irp->IoStatus.Status = status;
  282. IoReleaseRemoveLock(&devext->RemoveLock, Irp);
  283. IoCompleteRequest(Irp, IO_NO_INCREMENT);
  284. fSkipCalldown = TRUE;
  285. break;
  286. case PowerDeviceD1:
  287. case PowerDeviceD2:
  288. case PowerDeviceD3:
  289. //BUGBUG: OemStandbyDevice(devext);
  290. PoSetPowerState(DevObj, PowerType, NewPowerState);
  291. devext->PowerState = NewPowerState.DeviceState;
  292. //BUGBUG: devext->dwfHPen |= HPENF_TABLET_STANDBY;
  293. IoReleaseRemoveLock(&devext->RemoveLock, Irp);
  294. Irp->IoStatus.Status = STATUS_SUCCESS;
  295. IoSkipCurrentIrpStackLocation(Irp);
  296. ENTER(2, (".PoCallDriver(DevObj=%p,Irp=%p)\n",
  297. GET_NEXT_DEVICE_OBJECT(DevObj), Irp));
  298. status = PoCallDriver(
  299. GET_NEXT_DEVICE_OBJECT(DevObj),
  300. Irp);
  301. EXIT(2, (".PoCallDriver=%x\n", status));
  302. fSkipCalldown = TRUE;
  303. break;
  304. }
  305. }
  306. break;
  307. case IRP_MN_WAIT_WAKE:
  308. case IRP_MN_QUERY_POWER:
  309. break;
  310. default:
  311. ERRPRINT(("unsupported power IRP (%s)\n",
  312. LookupName(irpsp->MinorFunction, PowerMinorFnNames)));
  313. break;
  314. }
  315. if (!fSkipCalldown)
  316. {
  317. IoSkipCurrentIrpStackLocation(Irp);
  318. ENTER(2, (".PoCallDriver(DevObj=%p,Irp=%p)\n",
  319. GET_NEXT_DEVICE_OBJECT(DevObj), Irp));
  320. status = PoCallDriver(GET_NEXT_DEVICE_OBJECT(DevObj), Irp);
  321. EXIT(2, (".PoCallDriver=%x\n", status));
  322. IoReleaseRemoveLock(&devext->RemoveLock, Irp);
  323. }
  324. }
  325. EXIT(1, ("=%x\n", status));
  326. return status;
  327. } //HpenPower
  328. /*****************************************************************************
  329. *
  330. * @doc INTERNAL
  331. *
  332. * @func NTSTATUS | InitDevice |
  333. * Get the device information and attempt to initialize a
  334. * configuration for a device. If we cannot identify this as a
  335. * valid HID device or configure the device, our start device
  336. * function is failed.
  337. *
  338. * @parm IN PDEVICE_OBJECT | DevObj | Points to the device object.
  339. * @parm IN PIRP | Irp | Points to an I/O request packet.
  340. *
  341. * @rvalue SUCCESS | returns STATUS_SUCCESS
  342. * @rvalue FAILURE | returns NT status code
  343. *
  344. *****************************************************************************/
  345. NTSTATUS INTERNAL
  346. InitDevice(
  347. IN PDEVICE_OBJECT DevObj,
  348. IN PIRP Irp
  349. )
  350. {
  351. PROCNAME("InitDevice")
  352. NTSTATUS status = STATUS_SUCCESS;
  353. PDEVICE_EXTENSION devext;
  354. PAGED_CODE();
  355. ENTER(2, ("(DevObj=%p,Irp=%p)\n", DevObj, Irp));
  356. devext = GET_MINIDRIVER_DEVICE_EXTENSION(DevObj);
  357. if (!(devext->dwfHPen & HPENF_SERIAL_OPENED))
  358. {
  359. //
  360. // If a create hasn't been sent down the stack, send one now.
  361. // The serial port driver requires a create before it will accept
  362. // any reads or ioctls.
  363. //
  364. PIO_STACK_LOCATION irpspNext = IoGetNextIrpStackLocation(Irp);
  365. NTSTATUS PrevStatus = Irp->IoStatus.Status;
  366. ULONG_PTR PrevInfo = Irp->IoStatus.Information;
  367. RtlZeroMemory(irpspNext, sizeof(*irpspNext));
  368. irpspNext->MajorFunction = IRP_MJ_CREATE;
  369. status = SendSyncIrp(GET_NEXT_DEVICE_OBJECT(DevObj), Irp, FALSE);
  370. if (NT_SUCCESS(status))
  371. {
  372. devext->dwfHPen |= HPENF_SERIAL_OPENED;
  373. Irp->IoStatus.Status = PrevStatus;
  374. Irp->IoStatus.Information = PrevInfo;
  375. }
  376. else
  377. {
  378. ERRPRINT(("failed to send CREATE IRP to serial port (status=%x)\n",
  379. status));
  380. }
  381. }
  382. if (NT_SUCCESS(status))
  383. {
  384. status = OemInitSerialPort(devext);
  385. if (NT_SUCCESS(status))
  386. {
  387. status = OemInitDevice(devext);
  388. }
  389. }
  390. EXIT(2, ("=%x\n", status));
  391. return status;
  392. } //InitDevice
  393. /*****************************************************************************
  394. *
  395. * @doc INTERNAL
  396. *
  397. * @func VOID | RemoveDevice | FDO Remove routine
  398. *
  399. * @parm IN PDEVICE_OBJECT | DevObj | Points to the device object.
  400. * @parm IN PIRP | Irp | Points to an I/O request packet.
  401. *
  402. *****************************************************************************/
  403. VOID INTERNAL
  404. RemoveDevice(
  405. PDEVICE_OBJECT DevObj,
  406. PIRP Irp
  407. )
  408. {
  409. PROCNAME("RemoveDevice")
  410. PDEVICE_EXTENSION devext;
  411. PAGED_CODE();
  412. ENTER(2, ("(DevObj=%p,Irp=%p)\n", DevObj, Irp));
  413. devext = GET_MINIDRIVER_DEVICE_EXTENSION(DevObj);
  414. ASSERT(devext->dwfHPen & HPENF_DEVICE_REMOVED);
  415. if (devext->dwfHPen & HPENF_SERIAL_OPENED)
  416. {
  417. PIO_STACK_LOCATION irpspNext;
  418. OemRemoveDevice(devext);
  419. irpspNext = IoGetNextIrpStackLocation(Irp);
  420. RtlZeroMemory(irpspNext, sizeof(*irpspNext));
  421. irpspNext->MajorFunction = IRP_MJ_CLEANUP;
  422. SendSyncIrp(GET_NEXT_DEVICE_OBJECT(DevObj), Irp, FALSE);
  423. irpspNext = IoGetNextIrpStackLocation(Irp);
  424. RtlZeroMemory(irpspNext, sizeof(*irpspNext));
  425. irpspNext->MajorFunction = IRP_MJ_CLOSE;
  426. SendSyncIrp(GET_NEXT_DEVICE_OBJECT(DevObj), Irp, FALSE);
  427. devext->dwfHPen &= ~HPENF_SERIAL_OPENED;
  428. }
  429. #ifdef DEBUG
  430. ExAcquireFastMutex(&gmutexDevExtList);
  431. RemoveEntryList(&devext->List);
  432. ExReleaseFastMutex (&gmutexDevExtList);
  433. #endif
  434. EXIT(2, ("!\n"));
  435. return;
  436. } //RemoveDevice
  437. /*****************************************************************************
  438. *
  439. * @doc INTERNAL
  440. *
  441. * @func NTSTATUS | SendSyncIrp |
  442. * Send an IRP synchronously down the stack.
  443. *
  444. * @parm IN PDEVICE_OBJECT | DevObj | Points to the device object.
  445. * @parm IN PIRP | Irp | Points to the IRP.
  446. * @parm IN BOOLEAN | fCopyToNext | if TRUE, copy the irpsp to next location.
  447. *
  448. * @rvalue SUCCESS | returns STATUS_SUCCESS
  449. * @rvalue FAILURE | returns NT status code
  450. *
  451. *****************************************************************************/
  452. NTSTATUS INTERNAL
  453. SendSyncIrp(
  454. IN PDEVICE_OBJECT DevObj,
  455. IN PIRP Irp,
  456. IN BOOLEAN fCopyToNext
  457. )
  458. {
  459. PROCNAME("SendSyncIrp")
  460. NTSTATUS status;
  461. PIO_STACK_LOCATION irpsp = IoGetCurrentIrpStackLocation(Irp);
  462. KEVENT event;
  463. PAGED_CODE();
  464. ENTER(2, ("(DevObj=%p,Irp=%p,fCopyToNext=%x,MajorFunc=%s)\n",
  465. DevObj, Irp, fCopyToNext,
  466. LookupName(irpsp->MajorFunction, MajorFnNames)));
  467. KeInitializeEvent(&event, SynchronizationEvent, FALSE);
  468. if (fCopyToNext)
  469. {
  470. IoCopyCurrentIrpStackLocationToNext(Irp);
  471. }
  472. IoSetCompletionRoutine(Irp, IrpCompletion, &event, TRUE, TRUE, TRUE);
  473. if (irpsp->MajorFunction == IRP_MJ_POWER)
  474. {
  475. ENTER(2, (".PoCallDriver(DevObj=%p,Irp=%p)\n", DevObj, Irp));
  476. status = PoCallDriver(DevObj, Irp);
  477. EXIT(2, (".IoCallDriver=%x\n", status));
  478. }
  479. else
  480. {
  481. ENTER(2, (".IoCallDriver(DevObj=%p,Irp=%p)\n", DevObj, Irp));
  482. status = IoCallDriver(DevObj, Irp);
  483. EXIT(2, (".IoCallDriver=%x\n", status));
  484. }
  485. if (status == STATUS_PENDING)
  486. {
  487. status = KeWaitForSingleObject(&event,
  488. Executive,
  489. KernelMode,
  490. FALSE,
  491. NULL);
  492. }
  493. if (NT_SUCCESS(status))
  494. {
  495. status = Irp->IoStatus.Status;
  496. }
  497. EXIT(2, ("=%x\n", status));
  498. return status;
  499. } //SendSyncIrp
  500. /*****************************************************************************
  501. *
  502. * @doc INTERNAL
  503. *
  504. * @func NTSTATUS | IrpCompletion | Completion routine for all IRPs.
  505. *
  506. * @parm IN PDEVICE_OBJECT | DevObj | Points to the device object.
  507. * @parm IN PIRP | Irp | Points to an I/O request packet.
  508. * @parm IN PKEVENT | Event | Points to the event to notify.
  509. *
  510. * @rvalue STATUS_MORE_PROCESSING_REQUIRED | We want the IRP back
  511. *
  512. *****************************************************************************/
  513. NTSTATUS INTERNAL
  514. IrpCompletion(
  515. IN PDEVICE_OBJECT DevObj,
  516. IN PIRP Irp,
  517. IN PKEVENT Event
  518. )
  519. {
  520. PROCNAME("IrpCompletion")
  521. ENTER(2, ("(DevObj=%p,Irp=%p,Event=%p)\n", DevObj, Irp, Event));
  522. UNREFERENCED_PARAMETER(DevObj);
  523. KeSetEvent(Event, 0, FALSE);
  524. /*
  525. * If the lower driver returned PENDING, mark our stack location as
  526. * pending also. This prevents the IRP's thread from being freed if
  527. * the client's call returns pending.
  528. */
  529. if (Irp->PendingReturned)
  530. {
  531. IoMarkIrpPending(Irp);
  532. }
  533. EXIT(2, ("=%x\n", STATUS_MORE_PROCESSING_REQUIRED));
  534. return STATUS_MORE_PROCESSING_REQUIRED;
  535. } //IrpCompletion