1 /*!
2 * \copyright Copyright (c) 2016-2021 Governikus GmbH & Co. KG, Germany
3 */
4
5 #include "ReaderDetector.h"
6
7 #include <CoreFoundation/CFNumber.h>
8
9 #include <IOKit/IOKitKeys.h>
10 #include <IOKit/usb/IOUSBLib.h>
11
12 #include <QLoggingCategory>
13
14 Q_DECLARE_LOGGING_CATEGORY(card_drivers)
15
16 using namespace governikus;
17
18
19 #define VENDOR_ID "idVendor"
20 #define PRODUCT_ID "idProduct"
21
22
deviceChanged(void * refCon,io_iterator_t iterator)23 static void deviceChanged(void* refCon, io_iterator_t iterator)
24 {
25 while (IOIteratorNext(iterator))
26 {
27 // Clear the recognized changes
28 }
29
30 qCDebug(card_drivers) << "System information: device changed";
31
32 ReaderDetector* readerDetector = static_cast<ReaderDetector*>(refCon);
33 Q_EMIT readerDetector->fireReaderChangeDetected();
34 }
35
36
listenTo(const io_name_t notificationType,ReaderDetector * readerDetector,io_iterator_t * iterator)37 static bool listenTo(const io_name_t notificationType, ReaderDetector* readerDetector, io_iterator_t* iterator)
38 {
39 //https://developer.apple.com/library/mac/documentation/DeviceDrivers/Conceptual/AccessingHardware/AH_Finding_Devices/AH_Finding_Devices.html
40
41 CFMutableDictionaryRef matchingDict = IOServiceMatching(kIOUSBDeviceClassName);
42 IONotificationPortRef notificationObject = IONotificationPortCreate(kIOMasterPortDefault);
43 CFRunLoopSourceRef notificationRunLoopSource = IONotificationPortGetRunLoopSource(notificationObject);
44 CFRunLoopAddSource(CFRunLoopGetCurrent(), notificationRunLoopSource, kCFRunLoopDefaultMode);
45 kern_return_t kr = IOServiceAddMatchingNotification(
46 notificationObject,
47 notificationType,
48 matchingDict,
49 deviceChanged,
50 readerDetector,
51 iterator);
52
53 if (kr != KERN_SUCCESS)
54 {
55 qCDebug(card_drivers) << "IOServiceAddMatchingNotification returned" << kr;
56 return false;
57 }
58
59 while (IOIteratorNext(*iterator))
60 {
61 // Clear already known devices and arm the notification mechanism
62 }
63
64 return true;
65 }
66
67
initNativeEvents()68 bool ReaderDetector::initNativeEvents()
69 {
70 bool succeed = true;
71 succeed &= listenTo(kIOPublishNotification, this, &mIteratorPublish);
72 succeed &= listenTo(kIOTerminatedNotification, this, &mIteratorTerminated);
73
74 return succeed;
75 }
76
77
terminateNativeEvents()78 bool ReaderDetector::terminateNativeEvents()
79 {
80 bool succeed = true;
81 succeed &= (IOObjectRelease(mIteratorPublish) == KERN_SUCCESS);
82 succeed &= (IOObjectRelease(mIteratorTerminated) == KERN_SUCCESS);
83
84 return succeed;
85 }
86
87
getUintValueFromDeviceRegistryEntry(io_object_t pDevice,CFStringRef pKey,uint * pResultValue)88 static bool getUintValueFromDeviceRegistryEntry(io_object_t pDevice, CFStringRef pKey, uint* pResultValue)
89 {
90 static const CFTypeID NUMBER_TYPE_ID = CFNumberGetTypeID();
91
92 CFTypeRef property = IORegistryEntryCreateCFProperty(pDevice, pKey, kCFAllocatorDefault, /* options */ 0);
93 if (property == NULL)
94 {
95 qCWarning(card_drivers) << "property" << pKey << "not found in registry entry";
96
97 return false;
98 }
99
100 if (CFGetTypeID(property) != NUMBER_TYPE_ID)
101 {
102 qCWarning(card_drivers) << "property" << pKey << "is not of a numeric type";
103
104 return false;
105 }
106
107 CFNumberRef number = static_cast<CFNumberRef>(property);
108 if (CFNumberGetType(number) != kCFNumberSInt32Type)
109 {
110 qCWarning(card_drivers) << "property" << pKey << "has the wrong numeric type";
111
112 return false;
113 }
114
115 const bool success = CFNumberGetValue(number, kCFNumberSInt32Type, pResultValue);
116 CFRelease(property);
117 if (!success)
118 {
119 qCWarning(card_drivers) << "error while reading numeric value from property" << pKey;
120 }
121
122 return success;
123 }
124
125
getDeviceIds(io_object_t pDevice)126 static UsbId getDeviceIds(io_object_t pDevice)
127 {
128 uint vendorId = 0x0;
129 uint productId = 0x0;
130
131 if (!getUintValueFromDeviceRegistryEntry(pDevice, CFSTR(VENDOR_ID), &vendorId))
132 {
133 qCDebug(card_drivers) << "missing or invalid vendor id";
134
135 return UsbId(0x0, 0x0);
136 }
137
138 if (!getUintValueFromDeviceRegistryEntry(pDevice, CFSTR(PRODUCT_ID), &productId))
139 {
140 qCDebug(card_drivers) << "missing or invalid product id";
141
142 return UsbId(0x0, 0x0);
143 }
144
145 return UsbId(vendorId, productId);
146 }
147
148
attachedDevIds() const149 QVector<UsbId> ReaderDetector::attachedDevIds() const
150 {
151 QVector<UsbId> result;
152 mach_port_t myMasterPort = kIOMasterPortDefault;
153 io_iterator_t deviceIterator = 0;
154 io_object_t currentDevice = 0;
155
156 kern_return_t createIteratorResult = IORegistryCreateIterator(myMasterPort, kIOUSBPlane, kIORegistryIterateRecursively, &deviceIterator);
157 if (createIteratorResult != kIOReturnSuccess)
158 {
159 qCWarning(card_drivers) << "creation of device iterator failed, exiting";
160
161 return QVector<UsbId>();
162 }
163
164 currentDevice = IOIteratorNext(deviceIterator);
165 while (currentDevice != 0)
166 {
167 UsbId ids = getDeviceIds(currentDevice);
168 if (ids.getVendorId() != 0 && ids.getProductId() != 0)
169 {
170 result += ids;
171 }
172
173 IOObjectRelease(currentDevice);
174 currentDevice = IOIteratorNext(deviceIterator);
175 }
176
177 IOObjectRelease(deviceIterator);
178
179 return result;
180 }
181