1/* 2 * @APPLE_LICENSE_HEADER_START@ 3 * 4 * Copyright (c) 1999-2003 Apple Computer, Inc. All Rights Reserved. 5 * 6 * This file contains Original Code and/or Modifications of Original Code 7 * as defined in and that are subject to the Apple Public Source License 8 * Version 2.0 (the 'License'). You may not use this file except in 9 * compliance with the License. Please obtain a copy of the License at 10 * http://www.opensource.apple.com/apsl/ and read it before using this 11 * file. 12 * 13 * The Original Code and all software distributed under the License are 14 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER 15 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, 16 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, 17 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. 18 * Please see the License for the specific language governing rights and 19 * limitations under the License. 20 * 21 * @APPLE_LICENSE_HEADER_END@ 22 */ 23/* 24 File: HIDGetValueCaps.c 25 26 Contains: xxx put contents here xxx 27 28 Version: xxx put version here xxx 29 30 Copyright: � 1999-2000 by Apple Computer, Inc., all rights reserved. 31 32 File Ownership: 33 34 DRI: xxx put dri here xxx 35 36 Other Contact: xxx put other contact here xxx 37 38 Technology: xxx put technology here xxx 39 40 Writers: 41 42 (KH) Keithen Hayenga 43 (BWS) Brent Schorsch 44 45 Change History (most recent first): 46 47 <USB8> 12/12/00 KH range count off by 1. 48 <USB7> 4/21/00 KH Added HIDGetValueCapabilities and 49 HIDGetSpecificValueCapabilities that now allow users to find HID 50 report units and exponents. 51 <USB6> 11/1/99 BWS [2405720] We need a better check for 'bit padding' items, 52 rather than just is constant. We will check to make sure the 53 item is constant, and has no usage, or zero usage. This means we 54 need to pass an additional parameter to some internal functions 55 <USB5> 5/3/99 BWS Fix typo 56 <USB4> 5/3/99 BWS We were not setting isStringRange, isDesignatorRange, and 57 isAbsolute 58 <USB3> 3/7/99 BWS When range/notRange were made a union, we missed this case where 59 they were both being set indescriminately 60 <USB2> 3/7/99 BWS [2311411] Had added missing fields to caps structure, but they 61 were not being filled in 62 <USB1> 3/5/99 BWS first checked in 63*/ 64 65#include "HIDLib.h" 66 67/* 68 *------------------------------------------------------------------------------ 69 * 70 * HIDGetSpecificValueCaps - Get the binary values for a report type 71 * 72 * Input: 73 * reportType - HIDP_Input, HIDP_Output, HIDP_Feature 74 * usagePage - Page Criteria or zero 75 * iCollection - Collection Criteria or zero 76 * usage - usage Criteria or zero 77 * valueCaps - ValueCaps Array 78 * piValueCapsLength - Maximum Entries 79 * ptPreparsedData - Pre-Parsed Data 80 * Output: 81 * piValueCapsLength - Entries Populated 82 * Returns: 83 * 84 *------------------------------------------------------------------------------ 85*/ 86OSStatus HIDGetSpecificValueCaps(HIDReportType reportType, 87 HIDUsage usagePage, 88 UInt32 iCollection, 89 HIDUsage usage, 90 HIDValueCapsPtr valueCaps, 91 UInt32 *piValueCapsLength, 92 HIDPreparsedDataRef preparsedDataRef) 93{ 94 HIDPreparsedDataPtr ptPreparsedData = (HIDPreparsedDataPtr) preparsedDataRef; 95 HIDCollection *ptCollection; 96 HIDCollection *ptParent; 97 HIDReportItem *ptReportItem; 98 HIDP_UsageItem *ptUsageItem; 99 HIDStringItem *ptStringItem; 100 HIDDesignatorItem *ptDesignatorItem; 101 HIDP_UsageItem *ptFirstCollectionUsageItem; 102 HIDValueCaps *ptCapability; 103 int iR, iU; 104 int parent; 105 int iReportItem, iUsageItem; 106 int iMaxCaps; 107 UInt32 iCount; 108 // There are 3 versions of HID Parser code all based on the same logic: OS 9 HID Library; 109 // OSX xnu; OSX IOKitUser. They should all be nearly the same logic. This version (xnu) 110 // is based on older OS 9 code. This version has added logic to maintain this startBit. 111 // I don't know why it is here, but believe if it is needed here, it would probably be 112 // needed in the other two implementations. Didn't have time to determine that at this 113 // time, so i'll leave this comment to remind me that we should reconcile the 3 versions. 114 UInt32 startBit; // Added esb 9-29-99 115 /*If I remember correctly, it was an optimization. Each time you ask for 116 a specific value capability, it would search through the entire report 117 descriptor to find it (my recollection is kind of hazy on this part). 118 The start bit allowed somebody (client maybe) to cache the information 119 on where in the report a specific value resided and the use that later 120 when fetching that value. That way, you don't have to keep going 121 through the parse tree to find where a value exists. I don't remember 122 if the implementation was completed or if I even used it. -esb */ 123/* 124 * Disallow Null Pointers 125*/ 126 if ((valueCaps == NULL) 127 || (piValueCapsLength == NULL) 128 || (ptPreparsedData == NULL)) 129 return kHIDNullPointerErr; 130 if (ptPreparsedData->hidTypeIfValid != kHIDOSType) 131 return kHIDInvalidPreparsedDataErr; 132/* 133 * Save the buffer size 134*/ 135 iMaxCaps = *piValueCapsLength; 136 *piValueCapsLength = 0; 137/* 138 * The Collection must be in range 139*/ 140 if (iCollection >= ptPreparsedData->collectionCount) 141 return kHIDBadParameterErr; 142/* 143 * Search only the scope of the Collection specified 144*/ 145 ptCollection = &ptPreparsedData->collections[iCollection]; 146 for (iR=0; iR<ptCollection->reportItemCount; iR++) 147 { 148 iReportItem = ptCollection->firstReportItem + iR; 149 ptReportItem = &ptPreparsedData->reportItems[iReportItem]; 150/* 151 * Search only reports of the proper type 152*/ 153 if ((ptReportItem->reportType == reportType) 154 && ((ptReportItem->globals.usagePage == usagePage) 155 || (usagePage == 0)) 156 && HIDIsVariable(ptReportItem, preparsedDataRef)) 157 { 158 startBit = ptReportItem->startBit; // Added esb 9-28-99 159/* 160 * Search the usages 161*/ 162 for (iU=0; iU<ptReportItem->usageItemCount; iU++) 163 { 164/* 165 * Copy all usages if the usage above is zero 166 * or copy all that "match" 167*/ 168 iUsageItem = ptReportItem->firstUsageItem + iU; 169 ptUsageItem = &ptPreparsedData->usageItems[iUsageItem]; 170 171 // �� we assume there is a 1-1 corresponence between usage items, string items, and designator items 172 // ���this is not necessarily the case, but its better than nothing 173 ptStringItem = &ptPreparsedData->stringItems[ptReportItem->firstStringItem + iU]; 174 ptDesignatorItem = &ptPreparsedData->desigItems[ptReportItem->firstDesigItem + iU]; 175 176 if (HIDUsageInRange(ptUsageItem,usagePage,usage)) 177 { 178/* 179 * Only copy if there's room 180*/ 181 if (*piValueCapsLength >= iMaxCaps) 182 return kHIDBufferTooSmallErr; 183 ptCapability = &valueCaps[(*piValueCapsLength)++]; 184/* 185 * Populate the Capability Structure 186*/ 187 parent = ptReportItem->parent; 188 ptParent = &ptPreparsedData->collections[parent]; 189 ptFirstCollectionUsageItem = &ptPreparsedData->usageItems[ptParent->firstUsageItem]; 190 ptCapability->collection = parent; 191 ptCapability->collectionUsagePage = ptParent->usagePage; 192 ptCapability->collectionUsage = ptFirstCollectionUsageItem->usage; 193 ptCapability->bitField = ptReportItem->dataModes; 194 ptCapability->reportID = ptReportItem->globals.reportID; 195 ptCapability->usagePage = ptUsageItem->usagePage; 196 197 ptCapability->isAbsolute = !(ptReportItem->dataModes & kHIDDataRelative); 198 199 ptCapability->isRange = ptUsageItem->isRange; 200 if (ptUsageItem->isRange) 201 { 202 ptCapability->u.range.usageMin = ptUsageItem->usageMinimum; 203 ptCapability->u.range.usageMax = ptUsageItem->usageMaximum; 204 } 205 else 206 ptCapability->u.notRange.usage = ptUsageItem->usage; 207 208 // if there really are that many items 209 if (iU < ptReportItem->stringItemCount) 210 { 211 ptCapability->isStringRange = ptStringItem->isRange; 212 213 if (ptStringItem->isRange) 214 { 215 ptCapability->u.range.stringMin = ptStringItem->minimum; 216 ptCapability->u.range.stringMax = ptStringItem->maximum; 217 } 218 else 219 ptCapability->u.notRange.stringIndex = ptStringItem->index; 220 } 221 // default, clear it 222 else 223 { 224 ptCapability->isStringRange = false; 225 ptCapability->u.notRange.stringIndex = 0; 226 } 227 228 // if there really are that many items 229 if (iU < ptReportItem->desigItemCount) 230 { 231 ptCapability->isDesignatorRange = ptDesignatorItem->isRange; 232 233 if (ptDesignatorItem->isRange) 234 { 235 ptCapability->u.range.designatorMin = ptDesignatorItem->minimum; 236 ptCapability->u.range.designatorMax = ptDesignatorItem->maximum; 237 } 238 else 239 ptCapability->u.notRange.designatorIndex = ptDesignatorItem->index; 240 } 241 // default, clear it 242 else 243 { 244 ptCapability->isDesignatorRange = false; 245 ptCapability->u.notRange.designatorIndex = 0; 246 } 247 248 ptCapability->bitSize = ptReportItem->globals.reportSize; 249 250 ptCapability->logicalMin = ptReportItem->globals.logicalMinimum; 251 ptCapability->logicalMax = ptReportItem->globals.logicalMaximum; 252 ptCapability->physicalMin = ptReportItem->globals.physicalMinimum; 253 ptCapability->physicalMax = ptReportItem->globals.physicalMaximum; 254 255 if (ptUsageItem->isRange) 256 { 257 iCount = ptUsageItem->usageMaximum - ptUsageItem->usageMinimum; 258 iCount++; // Range count was off by one. 259 } 260 else 261 // If we're not in a range, then there should be just one usage. 262 // Why do we have to call this function to determine that? Are we checking 263 // that there is that usage before we decide if usage count is 0 or 1? 264 // But haven't we already verified that we have this usage by the time we 265 // got here? 266 HIDHasUsage(preparsedDataRef,ptReportItem, 267 ptUsageItem->usagePage,ptUsageItem->usage, 268 NULL,&iCount); 269 ptCapability->reportCount = iCount; 270 ptCapability->startBit = startBit; 271 startBit += (ptCapability->bitSize * ptCapability->reportCount); 272 } 273 } 274 } 275 } 276 return kHIDSuccess; 277} 278 279/* 280 *------------------------------------------------------------------------------ 281 * 282 * HIDGetValueCaps - Get the binary values for a report type 283 * 284 * Input: 285 * reportType - HIDP_Input, HIDP_Output, HIDP_Feature 286 * valueCaps - ValueCaps Array 287 * piValueCapsLength - Maximum Entries 288 * ptPreparsedData - Pre-Parsed Data 289 * Output: 290 * piValueCapsLength - Entries Populated 291 * Returns: 292 * 293 *------------------------------------------------------------------------------ 294*/ 295OSStatus HIDGetValueCaps(HIDReportType reportType, 296 HIDValueCapsPtr valueCaps, 297 UInt32 *piValueCapsLength, 298 HIDPreparsedDataRef preparsedDataRef) 299{ 300 return HIDGetSpecificValueCaps(reportType,0,0,0,valueCaps, 301 piValueCapsLength,preparsedDataRef); 302} 303 304 305/* 306 *------------------------------------------------------------------------------ 307 * 308 * HIDGetSpecificValueCapabilities - Get the binary values for a report type 309 * This is the same as HIDGetSpecificValueCaps, 310 * except that it takes a HIDValueCapabilitiesPtr 311 * so it can return units and unitExponents. 312 * 313 * Input: 314 * reportType - HIDP_Input, HIDP_Output, HIDP_Feature 315 * usagePage - Page Criteria or zero 316 * iCollection - Collection Criteria or zero 317 * usage - usage Criteria or zero 318 * valueCaps - ValueCaps Array 319 * piValueCapsLength - Maximum Entries 320 * ptPreparsedData - Pre-Parsed Data 321 * Output: 322 * piValueCapsLength - Entries Populated 323 * Returns: 324 * 325 *------------------------------------------------------------------------------ 326*/ 327OSStatus HIDGetSpecificValueCapabilities(HIDReportType reportType, 328 HIDUsage usagePage, 329 UInt32 iCollection, 330 HIDUsage usage, 331 HIDValueCapabilitiesPtr valueCaps, 332 UInt32 *piValueCapsLength, 333 HIDPreparsedDataRef preparsedDataRef) 334{ 335 HIDPreparsedDataPtr ptPreparsedData = (HIDPreparsedDataPtr) preparsedDataRef; 336 HIDCollection *ptCollection; 337 HIDCollection *ptParent; 338 HIDReportItem *ptReportItem; 339 HIDP_UsageItem *ptUsageItem; 340 HIDStringItem *ptStringItem; 341 HIDDesignatorItem *ptDesignatorItem; 342 HIDP_UsageItem *ptFirstCollectionUsageItem; 343 HIDValueCapabilities *ptCapability; 344 int iR, iU; 345 int parent; 346 int iReportItem, iUsageItem; 347 int iMaxCaps; 348 UInt32 iCount; 349 // There are 3 versions of HID Parser code all based on the same logic: OS 9 HID Library; 350 // OSX xnu; OSX IOKitUser. They should all be nearly the same logic. This version (xnu) 351 // is based on older OS 9 code. This version has added logic to maintain this startBit. 352 // I don't know why it is here, but believe if it is needed here, it would probably be 353 // needed in the other two implementations. Didn't have time to determine that at this 354 // time, so i'll leave this comment to remind me that we should reconcile the 3 versions. 355 UInt32 startBit; // Carried esb's logic down here when we added HIDGetSpecificValueCapabilities(). 356/* 357 * Disallow Null Pointers 358*/ 359 if ((valueCaps == NULL) 360 || (piValueCapsLength == NULL) 361 || (ptPreparsedData == NULL)) 362 return kHIDNullPointerErr; 363 if (ptPreparsedData->hidTypeIfValid != kHIDOSType) 364 return kHIDInvalidPreparsedDataErr; 365/* 366 * Save the buffer size 367*/ 368 iMaxCaps = *piValueCapsLength; 369 *piValueCapsLength = 0; 370/* 371 * The Collection must be in range 372*/ 373 if (iCollection >= ptPreparsedData->collectionCount) 374 return kHIDBadParameterErr; 375/* 376 * Search only the scope of the Collection specified 377*/ 378 ptCollection = &ptPreparsedData->collections[iCollection]; 379 for (iR=0; iR<ptCollection->reportItemCount; iR++) 380 { 381 iReportItem = ptCollection->firstReportItem + iR; 382 ptReportItem = &ptPreparsedData->reportItems[iReportItem]; 383/* 384 * Search only reports of the proper type 385*/ 386 if ((ptReportItem->reportType == reportType) 387 && ((ptReportItem->globals.usagePage == usagePage) 388 || (usagePage == 0)) 389 && HIDIsVariable(ptReportItem, preparsedDataRef)) 390 { 391 startBit = ptReportItem->startBit; // Same logic as Added esb 9-28-99 392/* 393 * Search the usages 394*/ 395 for (iU=0; iU<ptReportItem->usageItemCount; iU++) 396 { 397/* 398 * Copy all usages if the usage above is zero 399 * or copy all that "match" 400*/ 401 iUsageItem = ptReportItem->firstUsageItem + iU; 402 ptUsageItem = &ptPreparsedData->usageItems[iUsageItem]; 403 404 // �� we assume there is a 1-1 corresponence between usage items, string items, and designator items 405 // ���this is not necessarily the case, but its better than nothing 406 ptStringItem = &ptPreparsedData->stringItems[ptReportItem->firstStringItem + iU]; 407 ptDesignatorItem = &ptPreparsedData->desigItems[ptReportItem->firstDesigItem + iU]; 408 409 if (HIDUsageInRange(ptUsageItem,usagePage,usage)) 410 { 411/* 412 * Only copy if there's room 413*/ 414 if (*piValueCapsLength >= iMaxCaps) 415 return kHIDBufferTooSmallErr; 416 ptCapability = &valueCaps[(*piValueCapsLength)++]; 417 418/* 419 * Populate the Capability Structure 420*/ 421 parent = ptReportItem->parent; 422 ptParent = &ptPreparsedData->collections[parent]; 423 ptFirstCollectionUsageItem = &ptPreparsedData->usageItems[ptParent->firstUsageItem]; 424 ptCapability->collection = parent; 425 ptCapability->collectionUsagePage = ptParent->usagePage; 426 ptCapability->collectionUsage = ptFirstCollectionUsageItem->usage; 427 ptCapability->bitField = ptReportItem->dataModes; 428 ptCapability->reportID = ptReportItem->globals.reportID; 429 ptCapability->usagePage = ptUsageItem->usagePage; 430 ptCapability->unitExponent = ptReportItem->globals.unitExponent; 431 ptCapability->units = ptReportItem->globals.units; 432// ptCapability->reserved = 0; // for future OS 9 expansion 433 ptCapability->startBit = 0; // init esb added field. 434// ptCapability->pbVersion = kHIDCurrentCapabilitiesPBVersion; 435 ptCapability->pbVersion = 2; 436 437 ptCapability->isAbsolute = !(ptReportItem->dataModes & kHIDDataRelative); 438 439 ptCapability->isRange = ptUsageItem->isRange; 440 if (ptUsageItem->isRange) 441 { 442 ptCapability->u.range.usageMin = ptUsageItem->usageMinimum; 443 ptCapability->u.range.usageMax = ptUsageItem->usageMaximum; 444 } 445 else 446 ptCapability->u.notRange.usage = ptUsageItem->usage; 447 448 // if there really are that many items 449 if (iU < ptReportItem->stringItemCount) 450 { 451 ptCapability->isStringRange = ptStringItem->isRange; 452 453 if (ptStringItem->isRange) 454 { 455 ptCapability->u.range.stringMin = ptStringItem->minimum; 456 ptCapability->u.range.stringMax = ptStringItem->maximum; 457 } 458 else 459 ptCapability->u.notRange.stringIndex = ptStringItem->index; 460 } 461 // default, clear it 462 else 463 { 464 ptCapability->isStringRange = false; 465 ptCapability->u.notRange.stringIndex = 0; 466 } 467 468 // if there really are that many items 469 if (iU < ptReportItem->desigItemCount) 470 { 471 ptCapability->isDesignatorRange = ptDesignatorItem->isRange; 472 473 if (ptDesignatorItem->isRange) 474 { 475 ptCapability->u.range.designatorMin = ptDesignatorItem->minimum; 476 ptCapability->u.range.designatorMax = ptDesignatorItem->maximum; 477 } 478 else 479 ptCapability->u.notRange.designatorIndex = ptDesignatorItem->index; 480 } 481 // default, clear it 482 else 483 { 484 ptCapability->isDesignatorRange = false; 485 ptCapability->u.notRange.designatorIndex = 0; 486 } 487 488 ptCapability->bitSize = ptReportItem->globals.reportSize; 489 490 ptCapability->logicalMin = ptReportItem->globals.logicalMinimum; 491 ptCapability->logicalMax = ptReportItem->globals.logicalMaximum; 492 ptCapability->physicalMin = ptReportItem->globals.physicalMinimum; 493 ptCapability->physicalMax = ptReportItem->globals.physicalMaximum; 494 495 if (ptUsageItem->isRange) 496 { 497 iCount = ptUsageItem->usageMaximum - ptUsageItem->usageMinimum; 498 iCount++; // Range count was off by one. 499 } 500 else 501 HIDHasUsage(preparsedDataRef,ptReportItem, 502 ptUsageItem->usagePage,ptUsageItem->usage, 503 NULL,&iCount); 504 ptCapability->reportCount = iCount; 505 ptCapability->startBit = startBit; // more of same logic. 506 startBit += (ptCapability->bitSize * ptCapability->reportCount); 507 } 508 } 509 } 510 } 511 return kHIDSuccess; 512} 513 514/* 515 *------------------------------------------------------------------------------ 516 * 517 * HIDGetValueCapabilities - Get the binary values for a report type 518 * This is the same as HIDGetValueCaps, 519 * except that it takes a HIDValueCapabilitiesPtr 520 * so it can return units and unitExponents. 521 * 522 * Input: 523 * reportType - HIDP_Input, HIDP_Output, HIDP_Feature 524 * valueCaps - ValueCaps Array 525 * piValueCapsLength - Maximum Entries 526 * ptPreparsedData - Pre-Parsed Data 527 * Output: 528 * piValueCapsLength - Entries Populated 529 * Returns: 530 * 531 *------------------------------------------------------------------------------ 532*/ 533OSStatus HIDGetValueCapabilities(HIDReportType reportType, 534 HIDValueCapabilitiesPtr valueCaps, 535 UInt32 *piValueCapsLength, 536 HIDPreparsedDataRef preparsedDataRef) 537{ 538 return HIDGetSpecificValueCapabilities(reportType,0,0,0,valueCaps, 539 piValueCapsLength,preparsedDataRef); 540} 541