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.

601 lines
20 KiB

  1. /*++
  2. Copyright (c) 1996 Microsoft Corporation
  3. Module Name:
  4. report.c
  5. Abstract:
  6. This module contains the code for reading/writing hid reports and
  7. translating those HID reports into useful information.
  8. Environment:
  9. User mode
  10. @@BEGIN_DDKSPLIT
  11. Revision History:
  12. Nov-96 : Created by Kenneth D. Ray
  13. @@END_DDKSPLIT
  14. --*/
  15. #include <stdlib.h>
  16. #include <wtypes.h>
  17. #include "hidsdi.h"
  18. #include "hid.h"
  19. BOOLEAN
  20. UnpackReport (
  21. IN PCHAR ReportBuffer,
  22. IN USHORT ReportBufferLength,
  23. IN HIDP_REPORT_TYPE ReportType,
  24. IN OUT PHID_DATA Data,
  25. IN ULONG DataLength,
  26. IN PHIDP_PREPARSED_DATA Ppd
  27. );
  28. BOOLEAN
  29. PackReport (
  30. OUT PCHAR ReportBuffer,
  31. IN USHORT ReportBufferLength,
  32. IN HIDP_REPORT_TYPE ReportType,
  33. IN PHID_DATA Data,
  34. IN ULONG DataLength,
  35. IN PHIDP_PREPARSED_DATA Ppd
  36. );
  37. BOOLEAN
  38. Read (
  39. PHID_DEVICE HidDevice
  40. )
  41. /*++
  42. RoutineDescription:
  43. Given a struct _HID_DEVICE, obtain a read report and unpack the values
  44. into the InputData array.
  45. --*/
  46. {
  47. DWORD bytesRead;
  48. if (!ReadFile (HidDevice->HidDevice,
  49. HidDevice->InputReportBuffer,
  50. HidDevice->Caps.InputReportByteLength,
  51. &bytesRead,
  52. NULL))
  53. {
  54. return FALSE;
  55. }
  56. ASSERT (bytesRead == HidDevice->Caps.InputReportByteLength);
  57. if (bytesRead != HidDevice->Caps.InputReportByteLength)
  58. {
  59. return FALSE;
  60. }
  61. return UnpackReport (HidDevice->InputReportBuffer,
  62. HidDevice->Caps.InputReportByteLength,
  63. HidP_Input,
  64. HidDevice->InputData,
  65. HidDevice->InputDataLength,
  66. HidDevice->Ppd);
  67. }
  68. BOOLEAN
  69. ReadOverlapped (
  70. PHID_DEVICE HidDevice,
  71. HANDLE CompletionEvent
  72. )
  73. /*++
  74. RoutineDescription:
  75. Given a struct _HID_DEVICE, obtain a read report and unpack the values
  76. into the InputData array.
  77. --*/
  78. {
  79. static OVERLAPPED overlap;
  80. DWORD bytesRead;
  81. BOOL readStatus;
  82. /*
  83. // Setup the overlap structure using the completion event passed in to
  84. // to use for signalling the completion of the Read
  85. */
  86. memset(&overlap, 0, sizeof(OVERLAPPED));
  87. overlap.hEvent = CompletionEvent;
  88. /*
  89. // Execute the read call saving the return code to determine how to
  90. // proceed (ie. the read completed synchronously or not).
  91. */
  92. readStatus = ReadFile ( HidDevice -> HidDevice,
  93. HidDevice -> InputReportBuffer,
  94. HidDevice -> Caps.InputReportByteLength,
  95. &bytesRead,
  96. &overlap);
  97. /*
  98. // If the readStatus is FALSE, then one of two cases occurred.
  99. // 1) ReadFile call succeeded but the Read is an overlapped one. Here,
  100. // we should return TRUE to indicate that the Read succeeded. However,
  101. // the calling thread should be blocked on the completion event
  102. // which means it won't continue until the read actually completes
  103. //
  104. // 2) The ReadFile call failed for some unknown reason...In this case,
  105. // the return code will be FALSE
  106. */
  107. if (!readStatus)
  108. {
  109. return (ERROR_IO_PENDING == GetLastError());
  110. }
  111. /*
  112. // If readStatus is TRUE, then the ReadFile call completed synchronously,
  113. // since the calling thread is probably going to wait on the completion
  114. // event, signal the event so it knows it can continue.
  115. */
  116. else
  117. {
  118. SetEvent(CompletionEvent);
  119. return (TRUE);
  120. }
  121. }
  122. BOOLEAN
  123. Write (
  124. PHID_DEVICE HidDevice
  125. )
  126. /*++
  127. RoutineDescription:
  128. Given a struct _HID_DEVICE, take the information in the HID_DATA array
  129. pack it into multiple write reports and send each report to the HID device
  130. --*/
  131. {
  132. DWORD bytesWritten;
  133. PHID_DATA pData;
  134. ULONG Index;
  135. BOOLEAN Status;
  136. BOOLEAN WriteStatus;
  137. /*
  138. // Begin by looping through the HID_DEVICE's HID_DATA structure and setting
  139. // the IsDataSet field to FALSE to indicate that each structure has
  140. // not yet been set for this Write call.
  141. */
  142. pData = HidDevice -> OutputData;
  143. for (Index = 0; Index < HidDevice -> OutputDataLength; Index++, pData++)
  144. {
  145. pData -> IsDataSet = FALSE;
  146. }
  147. /*
  148. // In setting all the data in the reports, we need to pack a report buffer
  149. // and call WriteFile for each report ID that is represented by the
  150. // device structure. To do so, the IsDataSet field will be used to
  151. // determine if a given report field has already been set.
  152. */
  153. Status = TRUE;
  154. pData = HidDevice -> OutputData;
  155. for (Index = 0; Index < HidDevice -> OutputDataLength; Index++, pData++)
  156. {
  157. if (!pData -> IsDataSet)
  158. {
  159. /*
  160. // Package the report for this data structure. PackReport will
  161. // set the IsDataSet fields of this structure and any other
  162. // structures that it includes in the report with this structure
  163. */
  164. PackReport (HidDevice->OutputReportBuffer,
  165. HidDevice->Caps.OutputReportByteLength,
  166. HidP_Output,
  167. pData,
  168. HidDevice->OutputDataLength - Index,
  169. HidDevice->Ppd);
  170. /*
  171. // Now a report has been packaged up...Send it down to the device
  172. */
  173. WriteStatus = WriteFile (HidDevice->HidDevice,
  174. HidDevice->OutputReportBuffer,
  175. HidDevice->Caps.OutputReportByteLength,
  176. &bytesWritten,
  177. NULL) && (bytesWritten == HidDevice -> Caps.OutputReportByteLength);
  178. Status = Status && WriteStatus;
  179. }
  180. }
  181. return (Status);
  182. }
  183. BOOLEAN
  184. SetFeature (
  185. PHID_DEVICE HidDevice
  186. )
  187. /*++
  188. RoutineDescription:
  189. Given a struct _HID_DEVICE, take the information in the HID_DATA array
  190. pack it into multiple reports and send it to the hid device via HidD_SetFeature()
  191. --*/
  192. {
  193. PHID_DATA pData;
  194. ULONG Index;
  195. BOOLEAN Status;
  196. BOOLEAN FeatureStatus;
  197. /*
  198. // Begin by looping through the HID_DEVICE's HID_DATA structure and setting
  199. // the IsDataSet field to FALSE to indicate that each structure has
  200. // not yet been set for this SetFeature() call.
  201. */
  202. pData = HidDevice -> FeatureData;
  203. for (Index = 0; Index < HidDevice -> FeatureDataLength; Index++, pData++)
  204. {
  205. pData -> IsDataSet = FALSE;
  206. }
  207. /*
  208. // In setting all the data in the reports, we need to pack a report buffer
  209. // and call WriteFile for each report ID that is represented by the
  210. // device structure. To do so, the IsDataSet field will be used to
  211. // determine if a given report field has already been set.
  212. */
  213. Status = TRUE;
  214. pData = HidDevice -> FeatureData;
  215. for (Index = 0; Index < HidDevice -> FeatureDataLength; Index++, pData++)
  216. {
  217. if (!pData -> IsDataSet)
  218. {
  219. /*
  220. // Package the report for this data structure. PackReport will
  221. // set the IsDataSet fields of this structure and any other
  222. // structures that it includes in the report with this structure
  223. */
  224. PackReport (HidDevice->FeatureReportBuffer,
  225. HidDevice->Caps.FeatureReportByteLength,
  226. HidP_Feature,
  227. pData,
  228. HidDevice->FeatureDataLength - Index,
  229. HidDevice->Ppd);
  230. /*
  231. // Now a report has been packaged up...Send it down to the device
  232. */
  233. FeatureStatus =(HidD_SetFeature (HidDevice->HidDevice,
  234. HidDevice->FeatureReportBuffer,
  235. HidDevice->Caps.FeatureReportByteLength));
  236. Status = Status && FeatureStatus;
  237. }
  238. }
  239. return (Status);
  240. }
  241. BOOLEAN
  242. GetFeature (
  243. PHID_DEVICE HidDevice
  244. )
  245. /*++
  246. RoutineDescription:
  247. Given a struct _HID_DEVICE, fill in the feature data structures with
  248. all features on the device. May issue multiple HidD_GetFeature() calls to
  249. deal with multiple report IDs.
  250. --*/
  251. {
  252. ULONG Index;
  253. PHID_DATA pData;
  254. BOOLEAN FeatureStatus;
  255. BOOLEAN Status;
  256. /*
  257. // As with writing data, the IsDataSet value in all the structures should be
  258. // set to FALSE to indicate that the value has yet to have been set
  259. */
  260. pData = HidDevice -> FeatureData;
  261. for (Index = 0; Index < HidDevice -> FeatureDataLength; Index++, pData++)
  262. {
  263. pData -> IsDataSet = FALSE;
  264. }
  265. /*
  266. // Next, each structure in the HID_DATA buffer is filled in with a value
  267. // that is retrieved from one or more calls to HidD_GetFeature. The
  268. // number of calls is equal to the number of reportIDs on the device
  269. */
  270. Status = TRUE;
  271. pData = HidDevice -> FeatureData;
  272. for (Index = 0; Index < HidDevice -> FeatureDataLength; Index++, pData++)
  273. {
  274. /*
  275. // If a value has yet to have been set for this structure, build a report
  276. // buffer with its report ID as the first byte of the buffer and pass
  277. // it in the HidD_GetFeature call. Specifying the report ID in the
  278. // first specifies which report is actually retrieved from the device.
  279. // The rest of the buffer should be zeroed before the call
  280. */
  281. if (!pData -> IsDataSet)
  282. {
  283. memset(HidDevice -> FeatureReportBuffer, 0x00, HidDevice->Caps.FeatureReportByteLength);
  284. HidDevice -> FeatureReportBuffer[0] = (UCHAR) pData -> ReportID;
  285. FeatureStatus = HidD_GetFeature (HidDevice->HidDevice,
  286. HidDevice->FeatureReportBuffer,
  287. HidDevice->Caps.FeatureReportByteLength);
  288. /*
  289. // If the return value is TRUE, scan through the rest of the HID_DATA
  290. // structures and fill whatever values we can from this report
  291. */
  292. if (FeatureStatus)
  293. {
  294. FeatureStatus = UnpackReport ( HidDevice->FeatureReportBuffer,
  295. HidDevice->Caps.FeatureReportByteLength,
  296. HidP_Feature,
  297. HidDevice->FeatureData,
  298. HidDevice->FeatureDataLength,
  299. HidDevice->Ppd);
  300. }
  301. Status = Status && FeatureStatus;
  302. }
  303. }
  304. return (Status);
  305. }
  306. BOOLEAN
  307. UnpackReport (
  308. IN PCHAR ReportBuffer,
  309. IN USHORT ReportBufferLength,
  310. IN HIDP_REPORT_TYPE ReportType,
  311. IN OUT PHID_DATA Data,
  312. IN ULONG DataLength,
  313. IN PHIDP_PREPARSED_DATA Ppd
  314. )
  315. /*++
  316. Routine Description:
  317. Given ReportBuffer representing a report from a HID device where the first
  318. byte of the buffer is the report ID for the report, extract all the HID_DATA
  319. in the Data list from the given report.
  320. --*/
  321. {
  322. ULONG numUsages; // Number of usages returned from GetUsages.
  323. ULONG i;
  324. UCHAR reportID;
  325. ULONG Index;
  326. ULONG nextUsage;
  327. reportID = ReportBuffer[0];
  328. for (i = 0; i < DataLength; i++, Data++)
  329. {
  330. if (reportID == Data->ReportID)
  331. {
  332. if (Data->IsButtonData)
  333. {
  334. numUsages = Data->ButtonData.MaxUsageLength;
  335. Data->Status = HidP_GetUsages (ReportType,
  336. Data->UsagePage,
  337. 0, // All collections
  338. Data->ButtonData.Usages,
  339. &numUsages,
  340. Ppd,
  341. ReportBuffer,
  342. ReportBufferLength);
  343. //
  344. // Get usages writes the list of usages into the buffer
  345. // Data->ButtonData.Usages newUsage is set to the number of usages
  346. // written into this array.
  347. // A usage cannot not be defined as zero, so we'll mark a zero
  348. // following the list of usages to indicate the end of the list of
  349. // usages
  350. //
  351. // NOTE: One anomaly of the GetUsages function is the lack of ability
  352. // to distinguish the data for one ButtonCaps from another
  353. // if two different caps structures have the same UsagePage
  354. // For instance:
  355. // Caps1 has UsagePage 07 and UsageRange of 0x00 - 0x167
  356. // Caps2 has UsagePage 07 and UsageRange of 0xe0 - 0xe7
  357. //
  358. // However, calling GetUsages for each of the data structs
  359. // will return the same list of usages. It is the
  360. // responsibility of the caller to set in the HID_DEVICE
  361. // structure which usages actually are valid for the
  362. // that structure.
  363. //
  364. /*
  365. // Search through the usage list and remove those that
  366. // correspond to usages outside the define ranged for this
  367. // data structure.
  368. */
  369. for (Index = 0, nextUsage = 0; Index < numUsages; Index++)
  370. {
  371. if (Data -> ButtonData.UsageMin <= Data -> ButtonData.Usages[Index] &&
  372. Data -> ButtonData.Usages[Index] <= Data -> ButtonData.UsageMax)
  373. {
  374. Data -> ButtonData.Usages[nextUsage++] = Data -> ButtonData.Usages[Index];
  375. }
  376. }
  377. if (nextUsage < Data -> ButtonData.MaxUsageLength)
  378. {
  379. Data->ButtonData.Usages[nextUsage] = 0;
  380. }
  381. }
  382. else
  383. {
  384. Data->Status = HidP_GetUsageValue (
  385. ReportType,
  386. Data->UsagePage,
  387. 0, // All Collections.
  388. Data->ValueData.Usage,
  389. &Data->ValueData.Value,
  390. Ppd,
  391. ReportBuffer,
  392. ReportBufferLength);
  393. if (HIDP_STATUS_SUCCESS != Data->Status)
  394. {
  395. return (FALSE);
  396. }
  397. Data->Status = HidP_GetScaledUsageValue (
  398. ReportType,
  399. Data->UsagePage,
  400. 0, // All Collections.
  401. Data->ValueData.Usage,
  402. &Data->ValueData.ScaledValue,
  403. Ppd,
  404. ReportBuffer,
  405. ReportBufferLength);
  406. }
  407. Data -> IsDataSet = TRUE;
  408. }
  409. }
  410. return (TRUE);
  411. }
  412. BOOLEAN
  413. PackReport (
  414. OUT PCHAR ReportBuffer,
  415. IN USHORT ReportBufferLength,
  416. IN HIDP_REPORT_TYPE ReportType,
  417. IN PHID_DATA Data,
  418. IN ULONG DataLength,
  419. IN PHIDP_PREPARSED_DATA Ppd
  420. )
  421. /*++
  422. Routine Description:
  423. This routine takes in a list of HID_DATA structures (DATA) and builds
  424. in ReportBuffer the given report for all data values in the list that
  425. correspond to the report ID of the first item in the list.
  426. For every data structure in the list that has the same report ID as the first
  427. item in the list will be set in the report. Every data item that is
  428. set will also have it's IsDataSet field marked with TRUE.
  429. A return value of FALSE indicates an unexpected error occurred when setting
  430. a given data value. The caller should expect that assume that no values
  431. within the given data structure were set.
  432. A return value of TRUE indicates that all data values for the given report
  433. ID were set without error.
  434. --*/
  435. {
  436. ULONG numUsages; // Number of usages to set for a given report.
  437. ULONG i;
  438. ULONG CurrReportID;
  439. /*
  440. // All report buffers that are initially sent need to be zero'd out
  441. */
  442. memset (ReportBuffer, (UCHAR) 0, ReportBufferLength);
  443. /*
  444. // Go through the data structures and set all the values that correspond to
  445. // the CurrReportID which is obtained from the first data structure
  446. // in the list
  447. */
  448. CurrReportID = Data -> ReportID;
  449. for (i = 0; i < DataLength; i++, Data++)
  450. {
  451. /*
  452. // There are two different ways to determine if we set the current data
  453. // structure:
  454. // 1) Store the report ID were using and only attempt to set those
  455. // data structures that correspond to the given report ID. This
  456. // example shows this implementation.
  457. //
  458. // 2) Attempt to set all of the data structures and look for the
  459. // returned status value of HIDP_STATUS_INVALID_REPORT_ID. This
  460. // error code indicates that the given usage exists but has a
  461. // different report ID than the report ID in the current report
  462. // buffer
  463. */
  464. if (Data -> ReportID == CurrReportID)
  465. {
  466. if (Data->IsButtonData)
  467. {
  468. numUsages = Data->ButtonData.MaxUsageLength;
  469. Data->Status = HidP_SetUsages (ReportType,
  470. Data->UsagePage,
  471. 0, // All collections
  472. Data->ButtonData.Usages,
  473. &numUsages,
  474. Ppd,
  475. ReportBuffer,
  476. ReportBufferLength);
  477. }
  478. else
  479. {
  480. Data->Status = HidP_SetUsageValue (ReportType,
  481. Data->UsagePage,
  482. 0, // All Collections.
  483. Data->ValueData.Usage,
  484. Data->ValueData.Value,
  485. Ppd,
  486. ReportBuffer,
  487. ReportBufferLength);
  488. }
  489. if (HIDP_STATUS_SUCCESS != Data->Status)
  490. {
  491. return FALSE;
  492. }
  493. }
  494. }
  495. /*
  496. // At this point, all data structures that have the same ReportID as the
  497. // first one will have been set in the given report. Time to loop
  498. // through the structure again and mark all of those data structures as
  499. // having been set.
  500. */
  501. for (i = 0; i < DataLength; i++, Data++)
  502. {
  503. if (CurrReportID == Data -> ReportID)
  504. {
  505. Data -> IsDataSet = TRUE;
  506. }
  507. }
  508. return (TRUE);
  509. }