Leaked source code of windows server 2003
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.

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