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.

1618 lines
53 KiB

  1. /*
  2. * title: chid.cpp
  3. *
  4. * purpose: wdm kernel implementation of a hid device class
  5. *
  6. */
  7. // local prototypes
  8. #include "hidbatt.h"
  9. extern CHidDevice * pGlobalHidDevice[];
  10. bool GetNextUsage(
  11. CHidDevice * pThisDevice,
  12. SHORT CollectionID,
  13. USHORT NodeIndex,
  14. USHORT usUsageIndex,
  15. CUsage ** Usage)
  16. {
  17. int i;
  18. int UsageCounter = 0;
  19. // cycle through all the called out usages from the pHid structure
  20. // get feature usages
  21. for(i = 0; i < pThisDevice->m_pCaps->NumberFeatureValueCaps; i++)
  22. {
  23. if(pThisDevice->m_pHidDevice->FeatureValueCaps[i].LinkCollection == NodeIndex) // cardinal
  24. { // found a usage for this collection
  25. if(usUsageIndex == UsageCounter)
  26. {
  27. // got a usage to send back
  28. CUsage * pThisUsage = new (NonPagedPool, HidBattTag) CUsage();
  29. if (!pThisUsage) {
  30. // Could not allocate new CUsage, return error
  31. return FALSE;
  32. }
  33. pThisUsage->m_pValueCaps = &pThisDevice->m_pHidDevice->FeatureValueCaps[i];
  34. pThisUsage->m_eType = eFeatureValue;
  35. *Usage = pThisUsage;
  36. return TRUE;
  37. }
  38. UsageCounter++;
  39. }
  40. }
  41. // ditto feature buttons
  42. for(i = 0; i < pThisDevice->m_pCaps->NumberFeatureButtonCaps; i++)
  43. {
  44. if(pThisDevice->m_pHidDevice->FeatureButtonCaps[i].LinkCollection == NodeIndex )
  45. { // found a usage for this collection
  46. if(usUsageIndex == UsageCounter)
  47. {
  48. // got a usage to send back
  49. CUsage * pThisUsage = new (NonPagedPool, HidBattTag) CUsage();
  50. if (!pThisUsage) {
  51. // Could not allocate new CUsage, return error
  52. return FALSE;
  53. }
  54. pThisUsage->m_pButtonCaps = &pThisDevice->m_pHidDevice->FeatureButtonCaps[i];
  55. pThisUsage->m_eType = eFeatureButton;
  56. *Usage = pThisUsage;
  57. return TRUE;
  58. }
  59. UsageCounter++;
  60. }
  61. }
  62. // ditto input values
  63. for(i = 0; i < pThisDevice->m_pCaps->NumberInputValueCaps; i++)
  64. {
  65. if(pThisDevice->m_pHidDevice->InputValueCaps[i].LinkCollection == NodeIndex)
  66. { // found a usage for this collection
  67. if(usUsageIndex == UsageCounter)
  68. {
  69. // got a usage to send back
  70. CUsage * pThisUsage = new (NonPagedPool, HidBattTag) CUsage();
  71. if (!pThisUsage) {
  72. // Could not allocate new CUsage, return error
  73. return FALSE;
  74. }
  75. pThisUsage->m_pValueCaps = &pThisDevice->m_pHidDevice->InputValueCaps[i];
  76. pThisUsage->m_eType = eInputValue;
  77. *Usage = pThisUsage;
  78. return TRUE;
  79. }
  80. UsageCounter++;
  81. }
  82. }
  83. // ditto input buttons
  84. for(i = 0; i < pThisDevice->m_pCaps->NumberInputButtonCaps; i++)
  85. {
  86. if(pThisDevice->m_pHidDevice->InputButtonCaps[i].LinkCollection == NodeIndex)
  87. { // found a usage for this collection
  88. if(usUsageIndex == UsageCounter)
  89. {
  90. // got a usage to send back
  91. CUsage * pThisUsage = new (NonPagedPool, HidBattTag) CUsage();
  92. if (!pThisUsage) {
  93. // Could not allocate new CUsage, return error
  94. return FALSE;
  95. }
  96. pThisUsage->m_pButtonCaps = &pThisDevice->m_pHidDevice->InputButtonCaps[i];
  97. pThisUsage->m_eType = eInputButton;
  98. *Usage = pThisUsage;
  99. return TRUE;
  100. }
  101. UsageCounter++;
  102. }
  103. }
  104. // ditto Output values
  105. for(i = 0; i < pThisDevice->m_pCaps->NumberOutputValueCaps; i++)
  106. {
  107. if(pThisDevice->m_pHidDevice->OutputValueCaps[i].LinkCollection == NodeIndex)
  108. { // found a usage for this collection
  109. if(usUsageIndex == UsageCounter)
  110. {
  111. // got a usage to send back
  112. CUsage * pThisUsage = new (NonPagedPool, HidBattTag) CUsage();
  113. if (!pThisUsage) {
  114. // Could not allocate new CUsage, return error
  115. return FALSE;
  116. }
  117. pThisUsage->m_pValueCaps = &pThisDevice->m_pHidDevice->OutputValueCaps[i];
  118. pThisUsage->m_eType = eOutputValue;
  119. *Usage = pThisUsage;
  120. return TRUE;
  121. }
  122. UsageCounter++;
  123. }
  124. }
  125. // ditto Output buttons
  126. for(i = 0; i < pThisDevice->m_pCaps->NumberOutputButtonCaps; i++)
  127. {
  128. if(pThisDevice->m_pHidDevice->OutputButtonCaps[i].LinkCollection == NodeIndex)
  129. { // found a usage for this collection
  130. if(usUsageIndex == UsageCounter)
  131. {
  132. // got a usage to send back
  133. CUsage * pThisUsage = new (NonPagedPool, HidBattTag) CUsage();
  134. if (!pThisUsage) {
  135. // Could not allocate new CUsage, return error
  136. return FALSE;
  137. }
  138. pThisUsage->m_pButtonCaps = &pThisDevice->m_pHidDevice->OutputButtonCaps[i];
  139. pThisUsage->m_eType = eOutputButton;
  140. *Usage = pThisUsage;
  141. return TRUE;
  142. }
  143. UsageCounter++;
  144. }
  145. }
  146. return FALSE;
  147. }
  148. CTypeMask::CTypeMask()
  149. {
  150. // set members to zero
  151. ReportType = 0;
  152. bWriteable = 0;
  153. bIsString = 0;
  154. bIsNumber = 0;
  155. bAlertable = 0;
  156. bVolatile = 0;
  157. }
  158. CProperties::CProperties(CUsage * pUsage)
  159. {
  160. PHIDP_BUTTON_CAPS pButtCaps; // fill in the properties for this usage
  161. PHIDP_VALUE_CAPS pValueCaps;
  162. eHidType eType = pUsage->m_eType; // Cash local copy so compiler (and PREFAST
  163. // will know this value doesn't change.
  164. // (This causes more compact compiling as well)
  165. switch(eType)
  166. {
  167. case eFeatureButton:
  168. case eInputButton:
  169. case eOutputButton:
  170. pButtCaps = pUsage->m_pButtonCaps;
  171. m_UnitExponent = 0; // no exponents on buttons
  172. m_Unit = 0; // buttons don't have units
  173. m_LogicalMin = 0; // ditto for max and min pCaps->LogicalMin;
  174. m_LogicalMax = 0; // pCaps->LogicalMax;
  175. m_LinkCollection = pButtCaps->LinkCollection;
  176. m_ReportID = pButtCaps->ReportID;
  177. m_Usage = pButtCaps->NotRange.Usage;
  178. m_UsagePage = pButtCaps->UsagePage;
  179. break;
  180. case eFeatureValue:
  181. case eInputValue:
  182. case eOutputValue:
  183. pValueCaps = pUsage->m_pValueCaps;
  184. m_Unit = pValueCaps->Units;
  185. m_UnitExponent = (SHORT) pValueCaps->UnitsExp;
  186. m_LogicalMin = pValueCaps->LogicalMin;
  187. m_LogicalMax = pValueCaps->LogicalMax;
  188. m_LinkCollection = pValueCaps->LinkCollection;
  189. m_ReportID = pValueCaps->ReportID;
  190. m_Usage = pValueCaps->NotRange.Usage;
  191. m_UsagePage = pValueCaps->UsagePage;
  192. break;
  193. }
  194. // setup type mask
  195. m_pType = new (NonPagedPool, HidBattTag) CTypeMask();
  196. if (m_pType) {
  197. if(eType == eInputButton || eType == eInputValue)
  198. {
  199. m_pType->SetAlertable();
  200. }
  201. // set writability
  202. if(eType == eFeatureButton || eType == eOutputButton)
  203. {
  204. if(pButtCaps->BitField & 0x01)
  205. {
  206. m_pType->SetIsWriteable();
  207. }
  208. } else if(eType == eFeatureValue || eType == eOutputValue)
  209. {
  210. if(pValueCaps->BitField & 0x01)
  211. {
  212. m_pType->SetIsWriteable();
  213. }
  214. }
  215. // set volatility
  216. if(eType == eFeatureValue)
  217. {
  218. if(pValueCaps->BitField & 0x80)
  219. {
  220. m_pType->SetVolatile();
  221. }
  222. }
  223. if(eType == eFeatureButton)
  224. {
  225. if(pButtCaps->BitField & 0x80)
  226. {
  227. m_pType->SetVolatile();
  228. }
  229. }
  230. switch(eType)
  231. {
  232. case eFeatureButton:
  233. case eFeatureValue:
  234. m_pType->SetReportType(FeatureType);
  235. break;
  236. case eInputButton:
  237. case eInputValue:
  238. m_pType->SetReportType(InputType);
  239. break;
  240. case eOutputButton:
  241. case eOutputValue:
  242. m_pType->SetReportType(OutputType);
  243. }
  244. // set value to to number until I figure out how to do strings
  245. m_pType->SetIsNumber();
  246. }
  247. }
  248. CProperties::~CProperties()
  249. {
  250. if (m_pType) {
  251. delete m_pType;
  252. m_pType = NULL;
  253. }
  254. return;
  255. }
  256. CUsagePath::CUsagePath(USAGE UsagePage, USAGE UsageID, CUsage * pThisUsage)
  257. {
  258. // init members
  259. m_UsagePage = UsagePage;
  260. m_UsageNumber = UsageID;
  261. m_pUsage = pThisUsage;
  262. m_pNextEntry = NULL;
  263. return;
  264. }
  265. CHidDevice::CHidDevice()
  266. {
  267. // clear out usage arrays
  268. for(int i = 0; i<MAXREPORTID; i++)
  269. {
  270. m_InputUsageArrays[i] = NULL;
  271. m_FeatureBuffer[i] = NULL;
  272. m_ReportIdArray[i] = 0;
  273. }
  274. m_pThreadObject = NULL;
  275. m_pReadBuffer = NULL;
  276. m_pEventHandler = 0;
  277. }
  278. bool CHidDevice::OpenHidDevice(PDEVICE_OBJECT pDeviceObject)
  279. {
  280. NTSTATUS ntStatus;
  281. ULONG ulNodeCount;
  282. bool bResult;
  283. HID_COLLECTION_INFORMATION collectionInformation;
  284. HIDDebugBreak(HIDBATT_BREAK_ALWAYS);
  285. HidBattPrint(HIDBATT_TRACE,("CHidDevice::OpenHidDevice\n"));
  286. // first get collection information for this device
  287. ntStatus = DoIoctl(
  288. pDeviceObject,
  289. IOCTL_HID_GET_COLLECTION_INFORMATION,
  290. NULL,
  291. 0,
  292. &collectionInformation,
  293. sizeof(HID_COLLECTION_INFORMATION),
  294. (CHidDevice *) NULL
  295. );
  296. if(NT_ERROR(ntStatus))
  297. {
  298. return FALSE;
  299. }
  300. m_pPreparsedData = (PHIDP_PREPARSED_DATA)
  301. ExAllocatePoolWithTag(NonPagedPool,
  302. collectionInformation.DescriptorSize,
  303. HidBattTag);
  304. if(!m_pPreparsedData)
  305. {
  306. return FALSE;
  307. }
  308. ntStatus = DoIoctl(
  309. pDeviceObject,
  310. IOCTL_HID_GET_COLLECTION_DESCRIPTOR,
  311. NULL,
  312. 0,
  313. m_pPreparsedData,
  314. collectionInformation.DescriptorSize,
  315. (CHidDevice *) NULL
  316. );
  317. if(NT_ERROR(ntStatus))
  318. {
  319. ExFreePool(m_pPreparsedData);
  320. return FALSE;
  321. }
  322. // init the caps structure
  323. m_pCaps = (PHIDP_CAPS) ExAllocatePoolWithTag (NonPagedPool,
  324. sizeof(HIDP_CAPS),
  325. HidBattTag);
  326. if(!m_pCaps)
  327. {
  328. ExFreePool(m_pPreparsedData);
  329. return FALSE;
  330. }
  331. RtlZeroMemory(m_pCaps,sizeof(HIDP_CAPS));
  332. ntStatus = HidP_GetCaps (m_pPreparsedData, m_pCaps);
  333. if (NT_ERROR(ntStatus))
  334. {
  335. ExFreePool(m_pPreparsedData);
  336. ExFreePool(m_pCaps);
  337. return FALSE;
  338. }
  339. // set usage page and usage for application level
  340. m_UsagePage = m_pCaps->UsagePage;
  341. m_UsageID = m_pCaps->Usage;
  342. // init the collection array
  343. ulNodeCount = m_pCaps->NumberLinkCollectionNodes;
  344. HIDP_LINK_COLLECTION_NODE * pLinkNodes = (HIDP_LINK_COLLECTION_NODE*)
  345. ExAllocatePoolWithTag (NonPagedPool,
  346. sizeof(HIDP_LINK_COLLECTION_NODE) * ulNodeCount,
  347. HidBattTag);
  348. if(!pLinkNodes) return FALSE;
  349. RtlZeroMemory(pLinkNodes,sizeof(HIDP_LINK_COLLECTION_NODE) * ulNodeCount );
  350. ntStatus = HidP_GetLinkCollectionNodes(
  351. pLinkNodes,
  352. &ulNodeCount,
  353. m_pPreparsedData
  354. );
  355. if(ntStatus != HIDP_STATUS_SUCCESS)
  356. {
  357. ExFreePool( m_pPreparsedData);
  358. ExFreePool(m_pCaps);
  359. ExFreePool(pLinkNodes);
  360. return FALSE;
  361. }
  362. // the following call will init all the collections in the device
  363. CCollectionArray * ThisArray = new (NonPagedPool, HidBattTag) CCollectionArray(pLinkNodes,(USHORT) ulNodeCount, -1);
  364. if (!ThisArray) {
  365. // Creation of the collection failed, return failure
  366. return FALSE;
  367. }
  368. m_CollectionArray = ThisArray;
  369. // have each collection fill in its usage array
  370. // this call uses KR's methods to access and setup his original hid structures.
  371. // ... This data is then used to populate the the hid device class structures
  372. m_pHidDevice = SetupHidData(
  373. m_pPreparsedData,
  374. m_pCaps,
  375. pLinkNodes);
  376. for(int i = 0; i < ThisArray->m_CollectionCount; i++)
  377. {
  378. ThisArray->m_pCollections[i]->InitUsages(this);
  379. }
  380. ExFreePool(pLinkNodes);
  381. return TRUE;
  382. }
  383. CHidDevice::~CHidDevice()
  384. {
  385. ULONG i;
  386. // release any allocated memory and cleanup
  387. if (m_pHidDevice) {
  388. if (m_pHidDevice->InputButtonCaps) {
  389. ExFreePool (m_pHidDevice->InputButtonCaps);
  390. }
  391. if (m_pHidDevice->InputValueCaps) {
  392. ExFreePool (m_pHidDevice->InputValueCaps);
  393. }
  394. if (m_pHidDevice->OutputButtonCaps) {
  395. ExFreePool (m_pHidDevice->OutputButtonCaps);
  396. }
  397. if (m_pHidDevice->OutputValueCaps) {
  398. ExFreePool (m_pHidDevice->OutputValueCaps);
  399. }
  400. if (m_pHidDevice->FeatureButtonCaps) {
  401. ExFreePool (m_pHidDevice->FeatureButtonCaps);
  402. }
  403. if (m_pHidDevice->FeatureValueCaps) {
  404. ExFreePool (m_pHidDevice->FeatureValueCaps);
  405. }
  406. ExFreePool (m_pHidDevice);
  407. }
  408. if(m_CollectionArray) {
  409. delete m_CollectionArray;
  410. m_CollectionArray = NULL;
  411. }
  412. for (i = 0; i < MAXREPORTID; i++) {
  413. if(m_InputUsageArrays[i]) {
  414. if (m_InputUsageArrays[i]->m_pUsages) {
  415. ExFreePool (m_InputUsageArrays[i]->m_pUsages);
  416. }
  417. ExFreePool (m_InputUsageArrays[i]);
  418. m_InputUsageArrays[i] = NULL;
  419. }
  420. }
  421. if(m_pReadBuffer) {
  422. ExFreePool (m_pReadBuffer);
  423. m_pReadBuffer = NULL;
  424. }
  425. for (i = 0; i < MAXREPORTID; i++) {
  426. if(m_FeatureBuffer[i]) {
  427. ExFreePool (m_FeatureBuffer[i]);
  428. m_FeatureBuffer[i] = NULL;
  429. }
  430. }
  431. if (m_pPreparsedData) {
  432. ExFreePool (m_pPreparsedData);
  433. }
  434. if (m_pCaps) {
  435. ExFreePool (m_pCaps);
  436. }
  437. return;
  438. }
  439. CUsage * CHidDevice::FindUsage(CUsagePath * PathToUsage, USHORT usType)
  440. {
  441. int i = 0;
  442. CCollection * pActiveCollection = (CCollection *) NULL;
  443. CCollectionArray * pCurrentCArray = m_CollectionArray;
  444. // Index into collection array by usage page : usage id
  445. while(PathToUsage->m_pNextEntry)
  446. {
  447. // traversing a collection
  448. while( pCurrentCArray && i < pCurrentCArray->m_CollectionCount)
  449. {
  450. if(pCurrentCArray->m_pCollections[i]->m_UsagePage == PathToUsage->m_UsagePage &&
  451. pCurrentCArray->m_pCollections[i]->m_CollectionID == PathToUsage->m_UsageNumber)
  452. {
  453. // found a node, go down a level
  454. pActiveCollection = pCurrentCArray->m_pCollections[i];
  455. pCurrentCArray = pCurrentCArray->m_pCollections[i]->m_CollectionArray;
  456. i = 0;
  457. break;
  458. }
  459. i++;
  460. }
  461. if(i) return (CUsage *) NULL; // not found
  462. PathToUsage = PathToUsage->m_pNextEntry;
  463. }
  464. if(!pActiveCollection) return (CUsage *) NULL; // no collection found, shouldn't get here
  465. // got to the collection, check its usages
  466. CUsageArray * pCurrentUArray = pActiveCollection->m_UsageArray;
  467. if(!pCurrentUArray) return (CUsage *) NULL;
  468. // interate usage array
  469. for(i = 0; i < pCurrentUArray->m_UsageCount; i++)
  470. {
  471. if(pCurrentUArray->m_pUsages[i]->m_pProperties->m_Usage == PathToUsage->m_UsageNumber &&
  472. pCurrentUArray->m_pUsages[i]->m_pProperties->m_UsagePage == PathToUsage->m_UsagePage)
  473. {
  474. // got it !
  475. if(usType == WRITEABLE) // writable returns feature and output usages
  476. if(pCurrentUArray->m_pUsages[i]->m_eType == eFeatureValue ||
  477. pCurrentUArray->m_pUsages[i]->m_eType == eOutputValue ||
  478. pCurrentUArray->m_pUsages[i]->m_eType == eFeatureButton ||
  479. pCurrentUArray->m_pUsages[i]->m_eType == eOutputButton)
  480. // return writeable usage !
  481. return pCurrentUArray->m_pUsages[i];
  482. if(usType == READABLE) // returns input and feature types
  483. if(pCurrentUArray->m_pUsages[i]->m_eType == eFeatureValue ||
  484. pCurrentUArray->m_pUsages[i]->m_eType == eInputValue ||
  485. pCurrentUArray->m_pUsages[i]->m_eType == eFeatureButton ||
  486. pCurrentUArray->m_pUsages[i]->m_eType == eInputButton)
  487. // return readable usage !
  488. return pCurrentUArray->m_pUsages[i];
  489. }
  490. }
  491. return (CUsage *) NULL;
  492. }
  493. NTSTATUS CHidDevice::ActivateInput()
  494. {
  495. NTSTATUS ntStatus;
  496. HANDLE hReadThread;
  497. // init notification elements
  498. HidBattPrint(HIDBATT_TRACE, ("ActivateInput entered\n"));
  499. if(!m_pReadBuffer)
  500. {
  501. if (!m_pCaps->InputReportByteLength) {
  502. HidBattPrint(HIDBATT_ERROR, ("ActivateInput: InputReportByteLength = %08x; NumberInputButtonCaps = %08x; NumberInputValueCaps = %08x\n",
  503. m_pCaps->InputReportByteLength,
  504. m_pCaps->NumberInputButtonCaps,
  505. m_pCaps->NumberInputValueCaps));
  506. //
  507. // This just means that the battery doesn't give notifications.
  508. //
  509. return STATUS_SUCCESS;
  510. }
  511. m_pReadBuffer = (PBYTE) ExAllocatePoolWithTag (NonPagedPool,
  512. m_pCaps->InputReportByteLength,
  513. HidBattTag);
  514. if(!m_pReadBuffer)
  515. return STATUS_INSUFFICIENT_RESOURCES;
  516. }
  517. // init read event
  518. KeInitializeEvent(&m_kReadEvent,NotificationEvent,FALSE);
  519. ntStatus = PsCreateSystemThread(
  520. OUT &hReadThread,
  521. IN THREAD_ALL_ACCESS,
  522. IN NULL, // POBJECT_ATTRIBUTES ObjectAttributes
  523. IN NULL, // HANDLE ProcessHandle
  524. OUT NULL, // PCLIENT_ID ClientId
  525. IN ReadThread,
  526. IN this
  527. );
  528. if(NT_ERROR(ntStatus))
  529. {
  530. // kill refresh loop, then break
  531. HidBattPrint(HIDBATT_TRACE, ("ActivateInput error, exiting - Status = %x\n",ntStatus));
  532. ExFreePool(m_pReadBuffer);
  533. m_pReadBuffer = NULL;
  534. return ntStatus;
  535. }
  536. HidBattPrint(HIDBATT_TRACE, ("ActivateInput exiting = Status = %x\n",ntStatus));
  537. ntStatus = ObReferenceObjectByHandle (
  538. hReadThread,
  539. THREAD_ALL_ACCESS,
  540. NULL,
  541. KernelMode,
  542. &m_pThreadObject,
  543. NULL
  544. );
  545. if (!NT_SUCCESS (ntStatus)) {
  546. HidBattPrint(HIDBATT_ERROR, ("ActivateInput can't get thread object\n",ntStatus));
  547. // Return without closing hReadThread handle.
  548. // This will cause a reboot to be needed to fully unload the driver.
  549. return STATUS_SUCCESS;
  550. }
  551. ntStatus = ZwClose (hReadThread);
  552. // Ignore return value. We can't do anything about a failure, and the
  553. // driver will still work. It will simply result in leaking a thread
  554. // object when the device is removed.
  555. return STATUS_SUCCESS;
  556. }
  557. NTSTATUS ReadCompletionRoutine(PDEVICE_OBJECT pDO, PIRP pIrp,PVOID pContext)
  558. {
  559. CHidDevice * pHidDevice = (CHidDevice *) pContext;
  560. HidBattPrint(HIDBATT_TRACE,("Read Completed, IO Status = %x\n",pIrp->IoStatus.Status));
  561. KeSetEvent(&pHidDevice->m_kReadEvent,0,FALSE);
  562. return STATUS_MORE_PROCESSING_REQUIRED;
  563. }
  564. void _stdcall ReadThread(PVOID pContext)
  565. {
  566. USHORT usFailureCount = 0;
  567. // build a read irp for hid class
  568. USHORT usEventIndex = 0;
  569. NTSTATUS ntStatus = STATUS_SUCCESS;
  570. PVOID EventArray[2];
  571. PIO_STACK_LOCATION pNewStack;
  572. CBatteryDevExt * pDevExt;
  573. PMDL mdl;
  574. HIDDebugBreak(HIDBATT_BREAK_ALWAYS);
  575. HidBattPrint(HIDBATT_TRACE,("Read Thread entered\n"));
  576. //
  577. // first get our "this"
  578. //
  579. CHidDevice * pHidDev = (CHidDevice *) pContext;
  580. pDevExt = (CBatteryDevExt *) pHidDev->m_pEventContext;
  581. //
  582. // Hold the remove lock so the remove routine doesn't cancel the irp while
  583. // we are playing with it.
  584. //
  585. if (!NT_SUCCESS (IoAcquireRemoveLock (&pDevExt->m_StopLock, (PVOID) HidBattTag))) {
  586. goto ReadThreadCleanup1; // fail
  587. }
  588. //
  589. // Allocate Irp to be used and re-used
  590. //
  591. pHidDev->m_pReadIrp = IoAllocateIrp (pHidDev->m_pLowerDeviceObject->StackSize, FALSE);
  592. if(!pHidDev->m_pReadIrp) {
  593. goto ReadThreadCleanup1; // fail
  594. }
  595. //
  596. // Create MDL
  597. //
  598. mdl = IoAllocateMdl( pHidDev->m_pReadBuffer,
  599. pHidDev->m_pCaps->InputReportByteLength,
  600. FALSE,
  601. FALSE,
  602. (PIRP) NULL );
  603. if (!mdl) {
  604. goto ReadThreadCleanup2;
  605. }
  606. //
  607. // Lock IO buffer
  608. //
  609. __try {
  610. MmProbeAndLockPages( mdl,
  611. KernelMode,
  612. (LOCK_OPERATION) IoWriteAccess );
  613. } __except(EXCEPTION_EXECUTE_HANDLER) {
  614. ntStatus = STATUS_UNSUCCESSFUL;
  615. }
  616. if (!NT_SUCCESS(ntStatus)) {
  617. goto ReadThreadCleanup3;
  618. }
  619. while (TRUE) {
  620. IoReuseIrp (pHidDev->m_pReadIrp, STATUS_SUCCESS);
  621. pHidDev->m_pReadIrp->Tail.Overlay.Thread = PsGetCurrentThread();
  622. pHidDev->m_pReadIrp->MdlAddress = mdl;
  623. IoSetCompletionRoutine(pHidDev->m_pReadIrp,ReadCompletionRoutine,pHidDev,TRUE,TRUE,TRUE);
  624. pNewStack= IoGetNextIrpStackLocation(pHidDev->m_pReadIrp);
  625. pNewStack->FileObject = pHidDev->m_pFCB;
  626. pNewStack->MajorFunction = IRP_MJ_READ;
  627. pNewStack->Parameters.Read.Length = pHidDev->m_pCaps->InputReportByteLength;
  628. pNewStack->Parameters.Read.ByteOffset.QuadPart = 0;
  629. KeResetEvent(&pHidDev->m_kReadEvent);
  630. ntStatus = IoCallDriver(pHidDev->m_pLowerDeviceObject,pHidDev->m_pReadIrp);
  631. //
  632. // Don't hold the lock while we are waiting for the IRP to complete.
  633. // The remove routine will cancel the irp if needed.
  634. //
  635. IoReleaseRemoveLock (&pDevExt->m_StopLock, (PVOID) HidBattTag);
  636. if (ntStatus == STATUS_PENDING)
  637. {
  638. KeWaitForSingleObject(
  639. &pHidDev->m_kReadEvent,
  640. Executive,
  641. KernelMode,
  642. FALSE,
  643. NULL
  644. );
  645. ntStatus = pHidDev->m_pReadIrp->IoStatus.Status;
  646. }
  647. // we awoke on a read completion
  648. HidBattPrint(HIDBATT_TRACE,("Read woke: status = 0x%08x\n", ntStatus));
  649. if(ntStatus != STATUS_SUCCESS)
  650. {
  651. if(ntStatus == STATUS_DEVICE_NOT_CONNECTED
  652. || ntStatus == STATUS_CANCELLED)
  653. {
  654. HidBattPrint(HIDBATT_ERROR,("Read Failure - Status = %x\n",ntStatus));
  655. break;
  656. }
  657. usFailureCount++;
  658. if(usFailureCount++ == 10)
  659. {
  660. // stop trying
  661. HidBattPrint(HIDBATT_ERROR,("Read Failure - More than 10 retries\nStatus = %x\n",pHidDev->m_pReadIrp->IoStatus.Status));
  662. break;
  663. }
  664. //
  665. // Hold the lock while playing with the IRP
  666. // If we are being removed, we need to break out.
  667. //
  668. if (!NT_SUCCESS (IoAcquireRemoveLock (&pDevExt->m_StopLock, (PVOID) HidBattTag))) {
  669. break;
  670. }
  671. continue;
  672. }
  673. usFailureCount = 0;
  674. //
  675. // Hold the lock while playing with the IRP
  676. // If we are being removed, we need to break out.
  677. //
  678. if (!NT_SUCCESS (IoAcquireRemoveLock (&pDevExt->m_StopLock, (PVOID) HidBattTag))) {
  679. break;
  680. }
  681. // process input buffer
  682. USHORT usReportId = pHidDev->m_pReadBuffer[0];
  683. USHORT usIndex = pHidDev->GetIndexFromReportId(usReportId);
  684. if(usIndex == MAXREPORTID) // is this a report we recognize
  685. {
  686. HidBattPrint(HIDBATT_TRACE,("Read: don't recognize report: usIndex = 0x%08x\n", usIndex));
  687. continue; // we don't recognize this report
  688. }
  689. CUsageArray *pThisInputArray = pHidDev->m_InputUsageArrays[usIndex];
  690. if(!pThisInputArray)
  691. {
  692. HidBattPrint(HIDBATT_TRACE,("Read: nothing to update\n"));
  693. continue; // nothing to update
  694. }
  695. for(int i=0; i< pThisInputArray->m_UsageCount; i++)
  696. {
  697. HidBattPrint(HIDBATT_TRACE,("Read: Getting value\n"));
  698. pThisInputArray->m_pUsages[i]->GetValue();
  699. }
  700. } //while
  701. //
  702. // Cleanup
  703. //
  704. MmUnlockPages( mdl );
  705. ReadThreadCleanup3:
  706. IoFreeMdl(mdl);
  707. ReadThreadCleanup2:
  708. // Irp will be freed by Query remove/stop device thread after read thread has terminated.
  709. ReadThreadCleanup1:
  710. pDevExt->m_pBattery->m_Tag = BATTERY_TAG_INVALID;
  711. PsTerminateSystemThread(STATUS_SUCCESS);
  712. HidBattPrint(HIDBATT_ERROR,("Read thread terminated: Why am I seeing this?\n"));
  713. }
  714. // collectionarray methods
  715. CCollectionArray::CCollectionArray(PHIDP_LINK_COLLECTION_NODE pTheNodes, USHORT usNodeCount, SHORT sParentIndex)
  716. {
  717. HIDDebugBreak(HIDBATT_BREAK_NEVER);
  718. USHORT i;
  719. m_pCollections = 0;
  720. m_CollectionCount = 0;
  721. if(sParentIndex == -1) // exception processing for application level collection
  722. {
  723. m_pCollections = (CCollection **)
  724. ExAllocatePoolWithTag (NonPagedPool,
  725. sizeof(CCollection *),
  726. HidBattTag);
  727. if(!m_pCollections) return;
  728. RtlZeroMemory(m_pCollections,sizeof(CCollection *));
  729. m_pCollections[0] = new (NonPagedPool, HidBattTag) CCollection(pTheNodes,usNodeCount, 0); // get my children
  730. m_CollectionCount = 1;
  731. } else {
  732. for( i = 1; i < usNodeCount; i++) {
  733. PHIDP_LINK_COLLECTION_NODE pThisNode = &pTheNodes[i];
  734. if( (pTheNodes[i].Parent == sParentIndex) ) {
  735. m_CollectionCount++; // inc collection count
  736. if(!m_pCollections) {
  737. m_pCollections = (CCollection **)
  738. ExAllocatePoolWithTag (NonPagedPool,
  739. sizeof(CCollection *),
  740. HidBattTag);
  741. if(!m_pCollections) return;
  742. RtlZeroMemory(m_pCollections,sizeof(CCollection *));
  743. } else {
  744. // make the array bigger
  745. //m_Collections = (CCollection **) realloc(m_Collections,(m_CollectionCount * sizeof(CCollection *)));
  746. CCollection ** pTemp = m_pCollections;
  747. m_pCollections = (CCollection **)
  748. ExAllocatePoolWithTag (NonPagedPool,
  749. m_CollectionCount * sizeof(CCollection *),
  750. HidBattTag);
  751. if (!m_pCollections) {
  752. // Re-allocation failure, print error and revert to previous state and return
  753. HidBattPrint(HIDBATT_ERROR, ("CCollectionArray: Could not resize CCollection"));
  754. m_pCollections = pTemp;
  755. m_CollectionCount--;
  756. return;
  757. }
  758. RtlCopyMemory(m_pCollections,pTemp,(m_CollectionCount -1) * sizeof(CCollection *));
  759. ExFreePool(pTemp);
  760. }
  761. // add collection to array
  762. CCollection * TempCollection = new (NonPagedPool, HidBattTag) CCollection(pTheNodes,usNodeCount,i);
  763. if (!TempCollection) {
  764. // Could not allocate new CCollection, print debug message and return
  765. HidBattPrint(HIDBATT_ERROR, ("CCollectionArray: Could not allocate new CCollection"));
  766. return;
  767. }
  768. m_pCollections[m_CollectionCount-1] = TempCollection;
  769. }
  770. }
  771. }
  772. }
  773. CCollectionArray::~CCollectionArray()
  774. {
  775. while(m_CollectionCount) {
  776. delete m_pCollections[--m_CollectionCount];
  777. }
  778. if (m_pCollections) {
  779. ExFreePool (m_pCollections);
  780. }
  781. return;
  782. }
  783. CCollection::CCollection(PHIDP_LINK_COLLECTION_NODE pTheNodes, USHORT usNodeCount,USHORT usNodeIndex)
  784. {
  785. m_UsageArray = (CUsageArray *) NULL;
  786. m_CollectionArray = (CCollectionArray *) NULL; // init vars
  787. // setup this collection
  788. CCollectionArray * ThisArray = new (NonPagedPool, HidBattTag) CCollectionArray(pTheNodes,usNodeCount,usNodeIndex);
  789. if (ThisArray) {
  790. if(!ThisArray->m_CollectionCount) {// any child collections
  791. delete ThisArray;
  792. } else {
  793. m_CollectionArray = ThisArray;
  794. }
  795. }
  796. // set the info in this collection
  797. m_CollectionID = pTheNodes[usNodeIndex].LinkUsage;
  798. m_UsagePage = pTheNodes[usNodeIndex].LinkUsagePage;
  799. m_NodeIndex = usNodeIndex;
  800. }
  801. CCollection::~CCollection()
  802. {
  803. // delete all usages in the usage array
  804. if(m_UsageArray)
  805. {
  806. delete m_UsageArray;
  807. }
  808. // delete all the sub collections
  809. if(m_CollectionArray)
  810. {
  811. delete m_CollectionArray;
  812. }
  813. }
  814. void CCollection::InitUsages(CHidDevice * ThisDevice)
  815. {
  816. bool bResult = FALSE;
  817. USHORT usUsageIndex = 0;
  818. CUsage * pThisUsage ;
  819. USHORT usInputIndex;
  820. HIDDebugBreak(HIDBATT_BREAK_NEVER);
  821. while( bResult = GetNextUsage(ThisDevice,m_CollectionID,m_NodeIndex,usUsageIndex,&pThisUsage))
  822. {
  823. if(!m_UsageArray) // if first usage
  824. {
  825. m_UsageArray = new (NonPagedPool, HidBattTag) CUsageArray();
  826. if (!m_UsageArray) {
  827. delete pThisUsage;
  828. return;
  829. }
  830. }
  831. pThisUsage->SetCapabilities();
  832. pThisUsage->m_pHidDevice = ThisDevice; // store this usage's device pointer
  833. if(pThisUsage->m_eType == eInputButton ||
  834. pThisUsage->m_eType == eInputValue)
  835. {
  836. // get input array index
  837. usInputIndex = ThisDevice->AssignIndexToReportId(pThisUsage->m_pProperties->m_ReportID);
  838. if(!ThisDevice->m_InputUsageArrays[usInputIndex])
  839. {
  840. // no array in this report position yet, create
  841. ThisDevice->m_InputUsageArrays[usInputIndex] = new (NonPagedPool, HidBattTag) CUsageArray();
  842. if (!(ThisDevice->m_InputUsageArrays[usInputIndex])) return;
  843. }
  844. ThisDevice->m_InputUsageArrays[usInputIndex]->AddUsage(pThisUsage); // add input usages to refresh stack
  845. }
  846. usUsageIndex++;
  847. m_UsageArray->AddUsage(pThisUsage);
  848. }
  849. // also init all my collections
  850. if(!m_CollectionArray) return;
  851. for(int i = 0; i < m_CollectionArray->m_CollectionCount; i++)
  852. {
  853. m_CollectionArray->m_pCollections[i]->InitUsages(ThisDevice);
  854. }
  855. }
  856. USHORT CHidDevice::AssignIndexToReportId(USHORT usReportId)
  857. {
  858. USHORT i;
  859. HidBattPrint(HIDBATT_TRACE,("AssignIndexToReportId: ReportId = %x -- ", usReportId));
  860. for(i = 0;i < MAXREPORTID; i++)
  861. {
  862. if(!m_ReportIdArray[i]) {
  863. HidBattPrint(HIDBATT_TRACE,("Assigning to %x\n", i));
  864. m_ReportIdArray[i] = usReportId;
  865. return i;
  866. }
  867. if(m_ReportIdArray[i] == usReportId) {
  868. HidBattPrint(HIDBATT_TRACE,("Already assigned to %x\n", i));
  869. return i;
  870. }
  871. }
  872. //
  873. // It would be really nice if we could dynamically allocate more
  874. // since there isn't a small limit set to the number of report IDs.
  875. //
  876. ASSERTMSG("MAXREPORTID exceeded.\n", FALSE);
  877. return 0;
  878. }
  879. USHORT CHidDevice::GetIndexFromReportId(USHORT usReportId)
  880. {
  881. USHORT i;
  882. HidBattPrint(HIDBATT_TRACE,("GetIndexFromReportId: ReportId = %x\n", usReportId));
  883. for(i = 0; i< MAXREPORTID; i++) {
  884. if(m_ReportIdArray[i] == usReportId) {
  885. return i;
  886. }
  887. }
  888. HidBattPrint(HIDBATT_TRACE,("GetIndexFromReportId: Failed\n", usReportId));
  889. return i; // error return is MAXREPORTIDS
  890. }
  891. CUsagePath * CCollection::FindIndexedUsage(USHORT * pCurrentIndex, USHORT TargetIndex)
  892. {
  893. CUsagePath * ThisPath;
  894. CUsagePath * NewPath;
  895. if(m_UsageArray)
  896. {
  897. if(m_UsageArray->m_UsageCount + *pCurrentIndex > TargetIndex)
  898. {
  899. // do the arithmetic to get the current index
  900. int ThisIndex = TargetIndex - *pCurrentIndex;
  901. // found it, construct usage path
  902. ThisPath = new (NonPagedPool, HidBattTag) CUsagePath(
  903. m_UsagePage,
  904. m_CollectionID,
  905. m_UsageArray->m_pUsages[ThisIndex]
  906. );
  907. return ThisPath;
  908. }
  909. // didn't find it, inc current index
  910. *pCurrentIndex += m_UsageArray->m_UsageCount;
  911. }
  912. if(!m_CollectionArray) return NULL; // nothing more, quit
  913. // call out the sub collections
  914. for(int i = 0; i < m_CollectionArray->m_CollectionCount; i++)
  915. {
  916. ThisPath = m_CollectionArray->m_pCollections[i]->FindIndexedUsage(pCurrentIndex, TargetIndex);
  917. if(ThisPath)
  918. {
  919. // one of our subcollections had the usage, add us to the path
  920. NewPath = new (NonPagedPool, HidBattTag) CUsagePath(
  921. m_UsagePage,
  922. m_CollectionID,
  923. NULL
  924. );
  925. if (!NewPath) {
  926. delete ThisPath;
  927. return NULL;
  928. }
  929. NewPath->m_pNextEntry = ThisPath;
  930. return NewPath;
  931. }
  932. }
  933. return NULL;
  934. }
  935. CUsagePath::~CUsagePath()
  936. {
  937. CUsagePath * tempNextEntry;
  938. tempNextEntry = m_pNextEntry;
  939. m_pNextEntry = NULL;
  940. if (tempNextEntry) {
  941. delete tempNextEntry;
  942. }
  943. return;
  944. }
  945. CUsage::CUsage()
  946. {
  947. // do member init
  948. m_pProperties = (CProperties *) NULL;
  949. m_pButtonCaps = (HIDP_BUTTON_CAPS *) NULL;
  950. m_pValueCaps = (HIDP_VALUE_CAPS *)NULL;
  951. m_eType = (eHidType) 0;
  952. m_Value = 0;
  953. m_String = (char *)NULL;
  954. return;
  955. }
  956. CUsage::~CUsage()
  957. {
  958. // free all associated objects
  959. if(m_pProperties) {
  960. delete m_pProperties;
  961. }
  962. return;
  963. }
  964. bool CUsage::GetValue()
  965. {
  966. NTSTATUS ntStatus;
  967. ULONG ulResult;
  968. bool bResult;
  969. BYTE ReportID;
  970. USHORT usDummy;
  971. HIDDebugBreak(HIDBATT_BREAK_NEVER);
  972. switch(m_eType)
  973. {
  974. case eFeatureValue:
  975. case eFeatureButton:
  976. ReportID = (BYTE) m_pProperties->m_ReportID;
  977. // do we have the report that contains this data?
  978. if(!m_pHidDevice->m_FeatureBuffer[ReportID])
  979. {
  980. // must first create and fill buffer from getfeature
  981. // allocate memory
  982. m_pHidDevice->m_FeatureBuffer[ReportID] =
  983. (PBYTE) ExAllocatePoolWithTag (NonPagedPool,
  984. m_pHidDevice->m_pCaps->FeatureReportByteLength+1,
  985. HidBattTag);
  986. RtlZeroMemory(m_pHidDevice->m_FeatureBuffer[ReportID],
  987. m_pHidDevice->m_pCaps->FeatureReportByteLength+1);
  988. // setup first byte of buffer to report id
  989. *m_pHidDevice->m_FeatureBuffer[ReportID] = ReportID;
  990. // now read in report
  991. HIDDebugBreak(HIDBATT_BREAK_DEBUG);
  992. HidBattPrint(HIDBATT_TRACE,("GetFeature\n"));
  993. ntStatus = DoIoctl(
  994. m_pHidDevice->m_pLowerDeviceObject,
  995. IOCTL_HID_GET_FEATURE,
  996. NULL,
  997. 0,
  998. m_pHidDevice->m_FeatureBuffer[ReportID],
  999. m_pHidDevice->m_pCaps->FeatureReportByteLength+1,
  1000. m_pHidDevice
  1001. );
  1002. if (!NT_SUCCESS (ntStatus)) {
  1003. HidBattPrint(HIDBATT_DATA,("GetFeature - IOCTL_HID_GET_FEATURE 0x%08x\n", ntStatus));
  1004. }
  1005. }
  1006. if(m_pProperties->m_pType->IsVolatile())
  1007. {
  1008. // this is a volatile value, refresh report
  1009. RtlZeroMemory(m_pHidDevice->m_FeatureBuffer[ReportID],
  1010. m_pHidDevice->m_pCaps->FeatureReportByteLength+1);
  1011. // setup first byte of buffer to report id
  1012. *m_pHidDevice->m_FeatureBuffer[ReportID] = ReportID;
  1013. // now read in report
  1014. HIDDebugBreak(HIDBATT_BREAK_NEVER);
  1015. HidBattPrint(HIDBATT_TRACE,("GetFeature - Refresh\n"));
  1016. ntStatus = DoIoctl(
  1017. m_pHidDevice->m_pLowerDeviceObject,
  1018. IOCTL_HID_GET_FEATURE,
  1019. NULL,
  1020. 0,
  1021. m_pHidDevice->m_FeatureBuffer[ReportID],
  1022. m_pHidDevice->m_pCaps->FeatureReportByteLength+1,
  1023. m_pHidDevice
  1024. );
  1025. if (!NT_SUCCESS (ntStatus)) {
  1026. HidBattPrint(HIDBATT_DATA,("GetFeature - (volitile) IOCTL_HID_GET_FEATURE 0x%08x\n", ntStatus));
  1027. // return error, fixes bug #357483
  1028. return FALSE;
  1029. }
  1030. }
  1031. if(m_eType == eFeatureValue)
  1032. {
  1033. ntStatus = HidP_GetUsageValue(
  1034. HidP_Feature,
  1035. m_pProperties->m_UsagePage,
  1036. m_pProperties->m_LinkCollection,
  1037. m_pProperties->m_Usage,
  1038. &ulResult,
  1039. m_pHidDevice->m_pPreparsedData,
  1040. (char *) m_pHidDevice->m_FeatureBuffer[ReportID],
  1041. m_pHidDevice->m_pCaps->FeatureReportByteLength
  1042. );
  1043. if(!NT_SUCCESS(ntStatus))
  1044. {
  1045. HidBattPrint(HIDBATT_DATA,("GetFeature - HidP_GetUsageValue 0x%08x\n", ntStatus));
  1046. // return error
  1047. return FALSE;
  1048. }
  1049. } else
  1050. {
  1051. // must get button data
  1052. ULONG Buttons, BufferSize;
  1053. PUSAGE pButtonBuffer;
  1054. Buttons = HidP_MaxUsageListLength (HidP_Feature, 0, m_pHidDevice->m_pPreparsedData);
  1055. BufferSize = Buttons * sizeof(USAGE);
  1056. pButtonBuffer = (PUSAGE) ExAllocatePoolWithTag (NonPagedPool,
  1057. BufferSize,
  1058. HidBattTag);
  1059. if (pButtonBuffer==NULL) {
  1060. HidBattPrint(HIDBATT_DATA,("GetFeature - ExAllocatePoolWithTag returned NULL."));
  1061. // return error
  1062. return FALSE;
  1063. }
  1064. else {
  1065. RtlZeroMemory(pButtonBuffer,BufferSize);
  1066. ntStatus = HidP_GetButtons(
  1067. HidP_Feature,
  1068. m_pProperties->m_UsagePage,
  1069. m_pProperties->m_LinkCollection,
  1070. (PUSAGE) pButtonBuffer,
  1071. &Buttons,
  1072. m_pHidDevice->m_pPreparsedData,
  1073. (char *) m_pHidDevice->m_FeatureBuffer[ReportID],
  1074. m_pHidDevice->m_pCaps->FeatureReportByteLength
  1075. );
  1076. }
  1077. if(!NT_SUCCESS(ntStatus))
  1078. {
  1079. HidBattPrint(HIDBATT_DATA,("GetFeature - HidP_GetButtons 0x%08x\n", ntStatus));
  1080. // return error
  1081. return FALSE;
  1082. }
  1083. // get the value for the requested button
  1084. PUSAGE pUsage = (PUSAGE) pButtonBuffer;
  1085. ulResult = 0; // set to not found value
  1086. for(int i = 0; i < (long) Buttons; i++)
  1087. {
  1088. if(pUsage[i] == m_pProperties->m_Usage)
  1089. {
  1090. ulResult = 1;
  1091. break;
  1092. }
  1093. }
  1094. ExFreePool(pButtonBuffer);
  1095. }
  1096. m_Value = ulResult;
  1097. return TRUE;
  1098. break;
  1099. case eInputValue:
  1100. case eInputButton:
  1101. // have we had input data ?
  1102. if(!m_pHidDevice->m_pReadBuffer) break; // nope, leave
  1103. // do we have the report that contains this data?
  1104. ReportID = (BYTE) m_pProperties->m_ReportID;
  1105. if(!*m_pHidDevice->m_pReadBuffer == ReportID) break; // not us
  1106. if(m_eType == eInputValue)
  1107. {
  1108. ntStatus = HidP_GetUsageValue(
  1109. HidP_Input,
  1110. m_pProperties->m_UsagePage,
  1111. m_pProperties->m_LinkCollection,
  1112. m_pProperties->m_Usage,
  1113. &ulResult,
  1114. m_pHidDevice->m_pPreparsedData,
  1115. (char *)m_pHidDevice->m_pReadBuffer,
  1116. m_pHidDevice->m_pCaps->InputReportByteLength
  1117. );
  1118. if(NT_ERROR(ntStatus)) {
  1119. HidBattPrint(HIDBATT_DATA,("GetFeature - (Button) HidP_GetUsageValue 0x%08x\n", ntStatus));
  1120. return FALSE;
  1121. }
  1122. } else
  1123. {
  1124. // handle button
  1125. // must get button data
  1126. ULONG Buttons, BufferSize;
  1127. PUSAGE_AND_PAGE pButtonBuffer;
  1128. Buttons = HidP_MaxUsageListLength (HidP_Input, 0, m_pHidDevice->m_pPreparsedData);
  1129. BufferSize = Buttons * sizeof(USAGE_AND_PAGE);
  1130. pButtonBuffer = (PUSAGE_AND_PAGE)
  1131. ExAllocatePoolWithTag (NonPagedPool,
  1132. BufferSize,
  1133. HidBattTag);
  1134. RtlZeroMemory(pButtonBuffer,BufferSize);
  1135. ntStatus = HidP_GetButtons(
  1136. HidP_Input,
  1137. m_pProperties->m_UsagePage,
  1138. m_pProperties->m_LinkCollection,
  1139. (PUSAGE) pButtonBuffer,
  1140. &Buttons,
  1141. m_pHidDevice->m_pPreparsedData,
  1142. (char *) m_pHidDevice->m_pReadBuffer,
  1143. m_pHidDevice->m_pCaps->InputReportByteLength
  1144. );
  1145. if(!NT_SUCCESS(ntStatus))
  1146. {
  1147. HidBattPrint(HIDBATT_DATA,("GetFeature - (Button) HidP_GetButton 0x%08x\n", ntStatus));
  1148. // return error
  1149. return FALSE;
  1150. }
  1151. // get the value for the requested button
  1152. USAGE_AND_PAGE * UsagePage = (USAGE_AND_PAGE *) pButtonBuffer;
  1153. ulResult = 0; // set to not found value
  1154. for(int i = 0; i < (long) Buttons; i++)
  1155. {
  1156. if(UsagePage[i].Usage == m_pProperties->m_Usage)
  1157. // don't need to check usage page, because it was specified
  1158. // && UsagePage[i].UsagePage == m_pProperties->m_UsagePage)
  1159. {
  1160. ulResult = 1;
  1161. break;
  1162. }
  1163. }
  1164. ExFreePool(pButtonBuffer);
  1165. }
  1166. if(m_Value != ulResult)
  1167. {
  1168. m_Value = ulResult;
  1169. // there's been a change, check if this needs alerting
  1170. if(m_pProperties->m_pType->IsAlertable())
  1171. {
  1172. // call registered notification callback with
  1173. // ... passing the notificable usage object
  1174. if(m_pHidDevice->m_pEventHandler)
  1175. {
  1176. (*m_pHidDevice->m_pEventHandler)(
  1177. m_pHidDevice->m_pEventContext,
  1178. this);
  1179. }
  1180. }
  1181. }
  1182. return TRUE;
  1183. break;
  1184. }
  1185. return FALSE;
  1186. }
  1187. void CUsage::SetCapabilities()
  1188. {
  1189. // init capabilites from value caps and set properties for this usage
  1190. m_pProperties = new (NonPagedPool, HidBattTag) CProperties(this);
  1191. }
  1192. ULONG CUsage::GetUnit()
  1193. {
  1194. return m_pProperties->m_Unit;
  1195. }
  1196. SHORT CUsage::GetExponent()
  1197. {
  1198. return m_pProperties->m_UnitExponent;
  1199. }
  1200. NTSTATUS CUsage::GetString(char * pBuffer, USHORT buffLen, PULONG pBytesReturned)
  1201. {
  1202. char cBuffer[4];
  1203. ULONG StringIndex;
  1204. NTSTATUS ntStatus;
  1205. ULONG ulBytesWritten = 0;
  1206. bool bResult;
  1207. // first must update this usages value
  1208. bResult = GetValue();
  1209. if(!bResult) return STATUS_UNSUCCESSFUL;
  1210. RtlCopyMemory(cBuffer,&m_Value,sizeof(ULONG));
  1211. ntStatus = DoIoctl(
  1212. m_pHidDevice->m_pLowerDeviceObject,
  1213. IOCTL_HID_GET_INDEXED_STRING,
  1214. cBuffer,
  1215. 4,
  1216. pBuffer,
  1217. buffLen,
  1218. m_pHidDevice);
  1219. return ntStatus;
  1220. }
  1221. // utility to do writefile for output reports
  1222. NTSTATUS HidWriteFile(
  1223. CHidDevice * pHidDevice,
  1224. PVOID pOutputBuffer,
  1225. USHORT usBufferLen,
  1226. PULONG pulBytesWritten
  1227. )
  1228. {
  1229. KEVENT WrittenEvent;
  1230. IO_STATUS_BLOCK IoStatusBlock;
  1231. PIO_STACK_LOCATION pNewStack;
  1232. return STATUS_SUCCESS;
  1233. KeInitializeEvent(&WrittenEvent,NotificationEvent,FALSE);
  1234. // allocate write irp
  1235. PIRP pIrp = IoBuildSynchronousFsdRequest(
  1236. IRP_MJ_WRITE,
  1237. pHidDevice->m_pLowerDeviceObject,
  1238. pOutputBuffer,
  1239. usBufferLen,
  1240. 0,
  1241. &WrittenEvent,
  1242. &IoStatusBlock
  1243. );
  1244. if(!pIrp) return STATUS_INSUFFICIENT_RESOURCES;
  1245. pNewStack= IoGetNextIrpStackLocation(pIrp);
  1246. pNewStack->FileObject = pHidDevice->m_pFCB;
  1247. NTSTATUS ntStatus = IoCallDriver(pHidDevice->m_pLowerDeviceObject,pIrp);
  1248. if(NT_ERROR(ntStatus))
  1249. {
  1250. IoFreeIrp(pIrp);
  1251. return ntStatus;
  1252. }
  1253. ntStatus = KeWaitForSingleObject(
  1254. &WrittenEvent,
  1255. Executive,
  1256. KernelMode,
  1257. FALSE,
  1258. NULL
  1259. );
  1260. IoFreeIrp(pIrp); // done with Irp
  1261. if(NT_ERROR(ntStatus))
  1262. {
  1263. return ntStatus;
  1264. }
  1265. *pulBytesWritten = (ULONG)IoStatusBlock.Information;
  1266. return IoStatusBlock.Status;
  1267. }
  1268. bool CUsage::SetValue(ULONG ulValue)
  1269. {
  1270. NTSTATUS ntStatus;
  1271. USHORT ThisType;
  1272. char * pOutputBuffer;
  1273. USHORT usBufferLen;
  1274. bool bResult;
  1275. ULONG ulBytesWritten;
  1276. HIDDebugBreak(HIDBATT_BREAK_NEVER);
  1277. // first check that this is an output or feature report
  1278. if(m_eType == eInputButton ||
  1279. m_eType == eInputValue)
  1280. {
  1281. // if this is an input usage, reject update
  1282. return FALSE;
  1283. }
  1284. if(m_eType == eOutputButton ||
  1285. m_eType == eOutputValue)
  1286. {
  1287. ThisType = HidP_Output;
  1288. usBufferLen = m_pHidDevice->m_pCaps->OutputReportByteLength;
  1289. } else
  1290. {
  1291. ThisType = HidP_Feature;
  1292. usBufferLen = m_pHidDevice->m_pCaps->FeatureReportByteLength + 1; // for report id
  1293. }
  1294. pOutputBuffer = (char *) ExAllocatePoolWithTag (NonPagedPool,
  1295. usBufferLen+1,
  1296. HidBattTag);
  1297. if (!pOutputBuffer) {
  1298. // Allocation failed
  1299. return FALSE;
  1300. }
  1301. pOutputBuffer[0] = (char) m_pProperties->m_ReportID;
  1302. // setup buffer for write
  1303. ntStatus = HidP_SetUsageValue(
  1304. (HIDP_REPORT_TYPE) ThisType, // either feature or output
  1305. m_pProperties->m_UsagePage,
  1306. m_pProperties->m_LinkCollection,
  1307. m_pProperties->m_Usage,
  1308. ulValue,
  1309. m_pHidDevice->m_pPreparsedData,
  1310. pOutputBuffer,
  1311. usBufferLen-1
  1312. );
  1313. if(ThisType == HidP_Output)
  1314. {
  1315. ntStatus = HidWriteFile(
  1316. m_pHidDevice,
  1317. pOutputBuffer,
  1318. usBufferLen,
  1319. &ulBytesWritten
  1320. );
  1321. } else
  1322. {
  1323. ntStatus = DoIoctl(
  1324. m_pHidDevice->m_pLowerDeviceObject,
  1325. IOCTL_HID_SET_FEATURE,
  1326. pOutputBuffer, //NULL,
  1327. usBufferLen, //0,
  1328. pOutputBuffer,
  1329. usBufferLen,
  1330. m_pHidDevice
  1331. );
  1332. }
  1333. ExFreePool (pOutputBuffer);
  1334. return ntStatus ? FALSE:TRUE;
  1335. }
  1336. // Usage Array Class
  1337. CUsageArray::CUsageArray()
  1338. {
  1339. m_UsageCount = 0;
  1340. m_pUsages = (CUsage **) NULL;
  1341. return;
  1342. }
  1343. CUsageArray::~CUsageArray()
  1344. {
  1345. while(m_UsageCount) {
  1346. delete m_pUsages[--m_UsageCount];
  1347. }
  1348. if (m_pUsages) {
  1349. ExFreePool (m_pUsages);
  1350. }
  1351. return;
  1352. }
  1353. void CUsageArray::AddUsage(CUsage * pNewUsage)
  1354. {
  1355. HIDDebugBreak(HIDBATT_BREAK_NEVER);
  1356. if(!m_pUsages)
  1357. {
  1358. m_pUsages = (CUsage **) ExAllocatePoolWithTag (NonPagedPool,
  1359. sizeof(CUsage *),
  1360. HidBattTag);
  1361. } else
  1362. {
  1363. CUsage ** pTemp = m_pUsages;
  1364. m_pUsages = (CUsage **) ExAllocatePoolWithTag (NonPagedPool,
  1365. sizeof(CUsage *) * (m_UsageCount + 1),
  1366. HidBattTag);
  1367. if (m_pUsages) {
  1368. memcpy(m_pUsages,pTemp,sizeof(CUsage *) * m_UsageCount);
  1369. ExFreePool(pTemp);
  1370. }
  1371. }
  1372. if (m_pUsages) {
  1373. m_pUsages[m_UsageCount] = pNewUsage;
  1374. m_UsageCount++;
  1375. }
  1376. // else - no way to report allocation failure. The only indication is that
  1377. // m_UsageCount is not increamented. (v-stebe)
  1378. }