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.

625 lines
22 KiB

  1. /*****************************************************************************
  2. *
  3. * DIHidDat.c
  4. *
  5. * Copyright (c) 1996 Microsoft Corporation. All Rights Reserved.
  6. *
  7. * Abstract:
  8. *
  9. * HID data management.
  10. *
  11. * Contents:
  12. *
  13. * CHid_AddDeviceData
  14. *
  15. *****************************************************************************/
  16. #include "dinputpr.h"
  17. /*****************************************************************************
  18. *
  19. * The sqiffle for this file.
  20. *
  21. *****************************************************************************/
  22. #define sqfl sqflHidDev
  23. #ifdef HID_SUPPORT
  24. /*****************************************************************************
  25. *
  26. * @doc INTERNAL
  27. *
  28. * @method void | CHid | DelDeviceData |
  29. *
  30. * Remove an item of device data from the list.
  31. *
  32. * We grab the last item and slide it into place, updating
  33. * the various pointers as we go.
  34. *
  35. * @parm PHIDREPORTINFO | phri |
  36. *
  37. * The HID report from which the item is being deleted.
  38. *
  39. * @parm int | idataDel |
  40. *
  41. * The data value being deleted.
  42. *
  43. * @parm HIDP_REPORT_TYPE | type |
  44. *
  45. * The report type we are mangling with.
  46. *
  47. *****************************************************************************/
  48. void INTERNAL
  49. CHid_DelDeviceData(PCHID this, PHIDREPORTINFO phri, int idataDel,
  50. HIDP_REPORT_TYPE type)
  51. {
  52. DWORD dwBase = this->rgdwBase[type];
  53. int iobjDel = phri->rgdata[idataDel].DataIndex + dwBase;
  54. PHIDOBJCAPS phocDel = &this->rghoc[iobjDel];
  55. int idataSrc;
  56. SquirtSqflPtszV(sqflHidOutput,
  57. TEXT("DelDeviceData(%d) - cdataUsed = %d, obj=%d"),
  58. idataDel, phri->cdataUsed, iobjDel);
  59. AssertF(idataDel >= 0);
  60. AssertF(idataDel < phri->cdataUsed);
  61. AssertF(phri->cdataUsed > 0);
  62. /*
  63. * Wipe out the item being deleted.
  64. * Remember that the report needs to be rebuilt.
  65. */
  66. AssertF(phocDel->idata == idataDel);
  67. phocDel->idata = -1;
  68. phri->fNeedClear = TRUE;
  69. /*
  70. * Slide the top item into its place.
  71. */
  72. idataSrc = (int)--(phri->cdataUsed);
  73. if (idataSrc > idataDel) {
  74. int iobjSrc;
  75. PHIDOBJCAPS phocSrc;
  76. AssertF(idataSrc > 0 && idataSrc < phri->cdataMax);
  77. iobjSrc = phri->rgdata[idataSrc].DataIndex + dwBase;
  78. phocSrc = &this->rghoc[iobjSrc];
  79. AssertF(phocSrc->idata == idataSrc);
  80. phocSrc->idata = idataDel;
  81. phri->rgdata[idataDel] = phri->rgdata[idataSrc];
  82. }
  83. }
  84. /*****************************************************************************
  85. *
  86. * @doc INTERNAL
  87. *
  88. * @method void | CHid | ResetDeviceData |
  89. *
  90. * Clean out all old device data from the list.
  91. *
  92. * @parm PHIDREPORTINFO | phri |
  93. *
  94. * The HID report which should be reset.
  95. *
  96. * @parm HIDP_REPORT_TYPE | type |
  97. *
  98. * The report type we are mangling with.
  99. *
  100. *****************************************************************************/
  101. void EXTERNAL
  102. CHid_ResetDeviceData(PCHID this, PHIDREPORTINFO phri, HIDP_REPORT_TYPE type)
  103. {
  104. SquirtSqflPtszV(sqflHidOutput,
  105. TEXT("ResetDeviceData(%d) - cdataUsed = %d"),
  106. type, phri->cdataUsed);
  107. if (phri->cdataUsed) {
  108. int idata;
  109. DWORD dwBase = this->rgdwBase[type];
  110. phri->fNeedClear = TRUE;
  111. for (idata = 0; idata < phri->cdataUsed; idata++) {
  112. int iobj = phri->rgdata[idata].DataIndex + dwBase;
  113. PHIDOBJCAPS phoc = &this->rghoc[iobj];
  114. AssertF(phoc->idata == idata);
  115. phoc->idata = -1;
  116. }
  117. phri->cdataUsed = 0;
  118. }
  119. }
  120. /*****************************************************************************
  121. *
  122. * @doc INTERNAL
  123. *
  124. * @method HRESULT | CHid | AddDeviceData |
  125. *
  126. * Add (or replace) a piece of device data to the array.
  127. *
  128. * If we are removing a button, then we delete it, because
  129. * the HID way of talking about a button is "If you don't
  130. * talk about it, then it isn't set."
  131. *
  132. * @parm UINT | uiObj |
  133. *
  134. * The object being added.
  135. *
  136. * @parm DWORD | dwData |
  137. *
  138. * The data value to add.
  139. *
  140. * @returns
  141. *
  142. * Returns a COM error code. The following error codes are
  143. * intended to be illustrative and not necessarily comprehensive.
  144. *
  145. * <c DI_OK> = <c S_OK>: The operation completed successfully.
  146. *
  147. * <c DIERR_REPORTFULL>: Too many items are set in the report.
  148. * ISSUE-2001/03/29-timgill Need more document clarification
  149. *
  150. *****************************************************************************/
  151. HRESULT EXTERNAL
  152. CHid_AddDeviceData(PCHID this, UINT uiObj, DWORD dwData)
  153. {
  154. HRESULT hres;
  155. LPDIOBJECTDATAFORMAT podf;
  156. AssertF(uiObj < this->df.dwNumObjs);
  157. podf = &this->df.rgodf[uiObj];
  158. if (podf->dwType & DIDFT_OUTPUT) {
  159. PHIDOBJCAPS phoc = &this->rghoc[uiObj];
  160. PHIDGROUPCAPS pcaps = phoc->pcaps;
  161. PHIDREPORTINFO phri;
  162. // 7/19/2000(a-JiTay): IA64: Use %p format specifier for 32/64-bit pointers.
  163. SquirtSqflPtszV(sqflHidOutput,
  164. TEXT("CHid_AddDeviceData(%p, %d, %d) - type %d"),
  165. this, uiObj, dwData, pcaps->type);
  166. /*
  167. * Decide if it's HidP_Output or HidP_Feature.
  168. */
  169. AssertF(HidP_IsOutputLike(pcaps->type));
  170. switch (pcaps->type) {
  171. case HidP_Output: phri = &this->hriOut; break;
  172. case HidP_Feature: phri = &this->hriFea; break;
  173. default: AssertF(0); hres = E_FAIL; goto done;
  174. }
  175. AssertF(phri->cdataUsed <= phri->cdataMax);
  176. if (phoc->idata == -1) {
  177. SquirtSqflPtszV(sqflHidOutput,
  178. TEXT("CHid_AddDeviceData - no iData"));
  179. } else {
  180. AssertF(phoc->idata < phri->cdataUsed);
  181. AssertF(uiObj == phri->rgdata[phoc->idata].DataIndex +
  182. this->rgdwBase[pcaps->type]);
  183. SquirtSqflPtszV(sqflHidOutput,
  184. TEXT("CHid_AddDeviceData - iData = %d ")
  185. TEXT("DataIndex = %d"),
  186. phoc->idata,
  187. phri->rgdata[phoc->idata].DataIndex);
  188. }
  189. phri->fChanged = TRUE;
  190. if (pcaps->IsValue) {
  191. /*
  192. * Just swipe the value.
  193. * The fallthrough code will handle this.
  194. */
  195. } else {
  196. /*
  197. * If the button is being deleted, then delete it
  198. * and that's all.
  199. */
  200. if (dwData == 0) {
  201. if (phoc->idata >= 0) {
  202. CHid_DelDeviceData(this, phri, phoc->idata, pcaps->type);
  203. AssertF(phoc->idata == -1);
  204. } else {
  205. SquirtSqflPtszV(sqflHidOutput,
  206. TEXT("CHid_AddDeviceData - nop"));
  207. }
  208. hres = S_OK;
  209. goto done;
  210. } else {
  211. dwData = TRUE; /* HidP_SetData requires this for buttons */
  212. }
  213. }
  214. /*
  215. * If there is not already a slot for this item, then
  216. * find one.
  217. */
  218. if (phoc->idata < 0) {
  219. if (phri->cdataUsed < phri->cdataMax) {
  220. USHORT DataIndex;
  221. phoc->idata = phri->cdataUsed++;
  222. DataIndex = (USHORT)(uiObj - this->rgdwBase[pcaps->type]);
  223. phri->rgdata[phoc->idata].DataIndex = DataIndex;
  224. SquirtSqflPtszV(sqflHidOutput,
  225. TEXT("CHid_AddDeviceData - create iData = %d ")
  226. TEXT("DataIndex = %d"),
  227. phoc->idata,
  228. DataIndex);
  229. } else {
  230. RPF("SendDeviceData: No room for more data");
  231. hres = DIERR_REPORTFULL;
  232. goto done;
  233. }
  234. }
  235. AssertF(phri->cdataUsed <= phri->cdataMax);
  236. AssertF(phoc->idata >= 0 && phoc->idata < phri->cdataUsed);
  237. AssertF(uiObj == phri->rgdata[phoc->idata].DataIndex +
  238. this->rgdwBase[pcaps->type]);
  239. /*
  240. * Here it comes... The entire purpose of this function
  241. * is the following line of code... (Well, not the
  242. * *entire* purpose, but 90% of it...)
  243. */
  244. phri->rgdata[phoc->idata].RawValue = dwData;
  245. SquirtSqflPtszV(sqflHidOutput,
  246. TEXT("CHid_AddDeviceData - iData(%d) dwData = %d"),
  247. phoc->idata, dwData);
  248. hres = S_OK;
  249. done:;
  250. } else {
  251. RPF("SendDeviceData: Object %08x is not DIDFT_OUTPUT",
  252. podf->dwType);
  253. hres = E_INVALIDARG;
  254. }
  255. return hres;
  256. }
  257. /*****************************************************************************
  258. *
  259. * @doc INTERNAL
  260. *
  261. * @method HRESULT | CHid | SendHIDReport |
  262. *
  263. * Build up an output or feature report and send it.
  264. * If the report has not changed, then do nothing.
  265. *
  266. * @parm PHIDREPORTINFO | phri |
  267. *
  268. * Describes the HID report we should build.
  269. *
  270. * @parm OUTPUTHIDREPORT | OutputHIDReport |
  271. *
  272. * Output a HID report to wherever it's supposed to go.
  273. *
  274. * @parm HIDP_REPORT_TYPE | type |
  275. *
  276. * The report type being sent.
  277. * <c HidP_Output> or <c HidP_Feature>.
  278. *
  279. * @returns
  280. *
  281. * Returns a COM error code. The following error codes are
  282. * intended to be illustrative and not necessarily comprehensive.
  283. *
  284. * <c DI_OK> = <c S_OK>: The operation completed successfully
  285. * and the report is ready to be sent to the device.
  286. *
  287. * <c DIERR_REPORTFULL>: Too many items are set in the report.
  288. *
  289. * @cb HRESULT CALLBACK | SendHIDReportProc |
  290. *
  291. * An internal callback which takes a composed HID report
  292. * and sends it in the appropriate manner to the device.
  293. *
  294. * @parm PCHID | this |
  295. *
  296. * The device in question.
  297. *
  298. * @parm PHIDREPORTINFO | phri |
  299. *
  300. * The report being sent.
  301. *
  302. *****************************************************************************/
  303. STDMETHODIMP
  304. CHid_SendHIDReport(PCHID this, PHIDREPORTINFO phri, HIDP_REPORT_TYPE type,
  305. SENDHIDREPORT SendHIDReport)
  306. {
  307. HRESULT hres = S_OK;
  308. DWORD cdata;
  309. NTSTATUS stat;
  310. if (phri->fChanged) {
  311. if (phri->fNeedClear) {
  312. ZeroMemory(phri->pvReport, phri->cbReport);
  313. phri->fNeedClear = FALSE;
  314. }
  315. cdata = phri->cdataUsed;
  316. stat = HidP_SetData(type, phri->rgdata, &cdata, this->ppd,
  317. phri->pvReport, phri->cbReport);
  318. if (SUCCEEDED(stat) && (int)cdata == phri->cdataUsed) {
  319. if ( SUCCEEDED( hres = SendHIDReport(this, phri) ) ) {
  320. phri->fChanged = FALSE;
  321. }
  322. } else if (stat == HIDP_STATUS_BUFFER_TOO_SMALL) {
  323. hres = DIERR_REPORTFULL;
  324. } else {
  325. RPF("SendDeviceData: Unexpected HID failure");
  326. hres = E_FAIL;
  327. }
  328. } else {
  329. /* Vacuous success */
  330. }
  331. return hres;
  332. }
  333. /*****************************************************************************
  334. *
  335. * @doc INTERNAL
  336. *
  337. * @method NTSTATUS | CHid | ParseData |
  338. *
  339. * Parse a single input report and set up the
  340. * <e CHid.pvStage> buffer to contain the new device state.
  341. *
  342. * @parm HIDP_REPORT_TYPE | type |
  343. *
  344. * HID report type being parsed.
  345. *
  346. * @parm PHIDREPORTINFO | phri |
  347. *
  348. * Information that tells us how to parse the report.
  349. *
  350. *****************************************************************************/
  351. NTSTATUS INTERNAL
  352. CHid_ParseData(PCHID this, HIDP_REPORT_TYPE type, PHIDREPORTINFO phri)
  353. {
  354. NTSTATUS stat = E_FAIL;
  355. /*
  356. * Do this only if there are inputs at all. This avoids
  357. * annoying boundary conditions.
  358. */
  359. UCHAR uReportId;
  360. ULONG cdataMax = phri->cdataMax;
  361. if (cdataMax && phri->cbReport) {
  362. uReportId = *(UCHAR*)phri->pvReport;
  363. if( uReportId < this->wMaxReportId[type] &&
  364. *(this->pEnableReportId[type] + uReportId) )
  365. {
  366. stat = HidP_GetData(type, phri->rgdata, &cdataMax,
  367. this->ppd, phri->pvReport, phri->cbReport);
  368. if (SUCCEEDED(stat)) {
  369. ULONG idata;
  370. /*
  371. * If we successfully got stuff, then wipe out the old
  372. * buttons and start with new ones.
  373. *
  374. * HID data parsing rules differ from buttons to axes.
  375. * For buttons, the rule is that if it isn't in the
  376. * report, then the button isn't presed.
  377. *
  378. * Compare axes, where the rule is that if it isn't
  379. * in the report, then the value is unchanged.
  380. *
  381. * To avoid deleting buttons that are reported in reports
  382. * other than the one just received we check for multiple
  383. * reports during initialization and if necessary set up mask
  384. * arrays for the buttons. The mask is an arrays of bytes of
  385. * the same length as the button data, one for each report
  386. * that contains any buttons. If the device only has one
  387. * report there are no mask arrays so we can optimize by just
  388. * zeroing all the buttons. If the device has multiple
  389. * reports there is an array of pointers to the mask arrays,
  390. * if a report has no buttons, the pointer is NULL so no
  391. * further processing is required. For reports that do have
  392. * buttons, each byte in the button data is ANDed with the
  393. * corresponding byte in the mask so that only buttons in
  394. * the received report are zeroed.
  395. */
  396. if( this->rgpbButtonMasks == NULL )
  397. {
  398. /*
  399. * Only one report so just zero all buttons
  400. * This is the normal case so it is important that this
  401. * be done as quickly as possible.
  402. */
  403. ZeroMemory(pvAddPvCb(this->pvStage, this->ibButtonData),
  404. this->cbButtonData);
  405. }
  406. else
  407. {
  408. if( this->rgpbButtonMasks[uReportId-1] != NULL )
  409. {
  410. /*
  411. * ISSUE-2001/05/12-MarcAnd Could mask buttons faster
  412. * If we do this often, we could consider doing masks
  413. * with multiple bytes in each opperation.
  414. */
  415. PBYTE pbMask;
  416. PBYTE pbButtons;
  417. PBYTE pbButtonEnd = pvAddPvCb(this->pvStage, this->ibButtonData + this->cbButtonData);
  418. for( pbMask = this->rgpbButtonMasks[uReportId-1],
  419. pbButtons = pvAddPvCb(this->pvStage, this->ibButtonData);
  420. pbButtons < pbButtonEnd;
  421. pbMask++, pbButtons++ )
  422. {
  423. *pbButtons &= *pbMask;
  424. }
  425. }
  426. else
  427. {
  428. /*
  429. * No buttons in this report
  430. */
  431. }
  432. }
  433. for (idata = 0; idata < cdataMax; idata++) {
  434. UINT uiObj;
  435. PHIDGROUPCAPS pcaps;
  436. /*
  437. * Be careful and make sure that HID didn't
  438. * give us anything with a bogus item index.
  439. *
  440. * ISSUE-2001/03/29-timgill Not Feature-friendly.
  441. */
  442. AssertF(this->rgdwBase[HidP_Input] == 0);
  443. SquirtSqflPtszV(sqfl | sqflTrace,
  444. TEXT("HidP_GetData: %2d -> %d"),
  445. phri->rgdata[idata].DataIndex,
  446. phri->rgdata[idata].RawValue);
  447. uiObj = this->rgdwBase[type] + phri->rgdata[idata].DataIndex;
  448. if (uiObj < this->df.dwNumObjs &&
  449. (pcaps = this->rghoc[uiObj].pcaps) &&
  450. pcaps->type == type) {
  451. LPDIOBJECTDATAFORMAT podf;
  452. LONG lValue = (LONG)phri->rgdata[idata].RawValue;
  453. /*
  454. * Sign-extend the raw value if necessary.
  455. */
  456. if (lValue & pcaps->lMask ) {
  457. if( pcaps->IsSigned)
  458. lValue |= pcaps->lMask;
  459. else
  460. lValue &= pcaps->lMask;
  461. }
  462. if (HidP_IsOutputLike(pcaps->type)) {
  463. HRESULT hres;
  464. hres = CHid_AddDeviceData(this, uiObj, lValue);
  465. AssertF(SUCCEEDED(hres));
  466. }
  467. podf = &this->df.rgodf[uiObj];
  468. if (!pcaps->IsValue) {
  469. LPBYTE pb = pvAddPvCb(this->pvStage, podf->dwOfs);
  470. AssertF(lValue);
  471. *pb = 0x80;
  472. } else {
  473. LONG UNALIGNED *pl = pvAddPvCb(this->pvStage, podf->dwOfs);
  474. // ISSUE-2001/03/29-timgill need to consider how logical/physical mapping can alter scaling
  475. if (podf->dwType & DIDFT_RELAXIS) {
  476. if (pcaps->usGranularity) {
  477. lValue = -lValue * pcaps->usGranularity;
  478. }
  479. *pl += lValue;
  480. } else if ( (podf->dwType & DIDFT_ABSAXIS)
  481. #ifdef WINNT
  482. || ((podf->dwType & DIDFT_POV) && pcaps->IsPolledPOV)
  483. #endif
  484. ) {
  485. PJOYRANGECONVERT pjrc;
  486. *pl = lValue;
  487. /*
  488. * Apply the ramp if any.
  489. */
  490. pjrc = this->rghoc[uiObj].pjrc;
  491. if( pjrc
  492. && !( this->pvi->fl & VIFL_RELATIVE ) )
  493. {
  494. CCal_CookRange(pjrc, pl);
  495. }
  496. } else if (podf->dwType & DIDFT_BUTTON) {
  497. /*
  498. * Current applications do not expect any values
  499. * other than zero and 0x80. Just in case
  500. * someone has implemented an analog button the
  501. * way we had suggested, make sure we any value
  502. * greater than or equal to half pressed reports
  503. * 0x80 and anything else reports as zero.
  504. * Note, out of range values default to zero.
  505. */
  506. if( ( lValue <= pcaps->Logical.Max )
  507. && ( ( lValue - pcaps->Logical.Min ) >=
  508. ( ( ( pcaps->Logical.Max - pcaps->Logical.Min ) + 1 ) / 2 ) ) )
  509. {
  510. *((PBYTE)pl) = 0x80;
  511. }
  512. else
  513. {
  514. *((PBYTE)pl) = 0;
  515. }
  516. } else if (podf->dwType & DIDFT_POV) {
  517. /*
  518. * For (non-polled) POVs, an out of range value
  519. * is a NULL aka centered. Otherwise work out
  520. * the angle from the fraction of the circle.
  521. */
  522. if (lValue < pcaps->Logical.Min ||
  523. lValue > pcaps->Logical.Max) {
  524. *pl = JOY_POVCENTERED;
  525. } else {
  526. lValue -= pcaps->Logical.Min;
  527. *pl = lValue * pcaps->usGranularity;
  528. }
  529. }
  530. }
  531. } else {
  532. SquirtSqflPtszV(sqfl | sqflTrace,
  533. TEXT("HidP_GetData: Unable to use data element"));
  534. }
  535. }
  536. stat = S_OK;
  537. }
  538. stat = S_OK;
  539. }
  540. } else {
  541. stat = E_FAIL;
  542. }
  543. return stat;
  544. }
  545. #endif