1/* 2 * Copyright (c) 2000-2002 Apple Computer, Inc. All Rights Reserved. 3 * The contents of this file constitute Original Code as defined in and are 4 * subject to the Apple Public Source License Version 1.2 (the 'License'). 5 * You may not use this file except in compliance with the License. Please 6 * obtain a copy of the License at http://www.apple.com/publicsource and 7 * read it before using this file. 8 * 9 * This Original Code and all software distributed under the License are 10 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER 11 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, 12 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, FITNESS 13 * FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. Please 14 * see the License for the specific language governing rights and 15 * limitations under the License. 16 */ 17 18/****************************************************************** 19 20 MUSCLE SmartCard Development ( http://www.linuxnet.com ) 21 Title : hotplug_macosx.c 22 Package: pcsc lite 23 Author : Stephen M. Webb <stephenw@cryptocard.com> 24 Date : 03 Dec 2002 25 License: Copyright (C) 2002 David Corcoran 26 <corcoran@linuxnet.com> 27 Purpose: This provides a search API for hot pluggble 28 devices. 29 30********************************************************************/ 31 32#include <CoreFoundation/CoreFoundation.h> 33#include <IOKit/IOCFPlugIn.h> 34#include <IOKit/IOKitLib.h> 35#include <IOKit/usb/IOUSBLib.h> 36#include <stdlib.h> 37#include <string.h> 38 39#include "config.h" 40#include "wintypes.h" 41#include "pcsclite.h" 42#include "debuglog.h" 43#include "hotplug.h" 44#include "readerfactory.h" 45#include "thread_generic.h" 46 47#define PCSCLITE_HP_DROPDIR "/usr/libexec/SmartCardServices/drivers/" 48#define PCSCLITE_HP_MANUKEY_NAME "ifdVendorID" 49#define PCSCLITE_HP_PRODKEY_NAME "ifdProductID" 50#define PCSCLITE_HP_NAMEKEY_NAME "ifdFriendlyName" 51#define PCSCLITE_HP_IFACECLASSKEY_NAME "ifdInterfaceClass" 52#define PCSCLITE_HP_IFACESUBCLASSKEY_NAME "ifdInterfaceSubClass" 53#define PCSCLITE_HP_IFACEPROTOCOLKEY_NAME "ifdInterfaceProtocol" 54#define PCSCLITE_HP_BASE_PORT 0x200000 55 56 57/* 58 * Defines the type of driver in the driver vector 59 */ 60typedef enum 61{ 62 PCSCLITE_HP_Proprietary = 0, 63 PCSCLITE_HP_InterfaceClass = 1, 64 // * Could accomodate more types */ 65} HPDriverType; 66 67 68 69/* 70 * An aggregation of useful information on a driver bundle in the 71 * drop directory. 72 */ 73typedef struct HPDriver 74{ 75 UInt8 m_NotEOV; /* set to 1 for any driver before the end */ 76 UInt8 m_initialized; /* set to 1 on successful intialization */ 77 HPDriverType m_type; /* type of the driver in this element */ 78 UInt32 m_vendorId; /* unique vendor's manufacturer code */ 79 UInt32 m_productId; /* manufacturer's unique product code */ 80 UInt8 m_class; /* class of a non product specific driver */ 81 UInt8 m_subClass; /* subClass of a non product specific driver */ 82 UInt8 m_protocol; /* protocol of a non product specific driver */ 83 char* m_friendlyName; /* bundle friendly name */ 84 char* m_libPath; /* bundle's plugin library location */ 85} HPDriver, *HPDriverVector; 86 87/* 88 * An aggregation on information on currently active reader drivers. 89 */ 90typedef struct HPDevice 91{ 92 HPDriver* m_driver; /* driver bundle information */ 93 UInt32 m_address; /* unique system address of device */ 94 struct HPDevice* m_next; /* next device in list */ 95} HPDevice, *HPDeviceList; 96 97/* 98 * Pointer to a list of (currently) known hotplug reader devices (and their 99 * drivers). 100 */ 101static HPDeviceList sDeviceList = NULL; 102static IONotificationPortRef sNotificationPort = NULL; 103static io_iterator_t sUSBAppearedIter = NULL; 104static io_iterator_t sUSBRemovedIter = NULL; 105static io_iterator_t sPCCardAppearedIter = NULL; 106static io_iterator_t sPCCardRemovedIter = NULL; 107 108/* 109 * A callback to handle the asynchronous appearance of new devices that are 110 * candidates for PCSC readers. 111 */ 112static void 113HPDeviceAppeared(void* refCon, io_iterator_t iterator) 114{ 115 kern_return_t kret; 116 io_service_t obj; 117 while ((obj = IOIteratorNext(iterator))) 118 { 119 kret = IOObjectRelease(obj); 120 } 121 122 HPSearchHotPluggables(); 123} 124 125/* 126 * A callback to handle the asynchronous disappearance of devices that are 127 * possibly PCSC readers. 128 */ 129static void 130HPDeviceDisappeared(void* refCon, io_iterator_t iterator) 131{ 132 kern_return_t kret; 133 io_service_t obj; 134 while ((obj = IOIteratorNext(iterator))) 135 { 136 kret = IOObjectRelease(obj); 137 } 138 HPSearchHotPluggables(); 139} 140 141 142/* 143 * Creates a vector of driver bundle info structures from the hot-plug driver 144 * directory. 145 * 146 * Returns NULL on error and a pointer to an allocated HPDriver vector on 147 * success. The caller must free the HPDriver with a call to 148 * HPDriversRelease(). 149 */ 150static HPDriverVector 151HPDriversGetFromDirectory(const char* driverBundlePath) 152{ 153 HPDriverVector bundleVector = NULL; 154 CFArrayRef bundleArray; 155 CFStringRef driverBundlePathString; 156 driverBundlePathString = CFStringCreateWithCString(kCFAllocatorDefault, 157 driverBundlePath, 158 kCFStringEncodingMacRoman); 159 CFURLRef pluginUrl = CFURLCreateWithFileSystemPath(kCFAllocatorDefault, 160 driverBundlePathString, 161 kCFURLPOSIXPathStyle, TRUE); 162 CFRelease(driverBundlePathString); 163 if (!pluginUrl) 164 { 165 DebugLogA("error getting plugin directory URL"); 166 return bundleVector; 167 } 168 bundleArray = CFBundleCreateBundlesFromDirectory(kCFAllocatorDefault, 169 pluginUrl, 170 NULL); 171 if (!bundleArray) 172 { 173 DebugLogA("error getting plugin directory bundles"); 174 return bundleVector; 175 } 176 CFRelease(pluginUrl); 177 178 size_t bundleArraySize = CFArrayGetCount(bundleArray); 179 // bundleArraySize + 1 <- because the last vector element is 180 // blank and is used to determine the length (m_NotEOV == 0) 181 bundleVector = (HPDriver*)calloc(bundleArraySize + 1, sizeof(HPDriver)); 182 if (!bundleVector) 183 { 184 DebugLogA("memory allocation failure"); 185 return bundleVector; 186 } 187 188 int i = 0; 189 for (; i < bundleArraySize; ++i) 190 { 191 HPDriver* driverBundle = bundleVector + i; 192 // This is not the last 193 driverBundle->m_NotEOV = 1; 194 CFBundleRef currBundle = (CFBundleRef)CFArrayGetValueAtIndex(bundleArray, i); 195 CFDictionaryRef dict = CFBundleGetInfoDictionary(currBundle); 196 197 CFURLRef bundleUrl = CFBundleCopyBundleURL(currBundle); 198 CFStringRef bundlePath = CFURLCopyPath(bundleUrl); 199 driverBundle->m_libPath = strdup(CFStringGetCStringPtr(bundlePath, 200 CFStringGetSystemEncoding())); 201 if (driverBundle->m_libPath == NULL) 202 { 203 DebugLogA("memory allocation failure"); 204 return bundleVector; 205 } 206 UInt32 vendorId = 0; 207 UInt8 gotVendorId = 0; 208 UInt32 productId = 0; 209 UInt8 gotProductId = 0; 210 211 CFStringRef strValue = (CFStringRef)CFDictionaryGetValue(dict, 212 CFSTR(PCSCLITE_HP_MANUKEY_NAME)); 213 if (strValue) 214 { 215 gotVendorId = 1; 216 vendorId = strtoul(CFStringGetCStringPtr(strValue, 217 CFStringGetSystemEncoding()), 218 NULL, 16); 219 220 strValue = (CFStringRef)CFDictionaryGetValue(dict, 221 CFSTR(PCSCLITE_HP_PRODKEY_NAME)); 222 if (strValue) 223 { 224 gotProductId = 1; 225 productId = strtoul(CFStringGetCStringPtr(strValue, 226 CFStringGetSystemEncoding()), 227 NULL, 16); 228 } 229 } 230 if (gotVendorId && gotProductId) 231 { 232 /* This is a product-specific driver */ 233 driverBundle->m_productId = productId; 234 driverBundle->m_vendorId = vendorId; 235 driverBundle->m_type = PCSCLITE_HP_Proprietary; 236 } 237 else 238 { 239 /* If not a product-specific driver, it must be */ 240 /* an interface class-specifc driver */ 241 UInt8 class; 242 UInt8 subClass; 243 UInt8 protocol; 244 245 strValue = (CFStringRef)CFDictionaryGetValue(dict, 246 CFSTR(PCSCLITE_HP_IFACECLASSKEY_NAME)); 247 if (strValue) 248 { 249 class = (UInt8) strtoul(CFStringGetCStringPtr(strValue, 250 CFStringGetSystemEncoding()), 251 NULL, 16); 252 driverBundle->m_class = class; 253 } 254 else 255 { 256 DebugLogB("Malformed bundle (class absent) in driver folder: %s. Will be ignored", 257 driverBundle->m_libPath); 258 free(driverBundle->m_libPath); 259 driverBundle->m_libPath = NULL; 260 continue; 261 } 262 strValue = (CFStringRef)CFDictionaryGetValue(dict, 263 CFSTR(PCSCLITE_HP_IFACESUBCLASSKEY_NAME)); 264 if (strValue) 265 { 266 subClass = (UInt8) strtoul(CFStringGetCStringPtr(strValue, 267 CFStringGetSystemEncoding()), 268 NULL, 16); 269 driverBundle->m_subClass = subClass; 270 } 271 else 272 { 273 DebugLogB("Malformed bundle (subClass absent) in driver folder: %s. Will be ignored", 274 driverBundle->m_libPath); 275 free(driverBundle->m_libPath); 276 driverBundle->m_libPath = NULL; 277 continue; 278 } 279 strValue = (CFStringRef)CFDictionaryGetValue(dict, 280 CFSTR(PCSCLITE_HP_IFACEPROTOCOLKEY_NAME)); 281 if (strValue) 282 { 283 protocol = (UInt8) strtoul(CFStringGetCStringPtr(strValue, 284 CFStringGetSystemEncoding()), 285 NULL, 16); 286 driverBundle->m_protocol = protocol; 287 } 288 else 289 { 290 DebugLogB("Malformed bundle (protocol absent) in driver folder: %s. Will be ignored", 291 driverBundle->m_libPath); 292 free(driverBundle->m_libPath); 293 driverBundle->m_libPath = NULL; 294 continue; 295 } 296 driverBundle->m_type = PCSCLITE_HP_InterfaceClass; 297 } 298 strValue = (CFStringRef)CFDictionaryGetValue(dict, 299 CFSTR(PCSCLITE_HP_NAMEKEY_NAME)); 300 if (!strValue) 301 { 302 DebugLogB("Product friendly name absent in driver folder: %s.", 303 driverBundle->m_libPath); 304 driverBundle->m_friendlyName = strdup("unnamed device"); 305 } 306 else 307 { 308 const char* cstr = CFStringGetCStringPtr(strValue, 309 CFStringGetSystemEncoding()); 310 driverBundle->m_friendlyName = strdup(cstr); 311 } 312 driverBundle->m_initialized = 1; 313 } 314 CFRelease(bundleArray); 315 return bundleVector; 316} 317 318/* 319 * Copies a driver bundle instance. 320 */ 321static HPDriver* 322HPDriverCopy(HPDriver* rhs) 323{ 324 if (!rhs) 325 { 326 return NULL; 327 } 328 HPDriver* newDriverBundle = (HPDriver*)calloc(1, sizeof(HPDriver)); 329 if (!newDriverBundle) 330 { 331 return NULL; 332 } 333 334 newDriverBundle->m_initialized = rhs->m_initialized; 335 newDriverBundle->m_type = rhs->m_type; 336 newDriverBundle->m_vendorId = rhs->m_vendorId; 337 newDriverBundle->m_productId = rhs->m_productId; 338 339 newDriverBundle->m_class = rhs->m_class; 340 newDriverBundle->m_subClass = rhs->m_subClass; 341 newDriverBundle->m_friendlyName = strdup(rhs->m_friendlyName); 342 newDriverBundle->m_libPath = strdup(rhs->m_libPath); 343 if (newDriverBundle->m_friendlyName == NULL) 344 { 345 if (newDriverBundle->m_libPath != NULL) 346 { 347 free(newDriverBundle->m_libPath); 348 } 349 free(newDriverBundle); 350 return NULL; 351 } 352 353 if (newDriverBundle->m_libPath == NULL) 354 { 355 if (newDriverBundle->m_friendlyName != NULL) 356 { 357 free(newDriverBundle->m_friendlyName); 358 } 359 free(newDriverBundle); 360 return NULL; 361 } 362 return newDriverBundle; 363} 364 365/* 366 * Releases resources allocated to a driver bundle vector. 367 */ 368static void 369HPDriverRelease(HPDriver* driverBundle) 370{ 371 if (driverBundle) 372 { 373 free(driverBundle->m_friendlyName); 374 free(driverBundle->m_libPath); 375 } 376} 377 378/* 379 * Releases resources allocated to a driver bundle vector. 380 */ 381static void 382HPDriverVectorRelease(HPDriverVector driverBundleVector) 383{ 384 if (driverBundleVector) 385 { 386 HPDriver* b = driverBundleVector; 387 for (; b->m_initialized; ++b) 388 { 389 HPDriverRelease(b); 390 } 391 free(driverBundleVector); 392 } 393} 394 395/* 396 * Inserts a new reader device in the list. 397 */ 398static HPDeviceList 399HPDeviceListInsert(HPDeviceList list, HPDriver* bundle, UInt32 address) 400{ 401 HPDevice* newReader = (HPDevice*)calloc(1, sizeof(HPDevice)); 402 if (!newReader) 403 { 404 DebugLogA("memory allocation failure"); 405 return list; 406 } 407 newReader->m_driver = HPDriverCopy(bundle); 408 newReader->m_address = address; 409 newReader->m_next = list; 410 return newReader; 411} 412 413/* 414 * Frees resources allocated to a HPDeviceList. 415 */ 416static void 417HPDeviceListRelease(HPDeviceList list) 418{ 419 HPDevice* p = list; 420 for (; p; p = p->m_next) 421 { 422 HPDriverRelease(p->m_driver); 423 } 424} 425 426/* 427 * Compares two driver bundle instances for equality. 428 */ 429static int 430HPDeviceEquals(HPDevice* a, HPDevice* b) 431{ 432 int res; 433 if (a->m_driver->m_type == b->m_driver->m_type) 434 { 435 if (a->m_driver->m_type == PCSCLITE_HP_Proprietary) 436 { 437 // a and b have same vendor and product id 438 res = (a->m_driver->m_vendorId == b->m_driver->m_vendorId) 439 && (a->m_driver->m_productId == b->m_driver->m_productId); 440 } 441 else 442 { 443 // a and b have same class 444 res = (a->m_driver->m_subClass == b->m_driver->m_subClass) 445 && (a->m_driver->m_class == b->m_driver->m_class); 446 } 447 // AND have the same address 448 res = res && (a->m_address == b->m_address); 449 450 return res; 451 } 452 return 0; 453} 454 455/* 456 * Finds USB devices currently registered in the system that match any of 457 * the drivers detected in the driver bundle vector. 458 */ 459static int 460HPDriversMatchUSBDevices(HPDriverVector driverBundle, HPDeviceList* readerList) 461{ 462 CFDictionaryRef usbMatch = IOServiceMatching("IOUSBDevice"); 463 if (0 == usbMatch) 464 { 465 DebugLogA("error getting USB match from IOServiceMatching()"); 466 return 1; 467 } 468 469 io_iterator_t usbIter; 470 kern_return_t kret = IOServiceGetMatchingServices(kIOMasterPortDefault, 471 usbMatch, 472 &usbIter); 473 if (kret != 0) 474 { 475 DebugLogA("error getting iterator from IOServiceGetMatchingServices()"); 476 return 1; 477 } 478 479 io_object_t usbDevice = 0; 480 while ((usbDevice = IOIteratorNext(usbIter))) 481 { 482 IOCFPlugInInterface** iodev; 483 SInt32 score; 484 kret = IOCreatePlugInInterfaceForService(usbDevice, 485 kIOUSBDeviceUserClientTypeID, 486 kIOCFPlugInInterfaceID, 487 &iodev, 488 &score); 489 IOObjectRelease(usbDevice); 490 if (kret != 0) 491 { 492 DebugLogA("error getting plugin interface from IOCreatePlugInInterfaceForService()"); 493 continue; 494 } 495 496 IOUSBDeviceInterface245** usbdev; 497 HRESULT hres = (*iodev)->QueryInterface(iodev, 498 CFUUIDGetUUIDBytes(kIOUSBDeviceInterfaceID245), 499 (LPVOID*)&usbdev); 500 if (hres) 501 { 502 DebugLogA("error querying interface in QueryInterface()"); 503 IODestroyPlugInInterface ( iodev ); 504 continue; 505 } 506 507 else 508 { 509 510 UInt16 vendorId = 0; 511 UInt16 productId = 0; 512 UInt32 usbAddress = 0; 513 kret = (*usbdev)->GetDeviceVendor(usbdev, &vendorId); 514 kret = (*usbdev)->GetDeviceProduct(usbdev, &productId); 515 kret = (*usbdev)->GetLocationID(usbdev, &usbAddress); 516 517 HPDriver* driver = driverBundle; 518 int match = 0; 519 for (; driver->m_NotEOV; ++driver) 520 { 521 if (!driver->m_initialized) 522 { 523 // Malformed driver, skip 524 continue; 525 } 526 if ( (driver->m_type == PCSCLITE_HP_Proprietary) 527 && (driver->m_vendorId == vendorId) 528 && (driver->m_productId == productId)) 529 { 530 *readerList = HPDeviceListInsert(*readerList, driver, usbAddress); 531 match = 1; 532 } 533 } 534 if (!match) 535 { 536 // Now try to locate Interfaces with supported classes 537 // We create an interface iterator for each of the 538 // classes supported by drivers of PCSCLITE_HP_InterfaceClass 539 // type. 540 541 // Using IOServiceMatching(kIOUSBInterfaceClassName) 542 // does not seem feasible as there does not seem to be a 543 // way to limit the search to the device we are currently 544 // analysing 545 546 // Another option would be to iterate on all interfaces 547 // and get the class of each of them. This is probably 548 // not interesting as the list of PCSCLITE_HP_InterfaceClass 549 // type of readers should only have one element (CCID) 550 551 // Restart scan at the begining of the array 552 driver = driverBundle; 553 // Iterate on PCSCLITE_HP_InterfaceClass driver types 554 for (; driver->m_NotEOV; ++driver) 555 { 556 if (!driver->m_initialized) 557 { 558 // Malformed driver, skip 559 continue; 560 } 561 if ( driver->m_type == PCSCLITE_HP_InterfaceClass) 562 { 563 // Iterate on interfaces of the current device 564 IOUSBFindInterfaceRequest interfaceClassRequest; 565 io_iterator_t interfaceIterator; 566 io_service_t interface; 567 568 interfaceClassRequest.bInterfaceClass = driver->m_class; 569 interfaceClassRequest.bInterfaceSubClass = driver->m_subClass; 570 interfaceClassRequest.bInterfaceProtocol = driver->m_protocol; 571 interfaceClassRequest.bAlternateSetting = kIOUSBFindInterfaceDontCare; 572 hres = (*usbdev)->CreateInterfaceIterator(usbdev, 573 &interfaceClassRequest, 574 &interfaceIterator); 575 if (hres) 576 { 577 // Continue to next driver class 578 continue; 579 } 580 581 while ( (interface = IOIteratorNext(interfaceIterator)) ) 582 { 583 // Found a matching device 584 *readerList = HPDeviceListInsert(*readerList, driver, usbAddress); 585 match = 1; 586 IOObjectRelease ( interface ); 587 } 588 589 IOObjectRelease ( interfaceIterator ); 590 591 } 592 } 593 // Add another if (!match) for other driver types 594 } 595 (*usbdev)->Release(usbdev); 596 IODestroyPlugInInterface ( iodev ); 597 } 598 } 599 600 IOObjectRelease(usbIter); 601 return 0; 602} 603 604/* 605 * Finds PC Card devices currently registered in the system that match any of 606 * the drivers detected in the driver bundle vector. 607 */ 608static int 609HPDriversMatchPCCardDevices(HPDriver* driverBundle, HPDeviceList* readerList) 610{ 611 CFDictionaryRef pccMatch = IOServiceMatching("IOPCCard16Device"); 612 if (0 == pccMatch) 613 { 614 DebugLogA("error getting PCCard match from IOServiceMatching()"); 615 return 1; 616 } 617 618 io_iterator_t pccIter; 619 kern_return_t kret = IOServiceGetMatchingServices(kIOMasterPortDefault, pccMatch, &pccIter); 620 if (kret != 0) 621 { 622 DebugLogA("error getting iterator from IOServiceGetMatchingServices()"); 623 return 1; 624 } 625 626 io_object_t pccDevice = 0; 627 while ((pccDevice = IOIteratorNext(pccIter))) 628 { 629 630 UInt32 vendorId = 0; 631 UInt32 productId = 0; 632 UInt32 pccAddress = 0; 633 CFTypeRef valueRef = IORegistryEntryCreateCFProperty(pccDevice, CFSTR("VendorID"), 634 kCFAllocatorDefault, 0); 635 if (!valueRef) 636 { 637 DebugLogA("error getting vendor"); 638 } 639 else 640 { 641 CFNumberGetValue((CFNumberRef)valueRef, kCFNumberSInt32Type, &vendorId); 642 CFRelease ( valueRef ); 643 } 644 valueRef = IORegistryEntryCreateCFProperty(pccDevice, CFSTR("DeviceID"), 645 kCFAllocatorDefault, 0); 646 if (!valueRef) 647 { 648 DebugLogA("error getting device"); 649 } 650 else 651 { 652 CFNumberGetValue((CFNumberRef)valueRef, kCFNumberSInt32Type, &productId); 653 CFRelease ( valueRef ); 654 } 655 valueRef = IORegistryEntryCreateCFProperty(pccDevice, CFSTR("SocketNumber"), 656 kCFAllocatorDefault, 0); 657 if (!valueRef) 658 { 659 DebugLogA("error getting PC Card socket"); 660 } 661 else 662 { 663 CFNumberGetValue((CFNumberRef)valueRef, kCFNumberSInt32Type, &pccAddress); 664 CFRelease ( valueRef ); 665 } 666 HPDriver* driver = driverBundle; 667 for (; driver->m_vendorId; ++driver) 668 { 669 if ((driver->m_vendorId == vendorId) 670 && (driver->m_productId == productId)) 671 { 672 *readerList = HPDeviceListInsert(*readerList, driver, pccAddress); 673 } 674 } 675 676 IOObjectRelease ( pccDevice ); 677 678 } 679 IOObjectRelease(pccIter); 680 return 0; 681} 682 683 684static void 685HPEstablishUSBNotification() 686{ 687 688 CFMutableDictionaryRef matchingDictionary; 689 IOReturn kret; 690 691 if ( sNotificationPort == NULL ) 692 sNotificationPort = IONotificationPortCreate(kIOMasterPortDefault); 693 694 CFRunLoopAddSource(CFRunLoopGetCurrent(), 695 IONotificationPortGetRunLoopSource(sNotificationPort), 696 kCFRunLoopDefaultMode); 697 698 matchingDictionary = IOServiceMatching("IOUSBDevice"); 699 if (!matchingDictionary) 700 { 701 DebugLogB("IOServiceMatching() failed", 0); 702 } 703 matchingDictionary = (CFMutableDictionaryRef)CFRetain(matchingDictionary); 704 705 kret = IOServiceAddMatchingNotification(sNotificationPort, 706 kIOMatchedNotification, 707 matchingDictionary, 708 HPDeviceAppeared, NULL, 709 &sUSBAppearedIter); 710 if (kret) 711 { 712 DebugLogB("IOServiceAddMatchingNotification()-1 failed with code %d", kret); 713 } 714 715 HPDeviceAppeared(NULL, sUSBAppearedIter); 716 717 kret = IOServiceAddMatchingNotification(sNotificationPort, 718 kIOTerminatedNotification, 719 matchingDictionary, 720 HPDeviceDisappeared, NULL, 721 &sUSBRemovedIter); 722 if (kret) 723 { 724 DebugLogB("IOServiceAddMatchingNotification()-2 failed with code %d", kret); 725 } 726 HPDeviceDisappeared(NULL, sUSBRemovedIter); 727} 728 729static void 730HPEstablishPCCardNotification() 731{ 732 733 CFMutableDictionaryRef matchingDictionary; 734 IOReturn kret; 735 736 if ( sNotificationPort == NULL ) 737 sNotificationPort = IONotificationPortCreate(kIOMasterPortDefault); 738 739 CFRunLoopAddSource(CFRunLoopGetCurrent(), 740 IONotificationPortGetRunLoopSource(sNotificationPort), 741 kCFRunLoopDefaultMode); 742 743 matchingDictionary = IOServiceMatching("IOPCCard16Device"); 744 if (!matchingDictionary) 745 { 746 DebugLogB("IOServiceMatching() failed", 0); 747 } 748 matchingDictionary = (CFMutableDictionaryRef)CFRetain(matchingDictionary); 749 750 kret = IOServiceAddMatchingNotification(sNotificationPort, 751 kIOMatchedNotification, 752 matchingDictionary, 753 HPDeviceAppeared, NULL, 754 &sPCCardAppearedIter); 755 if (kret) 756 { 757 DebugLogB("IOServiceAddMatchingNotification()-1 failed with code %d", kret); 758 } 759 HPDeviceAppeared(NULL, sPCCardAppearedIter); 760 761 kret = IOServiceAddMatchingNotification(sNotificationPort, 762 kIOTerminatedNotification, 763 matchingDictionary, 764 HPDeviceDisappeared, NULL, 765 &sPCCardRemovedIter); 766 if (kret) 767 { 768 DebugLogB("IOServiceAddMatchingNotification()-2 failed with code %d", kret); 769 } 770 HPDeviceDisappeared(NULL, sPCCardRemovedIter); 771} 772 773/* 774 * Thread runner (does not return). 775 */ 776static void 777HPDeviceNotificationThread() 778{ 779 HPEstablishUSBNotification(); 780 HPEstablishPCCardNotification(); 781 CFRunLoopRun(); 782} 783 784/* 785 * Scans the hotplug driver directory and looks in the system for matching devices. 786 * Adds or removes matching readers as necessary. 787 */ 788LONG 789HPSearchHotPluggables() 790{ 791 HPDriver* drivers = HPDriversGetFromDirectory(PCSCLITE_HP_DROPDIR); 792 if (!drivers) return 1; 793 794 HPDeviceList devices = NULL; 795 int istat; 796 istat = HPDriversMatchUSBDevices(drivers, &devices); 797 if (istat) 798 { 799 return -1; 800 } 801 istat = HPDriversMatchPCCardDevices(drivers, &devices); 802 if (istat) 803 { 804 return -1; 805 } 806 807 HPDevice* a = devices; 808 for (; a; a = a->m_next) 809 { 810 int found = 0; 811 HPDevice* b = sDeviceList; 812 for (; b; b = b->m_next) 813 { 814 if (HPDeviceEquals(a, b)) 815 { 816 found = 1; 817 break; 818 } 819 } 820 if (!found) 821 { 822 RFAddReader(a->m_driver->m_friendlyName, 823 PCSCLITE_HP_BASE_PORT + a->m_address, 824 a->m_driver->m_libPath); 825 } 826 } 827 828 a = sDeviceList; 829 for (; a; a = a->m_next) 830 { 831 int found = 0; 832 HPDevice* b = devices; 833 for (; b; b = b->m_next) 834 { 835 if (HPDeviceEquals(a, b)) 836 { 837 found = 1; 838 break; 839 } 840 } 841 if (!found) 842 { 843 RFRemoveReader(a->m_driver->m_friendlyName, 844 PCSCLITE_HP_BASE_PORT + a->m_address); 845 } 846 } 847 848 HPDeviceListRelease(sDeviceList); 849 sDeviceList = devices; 850 HPDriverVectorRelease(drivers); 851 return 0; 852} 853 854 855PCSCLITE_THREAD_T sHotplugWatcherThread; 856 857/* 858 * Sets up callbacks for device hotplug events. 859 */ 860LONG 861HPRegisterForHotplugEvents() 862{ 863 LONG sstat; 864 sstat = SYS_ThreadCreate(&sHotplugWatcherThread, 865 NULL, 866 (LPVOID)HPDeviceNotificationThread, 867 NULL); 868 return 0; 869} 870