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.

1046 lines
31 KiB

  1. /*++
  2. Copyright (c) 1997 Microsoft Corporation
  3. Module Name:
  4. pnp.c
  5. Abstract:
  6. This module contains plug & play code for the HID Mouse Filter Driver,
  7. including code for the creation and removal of HID mouse device contexts.
  8. Environment:
  9. Kernel & user mode.
  10. Revision History:
  11. Jan-1997 : Initial writing, Dan Markarian
  12. --*/
  13. //
  14. // For this module only we set the INITGUID macro before including wdm.h and
  15. // hidclass.h. This not only declares the GUIDs but also initializes them.
  16. //
  17. #include "mouhid.h"
  18. #include "hidclass.h"
  19. #include <initguid.h>
  20. #include <wdmguid.h>
  21. #ifdef ALLOC_PRAGMA
  22. #pragma alloc_text(PAGE,MouHid_CallHidClass)
  23. #pragma alloc_text(PAGE,MouHid_AddDevice)
  24. #pragma alloc_text(PAGE,MouHid_StartDevice)
  25. #pragma alloc_text(PAGE,MouHid_PnP)
  26. #endif
  27. NTSTATUS
  28. MouHid_CallHidClass(
  29. IN PDEVICE_EXTENSION Data,
  30. IN ULONG Ioctl,
  31. IN PVOID InputBuffer,
  32. IN ULONG InputBufferLength,
  33. IN OUT PVOID OutputBuffer,
  34. IN ULONG OutputBufferLength
  35. )
  36. /*++
  37. Routine Description:
  38. Make a *synchronous* request of the HID class driver
  39. Arguments:
  40. Ioctl - Value of the IOCTL request.
  41. InputBuffer - Buffer to be sent to the HID class driver.
  42. InputBufferLength - Size of buffer to be sent to the HID class driver.
  43. OutputBuffer - Buffer for received data from the HID class driver.
  44. OutputBufferLength - Size of receive buffer from the HID class.
  45. Return Value:
  46. STATUS_SUCCESS if successful,
  47. STATUS_UNSUCCESSFUL otherwise
  48. --*/
  49. {
  50. KEVENT event;
  51. IO_STATUS_BLOCK ioStatus;
  52. PIRP irp;
  53. PIO_STACK_LOCATION nextStack;
  54. NTSTATUS status = STATUS_SUCCESS;
  55. PAGED_CODE ();
  56. Print (DBG_PNP_TRACE, ("PNP-CallHidClass: Enter." ));
  57. //
  58. // Prepare to issue a synchronous request.
  59. //
  60. KeInitializeEvent(&event, NotificationEvent, FALSE);
  61. irp = IoBuildDeviceIoControlRequest (
  62. Ioctl,
  63. Data->TopOfStack,
  64. InputBuffer,
  65. InputBufferLength,
  66. OutputBuffer,
  67. OutputBufferLength,
  68. FALSE, // external IOCTL
  69. &event,
  70. &ioStatus);
  71. if (irp == NULL) {
  72. return STATUS_UNSUCCESSFUL;
  73. }
  74. //
  75. // Call the class driver to perform the operation. If the returned status
  76. // is PENDING, wait for the request to complete.
  77. //
  78. nextStack = IoGetNextIrpStackLocation(irp);
  79. ASSERT(nextStack != NULL);
  80. status = IoCallDriver(Data->TopOfStack, irp);
  81. if (status == STATUS_PENDING) {
  82. status = KeWaitForSingleObject(
  83. &event,
  84. Executive, // wait reason
  85. KernelMode,
  86. FALSE, // not alertable
  87. NULL); // no time out
  88. }
  89. if (NT_SUCCESS (status)) {
  90. status = ioStatus.Status;
  91. }
  92. Print (DBG_PNP_TRACE, ("PNP-CallHidClass: Enter." ));
  93. return status;
  94. }
  95. NTSTATUS
  96. MouHid_QueryDeviceKey (
  97. IN HANDLE Handle,
  98. IN PWCHAR ValueNameString,
  99. OUT PVOID Data,
  100. IN ULONG DataLength
  101. )
  102. {
  103. NTSTATUS status;
  104. UNICODE_STRING valueName;
  105. ULONG length;
  106. PKEY_VALUE_FULL_INFORMATION fullInfo;
  107. RtlInitUnicodeString (&valueName, ValueNameString);
  108. length = sizeof (KEY_VALUE_FULL_INFORMATION)
  109. + valueName.MaximumLength
  110. + DataLength;
  111. fullInfo = ExAllocatePool (PagedPool, length);
  112. if (fullInfo) {
  113. status = ZwQueryValueKey (Handle,
  114. &valueName,
  115. KeyValueFullInformation,
  116. fullInfo,
  117. length,
  118. &length);
  119. if (NT_SUCCESS (status)) {
  120. ASSERT (DataLength == fullInfo->DataLength);
  121. RtlCopyMemory (Data,
  122. ((PUCHAR) fullInfo) + fullInfo->DataOffset,
  123. fullInfo->DataLength);
  124. }
  125. ExFreePool (fullInfo);
  126. } else {
  127. status = STATUS_NO_MEMORY;
  128. }
  129. return status;
  130. }
  131. NTSTATUS
  132. MouHid_AddDevice (
  133. IN PDRIVER_OBJECT Driver,
  134. IN PDEVICE_OBJECT PDO
  135. )
  136. /*++
  137. Routine Description:
  138. Arguments:
  139. Return Value:
  140. NTSTATUS result code.
  141. --*/
  142. {
  143. NTSTATUS status = STATUS_SUCCESS;
  144. PDEVICE_EXTENSION data;
  145. PDEVICE_OBJECT device;
  146. HANDLE devInstRegKey;
  147. ULONG tmp = 0;
  148. POWER_STATE state;
  149. PAGED_CODE ();
  150. Print (DBG_PNP_TRACE, ("enter Add Device \n"));
  151. status = IoCreateDevice(Driver,
  152. sizeof(DEVICE_EXTENSION),
  153. NULL, // no name for this Filter DO
  154. FILE_DEVICE_MOUSE,
  155. 0,
  156. FALSE,
  157. &device);
  158. if (!NT_SUCCESS (status)) {
  159. return( status );
  160. }
  161. data = (PDEVICE_EXTENSION) device->DeviceExtension;
  162. //
  163. // Initialize the fields.
  164. //
  165. data->TopOfStack = IoAttachDeviceToDeviceStack (device, PDO);
  166. if (data->TopOfStack == NULL) {
  167. PIO_ERROR_LOG_PACKET errorLogEntry;
  168. //
  169. // Not good; in only extreme cases will this fail
  170. //
  171. errorLogEntry = (PIO_ERROR_LOG_PACKET)
  172. IoAllocateErrorLogEntry(Driver,
  173. (UCHAR) sizeof(IO_ERROR_LOG_PACKET));
  174. if (errorLogEntry) {
  175. errorLogEntry->ErrorCode = MOUHID_ATTACH_DEVICE_FAILED;
  176. errorLogEntry->DumpDataSize = 0;
  177. errorLogEntry->SequenceNumber = 0;
  178. errorLogEntry->MajorFunctionCode = 0;
  179. errorLogEntry->IoControlCode = 0;
  180. errorLogEntry->RetryCount = 0;
  181. errorLogEntry->UniqueErrorValue = 0;
  182. errorLogEntry->FinalStatus = STATUS_DEVICE_NOT_CONNECTED;
  183. IoWriteErrorLogEntry(errorLogEntry);
  184. }
  185. IoDeleteDevice(device);
  186. return STATUS_DEVICE_NOT_CONNECTED;
  187. }
  188. ASSERT (data->TopOfStack);
  189. data->Self = device;
  190. data->Started = FALSE;
  191. data->Initialized = FALSE;
  192. data->UnitId = (USHORT) InterlockedIncrement (&Globals.UnitId);
  193. data->PDO = PDO;
  194. data->ReadIrp = IoAllocateIrp (data->TopOfStack->StackSize, FALSE);
  195. // Initializiation happens automatically.
  196. if (NULL == data->ReadIrp) {
  197. IoDetachDevice (data->TopOfStack);
  198. IoDeleteDevice (device);
  199. return STATUS_INSUFFICIENT_RESOURCES;
  200. }
  201. KeInitializeEvent (&data->ReadCompleteEvent, SynchronizationEvent, FALSE);
  202. KeInitializeEvent (&data->ReadSentEvent, NotificationEvent, TRUE);
  203. IoInitializeRemoveLock (&data->RemoveLock, MOUHID_POOL_TAG, 1, 10);
  204. data->ReadFile = NULL;
  205. ExInitializeFastMutex (&data->CreateCloseMutex);
  206. data->InputData.UnitId = data->UnitId;
  207. //
  208. // Initialize the mouse attributes.
  209. //
  210. data->Attributes.MouseIdentifier = MOUSE_HID_HARDWARE;
  211. data->Attributes.SampleRate = 0;
  212. data->Attributes.InputDataQueueLength = 2;
  213. //
  214. // Find device specific parameters for this hid mouse device.
  215. //
  216. if (NT_SUCCESS (status)) {
  217. status = IoOpenDeviceRegistryKey (PDO,
  218. PLUGPLAY_REGKEY_DEVICE,
  219. STANDARD_RIGHTS_ALL,
  220. &devInstRegKey);
  221. data->FlipFlop = FALSE;
  222. if (NT_SUCCESS (status)) {
  223. status = MouHid_QueryDeviceKey (devInstRegKey,
  224. FLIP_FLOP_WHEEL,
  225. &tmp,
  226. sizeof (tmp));
  227. if (NT_SUCCESS (status)) {
  228. data->FlipFlop = (BOOLEAN) tmp;
  229. }
  230. status = MouHid_QueryDeviceKey (devInstRegKey,
  231. SCALING_FACTOR_WHEEL,
  232. &tmp,
  233. sizeof (tmp));
  234. if (NT_SUCCESS (status)) {
  235. data->WheelScalingFactor = (ULONG) tmp;
  236. } else {
  237. data->WheelScalingFactor = 120;
  238. }
  239. ZwClose (devInstRegKey);
  240. }
  241. status = STATUS_SUCCESS;
  242. }
  243. state.DeviceState = PowerDeviceD0;
  244. PoSetPowerState (device, DevicePowerState, state);
  245. data->WmiLibInfo.GuidCount = sizeof (MouHid_WmiGuidList) /
  246. sizeof (WMIGUIDREGINFO);
  247. ASSERT (1 == data->WmiLibInfo.GuidCount);
  248. data->WmiLibInfo.GuidList = MouHid_WmiGuidList;
  249. data->WmiLibInfo.QueryWmiRegInfo = MouHid_QueryWmiRegInfo;
  250. data->WmiLibInfo.QueryWmiDataBlock = MouHid_QueryWmiDataBlock;
  251. data->WmiLibInfo.SetWmiDataBlock = MouHid_SetWmiDataBlock;
  252. data->WmiLibInfo.SetWmiDataItem = MouHid_SetWmiDataItem;
  253. data->WmiLibInfo.ExecuteWmiMethod = NULL;
  254. data->WmiLibInfo.WmiFunctionControl = NULL;
  255. device->Flags |= DO_POWER_PAGABLE;
  256. device->Flags &= ~DO_DEVICE_INITIALIZING;
  257. return status;
  258. }
  259. NTSTATUS
  260. MouHid_StartDevice (
  261. IN PDEVICE_EXTENSION Data
  262. )
  263. /*++
  264. Routine Description:
  265. Arguments:
  266. Return Value:
  267. NTSTATUS result code.
  268. --*/
  269. {
  270. HIDP_CAPS caps; // the capabilities of the found hid device
  271. HID_COLLECTION_INFORMATION info;
  272. NTSTATUS status = STATUS_SUCCESS;
  273. PHIDP_PREPARSED_DATA preparsedData = NULL;
  274. PHID_EXTENSION hid = NULL;
  275. ULONG length, inputBufferLength, usageListLength;
  276. USHORT maxUsages;
  277. PCHAR buffer;
  278. USHORT slength;
  279. HIDP_VALUE_CAPS valueCaps;
  280. PAGED_CODE ();
  281. Print (DBG_PNP_TRACE, ("enter START Device \n"));
  282. //
  283. // Retrieve the capabilities of this hid device
  284. // IOCTL_HID_GET_COLLECTION_INFORMATION fills in HID_COLLECTION_INFORMATION.
  285. // we are interested in the Descriptor Size, which tells us how big a
  286. // buffer to allocate for the preparsed data.
  287. //
  288. if (!NT_SUCCESS (status = MouHid_CallHidClass (
  289. Data,
  290. IOCTL_HID_GET_COLLECTION_INFORMATION,
  291. 0, 0, // no input
  292. &info, sizeof (info)))) {
  293. goto MouHid_StartDeviceReject;
  294. }
  295. //
  296. // Allocate memory to hold the preparsed data.
  297. //
  298. preparsedData = (PHIDP_PREPARSED_DATA)
  299. ExAllocatePool (NonPagedPool, info.DescriptorSize);
  300. if (!preparsedData) {
  301. status = STATUS_INSUFFICIENT_RESOURCES;
  302. goto MouHid_StartDeviceReject;
  303. }
  304. //
  305. // Retrieve that information.
  306. //
  307. if (!NT_SUCCESS (status = MouHid_CallHidClass (
  308. Data,
  309. IOCTL_HID_GET_COLLECTION_DESCRIPTOR,
  310. 0, 0, // no input
  311. preparsedData, info.DescriptorSize))) {
  312. goto MouHid_StartDeviceReject;
  313. }
  314. //
  315. // Call the parser to determine the capabilites of this HID device.
  316. //
  317. if (!NT_SUCCESS (status = HidP_GetCaps (preparsedData, &caps))) {
  318. goto MouHid_StartDeviceReject;
  319. }
  320. //
  321. // Is this the thing we want?
  322. //
  323. // In this particular case we are looking for a keyboard.
  324. //
  325. if ( (HID_USAGE_PAGE_GENERIC == caps.UsagePage) &&
  326. ( (HID_USAGE_GENERIC_MOUSE == caps.Usage) ||
  327. ( (HID_USAGE_GENERIC_POINTER == caps.Usage) &&
  328. (!Globals.UseOnlyMice)))) {
  329. ;
  330. } else {
  331. //
  332. // Someone made an INF blunder!
  333. //
  334. ASSERT ( (HID_USAGE_PAGE_GENERIC == caps.UsagePage) &&
  335. ( (HID_USAGE_GENERIC_MOUSE == caps.Usage) ||
  336. ( (HID_USAGE_GENERIC_POINTER == caps.Usage) &&
  337. (!Globals.UseOnlyMice))));
  338. status = STATUS_UNSUCCESSFUL;
  339. goto MouHid_StartDeviceReject;
  340. }
  341. //
  342. // Note: here we might also want to check the button and value capabilities
  343. // of the device as well.
  344. //
  345. // Then let's use it.
  346. //
  347. //
  348. // a buffer length to allow an Input buffer, output buffer, feature buffer,
  349. // and the total number of usages that can be returned from a read packet.
  350. //
  351. maxUsages = (USHORT) HidP_MaxUsageListLength (HidP_Input,
  352. HID_USAGE_PAGE_BUTTON,
  353. preparsedData);
  354. //
  355. // Create space in the device extension for the buffer storage when working
  356. // with this HID device.
  357. //
  358. // We need four buffers to hold the button codes (length returned from
  359. // HidP_MaxUsageListLength) this will hold the current list of usages,
  360. // the previous list of usages, the ``Make'' and the ``Break'' lists.
  361. // We also need a place to put the input, output, and feature report
  362. // buffers.
  363. //
  364. usageListLength = ALIGNPTRLEN(maxUsages * sizeof (USAGE));
  365. inputBufferLength = ALIGNPTRLEN(caps.InputReportByteLength);
  366. length = (4 * usageListLength)
  367. + inputBufferLength
  368. + sizeof (HID_EXTENSION);
  369. Data->HidExtension = hid = ExAllocatePool (NonPagedPool, length);
  370. if (!hid) {
  371. status = STATUS_INSUFFICIENT_RESOURCES;
  372. goto MouHid_StartDeviceReject;
  373. }
  374. RtlZeroMemory (hid, length);
  375. //
  376. // Initialize the fields.
  377. //
  378. hid->Ppd = preparsedData;
  379. hid->Caps = caps;
  380. hid->MaxUsages = maxUsages;
  381. Data->Attributes.NumberOfButtons = (USHORT) maxUsages;
  382. hid->InputBuffer = buffer = hid->Buffer;
  383. hid->PreviousUsageList = (PUSAGE) (buffer += inputBufferLength);
  384. hid->CurrentUsageList = (PUSAGE) (buffer += usageListLength);
  385. hid->BreakUsageList = (PUSAGE) (buffer += usageListLength);
  386. hid->MakeUsageList = (PUSAGE) (buffer + usageListLength);
  387. //
  388. // Create the MDLs
  389. // HidClass uses direct IO so you need MDLs
  390. //
  391. hid->InputMdl = IoAllocateMdl (hid->InputBuffer, // The virtual address
  392. caps.InputReportByteLength, // length
  393. FALSE, // No associated IRP => not secondary
  394. FALSE, // No quota charge
  395. 0); // No associated IRP
  396. if (NULL == hid->InputMdl) {
  397. status = STATUS_INSUFFICIENT_RESOURCES;
  398. goto MouHid_StartDeviceReject;
  399. }
  400. MmBuildMdlForNonPagedPool (hid->InputMdl); // Build this MDL.
  401. //
  402. // Determine if X,Y,Z values are absolute or relative for this device.
  403. // Only check X axis (assume Y,Z are the same -- we have no choice but
  404. // to make this assumption since the MOUSE_INPUT_DATA structure does
  405. // not accomodate mixed absolute/relative position fields).
  406. //
  407. slength = 1;
  408. if (!NT_SUCCESS (status = HidP_GetSpecificValueCaps(
  409. HidP_Input,
  410. HID_USAGE_PAGE_GENERIC,
  411. 0,
  412. HID_USAGE_GENERIC_X,
  413. &valueCaps,
  414. &slength,
  415. preparsedData) ) ) {
  416. goto MouHid_StartDeviceReject;
  417. }
  418. ASSERT (1 == slength);
  419. if (valueCaps.IsAbsolute) {
  420. if ((HID_USAGE_GENERIC_POINTER == caps.Usage) &&
  421. (Globals.TreatAbsolutePointerAsAbsolute)) {
  422. //
  423. // All pointers that declare themselfs as Absolute should be
  424. // treated as such, regardless of the TreatAbsoluteAsRelative flag
  425. //
  426. Data->InputData.Flags = MOUSE_MOVE_ABSOLUTE;
  427. hid->IsAbsolute = TRUE;
  428. } else if (Globals.TreatAbsoluteAsRelative) {
  429. //
  430. // Here we have overriden the HID descriptors absolute flag.
  431. // We will treat this as a relative device even though it claims
  432. // to be an absolute device.
  433. //
  434. Data->InputData.Flags = MOUSE_MOVE_RELATIVE;
  435. hid->IsAbsolute = FALSE;
  436. //
  437. // Report the problem with this mouse's report descriptor and
  438. // report it to the user.
  439. //
  440. Data->ProblemFlags |= PROBLEM_BAD_ABSOLUTE_FLAG_X_Y;
  441. MouHid_LogError(Data->Self->DriverObject,
  442. MOUHID_INVALID_ABSOLUTE_AXES,
  443. NULL);
  444. } else {
  445. //
  446. // No switches with which to play. Do what seems natural
  447. //
  448. Data->InputData.Flags = MOUSE_MOVE_ABSOLUTE;
  449. hid->IsAbsolute = TRUE;
  450. }
  451. } else {
  452. Data->InputData.Flags = MOUSE_MOVE_RELATIVE;
  453. hid->IsAbsolute = FALSE;
  454. }
  455. //
  456. // Determine X axis usage value's bit size.
  457. //
  458. hid->BitSize.X = valueCaps.BitSize;
  459. hid->MaxX = valueCaps.PhysicalMax;
  460. hid->MaxX = (hid->MaxX) ? (hid->MaxX) : ((1 << (hid->BitSize.X - 1)) - 1);
  461. //
  462. // Determine Y axis usage value's bit size.
  463. //
  464. slength = 1;
  465. if (!NT_SUCCESS (status = HidP_GetSpecificValueCaps(
  466. HidP_Input,
  467. HID_USAGE_PAGE_GENERIC,
  468. 0,
  469. HID_USAGE_GENERIC_Y,
  470. &valueCaps,
  471. &slength,
  472. preparsedData) ) ) {
  473. goto MouHid_StartDeviceReject;
  474. }
  475. ASSERT (1 == slength);
  476. hid->BitSize.Y = valueCaps.BitSize;
  477. hid->MaxY = valueCaps.PhysicalMax;
  478. hid->MaxY = (hid->MaxY) ? (hid->MaxY) : ((1 << (hid->BitSize.Y - 1)) - 1);
  479. //
  480. // Initialize wheel usage not-detected flag to false (determined later).
  481. //
  482. hid->HasNoWheelUsage = FALSE;
  483. hid->HasNoZUsage = FALSE;
  484. //
  485. // Determine Z axis usage value's bit size (if this is a wheel mouse).
  486. // Note that a Z axis may not exist, so we handle this case differently.
  487. //
  488. slength = 1;
  489. if (NT_SUCCESS (HidP_GetSpecificValueCaps(
  490. HidP_Input,
  491. HID_USAGE_PAGE_GENERIC,
  492. 0,
  493. HID_USAGE_GENERIC_WHEEL,
  494. &valueCaps,
  495. &slength,
  496. preparsedData) ) && slength == 1) {
  497. hid->BitSize.Z = valueCaps.BitSize;
  498. Data->Attributes.MouseIdentifier = WHEELMOUSE_HID_HARDWARE;
  499. } else {
  500. // hid->HasNoWheelUsage = TRUE;
  501. slength = 1;
  502. if (NT_SUCCESS (HidP_GetSpecificValueCaps(
  503. HidP_Input,
  504. HID_USAGE_PAGE_GENERIC,
  505. 0,
  506. HID_USAGE_GENERIC_Z,
  507. &valueCaps,
  508. &slength,
  509. preparsedData) ) && slength == 1) {
  510. hid->BitSize.Z = valueCaps.BitSize;
  511. Data->Attributes.MouseIdentifier = WHEELMOUSE_HID_HARDWARE;
  512. } else {
  513. // hid->HasNoZUsage = TRUE;
  514. hid->BitSize.Z = 0;
  515. }
  516. }
  517. //
  518. // We are done. Return peacefully.
  519. //
  520. return status;
  521. MouHid_StartDeviceReject:
  522. if (preparsedData) {
  523. // no need to set hid->Ppd to NULL becuase we will be freeing it as well
  524. ExFreePool (preparsedData);
  525. }
  526. if (hid) {
  527. if (hid->InputMdl) {
  528. IoFreeMdl (hid->InputMdl);
  529. }
  530. ExFreePool (hid);
  531. Data->HidExtension = NULL;
  532. }
  533. return status;
  534. }
  535. NTSTATUS
  536. MouHid_PnP (
  537. IN PDEVICE_OBJECT DeviceObject,
  538. IN PIRP Irp
  539. )
  540. /*++
  541. Routine Description:
  542. The plug and play dispatch routines.
  543. Most of these this filter driver will completely ignore.
  544. In all cases it must pass on the IRP to the lower driver.
  545. Arguments:
  546. DeviceObject - pointer to a device object.
  547. Irp - pointer to an I/O Request Packet.
  548. Return Value:
  549. NT status code
  550. --*/
  551. {
  552. PDEVICE_EXTENSION data;
  553. PHID_EXTENSION hid;
  554. PIO_STACK_LOCATION stack;
  555. NTSTATUS status;
  556. ULONG i, j;
  557. LONG ioCount;
  558. PDEVICE_EXTENSION * classDataList;
  559. PAGED_CODE ();
  560. data = (PDEVICE_EXTENSION) DeviceObject->DeviceExtension;
  561. stack = IoGetCurrentIrpStackLocation (Irp);
  562. hid = data->HidExtension;
  563. status = IoAcquireRemoveLock (&data->RemoveLock, Irp);
  564. if (!NT_SUCCESS (status)) {
  565. //
  566. // Someone gave us a pnp irp after a remove. Unthinkable!
  567. //
  568. ASSERT (FALSE);
  569. Irp->IoStatus.Information = 0;
  570. Irp->IoStatus.Status = status;
  571. IoCompleteRequest (Irp, IO_NO_INCREMENT);
  572. return status;
  573. }
  574. Print(DBG_PNP_TRACE, ("PNP: Minor code = %x.", stack->MinorFunction));
  575. switch (stack->MinorFunction) {
  576. case IRP_MN_START_DEVICE:
  577. if (data->Started) {
  578. Print(DBG_PNP_INFO, ("PNP: Device already started." ));
  579. status = STATUS_SUCCESS;
  580. Irp->IoStatus.Status = status;
  581. IoCompleteRequest (Irp, IO_NO_INCREMENT);
  582. break;
  583. }
  584. //
  585. // The device is starting.
  586. //
  587. // We cannot touch the device (send it any non pnp irps) until a
  588. // start device has been passed down to the lower drivers.
  589. //
  590. IoCopyCurrentIrpStackLocationToNext (Irp);
  591. KeInitializeEvent(&data->StartEvent, NotificationEvent, FALSE);
  592. IoSetCompletionRoutine (Irp,
  593. MouHid_PnPComplete,
  594. data,
  595. TRUE,
  596. TRUE,
  597. TRUE); // No need for Cancel
  598. Irp->IoStatus.Status = STATUS_SUCCESS;
  599. status = IoCallDriver (data->TopOfStack, Irp);
  600. if (STATUS_PENDING == status) {
  601. KeWaitForSingleObject(
  602. &data->StartEvent,
  603. Executive, // Waiting for reason of a driver
  604. KernelMode, // Waiting in kernel mode
  605. FALSE, // No allert
  606. NULL); // No timeout
  607. }
  608. if (NT_SUCCESS (status) && NT_SUCCESS (Irp->IoStatus.Status)) {
  609. //
  610. // As we are successfully now back from our start device
  611. // we can do work.
  612. //
  613. if (!data->Initialized) {
  614. status = MouHid_StartDevice (data);
  615. if (NT_SUCCESS (status)) {
  616. IoWMIRegistrationControl(DeviceObject,
  617. WMIREG_ACTION_REGISTER
  618. );
  619. data->Started = TRUE;
  620. data->Initialized = TRUE;
  621. }
  622. } else {
  623. data->Started = TRUE;
  624. }
  625. }
  626. //
  627. // We must now complete the IRP, since we stopped it in the
  628. // completetion routine with MORE_PROCESSING_REQUIRED.
  629. //
  630. Irp->IoStatus.Status = status;
  631. Irp->IoStatus.Information = 0;
  632. IoCompleteRequest (Irp, IO_NO_INCREMENT);
  633. break;
  634. case IRP_MN_STOP_DEVICE:
  635. //
  636. // After the start IRP has been sent to the lower driver object, the
  637. // bus may NOT send any more IRPS down ``touch'' until another START
  638. // has occured.
  639. // What ever access is required must be done before the Irp is passed
  640. // on.
  641. //
  642. if (data->Started) {
  643. //
  644. // Do what ever
  645. //
  646. }
  647. //
  648. // We don't need a completion routine so fire and forget.
  649. //
  650. // Set the current stack location to the next stack location and
  651. // call the next device object.
  652. //
  653. //
  654. // Stop Device touching the hardware MouStopDevice(data, TRUE);
  655. //
  656. data->Started = FALSE;
  657. Irp->IoStatus.Status = STATUS_SUCCESS;
  658. IoSkipCurrentIrpStackLocation (Irp);
  659. status = IoCallDriver (data->TopOfStack, Irp);
  660. break;
  661. case IRP_MN_REMOVE_DEVICE:
  662. //
  663. // The PlugPlay system has dictacted the removal of this device. We
  664. // have no choise but to detach and delete the device objecct.
  665. // (If we wanted to express and interest in preventing this removal,
  666. // we should have filtered the query remove and query stop routines.)
  667. //
  668. // Note! we might receive a remove WITHOUT first receiving a stop.
  669. // ASSERT (!usbData->Removed);
  670. Print (DBG_PNP_TRACE, ("enter RemoveDevice \n"));
  671. IoWMIRegistrationControl(data->Self,
  672. WMIREG_ACTION_DEREGISTER
  673. );
  674. if (data->Started) {
  675. // Stop the device without touching the hardware.
  676. // MouStopDevice(data, FALSE);
  677. }
  678. //
  679. // Here if we had any outstanding requests in a personal queue we should
  680. // complete them all now.
  681. //
  682. // Note, the device could be GONE so we cannot send it any non-
  683. // PNP IRPS.
  684. //
  685. //
  686. // Cancel our read IRP. [DAN]
  687. // Note - waiting is only really necessary on 98, where pnp doesn't
  688. // make sure all handles are closed before sending the remove.
  689. //
  690. data->ShuttingDown = TRUE;
  691. KeWaitForSingleObject (&data->ReadSentEvent,
  692. Executive,
  693. KernelMode,
  694. FALSE,
  695. NULL
  696. );
  697. IoCancelIrp(data->ReadIrp);
  698. //
  699. // Send on the remove IRP
  700. //
  701. Irp->IoStatus.Status = STATUS_SUCCESS;
  702. IoSkipCurrentIrpStackLocation (Irp);
  703. status = IoCallDriver (data->TopOfStack, Irp);
  704. //
  705. // Wait for the remove lock to free.
  706. //
  707. IoReleaseRemoveLockAndWait (&data->RemoveLock, Irp);
  708. //
  709. // Free the associated memory.
  710. //
  711. IoFreeIrp (data->ReadIrp);
  712. if (hid) {
  713. //
  714. // If we are removed without being started then we will have
  715. // no hid extension
  716. //
  717. ExFreePool (hid->Ppd);
  718. IoFreeMdl (hid->InputMdl);
  719. ExFreePool (hid);
  720. }
  721. IoDetachDevice (data->TopOfStack);
  722. IoDeleteDevice (data->Self);
  723. return status;
  724. case IRP_MN_SURPRISE_REMOVAL:
  725. case IRP_MN_QUERY_REMOVE_DEVICE:
  726. case IRP_MN_CANCEL_REMOVE_DEVICE:
  727. case IRP_MN_QUERY_STOP_DEVICE:
  728. case IRP_MN_CANCEL_STOP_DEVICE:
  729. //
  730. // These IRPs have to have their status changed from
  731. // STATUS_NOT_SUPPORTED b4 passing them down.
  732. //
  733. Irp->IoStatus.Status = STATUS_SUCCESS;
  734. case IRP_MN_QUERY_DEVICE_RELATIONS:
  735. case IRP_MN_QUERY_INTERFACE:
  736. case IRP_MN_QUERY_CAPABILITIES:
  737. case IRP_MN_QUERY_RESOURCES:
  738. case IRP_MN_QUERY_RESOURCE_REQUIREMENTS:
  739. case IRP_MN_READ_CONFIG:
  740. case IRP_MN_WRITE_CONFIG:
  741. case IRP_MN_EJECT:
  742. case IRP_MN_SET_LOCK:
  743. case IRP_MN_QUERY_ID:
  744. case IRP_MN_QUERY_PNP_DEVICE_STATE:
  745. default:
  746. //
  747. // Here the filter driver might modify the behavior of these IRPS
  748. // Please see PlugPlay documentation for use of these IRPs.
  749. //
  750. IoSkipCurrentIrpStackLocation (Irp);
  751. status = IoCallDriver (data->TopOfStack, Irp);
  752. break;
  753. }
  754. IoReleaseRemoveLock (&data->RemoveLock, Irp);
  755. return status;
  756. }
  757. NTSTATUS
  758. MouHid_PnPComplete (
  759. IN PDEVICE_OBJECT DeviceObject,
  760. IN PIRP Irp,
  761. IN PVOID Context
  762. )
  763. /*++
  764. Routine Description:
  765. The pnp IRP is in the process of completing.
  766. signal
  767. Arguments:
  768. Context set to the device object in question.
  769. --*/
  770. {
  771. PIO_STACK_LOCATION stack;
  772. PDEVICE_EXTENSION data;
  773. NTSTATUS status;
  774. UNREFERENCED_PARAMETER (DeviceObject);
  775. status = STATUS_SUCCESS;
  776. data = (PDEVICE_EXTENSION) Context;
  777. stack = IoGetCurrentIrpStackLocation (Irp);
  778. if (Irp->PendingReturned) {
  779. IoMarkIrpPending( Irp );
  780. }
  781. switch (stack->MajorFunction) {
  782. case IRP_MJ_PNP:
  783. switch (stack->MinorFunction) {
  784. case IRP_MN_START_DEVICE:
  785. KeSetEvent (&data->StartEvent, 0, FALSE);
  786. //
  787. // Take the IRP back so that we can continue using it during
  788. // the IRP_MN_START_DEVICE dispatch routine.
  789. // NB: we will have to call IoCompleteRequest
  790. //
  791. return STATUS_MORE_PROCESSING_REQUIRED;
  792. default:
  793. break;
  794. }
  795. break;
  796. case IRP_MJ_POWER:
  797. default:
  798. break;
  799. }
  800. return status;
  801. }
  802. NTSTATUS
  803. MouHid_Power (
  804. IN PDEVICE_OBJECT DeviceObject,
  805. IN PIRP Irp
  806. )
  807. {
  808. PIO_STACK_LOCATION stack;
  809. NTSTATUS status;
  810. PDEVICE_EXTENSION data;
  811. POWER_STATE powerState;
  812. POWER_STATE_TYPE powerType;
  813. Print(DBG_POWER_TRACE, ("Power Enter." ));
  814. data = (PDEVICE_EXTENSION) DeviceObject->DeviceExtension;
  815. stack = IoGetCurrentIrpStackLocation (Irp);
  816. powerType = stack->Parameters.Power.Type;
  817. powerState = stack->Parameters.Power.State;
  818. status = IoAcquireRemoveLock (&data->RemoveLock, Irp);
  819. if (!NT_SUCCESS (status)) {
  820. PoStartNextPowerIrp (Irp);
  821. Irp->IoStatus.Status = status;
  822. IoCompleteRequest (Irp, IO_NO_INCREMENT);
  823. return status;
  824. }
  825. switch (stack->MinorFunction) {
  826. case IRP_MN_SET_POWER:
  827. Print(DBG_POWER_INFO, ("Power Setting %s state to %d\n",
  828. ((powerType == SystemPowerState) ? "System"
  829. : "Device"),
  830. powerState.SystemState));
  831. break;
  832. case IRP_MN_QUERY_POWER:
  833. Print (DBG_POWER_INFO, ("Power query %s status to %d\n",
  834. ((powerType == SystemPowerState) ? "System"
  835. : "Device"),
  836. powerState.SystemState));
  837. break;
  838. default:
  839. Print (DBG_POWER_ERROR, ("Power minor (0x%x) no known\n",
  840. stack->MinorFunction));
  841. }
  842. PoStartNextPowerIrp (Irp);
  843. IoSkipCurrentIrpStackLocation (Irp);
  844. status = PoCallDriver (data->TopOfStack, Irp);
  845. IoReleaseRemoveLock (&data->RemoveLock, Irp);
  846. return status;
  847. }