2 * Copyright (c) 2002 Apple Computer, Inc. All rights reserved.
4 * @APPLE_LICENSE_HEADER_START@
6 * The contents of this file constitute Original Code as defined in and
7 * are subject to the Apple Public Source License Version 1.1 (the
8 * "License"). You may not use this file except in compliance with the
9 * License. Please obtain a copy of the License at
10 * http://www.apple.com/publicsource and read it before using this file.
12 * This Original Code and all software distributed under the License are
13 * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
14 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
15 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
16 * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the
17 * License for the specific language governing rights and limitations
20 * @APPLE_LICENSE_HEADER_END@
24 * Modification History
26 * May 29, 2002 Roger Smith <rsmith@apple.com>
30 #include <sys/types.h>
31 #include <sys/param.h>
33 #include <mach/mach.h>
34 #include <mach-o/dyld.h>
37 #include <CoreFoundation/CoreFoundation.h>
38 #include <CoreFoundation/CFRuntime.h>
40 #include <SystemConfiguration/SystemConfiguration.h>
41 #include <SystemConfiguration/SCValidation.h>
42 #include <SystemConfiguration/SCPrivate.h>
44 #include <IOKit/IOKitLib.h>
48 #include "DeviceOnHold.h"
51 #define kIODeviceSupportsHoldKey "DeviceSupportsHold"
56 static const void *image
= NULL
;
58 const char *framework
= "/System/Library/Frameworks/IOKit.framework/IOKit";
60 const char *suffix
= getenv("DYLD_IMAGE_SUFFIX");
61 char path
[MAXPATHLEN
];
63 strcpy(path
, framework
);
64 if (suffix
) strcat(path
, suffix
);
65 if (0 <= stat(path
, &statbuf
)) {
66 image
= NSAddImage(path
, NSADDIMAGE_OPTION_NONE
);
68 image
= NSAddImage(framework
, NSADDIMAGE_OPTION_NONE
);
76 _IOIteratorNext(io_iterator_t iterator
)
78 static io_object_t (*dyfunc
)(io_iterator_t
) = NULL
;
80 void *image
= __loadIOKit();
81 if (image
) dyfunc
= NSAddressOfSymbol(NSLookupSymbolInImage(image
, "_IOIteratorNext", NSLOOKUPSYMBOLINIMAGE_OPTION_BIND
));
83 return dyfunc
? dyfunc(iterator
) : 0;
85 #define IOIteratorNext _IOIteratorNext
89 _IOMasterPort(mach_port_t bootstrapPort
, mach_port_t
*masterPort
)
91 static kern_return_t (*dyfunc
)(mach_port_t
, mach_port_t
*) = NULL
;
93 void *image
= __loadIOKit();
94 if (image
) dyfunc
= NSAddressOfSymbol(NSLookupSymbolInImage(image
, "_IOMasterPort", NSLOOKUPSYMBOLINIMAGE_OPTION_BIND
));
96 return dyfunc
? dyfunc(bootstrapPort
, masterPort
) : KERN_FAILURE
;
98 #define IOMasterPort _IOMasterPort
102 _IOObjectRelease(io_object_t object
)
104 static kern_return_t (*dyfunc
)(io_object_t
) = NULL
;
106 void *image
= __loadIOKit();
107 if (image
) dyfunc
= NSAddressOfSymbol(NSLookupSymbolInImage(image
, "_IOObjectRelease", NSLOOKUPSYMBOLINIMAGE_OPTION_BIND
));
109 return dyfunc
? dyfunc(object
) : KERN_FAILURE
;
111 #define IOObjectRelease _IOObjectRelease
115 _IORegistryEntryCreateCFProperties(io_registry_entry_t entry
, CFMutableDictionaryRef
*properties
, CFAllocatorRef allocator
, IOOptionBits options
)
117 static kern_return_t (*dyfunc
)(io_registry_entry_t
, CFMutableDictionaryRef
*, CFAllocatorRef
, IOOptionBits
) = NULL
;
119 void *image
= __loadIOKit();
120 if (image
) dyfunc
= NSAddressOfSymbol(NSLookupSymbolInImage(image
, "_IORegistryEntryCreateCFProperties", NSLOOKUPSYMBOLINIMAGE_OPTION_BIND
));
122 return dyfunc
? dyfunc(entry
, properties
, allocator
, options
) : KERN_FAILURE
;
124 #define IORegistryEntryCreateCFProperties _IORegistryEntryCreateCFProperties
128 _IORegistryEntryGetPath(io_registry_entry_t entry
, const io_name_t plane
, io_string_t path
)
130 static kern_return_t (*dyfunc
)(io_registry_entry_t
, const io_name_t
, io_string_t
) = NULL
;
132 void *image
= __loadIOKit();
133 if (image
) dyfunc
= NSAddressOfSymbol(NSLookupSymbolInImage(image
, "_IORegistryEntryGetPath", NSLOOKUPSYMBOLINIMAGE_OPTION_BIND
));
135 return dyfunc
? dyfunc(entry
, plane
, path
) : KERN_FAILURE
;
137 #define IORegistryEntryGetPath _IORegistryEntryGetPath
141 _IOServiceGetMatchingServices(mach_port_t masterPort
, CFDictionaryRef matching
, io_iterator_t
*existing
)
143 static kern_return_t (*dyfunc
)(mach_port_t
, CFDictionaryRef
, io_iterator_t
*) = NULL
;
145 void *image
= __loadIOKit();
146 if (image
) dyfunc
= NSAddressOfSymbol(NSLookupSymbolInImage(image
, "_IOServiceGetMatchingServices", NSLOOKUPSYMBOLINIMAGE_OPTION_BIND
));
148 return dyfunc
? dyfunc(masterPort
, matching
, existing
) : KERN_FAILURE
;
150 #define IOServiceGetMatchingServices _IOServiceGetMatchingServices
153 static CFMutableDictionaryRef
154 _IOServiceMatching(const char *name
)
156 static CFMutableDictionaryRef (*dyfunc
)(const char *) = NULL
;
158 void *image
= __loadIOKit();
159 if (image
) dyfunc
= NSAddressOfSymbol(NSLookupSymbolInImage(image
, "_IOServiceMatching", NSLOOKUPSYMBOLINIMAGE_OPTION_BIND
));
161 return dyfunc
? dyfunc(name
) : NULL
;
163 #define IOServiceMatching _IOServiceMatching
168 /* base CFType information */
169 CFRuntimeBase cfBase
;
171 /* device name (e.g. "modem") */
176 } DeviceOnHoldPrivate
, *DeviceOnHoldPrivateRef
;
180 __DeviceOnHoldCopyDescription(CFTypeRef cf
)
182 CFAllocatorRef allocator
= CFGetAllocator(cf
);
183 CFMutableStringRef result
;
185 result
= CFStringCreateMutable(allocator
, 0);
186 CFStringAppendFormat(result
, NULL
, CFSTR("<DeviceOnHold %p [%p]> {\n"), cf
, allocator
);
187 CFStringAppendFormat(result
, NULL
, CFSTR("}"));
194 __DeviceOnHoldDeallocate(CFTypeRef cf
)
196 DeviceOnHoldPrivateRef DeviceOnHoldPrivate
= (DeviceOnHoldPrivateRef
)cf
;
198 SCLog(_sc_verbose
, LOG_DEBUG
, CFSTR("__DeviceOnHoldDeallocate:"));
200 /* release resources */
201 if (DeviceOnHoldPrivate
->name
) CFRelease(DeviceOnHoldPrivate
->name
);
202 if (DeviceOnHoldPrivate
->sock
!= -1) {
210 static CFTypeID __kDeviceOnHoldTypeID
= _kCFRuntimeNotATypeID
;
213 static const CFRuntimeClass __DeviceOnHoldClass
= {
215 "DeviceOnHold", // className
218 __DeviceOnHoldDeallocate
, // dealloc
221 NULL
, // copyFormattingDesc
222 __DeviceOnHoldCopyDescription
// copyDebugDesc
226 static pthread_once_t initialized
= PTHREAD_ONCE_INIT
;
230 __DeviceOnHoldInitialize(void)
232 __kDeviceOnHoldTypeID
= _CFRuntimeRegisterClass(&__DeviceOnHoldClass
);
238 __DeviceOnHoldCreatePrivate(CFAllocatorRef allocator
)
240 DeviceOnHoldPrivateRef devicePrivate
;
243 /* initialize runtime */
244 pthread_once(&initialized
, __DeviceOnHoldInitialize
);
246 /* allocate session */
247 size
= sizeof(DeviceOnHoldPrivate
) - sizeof(CFRuntimeBase
);
248 devicePrivate
= (DeviceOnHoldPrivateRef
)_CFRuntimeCreateInstance(allocator
,
249 __kDeviceOnHoldTypeID
,
252 if (!devicePrivate
) {
256 devicePrivate
->name
= NULL
;
257 devicePrivate
->sock
= -1;
259 return (DeviceOnHoldRef
)devicePrivate
;
264 * TBD: We determine whether a device supports on hold capability by looking at
265 * the numeric property DeviceSupportsHold (1 - yes, 0 or no property - no). For
266 * the Apple Dash II internal modem we also use the property V92Modem to track
267 * this same capability.
271 IsDeviceOnHoldSupported(CFStringRef deviceName
, // "modem"
272 CFDictionaryRef options
)
274 CFMutableDictionaryRef deviceToMatch
;
275 u_int32_t deviceSupportsHoldValue
;
277 mach_port_t masterPort
;
278 io_iterator_t matchingServices
;
280 CFMutableDictionaryRef properties
;
281 Boolean result
= FALSE
;
282 io_service_t service
;
284 if (CFStringCompare(deviceName
, CFSTR("modem"), NULL
) == kCFCompareEqualTo
) {
285 kr
= IOMasterPort(MACH_PORT_NULL
, &masterPort
);
286 if (kr
!= KERN_SUCCESS
) {
290 deviceToMatch
= IOServiceMatching("InternalModemSupport");
291 if (!deviceToMatch
) {
295 kr
= IOServiceGetMatchingServices(masterPort
, deviceToMatch
, &matchingServices
);
296 if (kr
!= KERN_SUCCESS
) {
300 for ( ; service
= IOIteratorNext(matchingServices
) ; IOObjectRelease(service
)) {
303 kr
= IORegistryEntryGetPath(service
, kIOServicePlane
, path
);
304 assert( kr
== KERN_SUCCESS
);
306 // grab a copy of the properties
307 kr
= IORegistryEntryCreateCFProperties(service
, &properties
, kCFAllocatorDefault
, kNilOptions
);
308 assert( kr
== KERN_SUCCESS
);
310 num
= CFDictionaryGetValue(properties
, CFSTR(kIODeviceSupportsHoldKey
));
311 if (isA_CFNumber(num
)) {
312 CFNumberGetValue(num
, kCFNumberSInt32Type
, &deviceSupportsHoldValue
);
313 if (deviceSupportsHoldValue
== 1) {
318 CFRelease(properties
);
321 IOObjectRelease(matchingServices
);
324 // Note: The issue for the general case is how to go from the SystemConfiguration
325 // dynamic store to the actual driver. The devicesupportshold property is not
326 // copied the either of the setup/state descriptions so the caller would need
327 // to know the exact driver they are searching for.
338 DeviceOnHoldCreate(CFAllocatorRef allocator
,
339 CFStringRef deviceName
, // "modem"
340 CFDictionaryRef options
)
342 DeviceOnHoldRef device
= NULL
;
343 DeviceOnHoldPrivateRef devicePrivate
;
346 if (CFStringCompare(deviceName
, CFSTR("modem"), NULL
) != kCFCompareEqualTo
) {
350 device
= __DeviceOnHoldCreatePrivate(allocator
);
355 devicePrivate
= (DeviceOnHoldPrivateRef
)device
;
357 status
= MOHInit(&devicePrivate
->sock
, deviceName
);
363 devicePrivate
->name
= CFRetain(deviceName
);
371 DeviceOnHoldGetStatus(DeviceOnHoldRef device
)
373 DeviceOnHoldPrivateRef devicePrivate
= (DeviceOnHoldPrivateRef
)device
;
384 if (devicePrivate
->sock
== -1) {
388 err
= MOHExec(devicePrivate
->sock
,
390 MOH_SESSION_GET_STATUS
,
400 if (replyBufLen
== sizeof(result
)) {
401 result
= *(int32_t *)replyBuf
;
404 if (replyBuf
) CFAllocatorDeallocate(NULL
, replyBuf
);
410 DeviceOnHoldSuspend(DeviceOnHoldRef device
)
412 DeviceOnHoldPrivateRef devicePrivate
= (DeviceOnHoldPrivateRef
)device
;
417 Boolean result
= FALSE
;
423 if (devicePrivate
->sock
== -1) {
427 err
= MOHExec(devicePrivate
->sock
,
429 MOH_PUT_SESSION_ON_HOLD
,
439 if (replyBufLen
== sizeof(result
)) {
440 result
= (*(int32_t *)replyBuf
) ? TRUE
: FALSE
;
443 if (replyBuf
) CFAllocatorDeallocate(NULL
, replyBuf
);
449 DeviceOnHoldResume(DeviceOnHoldRef device
)
451 DeviceOnHoldPrivateRef devicePrivate
= (DeviceOnHoldPrivateRef
)device
;
456 Boolean result
= FALSE
;
462 if (devicePrivate
->sock
== -1) {
466 err
= MOHExec(devicePrivate
->sock
,
468 MOH_RESUME_SESSION_ON_HOLD
,NULL
,
477 if (replyBufLen
== sizeof(result
)) {
478 result
= (*(int32_t *)replyBuf
) ? TRUE
: FALSE
;
481 if (replyBuf
) CFAllocatorDeallocate(NULL
, replyBuf
);