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.

2510 lines
80 KiB

  1. /*++
  2. Copyright (c) 1996 Microsoft Corporation
  3. Module Name:
  4. util.c
  5. Abstract
  6. Internal utility functions for the HID class driver.
  7. Authors:
  8. Ervin P.
  9. Environment:
  10. Kernel mode only
  11. Revision History:
  12. --*/
  13. #include "pch.h"
  14. #ifdef ALLOC_PRAGMA
  15. #pragma alloc_text(PAGE, HidpAddDevice)
  16. #pragma alloc_text(PAGE, HidpDriverUnload)
  17. #pragma alloc_text(PAGE, HidpGetDeviceDescriptor)
  18. #pragma alloc_text(PAGE, HidpQueryDeviceCapabilities)
  19. #pragma alloc_text(PAGE, HidpQueryIdForClientPdo)
  20. #pragma alloc_text(PAGE, SubstituteBusNames)
  21. #pragma alloc_text(PAGE, BuildCompatibleID)
  22. #pragma alloc_text(PAGE, HidpQueryCollectionCapabilities)
  23. #pragma alloc_text(PAGE, HidpQueryDeviceRelations)
  24. #pragma alloc_text(PAGE, HidpCreateClientPDOs)
  25. #pragma alloc_text(PAGE, MakeClientPDOName)
  26. #pragma alloc_text(PAGE, HidpCreateSymbolicLink)
  27. #pragma alloc_text(PAGE, HidpQueryInterface)
  28. #endif
  29. /*
  30. ********************************************************************************
  31. * HidpCopyInputReportToUser
  32. ********************************************************************************
  33. *
  34. * Copy a read report into a user's buffer.
  35. *
  36. * Note: ReportData is already "cooked" (already has report-id byte at start of report).
  37. *
  38. */
  39. NTSTATUS HidpCopyInputReportToUser(
  40. IN PHIDCLASS_FILE_EXTENSION FileExtension,
  41. IN PUCHAR ReportData,
  42. IN OUT PULONG UserBufferLen,
  43. OUT PUCHAR UserBuffer
  44. )
  45. {
  46. NTSTATUS result = STATUS_DEVICE_DATA_ERROR;
  47. ULONG reportId;
  48. PHIDP_REPORT_IDS reportIdentifier;
  49. FDO_EXTENSION *fdoExtension = FileExtension->fdoExt;
  50. RUNNING_DISPATCH();
  51. ASSERT(fdoExtension->deviceDesc.CollectionDescLength > 0);
  52. reportId = (ULONG)*ReportData;
  53. reportIdentifier = GetReportIdentifier(fdoExtension, reportId);
  54. if (reportIdentifier){
  55. PHIDP_COLLECTION_DESC collectionDesc;
  56. PHIDCLASS_COLLECTION hidpCollection;
  57. collectionDesc = GetCollectionDesc(fdoExtension, reportIdentifier->CollectionNumber);
  58. hidpCollection = GetHidclassCollection(fdoExtension, reportIdentifier->CollectionNumber);
  59. if (collectionDesc && hidpCollection){
  60. ULONG reportLength = collectionDesc->InputLength;
  61. if (*UserBufferLen >= reportLength){
  62. RtlCopyMemory(UserBuffer, ReportData, reportLength);
  63. result = STATUS_SUCCESS;
  64. }
  65. else {
  66. result = STATUS_INVALID_BUFFER_SIZE;
  67. }
  68. /*
  69. * Return the actual length of the report (whether we copied or not).
  70. */
  71. *UserBufferLen = reportLength;
  72. }
  73. }
  74. ASSERT((result == STATUS_SUCCESS) || (result == STATUS_INVALID_BUFFER_SIZE));
  75. return result;
  76. }
  77. /*
  78. ********************************************************************************
  79. * HidpAddDevice
  80. ********************************************************************************
  81. *
  82. * Routine Description:
  83. *
  84. * This routine is called by configmgr when a new PDO is dected.
  85. * It creates an Functional Device Object (FDO) and attaches it to the
  86. * PDO.
  87. *
  88. * Arguments:
  89. *
  90. * DriverObject - pointer to the minidriver's driver object.
  91. *
  92. * PhysicalDeviceObject - pointer to the PDO that the minidriver got in it's
  93. * AddDevice() routine.
  94. *
  95. * Return Value:
  96. *
  97. * Standard NT return value.
  98. *
  99. */
  100. NTSTATUS HidpAddDevice(IN PDRIVER_OBJECT DriverObject, IN PDEVICE_OBJECT PhysicalDeviceObject)
  101. {
  102. PHIDCLASS_DRIVER_EXTENSION hidDriverExtension;
  103. PHIDCLASS_DEVICE_EXTENSION hidClassExtension;
  104. NTSTATUS status;
  105. UNICODE_STRING uPdoName;
  106. PWSTR wPdoName;
  107. PVOID miniDeviceExtension;
  108. ULONG totalExtensionSize;
  109. ULONG thisHidId;
  110. PDEVICE_OBJECT functionalDeviceObject;
  111. PAGED_CODE();
  112. DBG_COMMON_ENTRY()
  113. DBG_RECORD_DEVOBJ(PhysicalDeviceObject, "minidrvr PDO")
  114. //
  115. // Get a pointer to our per-driver extension, make sure it's one of ours.
  116. //
  117. hidDriverExtension = RefDriverExt(DriverObject);
  118. if (hidDriverExtension){
  119. ASSERT(DriverObject == hidDriverExtension->MinidriverObject);
  120. //
  121. // Construct a name for the FDO. The only requirement, really, is
  122. // that it's unique. For now we'll call them "_HIDx", where 'x' is some
  123. // unique number.
  124. //
  125. /*
  126. * PDO name has form "\Device\_HIDx".
  127. */
  128. wPdoName = ALLOCATEPOOL(NonPagedPool, sizeof(L"\\Device\\_HID00000000"));
  129. if (wPdoName){
  130. //
  131. // Get the current value of NextHidId and increment it. Since
  132. // InterlockedIncrement() returns the incremented value, subtract one to
  133. // get the pre-increment value of NextHidId;
  134. //
  135. thisHidId = InterlockedIncrement(&HidpNextHidNumber) - 1;
  136. swprintf(wPdoName, L"\\Device\\_HID%08x", thisHidId);
  137. RtlInitUnicodeString(&uPdoName, wPdoName);
  138. //
  139. // We've got a counted-string version of the device object name. Calculate
  140. // the total size of the device extension and create the FDO.
  141. //
  142. totalExtensionSize = sizeof(HIDCLASS_DEVICE_EXTENSION) +
  143. hidDriverExtension->DeviceExtensionSize;
  144. status = IoCreateDevice( DriverObject, // driver object
  145. totalExtensionSize, // extension size
  146. &uPdoName, // name of the FDO
  147. FILE_DEVICE_UNKNOWN, // what the hell
  148. 0, // DeviceCharacteristics
  149. FALSE, // not exclusive
  150. &functionalDeviceObject );
  151. if (NT_SUCCESS(status)){
  152. DBG_RECORD_DEVOBJ(functionalDeviceObject, "device FDO")
  153. ObReferenceObject(functionalDeviceObject);
  154. ASSERT(DriverObject->DeviceObject == functionalDeviceObject);
  155. ASSERT(functionalDeviceObject->DriverObject == DriverObject);
  156. //
  157. // We've created the device object. Fill in the minidriver's extension
  158. // pointer and attach this FDO to the PDO.
  159. //
  160. hidClassExtension = functionalDeviceObject->DeviceExtension;
  161. RtlZeroMemory(hidClassExtension, totalExtensionSize);
  162. hidClassExtension->isClientPdo = FALSE;
  163. //
  164. // Assign the name of the minidriver's PDO to our FDO.
  165. //
  166. hidClassExtension->fdoExt.name = uPdoName;
  167. //
  168. // The minidriver extension lives in the device extension and starts
  169. // immediately after our HIDCLASS_DEVICE_EXTENSION structure. Note
  170. // that the first structure in the HIDCLASS_DEVICE_EXTENSION is the
  171. // public HID_DEVICE_EXTENSION structure, which is where the pointer
  172. // to the minidriver's per-device extension area lives.
  173. //
  174. miniDeviceExtension = (PVOID)(hidClassExtension + 1);
  175. hidClassExtension->hidExt.MiniDeviceExtension = miniDeviceExtension;
  176. //
  177. // Get a pointer to the physical device object passed in. This device
  178. // object should already have the DO_DEVICE_INITIALIZING flag cleared.
  179. //
  180. ASSERT( (PhysicalDeviceObject->Flags & DO_DEVICE_INITIALIZING) == 0 );
  181. //
  182. // Attach the FDO to the PDO, storing the device object at the top of the
  183. // stack in our device extension.
  184. //
  185. hidClassExtension->hidExt.NextDeviceObject =
  186. IoAttachDeviceToDeviceStack( functionalDeviceObject,
  187. PhysicalDeviceObject );
  188. ASSERT(DriverObject->DeviceObject == functionalDeviceObject);
  189. ASSERT(functionalDeviceObject->DriverObject == DriverObject);
  190. //
  191. // The functional device requires two stack locations: one for the class
  192. // driver, and one for the minidriver.
  193. //
  194. functionalDeviceObject->StackSize++;
  195. //
  196. // We'll need a pointer to the physical device object as well for PnP
  197. // purposes. Note that it's a virtual certainty that NextDeviceObject
  198. // and PhysicalDeviceObject are identical.
  199. //
  200. hidClassExtension->hidExt.PhysicalDeviceObject = PhysicalDeviceObject;
  201. hidClassExtension->Signature = HID_DEVICE_EXTENSION_SIG;
  202. hidClassExtension->fdoExt.fdo = functionalDeviceObject;
  203. hidClassExtension->fdoExt.driverExt = hidDriverExtension;
  204. hidClassExtension->fdoExt.outstandingRequests = 0;
  205. hidClassExtension->fdoExt.openCount = 0;
  206. hidClassExtension->fdoExt.state = DEVICE_STATE_INITIALIZED;
  207. //
  208. // Selective suspend portion.
  209. //
  210. hidClassExtension->fdoExt.idleState = IdleDisabled;
  211. hidClassExtension->fdoExt.idleTimeoutValue = BAD_POINTER;
  212. KeInitializeSpinLock(&hidClassExtension->fdoExt.idleNotificationSpinLock);
  213. KeInitializeEvent(&hidClassExtension->fdoExt.idleDoneEvent, NotificationEvent, TRUE);
  214. hidClassExtension->fdoExt.idleNotificationRequest = BAD_POINTER;
  215. hidClassExtension->fdoExt.idleCallbackInfo.IdleCallback = HidpIdleNotificationCallback;
  216. hidClassExtension->fdoExt.idleCallbackInfo.IdleContext = (PVOID) hidClassExtension;
  217. hidClassExtension->fdoExt.systemPowerState = PowerSystemWorking;
  218. hidClassExtension->fdoExt.devicePowerState = PowerDeviceD0;
  219. hidClassExtension->fdoExt.waitWakeIrp = BAD_POINTER;
  220. KeInitializeSpinLock(&hidClassExtension->fdoExt.waitWakeSpinLock);
  221. hidClassExtension->fdoExt.isWaitWakePending = FALSE;
  222. InitializeListHead(&hidClassExtension->fdoExt.collectionWaitWakeIrpQueue);
  223. KeInitializeSpinLock(&hidClassExtension->fdoExt.collectionWaitWakeIrpQueueSpinLock);
  224. InitializeListHead(&hidClassExtension->fdoExt.collectionPowerDelayedIrpQueue);
  225. KeInitializeSpinLock(&hidClassExtension->fdoExt.collectionPowerDelayedIrpQueueSpinLock);
  226. hidClassExtension->fdoExt.numPendingPowerDelayedIrps = 0;
  227. hidClassExtension->fdoExt.BusNumber = thisHidId;
  228. #if DBG
  229. InitFdoExtDebugInfo(hidClassExtension);
  230. #endif
  231. EnqueueFdoExt(&hidClassExtension->fdoExt);
  232. /*
  233. * Indicate that this device object does direct I/O.
  234. *
  235. * Set the flag that causes the IO subsystem to decrement the device
  236. * object's reference count *before* sending down IRP_MJ_CLOSEs. We
  237. * need this because we delete the device object on the last close.
  238. */
  239. functionalDeviceObject->Flags |= DO_DIRECT_IO;
  240. /*
  241. * The DO_POWER_PAGABLE bit of a device object
  242. * indicates to the kernel that the power-handling
  243. * code of the corresponding driver is pageable, and
  244. * so must be called at IRQL 0.
  245. * As a filter driver, we do not want to change the power
  246. * behavior of the driver stack in any way; therefore,
  247. * we copy this bit from the lower device object.
  248. */
  249. functionalDeviceObject->Flags |= (PhysicalDeviceObject->Flags & DO_POWER_PAGABLE);
  250. /*
  251. * Must clear the initializing flag after initialization complete.
  252. */
  253. functionalDeviceObject->Flags &= ~DO_DEVICE_INITIALIZING;
  254. ReadDeviceFlagsFromRegistry(&hidClassExtension->fdoExt,
  255. PhysicalDeviceObject);
  256. //
  257. // Since we have NOT seen a start device, we CANNOT send any non
  258. // pnp irps to the device yet. We need to do that in the start
  259. // device requests.
  260. //
  261. //
  262. // Call the minidriver to let it do any extension initialization
  263. //
  264. status = hidDriverExtension->AddDevice(DriverObject, functionalDeviceObject);
  265. if (!NT_SUCCESS(status)) {
  266. DequeueFdoExt(&hidClassExtension->fdoExt);
  267. IoDetachDevice(hidClassExtension->hidExt.NextDeviceObject);
  268. ObDereferenceObject(functionalDeviceObject);
  269. IoDeleteDevice(functionalDeviceObject);
  270. ExFreePool( wPdoName );
  271. }
  272. }
  273. else {
  274. TRAP;
  275. ExFreePool( wPdoName );
  276. }
  277. }
  278. else {
  279. TRAP;
  280. status = STATUS_INSUFFICIENT_RESOURCES;
  281. }
  282. if (!NT_SUCCESS(status)){
  283. DerefDriverExt(DriverObject);
  284. }
  285. }
  286. else {
  287. ASSERT(hidDriverExtension);
  288. status = STATUS_DEVICE_CONFIGURATION_ERROR;
  289. }
  290. DBGSUCCESS(status, TRUE)
  291. DBG_COMMON_EXIT()
  292. return status;
  293. }
  294. /*
  295. ********************************************************************************
  296. * HidpDriverUnload
  297. ********************************************************************************
  298. *
  299. *
  300. */
  301. VOID HidpDriverUnload(IN struct _DRIVER_OBJECT *minidriverObject)
  302. {
  303. PHIDCLASS_DRIVER_EXTENSION hidDriverExt;
  304. PAGED_CODE();
  305. DBG_COMMON_ENTRY()
  306. /*
  307. * This extra de-reference will cause our hidDriverExtension's
  308. * reference count to eventually go to -1; at that time, we'll
  309. * dequeue it.
  310. */
  311. hidDriverExt = DerefDriverExt(minidriverObject);
  312. ASSERT(hidDriverExt);
  313. /*
  314. * Chain the unload call to the minidriver.
  315. */
  316. hidDriverExt->DriverUnload(minidriverObject);
  317. DBG_COMMON_EXIT()
  318. }
  319. NTSTATUS GetHIDRawReportDescriptor(FDO_EXTENSION *fdoExt, PIRP irp, ULONG descriptorLen)
  320. {
  321. NTSTATUS status;
  322. if (descriptorLen){
  323. PUCHAR rawReportDescriptor = ALLOCATEPOOL(NonPagedPool, descriptorLen);
  324. if (rawReportDescriptor){
  325. const ULONG retries = 3;
  326. ULONG i;
  327. for (i = 0; i < retries; i++){
  328. PIO_STACK_LOCATION irpSp;
  329. irp->UserBuffer = rawReportDescriptor;
  330. irpSp = IoGetNextIrpStackLocation(irp);
  331. ASSERT(irpSp->Parameters.DeviceIoControl.InputBufferLength == 0);
  332. ASSERT(irpSp->Parameters.DeviceIoControl.Type3InputBuffer == NULL);
  333. irpSp->MajorFunction = IRP_MJ_INTERNAL_DEVICE_CONTROL;
  334. irpSp->Parameters.DeviceIoControl.OutputBufferLength = descriptorLen;
  335. irpSp->Parameters.DeviceIoControl.IoControlCode = IOCTL_HID_GET_REPORT_DESCRIPTOR;
  336. //
  337. // Call the minidriver to get the report descriptor.
  338. //
  339. status = HidpCallDriverSynchronous(fdoExt->fdo, irp);
  340. if (NT_SUCCESS(status)){
  341. if (irp->IoStatus.Information == descriptorLen){
  342. fdoExt->rawReportDescriptionLength = descriptorLen;
  343. fdoExt->rawReportDescription = rawReportDescriptor;
  344. break;
  345. } else {
  346. DBGWARN(("GetHIDRawReportDescriptor (attempt #%d) returned %xh/%xh bytes", i, irp->IoStatus.Information, descriptorLen))
  347. status = STATUS_DEVICE_DATA_ERROR;
  348. }
  349. } else {
  350. DBGWARN(("GetHIDRawReportDescriptor (attempt #%d) failed with status %xh.", i, status))
  351. }
  352. }
  353. if (!NT_SUCCESS(status)){
  354. DBGWARN(("GetHIDRawReportDescriptor failed %d times.", retries))
  355. ExFreePool(rawReportDescriptor);
  356. }
  357. } else {
  358. DBGWARN(("alloc failed in GetHIDRawReportDescriptor"))
  359. status = STATUS_INSUFFICIENT_RESOURCES;
  360. }
  361. }
  362. else {
  363. DBGWARN(("GetHIDRawReportDescriptor: descriptorLen is zero."))
  364. status = STATUS_DEVICE_DATA_ERROR;
  365. }
  366. DBGSUCCESS(status, FALSE)
  367. return status;
  368. }
  369. /*
  370. ********************************************************************************
  371. * HidpGetDeviceDescriptor
  372. ********************************************************************************
  373. *
  374. *
  375. */
  376. NTSTATUS HidpGetDeviceDescriptor(FDO_EXTENSION *fdoExtension)
  377. {
  378. PIRP irp;
  379. PIO_STACK_LOCATION irpSp;
  380. NTSTATUS status;
  381. PHID_DESCRIPTOR hidDescriptor;
  382. ULONG rawReportDescriptorLength;
  383. PAGED_CODE();
  384. /*
  385. * Retrieve:
  386. *
  387. * 1. Device descriptor (fixed portion)
  388. * 2. Device attributes
  389. * 3. Report descriptor
  390. */
  391. hidDescriptor = &fdoExtension->hidDescriptor;
  392. irp = IoAllocateIrp(fdoExtension->fdo->StackSize, FALSE);
  393. if (irp){
  394. irpSp = IoGetNextIrpStackLocation(irp);
  395. irpSp->MajorFunction = IRP_MJ_INTERNAL_DEVICE_CONTROL;
  396. irpSp->Parameters.DeviceIoControl.IoControlCode = IOCTL_HID_GET_DEVICE_DESCRIPTOR;
  397. /*
  398. * This IOCTL uses buffering type METHOD_NEITHER, so
  399. * the buffer is simply passed in irp->UserBuffer.
  400. */
  401. irp->UserBuffer = hidDescriptor;
  402. irpSp->Parameters.DeviceIoControl.OutputBufferLength = sizeof(HID_DESCRIPTOR);
  403. irpSp->Parameters.DeviceIoControl.Type3InputBuffer = NULL;
  404. status = HidpCallDriverSynchronous(fdoExtension->fdo, irp);
  405. DBGASSERT((status == STATUS_SUCCESS),
  406. ("STATUS_SUCCESS not returned, %x returned",status),
  407. TRUE)
  408. if (status == STATUS_SUCCESS){
  409. if (irp->IoStatus.Information == sizeof(HID_DESCRIPTOR)){
  410. irpSp = IoGetNextIrpStackLocation(irp);
  411. ASSERT(irpSp->MajorFunction == IRP_MJ_INTERNAL_DEVICE_CONTROL);
  412. ASSERT(irpSp->Parameters.DeviceIoControl.InputBufferLength == 0);
  413. ASSERT(!irpSp->Parameters.DeviceIoControl.Type3InputBuffer);
  414. irpSp->Parameters.DeviceIoControl.IoControlCode = IOCTL_HID_GET_DEVICE_ATTRIBUTES;
  415. irp->UserBuffer = &fdoExtension->hidDeviceAttributes;
  416. irpSp->Parameters.DeviceIoControl.OutputBufferLength = sizeof(HID_DEVICE_ATTRIBUTES);
  417. status = HidpCallDriverSynchronous(fdoExtension->fdo, irp);
  418. DBGASSERT((status == STATUS_SUCCESS),
  419. ("STATUS_SUCCESS not returned, %x returned",status),
  420. TRUE)
  421. if (NT_SUCCESS (status)) {
  422. ULONG i;
  423. /*
  424. * We've got a hid descriptor, now we need to read the report descriptor.
  425. *
  426. * Find the descriptor describing the report.
  427. */
  428. rawReportDescriptorLength = 0;
  429. for (i = 0; i < hidDescriptor->bNumDescriptors; i++){
  430. if (hidDescriptor->DescriptorList[i].bReportType == HID_REPORT_DESCRIPTOR_TYPE){
  431. rawReportDescriptorLength = (ULONG)hidDescriptor->DescriptorList[i].wReportLength;
  432. break;
  433. }
  434. }
  435. status = GetHIDRawReportDescriptor(fdoExtension, irp, rawReportDescriptorLength);
  436. }
  437. else {
  438. status = STATUS_DEVICE_DATA_ERROR;
  439. }
  440. }
  441. else {
  442. status = STATUS_DEVICE_DATA_ERROR;
  443. }
  444. }
  445. else {
  446. status = STATUS_DEVICE_DATA_ERROR;
  447. }
  448. IoFreeIrp(irp);
  449. }
  450. else {
  451. status = STATUS_INSUFFICIENT_RESOURCES;
  452. }
  453. DBGSUCCESS(status, FALSE)
  454. return status;
  455. }
  456. /*
  457. ********************************************************************************
  458. * HidpCreateSymbolicLink
  459. ********************************************************************************
  460. *
  461. *
  462. */
  463. NTSTATUS HidpCreateSymbolicLink(
  464. IN PDO_EXTENSION *pdoExt,
  465. IN ULONG collectionNum,
  466. IN BOOLEAN Create,
  467. IN PDEVICE_OBJECT Pdo
  468. )
  469. {
  470. NTSTATUS status;
  471. PHIDCLASS_COLLECTION classCollection;
  472. PAGED_CODE();
  473. classCollection = GetHidclassCollection(&pdoExt->deviceFdoExt->fdoExt, collectionNum);
  474. if (classCollection){
  475. //
  476. // We've got a collection. Figure out what it is and create a symbolic
  477. // link for it. For now we assign the "input" guid to all hid devices.
  478. // The reference string is simply the collection number, zero-padded
  479. // to eight digits.
  480. //
  481. if (Create){
  482. /*
  483. * Mark the PDO as initialized
  484. */
  485. Pdo->Flags |= DO_DIRECT_IO;
  486. Pdo->Flags &= ~DO_DEVICE_INITIALIZING;
  487. /*
  488. * Create the symbolic link
  489. */
  490. status = IoRegisterDeviceInterface(
  491. Pdo,
  492. (LPGUID)&GUID_CLASS_INPUT,
  493. NULL,
  494. &classCollection->SymbolicLinkName );
  495. if (NT_SUCCESS(status)){
  496. /*
  497. * Now set the symbolic link for the association and store it..
  498. */
  499. ASSERT(ISPTR(pdoExt->name));
  500. status = IoSetDeviceInterfaceState(&classCollection->SymbolicLinkName, TRUE);
  501. }
  502. }
  503. else {
  504. /*
  505. * Disable the symbolic link
  506. */
  507. if (ISPTR(classCollection->SymbolicLinkName.Buffer)){
  508. status = IoSetDeviceInterfaceState(&classCollection->SymbolicLinkName, FALSE);
  509. ExFreePool( classCollection->SymbolicLinkName.Buffer );
  510. classCollection->SymbolicLinkName.Buffer = BAD_POINTER;
  511. }
  512. else {
  513. status = STATUS_SUCCESS;
  514. }
  515. }
  516. }
  517. else {
  518. status = STATUS_DEVICE_CONFIGURATION_ERROR;
  519. }
  520. DBGSUCCESS(status, TRUE)
  521. return status;
  522. }
  523. /*
  524. ********************************************************************************
  525. * EnqueueInterruptReport
  526. ********************************************************************************
  527. *
  528. *
  529. */
  530. VOID EnqueueInterruptReport(PHIDCLASS_FILE_EXTENSION fileExtension,
  531. PHIDCLASS_REPORT report)
  532. {
  533. PHIDCLASS_REPORT reportToDrop = NULL;
  534. RUNNING_DISPATCH();
  535. /*
  536. * If the queue is full, drop the oldest report.
  537. */
  538. if (fileExtension->CurrentInputReportQueueSize >= fileExtension->MaximumInputReportQueueSize){
  539. PLIST_ENTRY listEntry;
  540. #if DBG
  541. if (fileExtension->dbgNumReportsDroppedSinceLastRead++ == 0){
  542. DBGWARN(("HIDCLASS dropping input reports because report queue (size %xh) is full ...", fileExtension->MaximumInputReportQueueSize))
  543. DBGASSERT((fileExtension->CurrentInputReportQueueSize == fileExtension->MaximumInputReportQueueSize),
  544. ("Current report queue size (%xh) is greater than maximum (%xh)",
  545. fileExtension->CurrentInputReportQueueSize,
  546. fileExtension->MaximumInputReportQueueSize),
  547. FALSE);
  548. }
  549. #endif
  550. ASSERT(!IsListEmpty(&fileExtension->ReportList));
  551. listEntry = RemoveHeadList(&fileExtension->ReportList);
  552. reportToDrop = CONTAINING_RECORD(listEntry, HIDCLASS_REPORT, ListEntry);
  553. fileExtension->CurrentInputReportQueueSize--;
  554. }
  555. /*
  556. * Now queue the current report
  557. */
  558. InsertTailList(&fileExtension->ReportList, &report->ListEntry);
  559. fileExtension->CurrentInputReportQueueSize++;
  560. /*
  561. * We don't have to be running < DPC_LEVEL to release reports since they
  562. * are allocated using NonPagePool.
  563. */
  564. if (reportToDrop){
  565. ExFreePool(reportToDrop);
  566. }
  567. }
  568. /*
  569. ********************************************************************************
  570. * DequeueInterruptReport
  571. ********************************************************************************
  572. *
  573. * Return the next interrupt report in the queue.
  574. * If maxLen is not -1, then only return the report if it is <= maxlen.
  575. */
  576. PHIDCLASS_REPORT DequeueInterruptReport(PHIDCLASS_FILE_EXTENSION fileExtension,
  577. LONG maxLen)
  578. {
  579. PHIDCLASS_REPORT report;
  580. RUNNING_DISPATCH();
  581. if (IsListEmpty(&fileExtension->ReportList)){
  582. report = NULL;
  583. }
  584. else {
  585. PLIST_ENTRY listEntry = RemoveHeadList(&fileExtension->ReportList);
  586. report = CONTAINING_RECORD(listEntry, HIDCLASS_REPORT, ListEntry);
  587. if ((maxLen > 0) && (report->reportLength > (ULONG)maxLen)){
  588. /*
  589. * This report is too big for the caller.
  590. * So put the report back in the queue and return NULL.
  591. */
  592. InsertHeadList(&fileExtension->ReportList, &report->ListEntry);
  593. report = NULL;
  594. }
  595. else {
  596. InitializeListHead(&report->ListEntry);
  597. ASSERT(fileExtension->CurrentInputReportQueueSize > 0);
  598. fileExtension->CurrentInputReportQueueSize--;
  599. #if DBG
  600. if (fileExtension->dbgNumReportsDroppedSinceLastRead > 0){
  601. DBGWARN(("... successful read(/flush) after %d reports were dropped.", fileExtension->dbgNumReportsDroppedSinceLastRead));
  602. fileExtension->dbgNumReportsDroppedSinceLastRead = 0;
  603. }
  604. #endif
  605. }
  606. }
  607. return report;
  608. }
  609. /*
  610. ********************************************************************************
  611. * HidpDestroyFileExtension
  612. ********************************************************************************
  613. *
  614. *
  615. */
  616. VOID HidpDestroyFileExtension(PHIDCLASS_COLLECTION collection, PHIDCLASS_FILE_EXTENSION FileExtension)
  617. {
  618. PFILE_OBJECT fileObject;
  619. //
  620. // Flush all of the pending reports on the file extension
  621. //
  622. HidpFlushReportQueue(FileExtension);
  623. /*
  624. * Fail all the pending reads
  625. * (it would be nice if apps always cancelled all their reads
  626. * before closing the device, but this is not always the case).
  627. */
  628. CompleteAllPendingReadsForFileExtension(collection, FileExtension);
  629. //
  630. // Indicate in the file object that this file extension has gone away.
  631. //
  632. fileObject = FileExtension->FileObject;
  633. #if DBG
  634. fileObject->FsContext = NULL;
  635. #endif
  636. //
  637. // Free our extension
  638. //
  639. #if DBG
  640. FileExtension->Signature = ~HIDCLASS_FILE_EXTENSION_SIG;
  641. #endif
  642. ExFreePool( FileExtension );
  643. }
  644. /*
  645. ********************************************************************************
  646. * HidpFlushReportQueue
  647. ********************************************************************************
  648. *
  649. *
  650. */
  651. VOID HidpFlushReportQueue(IN PHIDCLASS_FILE_EXTENSION fileExtension)
  652. {
  653. PHIDCLASS_REPORT report;
  654. KIRQL oldIrql;
  655. LockFileExtension(fileExtension, &oldIrql);
  656. while (report = DequeueInterruptReport(fileExtension, -1)){
  657. //
  658. // Ok to call this at DISPATCH_LEVEL, since report is NonPagedPool
  659. //
  660. ExFreePool(report);
  661. }
  662. UnlockFileExtension(fileExtension, oldIrql);
  663. }
  664. /*
  665. ********************************************************************************
  666. * HidpGetCollectionInformation
  667. ********************************************************************************
  668. *
  669. *
  670. */
  671. NTSTATUS HidpGetCollectionInformation(
  672. IN FDO_EXTENSION *fdoExtension,
  673. IN ULONG collectionNumber,
  674. IN PVOID Buffer,
  675. IN OUT PULONG BufferSize
  676. )
  677. {
  678. HID_COLLECTION_INFORMATION hidCollectionInfo;
  679. PHIDP_COLLECTION_DESC hidCollectionDesc;
  680. ULONG bytesToCopy;
  681. NTSTATUS status;
  682. /*
  683. * Get a pointer to the appropriate collection descriptor.
  684. */
  685. hidCollectionDesc = GetCollectionDesc(fdoExtension, collectionNumber);
  686. if (hidCollectionDesc){
  687. //
  688. // Fill in hidCollectionInfo
  689. //
  690. hidCollectionInfo.DescriptorSize = hidCollectionDesc->PreparsedDataLength;
  691. hidCollectionInfo.Polled = fdoExtension->driverExt->DevicesArePolled;
  692. hidCollectionInfo.VendorID = fdoExtension->hidDeviceAttributes.VendorID;
  693. hidCollectionInfo.ProductID = fdoExtension->hidDeviceAttributes.ProductID;
  694. hidCollectionInfo.VersionNumber = fdoExtension->hidDeviceAttributes.VersionNumber;
  695. //
  696. // Copy as much of hidCollectionInfo as will fit in the output buffer.
  697. //
  698. if (*BufferSize < sizeof( HID_COLLECTION_INFORMATION)){
  699. /*
  700. * The user's buffer is not big enough.
  701. * We'll return the size that the buffer needs to be.
  702. * Must return this with a real error code (not a warning)
  703. * so that IO post-processing does not copy into (and past)
  704. * the user's buffer.
  705. */
  706. bytesToCopy = *BufferSize;
  707. status = STATUS_INVALID_BUFFER_SIZE;
  708. }
  709. else {
  710. bytesToCopy = sizeof( HID_COLLECTION_INFORMATION );
  711. status = STATUS_SUCCESS;
  712. }
  713. RtlCopyMemory(Buffer, &hidCollectionInfo, bytesToCopy);
  714. *BufferSize = sizeof (HID_COLLECTION_INFORMATION);
  715. }
  716. else {
  717. status = STATUS_DATA_ERROR;
  718. }
  719. DBGSUCCESS(status, TRUE)
  720. return status;
  721. }
  722. /*
  723. ********************************************************************************
  724. * HidpGetCollectionDescriptor
  725. ********************************************************************************
  726. *
  727. *
  728. */
  729. NTSTATUS HidpGetCollectionDescriptor( IN FDO_EXTENSION *fdoExtension,
  730. IN ULONG collectionId,
  731. IN PVOID Buffer,
  732. IN OUT PULONG BufferSize)
  733. {
  734. PHIDP_COLLECTION_DESC hidCollectionDesc;
  735. ULONG bytesToCopy;
  736. NTSTATUS status;
  737. hidCollectionDesc = GetCollectionDesc(fdoExtension, collectionId);
  738. if (hidCollectionDesc){
  739. /*
  740. * Copy as much of the preparsed data as will fit in the output buffer.
  741. */
  742. if (*BufferSize < hidCollectionDesc->PreparsedDataLength){
  743. /*
  744. * The user's buffer is not big enough for all the
  745. * preparsed data.
  746. * We'll return the size that the buffer needs to be.
  747. * Must return this with a real error code (not a warning)
  748. * so that IO post-processing does not copy into (and past)
  749. * the user's buffer.
  750. */
  751. bytesToCopy = *BufferSize;
  752. status = STATUS_INVALID_BUFFER_SIZE;
  753. }
  754. else {
  755. bytesToCopy = hidCollectionDesc->PreparsedDataLength;
  756. status = STATUS_SUCCESS;
  757. }
  758. RtlCopyMemory(Buffer, hidCollectionDesc->PreparsedData, bytesToCopy);
  759. *BufferSize = hidCollectionDesc->PreparsedDataLength;
  760. }
  761. else {
  762. status = STATUS_DATA_ERROR;
  763. }
  764. DBGSUCCESS(status, TRUE)
  765. return status;
  766. }
  767. /*
  768. ********************************************************************************
  769. * GetReportIdentifier
  770. ********************************************************************************
  771. *
  772. *
  773. */
  774. PHIDP_REPORT_IDS GetReportIdentifier(FDO_EXTENSION *fdoExtension, ULONG reportId)
  775. {
  776. PHIDP_REPORT_IDS result = NULL;
  777. PHIDP_DEVICE_DESC deviceDesc = &fdoExtension->deviceDesc;
  778. ULONG i;
  779. if (deviceDesc->ReportIDs){
  780. for (i = 0; i < deviceDesc->ReportIDsLength; i++){
  781. if (deviceDesc->ReportIDs[i].ReportID == reportId){
  782. result = &deviceDesc->ReportIDs[i];
  783. break;
  784. }
  785. }
  786. }
  787. if (fdoExtension->deviceSpecificFlags & DEVICE_FLAG_ALLOW_FEATURE_ON_NON_FEATURE_COLLECTION){
  788. /*
  789. * This call from HidpGetSetFeature can fail because we allow
  790. * feature access on non-feature collections.
  791. */
  792. }
  793. else {
  794. DBGASSERT(result, ("Bogus report identifier requested %d", reportId), FALSE)
  795. }
  796. return result;
  797. }
  798. /*
  799. ********************************************************************************
  800. * GetCollectionDesc
  801. ********************************************************************************
  802. *
  803. *
  804. */
  805. PHIDP_COLLECTION_DESC GetCollectionDesc(FDO_EXTENSION *fdoExtension, ULONG collectionId)
  806. {
  807. PHIDP_COLLECTION_DESC result = NULL;
  808. PHIDP_DEVICE_DESC deviceDesc = &fdoExtension->deviceDesc;
  809. ULONG i;
  810. if (deviceDesc->CollectionDesc){
  811. for (i = 0; i < deviceDesc->CollectionDescLength; i++){
  812. if (deviceDesc->CollectionDesc[i].CollectionNumber == collectionId){
  813. result = &deviceDesc->CollectionDesc[i];
  814. break;
  815. }
  816. }
  817. }
  818. ASSERT(result);
  819. return result;
  820. }
  821. /*
  822. ********************************************************************************
  823. * GetHidclassCollection
  824. ********************************************************************************
  825. *
  826. */
  827. PHIDCLASS_COLLECTION GetHidclassCollection(FDO_EXTENSION *fdoExtension, ULONG collectionId)
  828. {
  829. PHIDCLASS_COLLECTION result = NULL;
  830. PHIDP_DEVICE_DESC deviceDesc = &fdoExtension->deviceDesc;
  831. ULONG i;
  832. if (ISPTR(fdoExtension->classCollectionArray)){
  833. for (i = 0; i < deviceDesc->CollectionDescLength; i++){
  834. if (fdoExtension->classCollectionArray[i].CollectionNumber == collectionId){
  835. result = &fdoExtension->classCollectionArray[i];
  836. break;
  837. }
  838. }
  839. }
  840. return result;
  841. }
  842. /*
  843. ********************************************************************************
  844. * MakeClientPDOName
  845. ********************************************************************************
  846. *
  847. *
  848. */
  849. PUNICODE_STRING MakeClientPDOName(PUNICODE_STRING fdoName, ULONG collectionId)
  850. {
  851. PUNICODE_STRING uPdoName;
  852. PAGED_CODE();
  853. uPdoName = (PUNICODE_STRING)ALLOCATEPOOL(NonPagedPool, sizeof(UNICODE_STRING));
  854. if (uPdoName){
  855. PWSTR wPdoName;
  856. wPdoName = (PWSTR)ALLOCATEPOOL(
  857. PagedPool,
  858. fdoName->Length+sizeof(L"#COLLECTION0000000x"));
  859. if (wPdoName){
  860. swprintf(wPdoName, L"%s#COLLECTION%08x", fdoName->Buffer, collectionId);
  861. RtlInitUnicodeString(uPdoName, wPdoName);
  862. }
  863. else {
  864. ExFreePool(uPdoName);
  865. uPdoName = NULL;
  866. }
  867. }
  868. return uPdoName;
  869. }
  870. /*
  871. ********************************************************************************
  872. * HidpCreateClientPDOs
  873. ********************************************************************************
  874. *
  875. *
  876. */
  877. NTSTATUS HidpCreateClientPDOs(PHIDCLASS_DEVICE_EXTENSION hidClassExtension)
  878. {
  879. NTSTATUS ntStatus = STATUS_SUCCESS;
  880. PHIDCLASS_DRIVER_EXTENSION hidDriverExtension;
  881. FDO_EXTENSION *fdoExt;
  882. PAGED_CODE();
  883. ASSERT(!hidClassExtension->isClientPdo);
  884. fdoExt = &hidClassExtension->fdoExt;
  885. hidDriverExtension = RefDriverExt(fdoExt->driverExt->MinidriverObject);
  886. if (hidDriverExtension){
  887. /*
  888. * We will create one PDO for each collection on this device.
  889. */
  890. ULONG numPDOs = fdoExt->deviceDesc.CollectionDescLength;
  891. if (numPDOs){
  892. fdoExt->deviceRelations = (PDEVICE_RELATIONS)
  893. ALLOCATEPOOL(NonPagedPool, sizeof(DEVICE_RELATIONS) + (numPDOs*sizeof(PDEVICE_OBJECT)));
  894. if (fdoExt->deviceRelations){
  895. fdoExt->collectionPdoExtensions =
  896. ALLOCATEPOOL(NonPagedPool, numPDOs*sizeof(PHIDCLASS_DEVICE_EXTENSION));
  897. if (fdoExt->collectionPdoExtensions){
  898. ULONG i;
  899. fdoExt->deviceRelations->Count = numPDOs;
  900. for (i = 0; i < numPDOs; i++){
  901. PUNICODE_STRING uPdoName;
  902. ULONG totalExtensionSize;
  903. ULONG collectionNum = fdoExt->deviceDesc.CollectionDesc[i].CollectionNumber;
  904. PDEVICE_OBJECT newClientPdo;
  905. /*
  906. * Construct a name for the PDO we're about to create.
  907. */
  908. uPdoName = MakeClientPDOName(&fdoExt->name, collectionNum);
  909. if (uPdoName){
  910. /*
  911. * We use the same device extension for the client PDOs as for our FDO.
  912. */
  913. totalExtensionSize = sizeof(HIDCLASS_DEVICE_EXTENSION) +
  914. hidDriverExtension->DeviceExtensionSize;
  915. /*
  916. * Create a PDO to represent this collection.
  917. * Since hidclass is not a real driver, it does not have a driver object;
  918. * so just use the minidriver's driver object.
  919. *
  920. * NOTE - newClientPdo->NextDevice will point to this minidriver's NextDevice
  921. */
  922. ntStatus = IoCreateDevice( hidDriverExtension->MinidriverObject, // driver object
  923. totalExtensionSize, // extension size
  924. uPdoName, // name of the PDO
  925. FILE_DEVICE_UNKNOWN, // Device type
  926. 0, // DeviceCharacteristics
  927. FALSE, // not exclusive
  928. &newClientPdo);
  929. if (NT_SUCCESS(ntStatus)){
  930. PHIDCLASS_DEVICE_EXTENSION clientPdoExtension = newClientPdo->DeviceExtension;
  931. USHORT usagePage = fdoExt->deviceDesc.CollectionDesc[i].UsagePage;
  932. USHORT usage = fdoExt->deviceDesc.CollectionDesc[i].Usage;
  933. DBG_RECORD_DEVOBJ(newClientPdo, "cltn PDO")
  934. ObReferenceObject(newClientPdo);
  935. /*
  936. * We may pass Irps from the upper stack to the lower stack,
  937. * so make sure there are enough stack locations for the IRPs
  938. * we pass down.
  939. */
  940. newClientPdo->StackSize = fdoExt->fdo->StackSize+1;
  941. /*
  942. * Initialize the PDO's extension
  943. */
  944. RtlZeroMemory(clientPdoExtension, totalExtensionSize);
  945. clientPdoExtension->hidExt = hidClassExtension->hidExt;
  946. clientPdoExtension->isClientPdo = TRUE;
  947. clientPdoExtension->Signature = HID_DEVICE_EXTENSION_SIG;
  948. clientPdoExtension->pdoExt.collectionNum = collectionNum;
  949. clientPdoExtension->pdoExt.collectionIndex = i;
  950. clientPdoExtension->pdoExt.pdo = newClientPdo;
  951. clientPdoExtension->pdoExt.state = COLLECTION_STATE_UNINITIALIZED;
  952. clientPdoExtension->pdoExt.deviceFdoExt = hidClassExtension;
  953. clientPdoExtension->pdoExt.StatusChangeFn = BAD_POINTER;
  954. clientPdoExtension->pdoExt.name = uPdoName;
  955. clientPdoExtension->pdoExt.devicePowerState = PowerDeviceD0;
  956. clientPdoExtension->pdoExt.systemPowerState = fdoExt->systemPowerState;
  957. clientPdoExtension->pdoExt.MouseOrKeyboard =
  958. ((usagePage == HID_USAGE_PAGE_GENERIC) &&
  959. ((usage == HID_USAGE_GENERIC_POINTER) ||
  960. (usage == HID_USAGE_GENERIC_MOUSE) ||
  961. (usage == HID_USAGE_GENERIC_KEYBOARD) ||
  962. (usage == HID_USAGE_GENERIC_KEYPAD)));
  963. IoInitializeRemoveLock (&clientPdoExtension->pdoExt.removeLock, HIDCLASS_POOL_TAG, 0, 10);
  964. KeInitializeSpinLock (&clientPdoExtension->pdoExt.remoteWakeSpinLock);
  965. clientPdoExtension->pdoExt.remoteWakeIrp = NULL;
  966. /*
  967. * Store a pointer to the new PDO in the FDO extension's deviceRelations array.
  968. */
  969. fdoExt->deviceRelations->Objects[i] = newClientPdo;
  970. /*
  971. * Store a pointer to the PDO's extension.
  972. */
  973. fdoExt->collectionPdoExtensions[i] = clientPdoExtension;
  974. newClientPdo->Flags |= DO_POWER_PAGABLE;
  975. newClientPdo->Flags &= ~DO_DEVICE_INITIALIZING;
  976. }
  977. else {
  978. break;
  979. }
  980. }
  981. else {
  982. ntStatus = STATUS_NO_MEMORY;
  983. }
  984. }
  985. if (!NT_SUCCESS(ntStatus)){
  986. ExFreePool(fdoExt->collectionPdoExtensions);
  987. fdoExt->collectionPdoExtensions = BAD_POINTER;
  988. }
  989. }
  990. else {
  991. ntStatus = STATUS_NO_MEMORY;
  992. }
  993. if (!NT_SUCCESS(ntStatus)){
  994. ExFreePool(fdoExt->deviceRelations);
  995. fdoExt->deviceRelations = BAD_POINTER;
  996. }
  997. }
  998. else {
  999. ntStatus = STATUS_NO_MEMORY;
  1000. }
  1001. }
  1002. else {
  1003. ASSERT(numPDOs);
  1004. ntStatus = STATUS_DEVICE_CONFIGURATION_ERROR;
  1005. }
  1006. DerefDriverExt(fdoExt->driverExt->MinidriverObject);
  1007. }
  1008. else {
  1009. ASSERT(hidDriverExtension);
  1010. ntStatus = STATUS_DEVICE_CONFIGURATION_ERROR;
  1011. }
  1012. DBGSUCCESS(ntStatus, TRUE)
  1013. return ntStatus;
  1014. }
  1015. /*
  1016. ********************************************************************************
  1017. * MemDup
  1018. ********************************************************************************
  1019. *
  1020. * Return a fresh copy of the argument.
  1021. *
  1022. */
  1023. PVOID MemDup(POOL_TYPE PoolType, PVOID dataPtr, ULONG length)
  1024. {
  1025. PVOID newPtr;
  1026. newPtr = (PVOID)ALLOCATEPOOL(PoolType, length);
  1027. if (newPtr){
  1028. RtlCopyMemory(newPtr, dataPtr, length);
  1029. }
  1030. ASSERT(newPtr);
  1031. return newPtr;
  1032. }
  1033. /*
  1034. ********************************************************************************
  1035. * WStrLen
  1036. ********************************************************************************
  1037. *
  1038. */
  1039. ULONG WStrLen(PWCHAR str)
  1040. {
  1041. ULONG result = 0;
  1042. while (*str++ != UNICODE_NULL){
  1043. result++;
  1044. }
  1045. return result;
  1046. }
  1047. /*
  1048. ********************************************************************************
  1049. * WStrCpy
  1050. ********************************************************************************
  1051. *
  1052. */
  1053. ULONG WStrCpy(PWCHAR dest, PWCHAR src)
  1054. {
  1055. ULONG result = 0;
  1056. while (*dest++ = *src++){
  1057. result++;
  1058. }
  1059. return result;
  1060. }
  1061. BOOLEAN WStrCompareN(PWCHAR str1, PWCHAR str2, ULONG maxChars)
  1062. {
  1063. while ((maxChars > 0) && *str1 && (*str1 == *str2)){
  1064. maxChars--;
  1065. str1++;
  1066. str2++;
  1067. }
  1068. return (BOOLEAN)((maxChars == 0) || (!*str1 && !*str2));
  1069. }
  1070. /*
  1071. ********************************************************************************
  1072. * HidpNumberToString
  1073. ********************************************************************************
  1074. *
  1075. */
  1076. void HidpNumberToString(PWCHAR String, USHORT Number, USHORT stringLen)
  1077. {
  1078. const static WCHAR map[] = L"0123456789ABCDEF";
  1079. LONG i = 0;
  1080. ULONG nibble = 0;
  1081. ASSERT(stringLen);
  1082. for (i = stringLen-1; i >= 0; i--) {
  1083. String[i] = map[Number & 0x0F];
  1084. Number >>= 4;
  1085. }
  1086. }
  1087. /*
  1088. ********************************************************************************
  1089. * CopyDeviceRelations
  1090. ********************************************************************************
  1091. *
  1092. *
  1093. */
  1094. PDEVICE_RELATIONS CopyDeviceRelations(PDEVICE_RELATIONS deviceRelations)
  1095. {
  1096. PDEVICE_RELATIONS newDeviceRelations;
  1097. if (deviceRelations){
  1098. ULONG size = sizeof(DEVICE_RELATIONS) + (deviceRelations->Count*sizeof(PDEVICE_OBJECT));
  1099. newDeviceRelations = MemDup(PagedPool, deviceRelations, size);
  1100. }
  1101. else {
  1102. newDeviceRelations = NULL;
  1103. }
  1104. return newDeviceRelations;
  1105. }
  1106. /*
  1107. ********************************************************************************
  1108. * HidpQueryDeviceRelations
  1109. ********************************************************************************
  1110. *
  1111. *
  1112. */
  1113. NTSTATUS HidpQueryDeviceRelations(IN PHIDCLASS_DEVICE_EXTENSION hidClassExtension, IN OUT PIRP Irp)
  1114. {
  1115. PIO_STACK_LOCATION ioStack;
  1116. NTSTATUS ntStatus = STATUS_SUCCESS;
  1117. PAGED_CODE();
  1118. ASSERT(!hidClassExtension->isClientPdo);
  1119. ioStack = IoGetCurrentIrpStackLocation(Irp);
  1120. if (ioStack->Parameters.QueryDeviceRelations.Type == BusRelations) {
  1121. if (hidClassExtension->fdoExt.deviceRelations){
  1122. /*
  1123. * Don't call HidpCreateClientPDOs again if it's
  1124. * already been called for this device.
  1125. */
  1126. ntStatus = STATUS_SUCCESS;
  1127. }
  1128. else {
  1129. ntStatus = HidpCreateClientPDOs(hidClassExtension);
  1130. }
  1131. if (NT_SUCCESS(ntStatus)){
  1132. ULONG i;
  1133. /*
  1134. * NTKERN expects a new pointer each time it calls QUERY_DEVICE_RELATIONS;
  1135. * it then FREES THE POINTER.
  1136. * So we have to return a new pointer each time, whether or not we actually
  1137. * created our copy of the device relations for this call.
  1138. */
  1139. Irp->IoStatus.Information = (ULONG_PTR)CopyDeviceRelations(hidClassExtension->fdoExt.deviceRelations);
  1140. if (Irp->IoStatus.Information){
  1141. /*
  1142. * PnP dereferences each device object
  1143. * in the device relations list after each call.
  1144. * So for each call, add an extra reference.
  1145. */
  1146. for (i = 0; i < hidClassExtension->fdoExt.deviceRelations->Count; i++){
  1147. ObReferenceObject(hidClassExtension->fdoExt.deviceRelations->Objects[i]);
  1148. hidClassExtension->fdoExt.deviceRelations->Objects[i]->Flags &= ~DO_DEVICE_INITIALIZING;
  1149. }
  1150. }
  1151. else {
  1152. ntStatus = STATUS_INSUFFICIENT_RESOURCES;
  1153. }
  1154. }
  1155. DBGSUCCESS(ntStatus, TRUE)
  1156. }
  1157. else {
  1158. /*
  1159. * We don't support this option, so just maintain
  1160. * the current status (do not return STATUS_NOT_SUPPORTED).
  1161. */
  1162. ntStatus = Irp->IoStatus.Status;
  1163. }
  1164. return ntStatus;
  1165. }
  1166. /*
  1167. ********************************************************************************
  1168. * HidpQueryCollectionCapabilities
  1169. ********************************************************************************
  1170. *
  1171. *
  1172. */
  1173. NTSTATUS HidpQueryCollectionCapabilities( PDO_EXTENSION *pdoExt,
  1174. IN OUT PIRP Irp)
  1175. {
  1176. PDEVICE_CAPABILITIES deviceCapabilities;
  1177. PIO_STACK_LOCATION ioStack;
  1178. FDO_EXTENSION *fdoExt;
  1179. NTSTATUS status;
  1180. PAGED_CODE();
  1181. ASSERT(pdoExt->deviceFdoExt->Signature == HID_DEVICE_EXTENSION_SIG);
  1182. fdoExt = &pdoExt->deviceFdoExt->fdoExt;
  1183. ioStack = IoGetCurrentIrpStackLocation(Irp);
  1184. deviceCapabilities = ioStack->Parameters.DeviceCapabilities.Capabilities;
  1185. if (deviceCapabilities){
  1186. /*
  1187. * Set all fields for the collection-PDO as for the device-FDO
  1188. * by default.
  1189. */
  1190. *deviceCapabilities = fdoExt->deviceCapabilities;
  1191. /*
  1192. * Now override the fields we care about.
  1193. */
  1194. deviceCapabilities->LockSupported = FALSE;
  1195. deviceCapabilities->EjectSupported = FALSE;
  1196. deviceCapabilities->Removable = FALSE;
  1197. deviceCapabilities->DockDevice = FALSE;
  1198. deviceCapabilities->UniqueID = FALSE;
  1199. deviceCapabilities->SilentInstall = TRUE;
  1200. /*
  1201. * This field is very important;
  1202. * it causes HIDCLASS to get the START_DEVICE IRP immediately,
  1203. * if the device is not a keyboard or mouse.
  1204. */
  1205. deviceCapabilities->RawDeviceOK = !pdoExt->MouseOrKeyboard;
  1206. /*
  1207. * This bit indicates that the device may be removed on NT
  1208. * without running the 'hot-unplug' utility.
  1209. */
  1210. deviceCapabilities->SurpriseRemovalOK = TRUE;
  1211. DBGVERBOSE(("WAKE info: sysWake=%d devWake=%d; wake from D0=%d D1=%d D2=%d D3=%d.",
  1212. deviceCapabilities->SystemWake,
  1213. deviceCapabilities->DeviceWake,
  1214. (ULONG)deviceCapabilities->WakeFromD0,
  1215. (ULONG)deviceCapabilities->WakeFromD1,
  1216. (ULONG)deviceCapabilities->WakeFromD2,
  1217. (ULONG)deviceCapabilities->WakeFromD3))
  1218. status = STATUS_SUCCESS;
  1219. }
  1220. else {
  1221. status = STATUS_DEVICE_CONFIGURATION_ERROR;
  1222. }
  1223. Irp->IoStatus.Information = (ULONG_PTR)deviceCapabilities;
  1224. DBGSUCCESS(status, TRUE)
  1225. return status;
  1226. }
  1227. /*
  1228. ********************************************************************************
  1229. * BuildCompatibleID
  1230. ********************************************************************************
  1231. *
  1232. * Return a multi-string consisting of compatibility id's for this device
  1233. * in increasingly generic order (ending with HID_GENERIC_DEVICE).
  1234. *
  1235. * author: kenray
  1236. *
  1237. */
  1238. PWSTR BuildCompatibleID(PHIDCLASS_DEVICE_EXTENSION hidClassExtension)
  1239. {
  1240. USHORT usage, usagePage;
  1241. ULONG spLength;
  1242. ULONG totLength;
  1243. ULONG i;
  1244. PWSTR specificId = NULL;
  1245. PWSTR compatIdList;
  1246. PWSTR genericId;
  1247. FDO_EXTENSION *fdoExt;
  1248. PAGED_CODE();
  1249. ASSERT(hidClassExtension->isClientPdo);
  1250. fdoExt = &hidClassExtension->pdoExt.deviceFdoExt->fdoExt;
  1251. ASSERT(ISPTR(fdoExt->deviceDesc.CollectionDesc));
  1252. i = hidClassExtension->pdoExt.collectionIndex;
  1253. usagePage = fdoExt->deviceDesc.CollectionDesc[i].UsagePage;
  1254. usage = fdoExt->deviceDesc.CollectionDesc[i].Usage;
  1255. switch (usagePage) {
  1256. case HID_USAGE_PAGE_GENERIC:
  1257. switch (usage) {
  1258. case HID_USAGE_GENERIC_POINTER:
  1259. case HID_USAGE_GENERIC_MOUSE:
  1260. specificId = HIDCLASS_SYSTEM_MOUSE;
  1261. break;
  1262. case HID_USAGE_GENERIC_KEYBOARD:
  1263. case HID_USAGE_GENERIC_KEYPAD:
  1264. specificId = HIDCLASS_SYSTEM_KEYBOARD;
  1265. break;
  1266. case HID_USAGE_GENERIC_JOYSTICK:
  1267. case HID_USAGE_GENERIC_GAMEPAD:
  1268. specificId = HIDCLASS_SYSTEM_GAMING_DEVICE;
  1269. break;
  1270. case HID_USAGE_GENERIC_SYSTEM_CTL:
  1271. specificId = HIDCLASS_SYSTEM_CONTROL;
  1272. break;
  1273. }
  1274. break;
  1275. case HID_USAGE_PAGE_CONSUMER:
  1276. specificId = HIDCLASS_SYSTEM_CONSUMER_DEVICE;
  1277. break;
  1278. default:
  1279. break;
  1280. }
  1281. spLength = (specificId) ? (WStrLen(specificId)+1) : 0;
  1282. totLength = spLength +
  1283. HIDCLASS_COMPATIBLE_ID_GENERIC_LENGTH +
  1284. HIDCLASS_COMPATIBLE_ID_STANDARD_LENGTH +
  1285. 1;
  1286. compatIdList = ALLOCATEPOOL(NonPagedPool, totLength * sizeof(WCHAR));
  1287. if (compatIdList) {
  1288. RtlZeroMemory (compatIdList, totLength * sizeof(WCHAR));
  1289. if (specificId) {
  1290. RtlCopyMemory (compatIdList, specificId, spLength * sizeof (WCHAR));
  1291. }
  1292. genericId = compatIdList + spLength;
  1293. totLength = HIDCLASS_COMPATIBLE_ID_GENERIC_LENGTH;
  1294. RtlCopyMemory (genericId,
  1295. HIDCLASS_COMPATIBLE_ID_GENERIC_NAME,
  1296. totLength*sizeof(WCHAR));
  1297. HidpNumberToString (genericId + HIDCLASS_COMPATIBLE_ID_PAGE_OFFSET,
  1298. usagePage,
  1299. 4);
  1300. HidpNumberToString (genericId + HIDCLASS_COMPATIBLE_ID_USAGE_OFFSET,
  1301. usage,
  1302. 4);
  1303. RtlCopyMemory (genericId + totLength,
  1304. HIDCLASS_COMPATIBLE_ID_STANDARD_NAME,
  1305. HIDCLASS_COMPATIBLE_ID_STANDARD_LENGTH * sizeof (WCHAR));
  1306. }
  1307. return compatIdList;
  1308. }
  1309. /*
  1310. ********************************************************************************
  1311. * SubstituteBusNames
  1312. ********************************************************************************
  1313. *
  1314. * oldIDs is a multi-String of hardware IDs.
  1315. *
  1316. * 1. Return a new string with each "<busName>\" prefix replaced by "HID\".
  1317. *
  1318. * 2. If the device has multiple collections, append "&Colxx" to each id.
  1319. *
  1320. */
  1321. PWCHAR SubstituteBusNames(PWCHAR oldIDs, FDO_EXTENSION *fdoExt, PDO_EXTENSION *pdoExt)
  1322. {
  1323. ULONG newIdLen;
  1324. PWCHAR id, newIDs;
  1325. ULONG numCollections;
  1326. WCHAR colNumStr[] = L"&Colxx";
  1327. PAGED_CODE();
  1328. numCollections = fdoExt->deviceDesc.CollectionDescLength;
  1329. ASSERT(numCollections > 0);
  1330. for (id = oldIDs, newIdLen = 0; *id; ){
  1331. ULONG thisIdLen = WStrLen(id);
  1332. /*
  1333. * This is a little sloppy because we're actually going to chop
  1334. * off the other bus name; but better this than walking each string.
  1335. */
  1336. newIdLen += thisIdLen + 1 + sizeof("HID\\");
  1337. if (numCollections > 1){
  1338. newIdLen += sizeof(colNumStr)/sizeof(WCHAR);
  1339. }
  1340. id += thisIdLen + 1;
  1341. }
  1342. /*
  1343. * Add one for the extra NULL at the end of the multi-string.
  1344. */
  1345. newIdLen++;
  1346. newIDs = ALLOCATEPOOL(NonPagedPool, newIdLen*sizeof(WCHAR));
  1347. if (newIDs){
  1348. ULONG oldIdOff, newIdOff;
  1349. /*
  1350. * Copy each string in the multi-string, replacing the bus name.
  1351. */
  1352. for (oldIdOff = newIdOff = 0; oldIDs[oldIdOff]; ){
  1353. ULONG thisIdLen = WStrLen(oldIDs+oldIdOff);
  1354. ULONG devIdOff;
  1355. /*
  1356. * Copy the new bus name to the new string.
  1357. */
  1358. newIdOff += WStrCpy(newIDs+newIdOff, L"HID\\");
  1359. /*
  1360. * Go past the old bus name in the old string.
  1361. */
  1362. for (devIdOff = 0; oldIDs[oldIdOff+devIdOff]; devIdOff++){
  1363. if (oldIDs[oldIdOff+devIdOff] == L'\\'){
  1364. break;
  1365. }
  1366. }
  1367. /*
  1368. * Copy the rest of this device id.
  1369. */
  1370. if (oldIDs[oldIdOff+devIdOff] == L'\\'){
  1371. devIdOff++;
  1372. }
  1373. else {
  1374. /*
  1375. * Strange -- no bus name in hardware id.
  1376. * Just copy the entire id.
  1377. */
  1378. devIdOff = 0;
  1379. }
  1380. newIdOff += WStrCpy(newIDs+newIdOff, oldIDs+oldIdOff+devIdOff);
  1381. if (numCollections > 1){
  1382. /*
  1383. * If there is more than one collection,
  1384. * then also append the collection number.
  1385. */
  1386. HidpNumberToString(colNumStr+4, (USHORT)pdoExt->collectionNum, 2);
  1387. newIdOff += WStrCpy(newIDs+newIdOff, colNumStr);
  1388. }
  1389. /*
  1390. * Go past the single string terminator.
  1391. */
  1392. newIdOff++;
  1393. oldIdOff += thisIdLen + 1;
  1394. }
  1395. /*
  1396. * Add extra NULL to terminate multi-string.
  1397. */
  1398. newIDs[newIdOff] = UNICODE_NULL;
  1399. }
  1400. return newIDs;
  1401. }
  1402. NTSTATUS
  1403. HidpQueryInterface(
  1404. IN PHIDCLASS_DEVICE_EXTENSION hidClassExtension,
  1405. IN OUT PIRP Irp
  1406. )
  1407. {
  1408. PIO_STACK_LOCATION irpSp;
  1409. PAGED_CODE();
  1410. ASSERT(hidClassExtension->isClientPdo);
  1411. irpSp = IoGetCurrentIrpStackLocation(Irp);
  1412. if (RtlEqualMemory(irpSp->Parameters.QueryInterface.InterfaceType,
  1413. &GUID_HID_INTERFACE_NOTIFY,
  1414. sizeof(GUID))) {
  1415. PDO_EXTENSION *pdoExt;
  1416. PHID_INTERFACE_NOTIFY_PNP notify;
  1417. notify = (PHID_INTERFACE_NOTIFY_PNP) irpSp->Parameters.QueryInterface.Interface;
  1418. if (notify->Size != sizeof(HID_INTERFACE_NOTIFY_PNP) ||
  1419. notify->Version < 1 ||
  1420. notify->StatusChangeFn == NULL) {
  1421. //
  1422. // return STATUS_UNSUPPORTED probably
  1423. //
  1424. return Irp->IoStatus.Status;
  1425. }
  1426. pdoExt = &hidClassExtension->pdoExt;
  1427. pdoExt->StatusChangeFn = notify->StatusChangeFn;
  1428. pdoExt->StatusChangeContext = notify->CallbackContext;
  1429. return STATUS_SUCCESS;
  1430. }
  1431. else if (RtlEqualMemory(irpSp->Parameters.QueryInterface.InterfaceType,
  1432. &GUID_HID_INTERFACE_HIDPARSE,
  1433. sizeof(GUID))) {
  1434. //
  1435. // Required for Generic Input, to remove the direct link
  1436. // b/w win32k and hidparse.
  1437. //
  1438. PHID_INTERFACE_HIDPARSE hidparse;
  1439. hidparse = (PHID_INTERFACE_HIDPARSE) irpSp->Parameters.QueryInterface.Interface;
  1440. if (hidparse->Size != sizeof(HID_INTERFACE_HIDPARSE) ||
  1441. hidparse->Version < 1) {
  1442. //
  1443. // return STATUS_UNSUPPORTED probably
  1444. //
  1445. return Irp->IoStatus.Status;
  1446. }
  1447. hidparse->HidpGetCaps = HidP_GetCaps;
  1448. return STATUS_SUCCESS;
  1449. }
  1450. //
  1451. // return STATUS_UNSUPPORTED probably
  1452. //
  1453. return Irp->IoStatus.Status;
  1454. }
  1455. /*
  1456. ********************************************************************************
  1457. * HidpQueryIdForClientPdo
  1458. ********************************************************************************
  1459. *
  1460. *
  1461. *
  1462. */
  1463. NTSTATUS HidpQueryIdForClientPdo (
  1464. IN PHIDCLASS_DEVICE_EXTENSION hidClassExtension,
  1465. IN OUT PIRP Irp
  1466. )
  1467. {
  1468. PIO_STACK_LOCATION irpSp;
  1469. NTSTATUS status;
  1470. PDO_EXTENSION *pdoExt;
  1471. FDO_EXTENSION *fdoExt;
  1472. PAGED_CODE();
  1473. ASSERT(hidClassExtension->isClientPdo);
  1474. pdoExt = &hidClassExtension->pdoExt;
  1475. fdoExt = &pdoExt->deviceFdoExt->fdoExt;
  1476. irpSp = IoGetCurrentIrpStackLocation( Irp );
  1477. switch (irpSp->Parameters.QueryId.IdType) {
  1478. case BusQueryHardwareIDs:
  1479. /*
  1480. * Call down to get a multi-string of hardware ids for the PDO.
  1481. */
  1482. IoCopyCurrentIrpStackLocationToNext(Irp);
  1483. status = HidpCallDriverSynchronous(fdoExt->fdo, Irp);
  1484. if (NT_SUCCESS(status)){
  1485. PWCHAR oldIDs, newIDs;
  1486. /*
  1487. * Replace the bus names in the current hardware IDs list with "HID\".
  1488. */
  1489. oldIDs = (PWCHAR)Irp->IoStatus.Information;
  1490. Irp->IoStatus.Information = (ULONG_PTR)BAD_POINTER;
  1491. newIDs = SubstituteBusNames(oldIDs, fdoExt, pdoExt);
  1492. ExFreePool(oldIDs);
  1493. if (newIDs){
  1494. /*
  1495. * Now append the compatible ids to the end of the HardwareIDs list.
  1496. */
  1497. PWCHAR compatIDs = BuildCompatibleID(hidClassExtension);
  1498. if (compatIDs){
  1499. ULONG basicIDsLen, compatIDsLen;
  1500. PWCHAR allHwIDs;
  1501. /*
  1502. * Find the lengths of the id multi-strings (not counting the extra NULL at end).
  1503. */
  1504. for (basicIDsLen = 0; newIDs[basicIDsLen]; basicIDsLen += WStrLen(newIDs+basicIDsLen)+1);
  1505. for (compatIDsLen = 0; compatIDs[compatIDsLen]; compatIDsLen += WStrLen(compatIDs+compatIDsLen)+1);
  1506. allHwIDs = ALLOCATEPOOL(PagedPool, (basicIDsLen+compatIDsLen+1)*sizeof(WCHAR));
  1507. if (allHwIDs){
  1508. RtlCopyMemory(allHwIDs, newIDs, basicIDsLen*sizeof(WCHAR));
  1509. RtlCopyMemory( allHwIDs+basicIDsLen,
  1510. compatIDs,
  1511. (compatIDsLen+1)*sizeof(WCHAR));
  1512. Irp->IoStatus.Information = (ULONG_PTR)allHwIDs;
  1513. }
  1514. else {
  1515. status = STATUS_INSUFFICIENT_RESOURCES;
  1516. }
  1517. ExFreePool(compatIDs);
  1518. }
  1519. else {
  1520. status = STATUS_INSUFFICIENT_RESOURCES;
  1521. }
  1522. ExFreePool(newIDs);
  1523. }
  1524. else {
  1525. status = STATUS_INSUFFICIENT_RESOURCES;
  1526. }
  1527. }
  1528. DBGSUCCESS(status, TRUE)
  1529. break;
  1530. case BusQueryDeviceID:
  1531. /*
  1532. * Call down to get a the device id for the device's PDO.
  1533. */
  1534. IoCopyCurrentIrpStackLocationToNext(Irp);
  1535. status = HidpCallDriverSynchronous(fdoExt->fdo, Irp);
  1536. if (NT_SUCCESS(status)){
  1537. PWCHAR oldId, newId, tmpId;
  1538. /*
  1539. * Replace the bus name (e.g. "USB\") with "HID\" in the device name.
  1540. */
  1541. /*
  1542. * First make this string into a multi-string.
  1543. */
  1544. oldId = (PWCHAR)Irp->IoStatus.Information;
  1545. tmpId = ALLOCATEPOOL(PagedPool, (WStrLen(oldId)+2)*sizeof(WCHAR));
  1546. if (tmpId){
  1547. ULONG len = WStrCpy(tmpId, oldId);
  1548. /*
  1549. * Add the extra NULL to terminate the multi-string.
  1550. */
  1551. tmpId[len+1] = UNICODE_NULL;
  1552. /*
  1553. * Change the bus name to "HID\"
  1554. */
  1555. newId = SubstituteBusNames(tmpId, fdoExt, pdoExt);
  1556. if (newId){
  1557. Irp->IoStatus.Information = (ULONG_PTR)newId;
  1558. }
  1559. else {
  1560. status = STATUS_DEVICE_DATA_ERROR;
  1561. Irp->IoStatus.Information = (ULONG_PTR)BAD_POINTER;
  1562. }
  1563. ExFreePool(tmpId);
  1564. }
  1565. else {
  1566. status = STATUS_DEVICE_DATA_ERROR;
  1567. Irp->IoStatus.Information = (ULONG_PTR)BAD_POINTER;
  1568. }
  1569. ExFreePool(oldId);
  1570. }
  1571. DBGSUCCESS(status, TRUE)
  1572. break;
  1573. case BusQueryInstanceID:
  1574. /*
  1575. * Produce an instance-id for this collection-PDO.
  1576. *
  1577. * Note: NTKERN frees the returned pointer, so we must provide a fresh pointer.
  1578. */
  1579. {
  1580. PWSTR instanceId = MemDup(PagedPool, L"0000", sizeof(L"0000"));
  1581. if (instanceId){
  1582. ULONG i;
  1583. /*
  1584. * Find this collection-PDO in the device-relations array
  1585. * and make the id be the PDO's index within that array.
  1586. */
  1587. for (i = 0; i < fdoExt->deviceRelations->Count; i++){
  1588. if (fdoExt->deviceRelations->Objects[i] == pdoExt->pdo){
  1589. swprintf(instanceId, L"%04x", i);
  1590. break;
  1591. }
  1592. }
  1593. ASSERT(i < fdoExt->deviceRelations->Count);
  1594. Irp->IoStatus.Information = (ULONG_PTR)instanceId;
  1595. status = STATUS_SUCCESS;
  1596. }
  1597. else {
  1598. status = STATUS_INSUFFICIENT_RESOURCES;
  1599. }
  1600. }
  1601. DBGSUCCESS(status, TRUE)
  1602. break;
  1603. case BusQueryCompatibleIDs:
  1604. // we now return the compatible id's at the end of HardwareIDs
  1605. // so that there is no UI on plug-in for a compatible-id match
  1606. // for a class-PDO.
  1607. // Irp->IoStatus.Information = (ULONG)BuildCompatibleID(hidClassExtension);
  1608. Irp->IoStatus.Information = (ULONG_PTR)ALLOCATEPOOL(PagedPool, sizeof(L"\0"));
  1609. if (Irp->IoStatus.Information) {
  1610. *(ULONG *)Irp->IoStatus.Information = 0; // double unicode-NULL.
  1611. status = STATUS_SUCCESS;
  1612. } else {
  1613. status = STATUS_INSUFFICIENT_RESOURCES;
  1614. ASSERT(0);
  1615. }
  1616. break;
  1617. default:
  1618. /*
  1619. * Do not return STATUS_NOT_SUPPORTED;
  1620. * keep the default status
  1621. * (this allows filter drivers to work).
  1622. */
  1623. status = Irp->IoStatus.Status;
  1624. break;
  1625. }
  1626. return status;
  1627. }
  1628. /*
  1629. ********************************************************************************
  1630. * AllClientPDOsInitialized
  1631. ********************************************************************************
  1632. *
  1633. *
  1634. */
  1635. BOOLEAN AllClientPDOsInitialized(FDO_EXTENSION *fdoExtension, BOOLEAN initialized)
  1636. {
  1637. BOOLEAN result = TRUE;
  1638. ULONG i;
  1639. if (ISPTR(fdoExtension->deviceRelations)){
  1640. for (i = 0; i < fdoExtension->deviceRelations->Count; i++){
  1641. PDEVICE_OBJECT pdo = fdoExtension->deviceRelations->Objects[i];
  1642. PHIDCLASS_DEVICE_EXTENSION pdoDevExt = pdo->DeviceExtension;
  1643. PDO_EXTENSION *pdoExt = &pdoDevExt->pdoExt;
  1644. /*
  1645. * Trick: compare !-results so that all TRUE values are equal
  1646. */
  1647. if (!initialized == !(pdoExt->state == COLLECTION_STATE_UNINITIALIZED)){
  1648. DBGVERBOSE(("AllClientPDOsInitialized is returning FALSE for pdo %x, state = %d",
  1649. pdo, pdoExt->state))
  1650. result = FALSE;
  1651. break;
  1652. }
  1653. }
  1654. }
  1655. else {
  1656. result = !initialized;
  1657. }
  1658. return result;
  1659. }
  1660. /*
  1661. ********************************************************************************
  1662. * AnyClientPDOsInitialized
  1663. ********************************************************************************
  1664. *
  1665. *
  1666. */
  1667. BOOLEAN AnyClientPDOsInitialized(FDO_EXTENSION *fdoExtension, BOOLEAN initialized)
  1668. {
  1669. BOOLEAN result = TRUE;
  1670. ULONG i;
  1671. if (ISPTR(fdoExtension->deviceRelations)){
  1672. for (i = 0; i < fdoExtension->deviceRelations->Count; i++){
  1673. PDEVICE_OBJECT pdo = fdoExtension->deviceRelations->Objects[i];
  1674. PHIDCLASS_DEVICE_EXTENSION pdoDevExt = pdo->DeviceExtension;
  1675. PDO_EXTENSION *pdoExt = &pdoDevExt->pdoExt;
  1676. if (!initialized != !(pdoExt->state == COLLECTION_STATE_UNINITIALIZED)){
  1677. result = TRUE;
  1678. break;
  1679. }
  1680. }
  1681. }
  1682. else {
  1683. result = !initialized;
  1684. }
  1685. return result;
  1686. }
  1687. /*
  1688. ********************************************************************************
  1689. * HidpDeleteDeviceObjects
  1690. ********************************************************************************
  1691. *
  1692. * Delete the device-FDO and collection-PDO's IF POSSIBLE.
  1693. * (must wait for REMOVE_DEVICE completion AND the IRP_MJ_CLOSE.
  1694. * Otherwise, return FALSE and we'll try again later.
  1695. *
  1696. *
  1697. */
  1698. BOOLEAN HidpDeleteDeviceObjects(FDO_EXTENSION *fdoExt)
  1699. {
  1700. ULONG i;
  1701. /*
  1702. * Do this switch-a-roo to thwart re-entrancy problems.
  1703. */
  1704. PDEVICE_OBJECT objToDelete = fdoExt->fdo;
  1705. fdoExt->fdo = BAD_POINTER;
  1706. if (ISPTR(fdoExt->deviceRelations)){
  1707. for (i = 0; i < fdoExt->deviceRelations->Count; i++){
  1708. PDO_EXTENSION *pdoExt = &fdoExt->collectionPdoExtensions[i]->pdoExt;
  1709. ASSERT(ISPTR(fdoExt->deviceRelations->Objects[i]));
  1710. if (ISPTR(pdoExt->name)){
  1711. RtlFreeUnicodeString(pdoExt->name);
  1712. ExFreePool(pdoExt->name);
  1713. pdoExt->name = BAD_POINTER;
  1714. }
  1715. /*
  1716. * Delete the client PDO.
  1717. * Don't touch the pdoExt after doing this.
  1718. */
  1719. ObDereferenceObject(fdoExt->deviceRelations->Objects[i]);
  1720. IoDeleteDevice(fdoExt->deviceRelations->Objects[i]);
  1721. }
  1722. ExFreePool(fdoExt->deviceRelations);
  1723. }
  1724. fdoExt->deviceRelations = BAD_POINTER;
  1725. if (ISPTR(fdoExt->collectionPdoExtensions)){
  1726. ExFreePool(fdoExt->collectionPdoExtensions);
  1727. }
  1728. fdoExt->collectionPdoExtensions = BAD_POINTER;
  1729. ObDereferenceObject(objToDelete);
  1730. IoDeleteDevice(objToDelete);
  1731. return TRUE;
  1732. }
  1733. /*
  1734. ********************************************************************************
  1735. * HidpQueryDeviceCapabilities
  1736. ********************************************************************************
  1737. *
  1738. *
  1739. *
  1740. */
  1741. NTSTATUS HidpQueryDeviceCapabilities( IN PDEVICE_OBJECT PdoDeviceObject,
  1742. IN PDEVICE_CAPABILITIES DeviceCapabilities)
  1743. {
  1744. PIRP irp;
  1745. NTSTATUS status;
  1746. PAGED_CODE();
  1747. irp = IoAllocateIrp(PdoDeviceObject->StackSize, FALSE);
  1748. if (irp) {
  1749. PIO_STACK_LOCATION nextStack;
  1750. KEVENT event;
  1751. nextStack = IoGetNextIrpStackLocation(irp);
  1752. ASSERT(nextStack);
  1753. nextStack->MajorFunction= IRP_MJ_PNP;
  1754. nextStack->MinorFunction= IRP_MN_QUERY_CAPABILITIES;
  1755. irp->IoStatus.Status = STATUS_NOT_SUPPORTED;
  1756. KeInitializeEvent(&event, NotificationEvent, FALSE);
  1757. IoSetCompletionRoutine(irp,
  1758. HidpQueryCapsCompletion,
  1759. &event,
  1760. TRUE,
  1761. TRUE,
  1762. TRUE);
  1763. RtlZeroMemory(DeviceCapabilities, sizeof(DEVICE_CAPABILITIES));
  1764. /*
  1765. * Caller needs to initialize some fields
  1766. */
  1767. DeviceCapabilities->Size = sizeof(DEVICE_CAPABILITIES);
  1768. DeviceCapabilities->Version = 1;
  1769. DeviceCapabilities->Address = -1;
  1770. DeviceCapabilities->UINumber = -1;
  1771. nextStack->Parameters.DeviceCapabilities.Capabilities = DeviceCapabilities;
  1772. status = IoCallDriver(PdoDeviceObject, irp);
  1773. if (status == STATUS_PENDING) {
  1774. KeWaitForSingleObject(
  1775. &event,
  1776. Suspended,
  1777. KernelMode,
  1778. FALSE,
  1779. NULL);
  1780. }
  1781. /*
  1782. * Note: we still own the IRP after the IoCallDriver() call
  1783. * because the completion routine returned
  1784. * STATUS_MORE_PROCESSING_REQUIRED.
  1785. */
  1786. status = irp->IoStatus.Status;
  1787. IoFreeIrp(irp);
  1788. }
  1789. else {
  1790. status = STATUS_INSUFFICIENT_RESOURCES;
  1791. }
  1792. return status;
  1793. }
  1794. /*
  1795. ********************************************************************************
  1796. * CheckReportPowerEvent
  1797. ********************************************************************************
  1798. *
  1799. * Check whether the read report includes a power event.
  1800. * If it does, notify the system by completing the saved power-event Irp.
  1801. *
  1802. * Note: report should point to a "cooked" report with the report-id byte
  1803. * included at the beginning of the report, whether or not the device
  1804. * included the report id.
  1805. *
  1806. */
  1807. VOID CheckReportPowerEvent( FDO_EXTENSION *fdoExt,
  1808. PHIDCLASS_COLLECTION collection,
  1809. PUCHAR report,
  1810. ULONG reportLen)
  1811. {
  1812. ULONG powerMask;
  1813. NTSTATUS status;
  1814. ASSERT(ISPTR(fdoExt->collectionPdoExtensions));
  1815. status = HidP_SysPowerEvent( report,
  1816. (USHORT)reportLen,
  1817. collection->phidDescriptor,
  1818. &powerMask);
  1819. if (NT_SUCCESS(status)){
  1820. if (powerMask){
  1821. /*
  1822. * This report contains a power event!
  1823. */
  1824. PIRP irpToComplete = NULL;
  1825. KIRQL oldIrql;
  1826. KeAcquireSpinLock(&collection->powerEventSpinLock, &oldIrql);
  1827. /*
  1828. * We should have gotten a IOCTL_GET_SYS_BUTTON_EVENT earlier and queued
  1829. * an IRP to return now.
  1830. */
  1831. if (ISPTR(collection->powerEventIrp)){
  1832. PDRIVER_CANCEL oldCancelRoutine;
  1833. /*
  1834. * "Dequeue" the power event IRP.
  1835. */
  1836. irpToComplete = collection->powerEventIrp;
  1837. oldCancelRoutine = IoSetCancelRoutine(irpToComplete, NULL);
  1838. if (oldCancelRoutine){
  1839. ASSERT(oldCancelRoutine == PowerEventCancelRoutine);
  1840. }
  1841. else {
  1842. /*
  1843. * This IRP was cancelled and the cancel routine WAS called.
  1844. * The cancel routine will complete this IRP
  1845. * as soon as we drop the spinlock, so don't touch the IRP.
  1846. */
  1847. ASSERT(irpToComplete->Cancel);
  1848. irpToComplete = NULL;
  1849. }
  1850. collection->powerEventIrp = BAD_POINTER;
  1851. }
  1852. else {
  1853. TRAP;
  1854. }
  1855. KeReleaseSpinLock(&collection->powerEventSpinLock, oldIrql);
  1856. /*
  1857. * If completing the IRP,
  1858. * do so after releasing all spinlocks.
  1859. */
  1860. if (irpToComplete){
  1861. /*
  1862. * Complete the IRP with the power mask.
  1863. *
  1864. */
  1865. ASSERT(irpToComplete->AssociatedIrp.SystemBuffer);
  1866. *(PULONG)irpToComplete->AssociatedIrp.SystemBuffer = powerMask;
  1867. irpToComplete->IoStatus.Information = sizeof(ULONG);
  1868. irpToComplete->IoStatus.Status = STATUS_SUCCESS;
  1869. IoCompleteRequest(irpToComplete, IO_NO_INCREMENT);
  1870. }
  1871. }
  1872. }
  1873. }
  1874. VOID ReadDeviceFlagsFromRegistry(FDO_EXTENSION *fdoExt, PDEVICE_OBJECT pdo)
  1875. {
  1876. NTSTATUS status;
  1877. HANDLE hRegDriver;
  1878. /*
  1879. * Open the driver registry key
  1880. * ( HKLM/System/CurrentControlSet/Control/Class/<GUID>/<#n> )
  1881. */
  1882. status = IoOpenDeviceRegistryKey( pdo,
  1883. PLUGPLAY_REGKEY_DRIVER,
  1884. KEY_READ,
  1885. &hRegDriver);
  1886. if (NT_SUCCESS(status)){
  1887. UNICODE_STRING deviceSpecificFlagsName;
  1888. HANDLE hRegDeviceSpecificFlags;
  1889. /*
  1890. * See if the DeviceSpecificFlags subkey exists.
  1891. */
  1892. RtlInitUnicodeString(&deviceSpecificFlagsName, L"DeviceSpecificFlags");
  1893. status = OpenSubkey( &hRegDeviceSpecificFlags,
  1894. hRegDriver,
  1895. &deviceSpecificFlagsName,
  1896. KEY_READ);
  1897. if (NT_SUCCESS(status)){
  1898. /*
  1899. * The registry DOES contain device-specific flags for this device.
  1900. */
  1901. /*
  1902. * The key value information struct is variable-length.
  1903. * The actual length is equal to the length of the base
  1904. * PKEY_VALUE_FULL_INFORMATION struct + the length of
  1905. * the name of the key + the length of the value.
  1906. * (The name of the key is a 4-byte hex number representing
  1907. * the 16-bit "source" usage value, written as a wide-char
  1908. * string; so with the terminating '\0', 5 wide chars).
  1909. */
  1910. #define MAX_DEVICE_SPECIFIC_FLAG_NAME_LEN 60
  1911. UCHAR keyValueBytes[sizeof(KEY_VALUE_FULL_INFORMATION)+(MAX_DEVICE_SPECIFIC_FLAG_NAME_LEN+1)*sizeof(WCHAR)+sizeof(ULONG)];
  1912. PKEY_VALUE_FULL_INFORMATION keyValueInfo = (PKEY_VALUE_FULL_INFORMATION)keyValueBytes;
  1913. ULONG actualLen;
  1914. ULONG keyIndex = 0;
  1915. do {
  1916. status = ZwEnumerateValueKey(
  1917. hRegDeviceSpecificFlags,
  1918. keyIndex,
  1919. KeyValueFullInformation,
  1920. keyValueInfo,
  1921. sizeof(keyValueBytes),
  1922. &actualLen);
  1923. if (NT_SUCCESS(status)){
  1924. PWCHAR valuePtr;
  1925. WCHAR valueBuf[2];
  1926. USHORT value;
  1927. ASSERT(keyValueInfo->Type == REG_SZ);
  1928. ASSERT(keyValueInfo->NameLength/sizeof(WCHAR) <= MAX_DEVICE_SPECIFIC_FLAG_NAME_LEN);
  1929. valuePtr = (PWCHAR)(((PCHAR)keyValueInfo)+keyValueInfo->DataOffset);
  1930. WStrNCpy(valueBuf, valuePtr, 1);
  1931. valueBuf[1] = L'\0';
  1932. value = (USHORT)LAtoX(valueBuf);
  1933. if (value){
  1934. if (!WStrNCmpI( keyValueInfo->Name,
  1935. L"AllowFeatureOnNonFeatureCollection",
  1936. keyValueInfo->NameLength/sizeof(WCHAR))){
  1937. DBGWARN(("Device HACK: allowing feature access on non-feature collections"))
  1938. fdoExt->deviceSpecificFlags |=
  1939. DEVICE_FLAG_ALLOW_FEATURE_ON_NON_FEATURE_COLLECTION;
  1940. }
  1941. }
  1942. keyIndex++;
  1943. }
  1944. } while (NT_SUCCESS(status));
  1945. ZwClose(hRegDeviceSpecificFlags);
  1946. }
  1947. ZwClose(hRegDriver);
  1948. }
  1949. else {
  1950. /*
  1951. * For 'raw' devices, IoOpenDeviceRegistryKey can fail on the
  1952. * initial 'raw' starts before the devnode is created.
  1953. */
  1954. }
  1955. }
  1956. LONG WStrNCmpI(PWCHAR s1, PWCHAR s2, ULONG n)
  1957. {
  1958. ULONG result;
  1959. while (n && *s1 && *s2 && ((*s1|0x20) == (*s2|0x20))){
  1960. s1++, s2++;
  1961. n--;
  1962. }
  1963. if (n){
  1964. result = ((*s1|0x20) > (*s2|0x20)) ? 1 : ((*s1|0x20) < (*s2|0x20)) ? -1 : 0;
  1965. }
  1966. else {
  1967. result = 0;
  1968. }
  1969. return result;
  1970. }
  1971. ULONG LAtoX(PWCHAR wHexString)
  1972. /*++
  1973. Routine Description:
  1974. Convert a hex string (without the '0x' prefix) to a ULONG.
  1975. Arguments:
  1976. wHexString - null-terminated wide-char hex string
  1977. (with no "0x" prefix)
  1978. Return Value:
  1979. ULONG value
  1980. --*/
  1981. {
  1982. ULONG i, result = 0;
  1983. for (i = 0; wHexString[i]; i++){
  1984. if ((wHexString[i] >= L'0') && (wHexString[i] <= L'9')){
  1985. result *= 0x10;
  1986. result += (wHexString[i] - L'0');
  1987. }
  1988. else if ((wHexString[i] >= L'a') && (wHexString[i] <= L'f')){
  1989. result *= 0x10;
  1990. result += (wHexString[i] - L'a' + 0x0a);
  1991. }
  1992. else if ((wHexString[i] >= L'A') && (wHexString[i] <= L'F')){
  1993. result *= 0x10;
  1994. result += (wHexString[i] - L'A' + 0x0a);
  1995. }
  1996. else {
  1997. ASSERT(0);
  1998. break;
  1999. }
  2000. }
  2001. return result;
  2002. }
  2003. ULONG WStrNCpy(PWCHAR dest, PWCHAR src, ULONG n)
  2004. {
  2005. ULONG result = 0;
  2006. while (n && (*dest++ = *src++)){
  2007. result++;
  2008. n--;
  2009. }
  2010. return result;
  2011. }
  2012. NTSTATUS OpenSubkey( OUT PHANDLE Handle,
  2013. IN HANDLE BaseHandle,
  2014. IN PUNICODE_STRING KeyName,
  2015. IN ACCESS_MASK DesiredAccess
  2016. )
  2017. {
  2018. OBJECT_ATTRIBUTES objectAttributes;
  2019. NTSTATUS status;
  2020. PAGED_CODE();
  2021. InitializeObjectAttributes( &objectAttributes,
  2022. KeyName,
  2023. OBJ_CASE_INSENSITIVE,
  2024. BaseHandle,
  2025. (PSECURITY_DESCRIPTOR) NULL );
  2026. status = ZwOpenKey(Handle, DesiredAccess, &objectAttributes);
  2027. return status;
  2028. }
  2029. PVOID
  2030. HidpGetSystemAddressForMdlSafe(PMDL MdlAddress)
  2031. {
  2032. PVOID buf = NULL;
  2033. /*
  2034. * Can't call MmGetSystemAddressForMdlSafe in a WDM driver,
  2035. * so set the MDL_MAPPING_CAN_FAIL bit and check the result
  2036. * of the mapping.
  2037. */
  2038. if (MdlAddress) {
  2039. MdlAddress->MdlFlags |= MDL_MAPPING_CAN_FAIL;
  2040. buf = MmGetSystemAddressForMdl(MdlAddress);
  2041. MdlAddress->MdlFlags &= (~MDL_MAPPING_CAN_FAIL);
  2042. }
  2043. else {
  2044. DBGASSERT(MdlAddress, ("MdlAddress passed into GetSystemAddress is NULL"), FALSE)
  2045. }
  2046. return buf;
  2047. }