2 * Copyright (c) 2004-2007,2011 Apple Inc. All Rights Reserved.
4 * @APPLE_LICENSE_HEADER_START@
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
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.
21 * @APPLE_LICENSE_HEADER_END@
26 // iodevices - code for finding and tracking devices via IOKit
28 #include "iodevices.h"
29 #include <security_utilities/cfutilities.h>
30 #include <IOKit/IOMessage.h>
31 #include <IOKit/usb/IOUSBLib.h>
33 using namespace MachPlusPlus
;
42 // Note that multiple MasterPort objects may refer to the same Mach port.
44 MasterPort::MasterPort()
46 Error::check(::IOMasterPort(MACH_PORT_NULL
, &port()));
51 // IOKit Devices (a small subset of functionality)
55 ::IOObjectRelease(mService
);
58 string
Device::name() const
61 Error::check(::IORegistryEntryGetName(mService
, tName
));
65 string
Device::name(const char *plane
) const
68 Error::check(::IORegistryEntryGetNameInPlane(mService
, plane
, tName
));
72 string
Device::path(const char *plane
) const
75 Error::check(::IORegistryEntryGetPath(mService
, plane
, tPath
));
79 CFDictionaryRef
Device::properties() const
81 CFMutableDictionaryRef dict
;
82 Error::check(::IORegistryEntryCreateCFProperties(mService
, &dict
, NULL
, 0));
86 CFTypeRef
Device::property(const char *name
) const
88 return ::IORegistryEntryCreateCFProperty(mService
, CFTempString(name
), NULL
, 0);
95 DeviceIterator::~DeviceIterator()
97 // drain the iterator to avoid port leakage
98 while (Device dev
= (*this)())
103 io_service_t
DeviceIterator::operator () ()
105 io_service_t dev
= ::IOIteratorNext(mIterator
);
114 DeviceMatch::DeviceMatch()
115 : CFRef
<CFMutableDictionaryRef
>(makeCFMutableDictionary())
117 CFError::check(*this);
120 DeviceMatch::DeviceMatch(const char *cls
)
121 : CFRef
<CFMutableDictionaryRef
>(::IOServiceMatching(cls
))
123 CFError::check(*this);
126 DeviceMatch::DeviceMatch(const char *cls
, const char *name
, uint32_t value
, ...)
127 : CFRef
<CFMutableDictionaryRef
>(::IOServiceMatching(cls
))
129 CFError::check(*this);
132 va_start(args
, value
);
135 name
= va_arg(args
, const char *);
138 value
= va_arg(args
, uint32_t);
142 void DeviceMatch::add(const char *name
, uint32_t value
)
144 CFRef
<CFNumberRef
> number
= CFNumberCreate(NULL
, kCFNumberSInt32Type
, &value
);
145 CFDictionarySetValue(*this, CFTempString(name
), number
);
152 NotificationPort::NotificationPort()
154 CFError::check(mPortRef
= ::IONotificationPortCreate(MasterPort()));
157 NotificationPort::NotificationPort(const MasterPort
&master
)
159 CFError::check(mPortRef
= ::IONotificationPortCreate(master
));
162 NotificationPort::~NotificationPort()
164 ::IONotificationPortDestroy(mPortRef
);
168 mach_port_t
NotificationPort::port() const
170 mach_port_t p
= ::IONotificationPortGetMachPort(mPortRef
);
175 CFRunLoopSourceRef
NotificationPort::source() const
177 CFRunLoopSourceRef rls
= ::IONotificationPortGetRunLoopSource(mPortRef
);
183 void NotificationPort::add(const DeviceMatch
&match
, Receiver
&receiver
, const char *type
)
185 io_iterator_t iterator
;
186 CFRetain(match
); // compensate for IOSAMN not retaining its argument
187 Error::check(::IOServiceAddMatchingNotification(mPortRef
, type
,
192 // run initial iterator to process existing devices
193 secdebug("iokit", "dispatching initial device match iterator %d", iterator
);
194 DeviceIterator
it(iterator
);
195 receiver
.ioChange(it
);
198 void NotificationPort::addInterestNotification(Receiver
&receiver
, io_service_t service
,
199 const io_name_t interestType
)
201 io_iterator_t iterator
;
202 mach_port_t pp
= NotificationPort::port();
204 secdebug("iokit", "NotificationPort::addInterest - type: %s [port: %p (0x%08X), service: 0x%08X]",
205 interestType
, mPortRef
, pp
, service
);
207 // We cannot throw if we get an error here since we will receive notifications
208 // from each plane, and not all planes have the necessary information to be
209 // able to add an interest notification
210 kern_return_t kr
= ::IOServiceAddInterestNotification(mPortRef
,
211 service
, interestType
, ioDeviceNotification
, &receiver
, &iterator
);
212 const char *msgstr
= mach_error_string(kr
);
213 const char *msgtyp
= mach_error_type(kr
);
214 if (msgstr
&& msgtyp
)
215 secdebug("iokit", " msg: %s, typ: %s", msgstr
, msgtyp
);
218 void NotificationPort::ioNotify(void *refCon
, io_iterator_t iterator
)
220 secdebug("iokit", "dispatching new device match iterator %d", iterator
);
221 DeviceIterator
it(iterator
);
223 reinterpret_cast<Receiver
*>(refCon
)->ioChange(it
);
225 secdebug("iokit", "ioChange callback threw an exception (ignored)");
229 void NotificationPort::ioDeviceNotification(void *refCon
, io_service_t service
,
230 natural_t messageType
, void *messageArgument
)
232 secdebug("iokit", "dispatching NEW device notification iterator, service 0x%08X, msg: 0x%04X, arg: %p",
233 service
, messageType
, messageArgument
);
235 const char *msgstr
= mach_error_string(messageType
);
236 const char *msgtyp
= mach_error_type(messageType
);
237 if (msgstr
&& msgtyp
)
238 secdebug("iokit", " msg: %s, typ: %s", msgstr
, msgtyp
);
240 if (service
!=io_service_t(-1))
241 reinterpret_cast<Receiver
*>(refCon
)->ioServiceChange(refCon
, service
, messageType
, messageArgument
);
245 // Abstract NotificationPort::Receivers
247 NotificationPort::Receiver::~Receiver()
252 // MachPortNotificationPorts
254 MachPortNotificationPort::MachPortNotificationPort()
256 NoReplyHandler::port(NotificationPort::port());
259 MachPortNotificationPort::~MachPortNotificationPort()
263 boolean_t
MachPortNotificationPort::handle(mach_msg_header_t
*in
)
265 ::IODispatchCalloutFromMessage(NULL
, in
, mPortRef
);
271 } // end namespace IOKit
272 } // end namespace Security