1/* 2 * Copyright (c) 2002-2005 Apple Computer, Inc. All rights reserved. 3 * 4 * @APPLE_LICENSE_HEADER_START@ 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/* 25 * Modification History 26 * 27 * May 29, 2002 Roger Smith <rsmith@apple.com> 28 * - initial revision 29 */ 30 31#include <sys/types.h> 32#include <mach/mach.h> 33#include <pthread.h> 34 35#include <CoreFoundation/CoreFoundation.h> 36#include <CoreFoundation/CFRuntime.h> 37 38#include <SystemConfiguration/SystemConfiguration.h> 39#include <SystemConfiguration/SCValidation.h> 40#include <SystemConfiguration/SCPrivate.h> 41 42#include <IOKit/IOKitLib.h> 43#include "dy_framework.h" 44 45#include "moh_msg.h" 46#include "moh.h" 47#include "DeviceOnHold.h" 48 49 50#define kIODeviceSupportsHoldKey "V92Modem" 51 52 53typedef struct { 54 55 /* base CFType information */ 56 CFRuntimeBase cfBase; 57 58 /* device name (e.g. "modem") */ 59 CFStringRef name; 60 61 int sock; 62 63} DeviceOnHoldPrivate, *DeviceOnHoldPrivateRef; 64 65 66static CFStringRef 67__DeviceOnHoldCopyDescription(CFTypeRef cf) 68{ 69 CFAllocatorRef allocator = CFGetAllocator(cf); 70 CFMutableStringRef result; 71 72 result = CFStringCreateMutable(allocator, 0); 73 CFStringAppendFormat(result, NULL, CFSTR("<DeviceOnHold %p [%p]> {\n"), cf, allocator); 74 CFStringAppendFormat(result, NULL, CFSTR("}")); 75 76 return result; 77} 78 79 80static void 81__DeviceOnHoldDeallocate(CFTypeRef cf) 82{ 83 DeviceOnHoldPrivateRef DeviceOnHoldPrivate = (DeviceOnHoldPrivateRef)cf; 84 85 /* release resources */ 86 if (DeviceOnHoldPrivate->name) CFRelease(DeviceOnHoldPrivate->name); 87 if (DeviceOnHoldPrivate->sock != -1) { 88 89 } 90 91 return; 92} 93 94 95static CFTypeID __kDeviceOnHoldTypeID = _kCFRuntimeNotATypeID; 96 97 98static const CFRuntimeClass __DeviceOnHoldClass = { 99 0, // version 100 "DeviceOnHold", // className 101 NULL, // init 102 NULL, // copy 103 __DeviceOnHoldDeallocate, // dealloc 104 NULL, // equal 105 NULL, // hash 106 NULL, // copyFormattingDesc 107 __DeviceOnHoldCopyDescription // copyDebugDesc 108}; 109 110 111static pthread_once_t initialized = PTHREAD_ONCE_INIT; 112 113static void 114__DeviceOnHoldInitialize(void) 115{ 116 __kDeviceOnHoldTypeID = _CFRuntimeRegisterClass(&__DeviceOnHoldClass); 117 return; 118} 119 120 121static DeviceOnHoldPrivateRef 122__DeviceOnHoldCreatePrivate(CFAllocatorRef allocator) 123{ 124 DeviceOnHoldPrivateRef devicePrivate; 125 uint32_t size; 126 127 /* initialize runtime */ 128 pthread_once(&initialized, __DeviceOnHoldInitialize); 129 130 /* allocate session */ 131 size = sizeof(DeviceOnHoldPrivate) - sizeof(CFRuntimeBase); 132 devicePrivate = (DeviceOnHoldPrivateRef)_CFRuntimeCreateInstance(allocator, 133 __kDeviceOnHoldTypeID, 134 size, 135 NULL); 136 if (!devicePrivate) { 137 return NULL; 138 } 139 140 devicePrivate->name = NULL; 141 devicePrivate->sock = -1; 142 143 return devicePrivate; 144} 145 146 147CFTypeID 148DeviceOnHoldGetTypeID(void) { 149 pthread_once(&initialized, __DeviceOnHoldInitialize); /* initialize runtime */ 150 return __kDeviceOnHoldTypeID; 151} 152 153 154/* 155 * TBD: We determine whether a device supports on hold capability by looking at 156 * the numeric property DeviceSupportsHold (1 - yes, 0 or no property - no). For 157 * the Apple Dash II internal modem we also use the property V92Modem to track 158 * this same capability. 159 */ 160 161Boolean 162IsDeviceOnHoldSupported(CFStringRef deviceName, // "modem" 163 CFDictionaryRef options) 164{ 165 CFMutableDictionaryRef deviceToMatch; 166 uint32_t deviceSupportsHoldValue; 167 kern_return_t kr; 168 static mach_port_t masterPort = MACH_PORT_NULL; 169 io_iterator_t matchingServices; 170 CFNumberRef num; 171 CFMutableDictionaryRef properties; 172 Boolean result = FALSE; 173 io_service_t service; 174 175 if (CFStringCompare(deviceName, CFSTR("modem"), 0) == kCFCompareEqualTo) { 176 if (masterPort == MACH_PORT_NULL) { 177 kr = IOMasterPort(MACH_PORT_NULL, &masterPort); 178 if (kr != KERN_SUCCESS) { 179 return FALSE; 180 } 181 } 182 183 deviceToMatch = IOServiceMatching("InternalModemSupport"); 184 if (deviceToMatch == NULL) { 185 return FALSE; 186 } 187 188 kr = IOServiceGetMatchingServices(masterPort, deviceToMatch, &matchingServices); 189 if (kr != KERN_SUCCESS) { 190 return FALSE; 191 } 192 193 for ( ; (service = IOIteratorNext(matchingServices)) ; IOObjectRelease(service)) { 194 io_string_t path; 195 196 kr = IORegistryEntryGetPath(service, kIOServicePlane, path); 197 assert( kr == KERN_SUCCESS ); 198 199 // grab a copy of the properties 200 kr = IORegistryEntryCreateCFProperties(service, &properties, kCFAllocatorDefault, kNilOptions); 201 assert( kr == KERN_SUCCESS ); 202 203 num = CFDictionaryGetValue(properties, CFSTR(kIODeviceSupportsHoldKey)); 204 if (isA_CFNumber(num)) { 205 CFNumberGetValue(num, kCFNumberSInt32Type, &deviceSupportsHoldValue); 206 if (deviceSupportsHoldValue == 1) { 207 result = TRUE; 208 } 209 } 210 211 CFRelease(properties); 212 } 213 214 IOObjectRelease(matchingServices); 215 } 216 217 // Note: The issue for the general case is how to go from the SystemConfiguration 218 // dynamic store to the actual driver. The devicesupportshold property is not 219 // copied the either of the setup/state descriptions so the caller would need 220 // to know the exact driver they are searching for. 221 222 return result; 223} 224 225 226DeviceOnHoldRef 227DeviceOnHoldCreate(CFAllocatorRef allocator, 228 CFStringRef deviceName, // "modem" 229 CFDictionaryRef options) 230{ 231 DeviceOnHoldPrivateRef devicePrivate; 232 int status; 233 234 if (CFStringCompare(deviceName, CFSTR("modem"), 0) != kCFCompareEqualTo) { 235 return NULL; 236 } 237 238 devicePrivate = __DeviceOnHoldCreatePrivate(allocator); 239 if (!devicePrivate) { 240 return NULL; 241 } 242 243 status = MOHInit(&devicePrivate->sock, deviceName); 244 if (status != 0) { 245 CFRelease(devicePrivate); 246 return NULL; 247 } 248 249 devicePrivate->name = CFStringCreateCopy(NULL, deviceName); 250 251 return (DeviceOnHoldRef)devicePrivate; 252} 253 254 255 256int32_t 257DeviceOnHoldGetStatus(DeviceOnHoldRef device) 258{ 259 DeviceOnHoldPrivateRef devicePrivate = (DeviceOnHoldPrivateRef)device; 260 int err; 261 uint32_t link = 1; 262 void *replyBuf; 263 size_t replyBufLen; 264 int32_t result = -1; 265 266 if (!device) { 267 return -1; 268 } 269 270 if (devicePrivate->sock == -1) { 271 return -1; 272 } 273 274 err = MOHExec(devicePrivate->sock, 275 link, 276 MOH_SESSION_GET_STATUS, 277 NULL, 278 0, 279 &replyBuf, 280 &replyBufLen); 281 282 if (err != 0) { 283 return -1; 284 } 285 286 if (replyBufLen == sizeof(result)) { 287 result = *(int32_t *)replyBuf; 288 } 289 290 if (replyBuf) CFAllocatorDeallocate(NULL, replyBuf); 291 return result; 292} 293 294 295Boolean 296DeviceOnHoldSuspend(DeviceOnHoldRef device) 297{ 298 DeviceOnHoldPrivateRef devicePrivate = (DeviceOnHoldPrivateRef)device; 299 int err; 300 uint32_t link = 1; 301 void *replyBuf; 302 size_t replyBufLen; 303 Boolean result = FALSE; 304 305 if (!device) { 306 return FALSE; 307 } 308 309 if (devicePrivate->sock == -1) { 310 return FALSE; 311 } 312 313 err = MOHExec(devicePrivate->sock, 314 link, 315 MOH_PUT_SESSION_ON_HOLD, 316 NULL, 317 0, 318 &replyBuf, 319 &replyBufLen); 320 321 if (err != 0) { 322 return -1; 323 } 324 325 if (replyBufLen == sizeof(result)) { 326 result = (*(int32_t *)replyBuf) ? TRUE : FALSE; 327 } 328 329 if (replyBuf) CFAllocatorDeallocate(NULL, replyBuf); 330 return result; 331} 332 333 334Boolean 335DeviceOnHoldResume(DeviceOnHoldRef device) 336{ 337 DeviceOnHoldPrivateRef devicePrivate = (DeviceOnHoldPrivateRef)device; 338 int err; 339 uint32_t link = 1; 340 void *replyBuf; 341 size_t replyBufLen; 342 Boolean result = FALSE; 343 344 if (!device) { 345 return FALSE; 346 } 347 348 if (devicePrivate->sock == -1) { 349 return FALSE; 350 } 351 352 err = MOHExec(devicePrivate->sock, 353 link, 354 MOH_RESUME_SESSION_ON_HOLD,NULL, 355 0, 356 &replyBuf, 357 &replyBufLen); 358 359 if (err != 0) { 360 return -1; 361 } 362 363 if (replyBufLen == sizeof(result)) { 364 result = (*(int32_t *)replyBuf) ? TRUE : FALSE; 365 } 366 367 if (replyBuf) CFAllocatorDeallocate(NULL, replyBuf); 368 return result; 369} 370