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.

828 lines
23 KiB

  1. /*++
  2. Copyright (c) 1996 Microsoft Corporation
  3. Module Name:
  4. pnp.c
  5. Abstract:
  6. This module contains the code
  7. for finding, adding, removing, and identifying hid devices.
  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 <basetyps.h>
  16. #include <stdlib.h>
  17. #include <wtypes.h>
  18. #include <setupapi.h>
  19. #include "hidsdi.h"
  20. #include "hid.h"
  21. BOOLEAN
  22. FindKnownHidDevices (
  23. OUT PHID_DEVICE * HidDevices, // A array of struct _HID_DEVICE
  24. OUT PULONG NumberDevices // the length of this array.
  25. )
  26. /*++
  27. Routine Description:
  28. Do the required PnP things in order to find all the HID devices in
  29. the system at this time.
  30. --*/
  31. {
  32. HDEVINFO hardwareDeviceInfo;
  33. SP_DEVICE_INTERFACE_DATA deviceInfoData;
  34. ULONG i;
  35. BOOLEAN done;
  36. PHID_DEVICE hidDeviceInst;
  37. GUID hidGuid;
  38. PSP_DEVICE_INTERFACE_DETAIL_DATA functionClassDeviceData = NULL;
  39. ULONG predictedLength = 0;
  40. ULONG requiredLength = 0;
  41. HidD_GetHidGuid (&hidGuid);
  42. *HidDevices = NULL;
  43. *NumberDevices = 0;
  44. //
  45. // Open a handle to the plug and play dev node.
  46. //
  47. hardwareDeviceInfo = SetupDiGetClassDevs ( &hidGuid,
  48. NULL, // Define no enumerator (global)
  49. NULL, // Define no
  50. (DIGCF_PRESENT | // Only Devices present
  51. DIGCF_DEVICEINTERFACE)); // Function class devices.
  52. //
  53. // Take a wild guess to start
  54. //
  55. *NumberDevices = 4;
  56. done = FALSE;
  57. deviceInfoData.cbSize = sizeof (SP_DEVICE_INTERFACE_DATA);
  58. i=0;
  59. while (!done)
  60. {
  61. *NumberDevices *= 2;
  62. if (*HidDevices)
  63. {
  64. *HidDevices =
  65. realloc (*HidDevices, (*NumberDevices * sizeof (HID_DEVICE)));
  66. }
  67. else
  68. {
  69. *HidDevices = calloc (*NumberDevices, sizeof (HID_DEVICE));
  70. }
  71. if (NULL == *HidDevices)
  72. {
  73. SetupDiDestroyDeviceInfoList (hardwareDeviceInfo);
  74. return FALSE;
  75. }
  76. hidDeviceInst = *HidDevices + i;
  77. for (; i < *NumberDevices; i++, hidDeviceInst++)
  78. {
  79. if (SetupDiEnumDeviceInterfaces (hardwareDeviceInfo,
  80. 0, // No care about specific PDOs
  81. &hidGuid,
  82. i,
  83. &deviceInfoData))
  84. {
  85. //
  86. // allocate a function class device data structure to receive the
  87. // goods about this particular device.
  88. //
  89. SetupDiGetDeviceInterfaceDetail (
  90. hardwareDeviceInfo,
  91. &deviceInfoData,
  92. NULL, // probing so no output buffer yet
  93. 0, // probing so output buffer length of zero
  94. &requiredLength,
  95. NULL); // not interested in the specific dev-node
  96. predictedLength = requiredLength;
  97. functionClassDeviceData = malloc (predictedLength);
  98. if (functionClassDeviceData)
  99. {
  100. functionClassDeviceData->cbSize = sizeof (SP_DEVICE_INTERFACE_DETAIL_DATA);
  101. }
  102. else
  103. {
  104. SetupDiDestroyDeviceInfoList (hardwareDeviceInfo);
  105. return FALSE;
  106. }
  107. //
  108. // Retrieve the information from Plug and Play.
  109. //
  110. if (! SetupDiGetDeviceInterfaceDetail (
  111. hardwareDeviceInfo,
  112. &deviceInfoData,
  113. functionClassDeviceData,
  114. predictedLength,
  115. &requiredLength,
  116. NULL))
  117. {
  118. SetupDiDestroyDeviceInfoList (hardwareDeviceInfo);
  119. return FALSE;
  120. }
  121. //
  122. // Open device with just generic query abilities to begin with
  123. //
  124. if (! OpenHidDevice (functionClassDeviceData -> DevicePath,
  125. FALSE, // ReadAccess - none
  126. FALSE, // WriteAccess - none
  127. FALSE, // Overlapped - no
  128. FALSE, // Exclusive - no
  129. TRUE, // GetDeviceInfo - yes
  130. hidDeviceInst))
  131. {
  132. SetupDiDestroyDeviceInfoList (hardwareDeviceInfo);
  133. return FALSE;
  134. }
  135. }
  136. else
  137. {
  138. if (ERROR_NO_MORE_ITEMS == GetLastError())
  139. {
  140. done = TRUE;
  141. break;
  142. }
  143. }
  144. }
  145. }
  146. *NumberDevices = i;
  147. SetupDiDestroyDeviceInfoList (hardwareDeviceInfo);
  148. return TRUE;
  149. }
  150. BOOLEAN
  151. OpenHidDevice (
  152. IN PCHAR DevicePath,
  153. IN BOOL HasReadAccess,
  154. IN BOOL HasWriteAccess,
  155. IN BOOL IsOverlapped,
  156. IN BOOL IsExclusive,
  157. IN BOOL GetDeviceInfo,
  158. IN OUT PHID_DEVICE HidDevice
  159. )
  160. /*++
  161. RoutineDescription:
  162. Given the HardwareDeviceInfo, representing a handle to the plug and
  163. play information, and deviceInfoData, representing a specific hid device,
  164. open that device and fill in all the relivant information in the given
  165. HID_DEVICE structure.
  166. return if the open and initialization was successfull or not.
  167. --*/
  168. {
  169. DWORD accessFlags = 0;
  170. DWORD sharingFlags = 0;
  171. BOOLEAN bSuccess;
  172. HidDevice -> DevicePath = malloc(strlen(DevicePath));
  173. if (NULL == HidDevice -> DevicePath)
  174. {
  175. return (FALSE);
  176. }
  177. strcpy(HidDevice -> DevicePath, DevicePath);
  178. if (HasReadAccess)
  179. {
  180. accessFlags |= GENERIC_READ;
  181. }
  182. if (HasWriteAccess)
  183. {
  184. accessFlags |= GENERIC_WRITE;
  185. }
  186. if (!IsExclusive)
  187. {
  188. sharingFlags = FILE_SHARE_READ | FILE_SHARE_WRITE;
  189. }
  190. HidDevice->HidDevice = CreateFile (DevicePath,
  191. accessFlags,
  192. sharingFlags,
  193. NULL, // no SECURITY_ATTRIBUTES structure
  194. OPEN_EXISTING, // No special create flags
  195. IsOverlapped ? FILE_FLAG_OVERLAPPED : 0,
  196. NULL); // No template file
  197. if (INVALID_HANDLE_VALUE == HidDevice->HidDevice)
  198. {
  199. free(HidDevice -> DevicePath);
  200. return FALSE;
  201. }
  202. HidDevice -> OpenedForRead = HasReadAccess;
  203. HidDevice -> OpenedForWrite = HasWriteAccess;
  204. HidDevice -> OpenedOverlapped = IsOverlapped;
  205. HidDevice -> OpenedExclusive = IsExclusive;
  206. //
  207. // If the device was not opened as overlapped, then fill in the rest of the
  208. // HidDevice structure. However, if opened as overlapped, this handle cannot
  209. // be used in the calls to the HidD_ exported functions since each of these
  210. // functions does synchronous I/O.
  211. //
  212. if (GetDeviceInfo)
  213. {
  214. if (!HidD_GetPreparsedData (HidDevice->HidDevice, &HidDevice->Ppd))
  215. {
  216. free(HidDevice -> DevicePath);
  217. CloseHandle(HidDevice -> HidDevice);
  218. return FALSE;
  219. }
  220. if (!HidD_GetAttributes (HidDevice->HidDevice, &HidDevice->Attributes))
  221. {
  222. free(HidDevice -> DevicePath);
  223. CloseHandle(HidDevice -> HidDevice);
  224. HidD_FreePreparsedData (HidDevice->Ppd);
  225. return FALSE;
  226. }
  227. if (!HidP_GetCaps (HidDevice->Ppd, &HidDevice->Caps))
  228. {
  229. free(HidDevice -> DevicePath);
  230. CloseHandle(HidDevice -> HidDevice);
  231. HidD_FreePreparsedData (HidDevice->Ppd);
  232. return FALSE;
  233. }
  234. //
  235. // At this point the client has a choice. It may chose to look at the
  236. // Usage and Page of the top level collection found in the HIDP_CAPS
  237. // structure. In this way it could just use the usages it knows about.
  238. // If either HidP_GetUsages or HidP_GetUsageValue return an error then
  239. // that particular usage does not exist in the report.
  240. // This is most likely the preferred method as the application can only
  241. // use usages of which it already knows.
  242. // In this case the app need not even call GetButtonCaps or GetValueCaps.
  243. //
  244. // In this example, however, we will call FillDeviceInfo to look for all
  245. // of the usages in the device.
  246. //
  247. bSuccess = FillDeviceInfo(HidDevice);
  248. if (FALSE == bSuccess)
  249. {
  250. return (FALSE);
  251. }
  252. }
  253. return (TRUE);
  254. }
  255. BOOLEAN
  256. FillDeviceInfo(
  257. IN PHID_DEVICE HidDevice
  258. )
  259. {
  260. USHORT numValues;
  261. USHORT numCaps;
  262. PHIDP_BUTTON_CAPS buttonCaps;
  263. PHIDP_VALUE_CAPS valueCaps;
  264. PHID_DATA data;
  265. ULONG i;
  266. USAGE usage;
  267. //
  268. // setup Input Data buffers.
  269. //
  270. //
  271. // Allocate memory to hold on input report
  272. //
  273. HidDevice->InputReportBuffer = (PCHAR)
  274. calloc (HidDevice->Caps.InputReportByteLength, sizeof (CHAR));
  275. //
  276. // Allocate memory to hold the button and value capabilities.
  277. // NumberXXCaps is in terms of array elements.
  278. //
  279. HidDevice->InputButtonCaps = buttonCaps = (PHIDP_BUTTON_CAPS)
  280. calloc (HidDevice->Caps.NumberInputButtonCaps, sizeof (HIDP_BUTTON_CAPS));
  281. if (NULL == buttonCaps)
  282. {
  283. return (FALSE);
  284. }
  285. HidDevice->InputValueCaps = valueCaps = (PHIDP_VALUE_CAPS)
  286. calloc (HidDevice->Caps.NumberInputValueCaps, sizeof (HIDP_VALUE_CAPS));
  287. if (NULL == valueCaps)
  288. {
  289. return(FALSE);
  290. }
  291. //
  292. // Have the HidP_X functions fill in the capability structure arrays.
  293. //
  294. numCaps = HidDevice->Caps.NumberInputButtonCaps;
  295. HidP_GetButtonCaps (HidP_Input,
  296. buttonCaps,
  297. &numCaps,
  298. HidDevice->Ppd);
  299. numCaps = HidDevice->Caps.NumberInputValueCaps;
  300. HidP_GetValueCaps (HidP_Input,
  301. valueCaps,
  302. &numCaps,
  303. HidDevice->Ppd);
  304. //
  305. // Depending on the device, some value caps structures may represent more
  306. // than one value. (A range). In the interest of being verbose, over
  307. // efficient, we will expand these so that we have one and only one
  308. // struct _HID_DATA for each value.
  309. //
  310. // To do this we need to count up the total number of values are listed
  311. // in the value caps structure. For each element in the array we test
  312. // for range if it is a range then UsageMax and UsageMin describe the
  313. // usages for this range INCLUSIVE.
  314. //
  315. numValues = 0;
  316. for (i = 0; i < HidDevice->Caps.NumberInputValueCaps; i++, valueCaps++)
  317. {
  318. if (valueCaps->IsRange)
  319. {
  320. numValues += valueCaps->Range.UsageMax - valueCaps->Range.UsageMin + 1;
  321. }
  322. else
  323. {
  324. numValues++;
  325. }
  326. }
  327. valueCaps = HidDevice->InputValueCaps;
  328. //
  329. // Allocate a buffer to hold the struct _HID_DATA structures.
  330. // One element for each set of buttons, and one element for each value
  331. // found.
  332. //
  333. HidDevice->InputDataLength = HidDevice->Caps.NumberInputButtonCaps
  334. + numValues;
  335. HidDevice->InputData = data = (PHID_DATA)
  336. calloc (HidDevice->InputDataLength, sizeof (HID_DATA));
  337. if (NULL == data)
  338. {
  339. return (FALSE);
  340. }
  341. //
  342. // Fill in the button data
  343. //
  344. for (i = 0;
  345. i < HidDevice->Caps.NumberInputButtonCaps;
  346. i++, data++, buttonCaps++)
  347. {
  348. data->IsButtonData = TRUE;
  349. data->Status = HIDP_STATUS_SUCCESS;
  350. data->UsagePage = buttonCaps->UsagePage;
  351. if (buttonCaps->IsRange)
  352. {
  353. data->ButtonData.UsageMin = buttonCaps -> Range.UsageMin;
  354. data->ButtonData.UsageMax = buttonCaps -> Range.UsageMax;
  355. }
  356. else
  357. {
  358. data -> ButtonData.UsageMin = data -> ButtonData.UsageMax = buttonCaps -> NotRange.Usage;
  359. }
  360. data->ButtonData.MaxUsageLength = HidP_MaxUsageListLength (
  361. HidP_Input,
  362. buttonCaps->UsagePage,
  363. HidDevice->Ppd);
  364. data->ButtonData.Usages = (PUSAGE)
  365. calloc (data->ButtonData.MaxUsageLength, sizeof (USAGE));
  366. data->ReportID = buttonCaps -> ReportID;
  367. }
  368. //
  369. // Fill in the value data
  370. //
  371. for (i = 0; i < numValues; i++, valueCaps++)
  372. {
  373. if (valueCaps->IsRange)
  374. {
  375. for (usage = valueCaps->Range.UsageMin;
  376. usage <= valueCaps->Range.UsageMax;
  377. usage++)
  378. {
  379. data->IsButtonData = FALSE;
  380. data->Status = HIDP_STATUS_SUCCESS;
  381. data->UsagePage = valueCaps->UsagePage;
  382. data->ValueData.Usage = usage;
  383. data->ReportID = valueCaps -> ReportID;
  384. data++;
  385. }
  386. }
  387. else
  388. {
  389. data->IsButtonData = FALSE;
  390. data->Status = HIDP_STATUS_SUCCESS;
  391. data->UsagePage = valueCaps->UsagePage;
  392. data->ValueData.Usage = valueCaps->NotRange.Usage;
  393. data->ReportID = valueCaps -> ReportID;
  394. data++;
  395. }
  396. }
  397. //
  398. // setup Output Data buffers.
  399. //
  400. HidDevice->OutputReportBuffer = (PCHAR)
  401. calloc (HidDevice->Caps.OutputReportByteLength, sizeof (CHAR));
  402. HidDevice->OutputButtonCaps = buttonCaps = (PHIDP_BUTTON_CAPS)
  403. calloc (HidDevice->Caps.NumberOutputButtonCaps, sizeof (HIDP_BUTTON_CAPS));
  404. if (NULL == buttonCaps)
  405. {
  406. return (FALSE);
  407. }
  408. HidDevice->OutputValueCaps = valueCaps = (PHIDP_VALUE_CAPS)
  409. calloc (HidDevice->Caps.NumberOutputValueCaps, sizeof (HIDP_VALUE_CAPS));
  410. if (NULL == valueCaps)
  411. {
  412. return (FALSE);
  413. }
  414. numCaps = HidDevice->Caps.NumberOutputButtonCaps;
  415. HidP_GetButtonCaps (HidP_Output,
  416. buttonCaps,
  417. &numCaps,
  418. HidDevice->Ppd);
  419. numCaps = HidDevice->Caps.NumberOutputValueCaps;
  420. HidP_GetValueCaps (HidP_Output,
  421. valueCaps,
  422. &numCaps,
  423. HidDevice->Ppd);
  424. numValues = 0;
  425. for (i = 0; i < HidDevice->Caps.NumberOutputValueCaps; i++, valueCaps++)
  426. {
  427. if (valueCaps->IsRange)
  428. {
  429. numValues += valueCaps->Range.UsageMax
  430. - valueCaps->Range.UsageMin + 1;
  431. }
  432. else
  433. {
  434. numValues++;
  435. }
  436. }
  437. valueCaps = HidDevice->OutputValueCaps;
  438. HidDevice->OutputDataLength = HidDevice->Caps.NumberOutputButtonCaps
  439. + numValues;
  440. HidDevice->OutputData = data = (PHID_DATA)
  441. calloc (HidDevice->OutputDataLength, sizeof (HID_DATA));
  442. if (NULL == data)
  443. {
  444. return (FALSE);
  445. }
  446. for (i = 0;
  447. i < HidDevice->Caps.NumberOutputButtonCaps;
  448. i++, data++, buttonCaps++)
  449. {
  450. data->IsButtonData = TRUE;
  451. data->Status = HIDP_STATUS_SUCCESS;
  452. data->UsagePage = buttonCaps->UsagePage;
  453. if (buttonCaps->IsRange)
  454. {
  455. data->ButtonData.UsageMin = buttonCaps -> Range.UsageMin;
  456. data->ButtonData.UsageMax = buttonCaps -> Range.UsageMax;
  457. }
  458. else
  459. {
  460. data -> ButtonData.UsageMin = data -> ButtonData.UsageMax = buttonCaps -> NotRange.Usage;
  461. }
  462. data->ButtonData.MaxUsageLength = HidP_MaxUsageListLength (
  463. HidP_Output,
  464. buttonCaps->UsagePage,
  465. HidDevice->Ppd);
  466. data->ButtonData.Usages = (PUSAGE)
  467. calloc (data->ButtonData.MaxUsageLength, sizeof (USAGE));
  468. data->ReportID = buttonCaps -> ReportID;
  469. }
  470. for (i = 0; i < numValues; i++, valueCaps++)
  471. {
  472. if (valueCaps->IsRange)
  473. {
  474. for (usage = valueCaps->Range.UsageMin;
  475. usage <= valueCaps->Range.UsageMax;
  476. usage++)
  477. {
  478. data->IsButtonData = FALSE;
  479. data->Status = HIDP_STATUS_SUCCESS;
  480. data->UsagePage = valueCaps->UsagePage;
  481. data->ValueData.Usage = usage;
  482. data->ReportID = valueCaps -> ReportID;
  483. data++;
  484. }
  485. }
  486. else
  487. {
  488. data->IsButtonData = FALSE;
  489. data->Status = HIDP_STATUS_SUCCESS;
  490. data->UsagePage = valueCaps->UsagePage;
  491. data->ValueData.Usage = valueCaps->NotRange.Usage;
  492. data->ReportID = valueCaps -> ReportID;
  493. data++;
  494. }
  495. }
  496. //
  497. // setup Feature Data buffers.
  498. //
  499. HidDevice->FeatureReportBuffer = (PCHAR)
  500. calloc (HidDevice->Caps.FeatureReportByteLength, sizeof (CHAR));
  501. HidDevice->FeatureButtonCaps = buttonCaps = (PHIDP_BUTTON_CAPS)
  502. calloc (HidDevice->Caps.NumberFeatureButtonCaps, sizeof (HIDP_BUTTON_CAPS));
  503. if (NULL == buttonCaps)
  504. {
  505. return (FALSE);
  506. }
  507. HidDevice->FeatureValueCaps = valueCaps = (PHIDP_VALUE_CAPS)
  508. calloc (HidDevice->Caps.NumberFeatureValueCaps, sizeof (HIDP_VALUE_CAPS));
  509. if (NULL == valueCaps)
  510. {
  511. return (FALSE);
  512. }
  513. numCaps = HidDevice->Caps.NumberFeatureButtonCaps;
  514. HidP_GetButtonCaps (HidP_Feature,
  515. buttonCaps,
  516. &numCaps,
  517. HidDevice->Ppd);
  518. numCaps = HidDevice->Caps.NumberFeatureValueCaps;
  519. HidP_GetValueCaps (HidP_Feature,
  520. valueCaps,
  521. &numCaps,
  522. HidDevice->Ppd);
  523. numValues = 0;
  524. for (i = 0; i < HidDevice->Caps.NumberFeatureValueCaps; i++, valueCaps++)
  525. {
  526. if (valueCaps->IsRange)
  527. {
  528. numValues += valueCaps->Range.UsageMax
  529. - valueCaps->Range.UsageMin + 1;
  530. }
  531. else
  532. {
  533. numValues++;
  534. }
  535. }
  536. valueCaps = HidDevice->FeatureValueCaps;
  537. HidDevice->FeatureDataLength = HidDevice->Caps.NumberFeatureButtonCaps
  538. + numValues;
  539. HidDevice->FeatureData = data = (PHID_DATA)
  540. calloc (HidDevice->FeatureDataLength, sizeof (HID_DATA));
  541. if (NULL == data)
  542. {
  543. return (FALSE);
  544. }
  545. for (i = 0;
  546. i < HidDevice->Caps.NumberFeatureButtonCaps;
  547. i++, data++, buttonCaps++)
  548. {
  549. data->IsButtonData = TRUE;
  550. data->Status = HIDP_STATUS_SUCCESS;
  551. data->UsagePage = buttonCaps->UsagePage;
  552. if (buttonCaps->IsRange)
  553. {
  554. data->ButtonData.UsageMin = buttonCaps -> Range.UsageMin;
  555. data->ButtonData.UsageMax = buttonCaps -> Range.UsageMax;
  556. }
  557. else
  558. {
  559. data -> ButtonData.UsageMin = data -> ButtonData.UsageMax = buttonCaps -> NotRange.Usage;
  560. }
  561. data->ButtonData.MaxUsageLength = HidP_MaxUsageListLength (
  562. HidP_Feature,
  563. buttonCaps->UsagePage,
  564. HidDevice->Ppd);
  565. data->ButtonData.Usages = (PUSAGE)
  566. calloc (data->ButtonData.MaxUsageLength, sizeof (USAGE));
  567. data->ReportID = buttonCaps -> ReportID;
  568. }
  569. for (i = 0; i < numValues; i++, valueCaps++)
  570. {
  571. if (valueCaps->IsRange)
  572. {
  573. for (usage = valueCaps->Range.UsageMin;
  574. usage <= valueCaps->Range.UsageMax;
  575. usage++)
  576. {
  577. data->IsButtonData = FALSE;
  578. data->Status = HIDP_STATUS_SUCCESS;
  579. data->UsagePage = valueCaps->UsagePage;
  580. data->ValueData.Usage = usage;
  581. data->ReportID = valueCaps -> ReportID;
  582. data++;
  583. }
  584. }
  585. else
  586. {
  587. data->IsButtonData = FALSE;
  588. data->Status = HIDP_STATUS_SUCCESS;
  589. data->UsagePage = valueCaps->UsagePage;
  590. data->ValueData.Usage = valueCaps->NotRange.Usage;
  591. data->ReportID = valueCaps -> ReportID;
  592. data++;
  593. }
  594. }
  595. return (TRUE);
  596. }
  597. VOID
  598. CloseHidDevices(
  599. IN PHID_DEVICE HidDevices,
  600. IN ULONG NumberDevices
  601. )
  602. {
  603. ULONG Index;
  604. for (Index = 0; Index < NumberDevices; Index++)
  605. {
  606. CloseHidDevice(HidDevices+Index, TRUE);
  607. }
  608. return;
  609. }
  610. VOID
  611. CloseHidDevice (
  612. IN PHID_DEVICE HidDevice,
  613. IN BOOL FreeDeviceInfo
  614. )
  615. {
  616. free(HidDevice -> DevicePath);
  617. if (INVALID_HANDLE_VALUE != HidDevice -> HidDevice)
  618. {
  619. CloseHandle(HidDevice -> HidDevice);
  620. }
  621. //
  622. // Only free these structure, if have a handle to an non-overlapped device
  623. //
  624. if (FreeDeviceInfo)
  625. {
  626. if (NULL != HidDevice -> Ppd)
  627. {
  628. HidD_FreePreparsedData(HidDevice -> Ppd);
  629. }
  630. if (NULL != HidDevice -> InputReportBuffer)
  631. {
  632. free(HidDevice -> InputReportBuffer);
  633. }
  634. if (NULL != HidDevice -> InputData)
  635. {
  636. free(HidDevice -> InputData);
  637. }
  638. if (NULL != HidDevice -> InputButtonCaps)
  639. {
  640. free(HidDevice -> InputButtonCaps);
  641. }
  642. if (NULL != HidDevice -> InputValueCaps)
  643. {
  644. free(HidDevice -> InputValueCaps);
  645. }
  646. if (NULL != HidDevice -> OutputReportBuffer)
  647. {
  648. free(HidDevice -> OutputReportBuffer);
  649. }
  650. if (NULL != HidDevice -> OutputData)
  651. {
  652. free(HidDevice -> OutputData);
  653. }
  654. if (NULL != HidDevice -> OutputButtonCaps)
  655. {
  656. free(HidDevice -> OutputButtonCaps);
  657. }
  658. if (NULL != HidDevice -> OutputValueCaps)
  659. {
  660. free(HidDevice -> OutputValueCaps);
  661. }
  662. if (NULL != HidDevice -> FeatureReportBuffer)
  663. {
  664. free(HidDevice -> FeatureReportBuffer);
  665. }
  666. if (NULL != HidDevice -> FeatureData)
  667. {
  668. free(HidDevice -> FeatureData);
  669. }
  670. if (NULL != HidDevice -> FeatureButtonCaps)
  671. {
  672. free(HidDevice -> FeatureButtonCaps);
  673. }
  674. if (NULL != HidDevice -> FeatureValueCaps)
  675. {
  676. free(HidDevice -> FeatureValueCaps);
  677. }
  678. }
  679. return;
  680. }