Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

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