/* * Copyright (c) 1998-2003 Apple Computer, Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ * * This file contains Original Code and/or Modifications of Original Code * as defined in and that are subject to the Apple Public Source License * Version 2.0 (the 'License'). You may not use this file except in * compliance with the License. Please obtain a copy of the License at * http://www.opensource.apple.com/apsl/ and read it before using this * file. * * The Original Code and all software distributed under the License are * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. * Please see the License for the specific language governing rights and * limitations under the License. * * @APPLE_LICENSE_HEADER_END@ */ //--------------------------------------------------------------------------- // Includes //--------------------------------------------------------------------------- #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #if UPS_DEBUG #include #endif #include "IOUPSPlugIn.h" #include "IOUPSPrivate.h" #define kDefaultUPSName "Generic UPS" //--------------------------------------------------------------------------- // Globals //--------------------------------------------------------------------------- static CFRunLoopSourceRef gClientRequestRunLoopSource = NULL; static CFRunLoopRef gMainRunLoop = NULL; static CFMutableArrayRef gUPSDataArrayRef = NULL; static IONotificationPortRef gNotifyPort = NULL; static io_iterator_t gAddedIter = MACH_PORT_NULL; //--------------------------------------------------------------------------- // TypeDefs //--------------------------------------------------------------------------- typedef struct UPSData { io_object_t notification; IOUPSPlugInInterface ** upsPlugInInterface; int upsID; Boolean isPresent; CFMutableDictionaryRef upsStoreDict; SCDynamicStoreRef upsStore; CFStringRef upsStoreKey; CFRunLoopSourceRef upsEventSource; CFRunLoopTimerRef upsEventTimer; } UPSData; typedef UPSData * UPSDataRef; //--------------------------------------------------------------------------- // Methods //--------------------------------------------------------------------------- static void SignalHandler(int sigraised); static void InitUPSNotifications(); static void UPSDeviceAdded(void *refCon, io_iterator_t iterator); static void DeviceNotification(void *refCon, io_service_t service, natural_t messageType, void *messageArgument); static void UPSEventCallback(void * target, IOReturn result, void *refcon, void *sender, CFDictionaryRef event); static void ProcessUPSEvent(UPSDataRef upsDataRef, CFDictionaryRef event); static UPSDataRef GetPrivateData( CFDictionaryRef properties ); static IOReturn CreatePowerManagerUPSEntry(UPSDataRef upsDataRef, CFDictionaryRef properties, CFSetRef capabilities); static Boolean SetupMIGServer(); //--------------------------------------------------------------------------- // main // //--------------------------------------------------------------------------- int main (int argc, const char * argv[]) { openlog("upsd", LOG_PID|LOG_NDELAY, LOG_USER); signal(SIGINT, SignalHandler); SetupMIGServer(); InitUPSNotifications(); CFRunLoopRun(); return 0; } //--------------------------------------------------------------------------- // SignalHandler //--------------------------------------------------------------------------- void SignalHandler(int sigraised) { syslog(LOG_INFO, "upsd: exiting SIGINT\n"); // Clean up here IONotificationPortDestroy(gNotifyPort); if (gAddedIter) { IOObjectRelease(gAddedIter); gAddedIter = 0; } exit(0); } //--------------------------------------------------------------------------- // SetupMIGServer //--------------------------------------------------------------------------- extern void upsd_mach_port_callback( CFMachPortRef port, void *msg, CFIndex size, void *info); Boolean SetupMIGServer() { Boolean result = true; kern_return_t kern_result = KERN_SUCCESS; CFRunLoopSourceContext sourceContext; unsigned int sourcePriority = 1; CFMachPortRef upsdMachPort = NULL; // must release /*if (IOUPSMIGServerIsRunning(&bootstrap_port, NULL)) { result = false; goto finish; }*/ kern_result = task_get_bootstrap_port(mach_task_self(), &bootstrap_port); if (kern_result != KERN_SUCCESS) { result = false; goto finish; } gMainRunLoop = CFRunLoopGetCurrent(); if (!gMainRunLoop) { result = false; goto finish; } bzero(&sourceContext, sizeof(CFRunLoopSourceContext)); sourceContext.version = 0; /***** * Add the runloop sources in decreasing priority. Signals are handled * first, followed by kernel requests, and then by client requests. * It's important that each source have a distinct priority; sharing * them causes unpredictable behavior with the runloop. */ upsdMachPort = CFMachPortCreate(kCFAllocatorDefault, upsd_mach_port_callback, NULL, NULL); gClientRequestRunLoopSource = CFMachPortCreateRunLoopSource( kCFAllocatorDefault, upsdMachPort, sourcePriority++); if (!gClientRequestRunLoopSource) { result = false; goto finish; } CFRunLoopAddSource(gMainRunLoop, gClientRequestRunLoopSource, kCFRunLoopDefaultMode); kern_result = bootstrap_register(bootstrap_port, kIOUPSPlugInServerName, CFMachPortGetPort(upsdMachPort)); switch (kern_result) { case BOOTSTRAP_SUCCESS: /* service not currently registered, "a good thing" (tm) */ break; case BOOTSTRAP_NOT_PRIVILEGED: syslog(LOG_INFO, "upsd exit: BOOTSTRAP_NOT_PRIVILIGED"); exit(EX_OSERR); case BOOTSTRAP_SERVICE_ACTIVE: syslog(LOG_INFO, "upsd exit: BOOTSTRAP_SERVICE_ACTIVE"); exit(EX_OSERR); default: syslog(LOG_INFO, "upsd exit: undefined mig error"); exit(EX_OSERR); } finish: if (gClientRequestRunLoopSource) CFRelease(gClientRequestRunLoopSource); if (upsdMachPort) CFRelease(upsdMachPort); return result; } //--------------------------------------------------------------------------- // InitUPSNotifications // // This routine just creates our master port for IOKit and turns around // and calls the routine that will alert us when a UPS Device is plugged in. //--------------------------------------------------------------------------- void InitUPSNotifications() { CFMutableDictionaryRef matchingDict; CFMutableDictionaryRef propertyDict; mach_port_t masterPort; kern_return_t kr; // first create a master_port for my task // kr = IOMasterPort(bootstrap_port, &masterPort); if (kr || !masterPort) return; // Create a notification port and add its run loop event source to our run loop // This is how async notifications get set up. // gNotifyPort = IONotificationPortCreate(masterPort); CFRunLoopAddSource( CFRunLoopGetCurrent(), IONotificationPortGetRunLoopSource(gNotifyPort), kCFRunLoopDefaultMode); // Create the IOKit notifications that we need // matchingDict = IOServiceMatching(kIOServiceClass); if (!matchingDict) return; propertyDict = CFDictionaryCreateMutable(kCFAllocatorDefault, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); if (!propertyDict) { CFRelease(matchingDict); return; } // We are only interested in devices that have kIOUPSDeviceKey property set CFDictionarySetValue(propertyDict, CFSTR(kIOUPSDeviceKey), kCFBooleanTrue); CFDictionarySetValue(matchingDict, CFSTR(kIOPropertyMatchKey), propertyDict); CFRelease(propertyDict); // Now set up a notification to be called when a device is first matched by I/O Kit. // Note that this will not catch any devices that were already plugged in so we take // care of those later. kr = IOServiceAddMatchingNotification(gNotifyPort, // notifyPort kIOFirstMatchNotification, // notificationType matchingDict, // matching UPSDeviceAdded, // callback NULL, // refCon &gAddedIter // notification ); if ( kr != kIOReturnSuccess ) return; UPSDeviceAdded( NULL, gAddedIter ); } //--------------------------------------------------------------------------- // UPSDeviceAdded // // This routine is the callback for our IOServiceAddMatchingNotification. // When we get called we will look at all the devices that were added and // we will: // // Create some private data to relate to each device // // Submit an IOServiceAddInterestNotification of type kIOGeneralInterest for // this device using the refCon field to store a pointer to our private data. // When we get called with this interest notification, we can grab the refCon // and access our private data. //--------------------------------------------------------------------------- void UPSDeviceAdded(void *refCon, io_iterator_t iterator) { io_object_t upsDevice = MACH_PORT_NULL; UPSDataRef upsDataRef = NULL; CFDictionaryRef upsProperties = NULL; CFDictionaryRef upsEvent = NULL; CFSetRef upsCapabilites = NULL; CFRunLoopSourceRef upsEventSource = NULL; CFRunLoopTimerRef upsEventTimer = NULL; CFTypeRef typeRef = NULL; IOCFPlugInInterface ** plugInInterface = NULL; IOUPSPlugInInterface_v140 ** upsPlugInInterface = NULL; HRESULT result = S_FALSE; IOReturn kr; SInt32 score; while ( upsDevice = IOIteratorNext(iterator) ) { // Create the CF plugin for this device kr = IOCreatePlugInInterfaceForService(upsDevice, kIOUPSPlugInTypeID, kIOCFPlugInInterfaceID, &plugInInterface, &score); if ( kr != kIOReturnSuccess ) goto UPSDEVICEADDED_NONPLUGIN_CLEANUP; // Grab the new v140 interface result = (*plugInInterface)->QueryInterface(plugInInterface, CFUUIDGetUUIDBytes(kIOUPSPlugInInterfaceID_v140), (LPVOID)&upsPlugInInterface); if ( ( result == S_OK ) && upsPlugInInterface ) { kr = (*upsPlugInInterface)->createAsyncEventSource(upsPlugInInterface, &typeRef); if ((kr != kIOReturnSuccess) || !typeRef) goto UPSDEVICEADDED_FAIL; if ( CFGetTypeID(typeRef) == CFRunLoopTimerGetTypeID() ) { upsEventTimer = typeRef; CFRunLoopAddTimer(CFRunLoopGetCurrent(), upsEventTimer, kCFRunLoopDefaultMode); } else if ( CFGetTypeID(typeRef) == CFRunLoopSourceGetTypeID() ) { upsEventSource = typeRef; CFRunLoopAddSource(CFRunLoopGetCurrent(), upsEventSource, kCFRunLoopDefaultMode); } } // Couldn't grab the new interface. Fallback on the old. else { result = (*plugInInterface)->QueryInterface(plugInInterface, CFUUIDGetUUIDBytes(kIOUPSPlugInInterfaceID), (LPVOID)&upsPlugInInterface); } // Got the interface if ( ( result == S_OK ) && upsPlugInInterface ) { kr = (*upsPlugInInterface)->getProperties(upsPlugInInterface, &upsProperties); if (kr != kIOReturnSuccess) goto UPSDEVICEADDED_FAIL; upsDataRef = GetPrivateData(upsProperties); if ( !upsDataRef ) goto UPSDEVICEADDED_FAIL; upsDataRef->upsPlugInInterface = upsPlugInInterface; upsDataRef->upsEventSource = upsEventSource; upsDataRef->upsEventTimer = upsEventTimer; upsDataRef->isPresent = true; kr = (*upsPlugInInterface)->getCapabilities(upsPlugInInterface, &upsCapabilites); if (kr != kIOReturnSuccess) goto UPSDEVICEADDED_FAIL; kr = CreatePowerManagerUPSEntry(upsDataRef, upsProperties, upsCapabilites); if (kr != kIOReturnSuccess) goto UPSDEVICEADDED_FAIL; kr = (*upsPlugInInterface)->getEvent(upsPlugInInterface, &upsEvent); if (kr != kIOReturnSuccess) goto UPSDEVICEADDED_FAIL; ProcessUPSEvent(upsDataRef, upsEvent); (*upsPlugInInterface)->setEventCallback(upsPlugInInterface, UPSEventCallback, NULL, upsDataRef); IOServiceAddInterestNotification( gNotifyPort, // notifyPort upsDevice, // service kIOGeneralInterest, // interestType DeviceNotification, // callback upsDataRef, // refCon &(upsDataRef->notification) // notification ); goto UPSDEVICEADDED_CLEANUP; } UPSDEVICEADDED_FAIL: // Failed to allocated a UPS interface. Do some cleanup if ( upsPlugInInterface ) { (*upsPlugInInterface)->Release(upsPlugInInterface); upsPlugInInterface = NULL; } if ( upsEventSource ) { CFRunLoopRemoveSource(CFRunLoopGetCurrent(), upsEventSource, kCFRunLoopDefaultMode); upsEventSource = NULL; } if ( upsEventTimer ) { CFRunLoopRemoveTimer(CFRunLoopGetCurrent(), upsEventTimer, kCFRunLoopDefaultMode); upsEventSource = NULL; } UPSDEVICEADDED_CLEANUP: // Clean up (*plugInInterface)->Release(plugInInterface); UPSDEVICEADDED_NONPLUGIN_CLEANUP: IOObjectRelease(upsDevice); } } //--------------------------------------------------------------------------- // DeviceNotification // // This routine will get called whenever any kIOGeneralInterest notification // happens. //--------------------------------------------------------------------------- void DeviceNotification(void * refCon, io_service_t service, natural_t messageType, void * messageArgument ) { kern_return_t kr; UPSDataRef upsDataRef = (UPSDataRef) refCon; if ( (upsDataRef != NULL) && (messageType == kIOMessageServiceIsTerminated) ) { upsDataRef->isPresent = FALSE; SCDynamicStoreRemoveValue(upsDataRef->upsStore, upsDataRef->upsStoreKey); if ( upsDataRef->upsEventSource ) { CFRunLoopRemoveSource(CFRunLoopGetCurrent(), upsDataRef->upsEventSource, kCFRunLoopDefaultMode); CFRelease(upsDataRef->upsEventSource); upsDataRef->upsEventSource = NULL; } if ( upsDataRef->upsEventTimer ) { CFRunLoopRemoveTimer(CFRunLoopGetCurrent(), upsDataRef->upsEventTimer, kCFRunLoopDefaultMode); CFRelease(upsDataRef->upsEventTimer); upsDataRef->upsEventTimer = NULL; } if (upsDataRef->upsPlugInInterface != NULL) { kr = (*(upsDataRef->upsPlugInInterface))->Release (upsDataRef->upsPlugInInterface); upsDataRef->upsPlugInInterface = NULL; } if (upsDataRef->notification != MACH_PORT_NULL) { kr = IOObjectRelease(upsDataRef->notification); upsDataRef->notification = MACH_PORT_NULL; } if (upsDataRef->upsStoreKey) { CFRelease(upsDataRef->upsStoreKey); upsDataRef->upsStoreKey = NULL; } if (upsDataRef->upsStoreDict) { CFRelease(upsDataRef->upsStoreDict); upsDataRef->upsStoreDict = NULL; } if (upsDataRef->upsStore) { CFRelease(upsDataRef->upsStore); upsDataRef->upsStore = NULL; } } } //--------------------------------------------------------------------------- // UPSEventCallback // // This routine will get called whenever any data is available from the UPS //--------------------------------------------------------------------------- void UPSEventCallback( void * target, IOReturn result, void * refcon, void * sender, CFDictionaryRef event) { ProcessUPSEvent((UPSDataRef) refcon, event); } //--------------------------------------------------------------------------- // ProcessUPSEvent // //--------------------------------------------------------------------------- void ProcessUPSEvent(UPSDataRef upsDataRef, CFDictionaryRef event) { UInt32 count, index; if ( !upsDataRef || !event) return; if ( count = CFDictionaryGetCount(event) ) { CFTypeRef * keys = (CFTypeRef *) malloc(sizeof(CFTypeRef) * count); CFTypeRef * values = (CFTypeRef *) malloc(sizeof(CFTypeRef) * count); CFDictionaryGetKeysAndValues(event, (const void **)keys, (const void **)values); for (index = 0; index < count; index++) CFDictionarySetValue(upsDataRef->upsStoreDict, keys[index], values[index]); free (keys); free (values); SCDynamicStoreSetValue(upsDataRef->upsStore, upsDataRef->upsStoreKey, upsDataRef->upsStoreDict); } } //--------------------------------------------------------------------------- // GetPrivateData // // Now that UPS entries remain in the System Configuration store, we also // preserve the UPSDeviceData struct that is associated with it. Before // getting a null entry from the gUPSDataRef that means we will have to // create a new UPSDeviceData struct, we check the existing ones to see if // there is a matching one that we can just reactivate. If we can't find an // existing UPSDeviceData struct, we will create the storage that is // necessary to keep track of the UPS. We also update the global array of // UPSDeviceData and fill in that data ref with the values that we want to // track from the UPS //--------------------------------------------------------------------------- UPSDataRef GetPrivateData( CFDictionaryRef properties ) { UPSDataRef upsDataRef = NULL; CFMutableDataRef data = NULL; UInt32 i = 0; UInt32 count = 0; // Allocated the global array if necessary if (!gUPSDataArrayRef && !(gUPSDataArrayRef = CFArrayCreateMutable(kCFAllocatorDefault, 0, &kCFTypeArrayCallBacks))) { return NULL; } // Get the device and vendor ID for this UPS so that we can see if we already have // an entry for it in our global data // // Find an empty location in our array count = CFArrayGetCount(gUPSDataArrayRef); for ( i = 0; i < count; i++) { data = (CFMutableDataRef)CFArrayGetValueAtIndex(gUPSDataArrayRef, i); if ( !data ) continue; upsDataRef =(UPSDataRef)CFDataGetMutableBytePtr(data); if (upsDataRef && !(upsDataRef->isPresent)) break; upsDataRef = NULL; } // No valid upsDataRef was found, so let's go ahead and allocate one if ( (upsDataRef == NULL) && (data = CFDataCreateMutable(kCFAllocatorDefault, sizeof(UPSData))) ) { upsDataRef =(UPSDataRef)CFDataGetMutableBytePtr(data); bzero( upsDataRef, sizeof(UPSData) ); CFArrayAppendValue(gUPSDataArrayRef, data); CFRelease(data); } // If we have a pointer to our global, then fill in some of the field in that structure // if ( upsDataRef != NULL ) { upsDataRef->upsID = i; } return upsDataRef; } //--------------------------------------------------------------------------- // CreatePowerManagerUPSEntry // //--------------------------------------------------------------------------- IOReturn CreatePowerManagerUPSEntry(UPSDataRef upsDataRef, CFDictionaryRef properties, CFSetRef capabilities) { CFMutableDictionaryRef upsStoreDict = NULL; CFStringRef upsName = NULL; CFStringRef transport = NULL; CFStringRef upsStoreKey = NULL; CFNumberRef number = NULL; SCDynamicStoreRef upsStore = NULL; IOReturn status = kIOReturnSuccess; int elementValue = 0; char upsLabelString[255]; if ( !upsDataRef || !properties || !capabilities) return kIOReturnError; upsStoreDict = CFDictionaryCreateMutable(kCFAllocatorDefault, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); // Set some Store values if ( upsStoreDict ) { // We need to save a name for this device. First, try to see if we have a USB Product Name. If // that fails then use the manufacturer and if that fails, then use a generic name. Couldn't we use // a serial # here? // upsName = (CFStringRef) CFDictionaryGetValue( properties, CFSTR( kIOPSNameKey ) ); if ( !upsName ) upsName = CFSTR(kDefaultUPSName); transport = (CFStringRef) CFDictionaryGetValue( properties, CFSTR( kIOPSTransportTypeKey ) ); CFDictionarySetValue(upsStoreDict, CFSTR(kIOPSNameKey), upsName); CFDictionarySetValue(upsStoreDict, CFSTR(kIOPSTransportTypeKey), transport); CFDictionarySetValue(upsStoreDict, CFSTR(kIOPSIsPresentKey), kCFBooleanTrue); CFDictionarySetValue(upsStoreDict, CFSTR(kIOPSIsChargingKey), kCFBooleanTrue); CFDictionarySetValue(upsStoreDict, CFSTR(kIOPSPowerSourceStateKey), CFSTR(kIOPSACPowerValue)); number = CFNumberCreate(kCFAllocatorDefault, kCFNumberIntType, &upsDataRef->upsID); CFDictionarySetValue(upsStoreDict, CFSTR(kIOPSPowerSourceIDKey), number); CFRelease(number); elementValue = 100; number = CFNumberCreate(kCFAllocatorDefault, kCFNumberIntType, &elementValue); CFDictionarySetValue(upsStoreDict, CFSTR(kIOPSMaxCapacityKey), number); CFRelease(number); if (CFSetContainsValue(capabilities, CFSTR(kIOPSCurrentCapacityKey))) { // Initialize kIOPSCurrentCapacityKey // // For Power Manager, we will be sharing capacity with Power Book battery capacities, so // we want a consistent measure. For now we have settled on percentage of full capacity. // elementValue = 100; number = CFNumberCreate(kCFAllocatorDefault, kCFNumberIntType, &elementValue); CFDictionarySetValue(upsStoreDict, CFSTR(kIOPSCurrentCapacityKey), number); CFRelease(number); } if (CFSetContainsValue(capabilities, CFSTR(kIOPSTimeToEmptyKey))) { // Initialize kIOPSTimeToEmptyKey (OS 9 PowerClass.c assumed 100 milliwatt-hours) // elementValue = 100; number = CFNumberCreate(kCFAllocatorDefault, kCFNumberIntType, &elementValue); CFDictionarySetValue(upsStoreDict, CFSTR(kIOPSTimeToEmptyKey), number); CFRelease(number); } if (CFSetContainsValue(capabilities, CFSTR(kIOPSVoltageKey))) { // Initialize kIOPSVoltageKey (OS 9 PowerClass.c assumed millivolts. // (Shouldn't that be 130,000 millivolts for AC?)) // Actually, Power Devices Usage Tables say units will be in Volts. // However we have to check what exponent is used because that may // make the value we get in centiVolts (exp = -2). So it looks like // OS 9 sources said millivolts, but used centivolts. Our final // answer should device by proper exponent to get back to Volts. // elementValue = 13 * 1000 / 100; number = CFNumberCreate(kCFAllocatorDefault, kCFNumberIntType, &elementValue); CFDictionarySetValue(upsStoreDict, CFSTR(kIOPSVoltageKey), number); CFRelease(number); } if (CFSetContainsValue(capabilities, CFSTR(kIOPSCurrentKey))) { // Initialize kIOPSCurrentKey (What would be a good amperage to // initialize to?) Same discussion as for Volts, where the unit // for current is Amps. But with typical exponents (-2), we get // centiAmps. Hmm... typical current for USB may be 500 milliAmps, // which would be .5 A. Since that is not an integer, that may be // why our displays get larger numbers // elementValue = 1; // Just a guess! number = CFNumberCreate(kCFAllocatorDefault, kCFNumberIntType, &elementValue); CFDictionarySetValue(upsStoreDict, CFSTR(kIOPSCurrentKey), number); CFRelease(number); } } upsStore = SCDynamicStoreCreate(kCFAllocatorDefault, CFSTR("UPS Power Manager"), NULL, NULL); // Uniquely name each Sys Config key // sprintf(upsLabelString,"/UPS%d", upsDataRef->upsID); #if 0 SCLog(TRUE, LOG_NOTICE, CFSTR("What does CreatePowerManagerUPSEntry think our key name is?")); SCLog(TRUE, LOG_NOTICE, CFSTR(" %@%@%@"), kSCDynamicStoreDomainState, CFSTR(kIOPSDynamicStorePath), CFStringCreateWithCStringNoCopy(NULL, upsLabelString, kCFStringEncodingMacRoman, kCFAllocatorNull)); #endif upsStoreKey = SCDynamicStoreKeyCreate(kCFAllocatorDefault, CFSTR("%@%@%@"), kSCDynamicStoreDomainState, CFSTR(kIOPSDynamicStorePath), CFStringCreateWithCStringNoCopy(NULL, upsLabelString, kCFStringEncodingMacRoman, kCFAllocatorNull)); if(!SCDynamicStoreSetValue(upsStore, upsStoreKey, upsStoreDict)) { status = SCError(); #if UPS_DEBUG SCLog(TRUE, LOG_NOTICE, CFSTR("UPSSupport: Encountered SCDynamicStoreSetValue error 0x%x"), status); #endif } // Store our SystemConfiguration variables in our private data // upsDataRef->upsStoreDict = upsStoreDict; upsDataRef->upsStore = upsStore; upsDataRef->upsStoreKey = upsStoreKey; return status; } //=========================================================================== // MIG Routines //=========================================================================== //--------------------------------------------------------------------------- // _io_ups_send_command // // This routine allow remote processes to issue commands to the UPS. It is // expected that command will come in as a serialized CFDictionaryRef. //--------------------------------------------------------------------------- kern_return_t _io_ups_send_command( mach_port_t server, int upsID, void * commandBuffer, IOByteCount commandSize) { CFDictionaryRef command; CFMutableDataRef data; UPSDataRef upsDataRef; IOReturn res = kIOReturnError; command = (CFDictionaryRef)IOCFUnserialize(commandBuffer, kCFAllocatorDefault, kNilOptions, NULL); if (command) { if (!gUPSDataArrayRef || (upsID >= CFArrayGetCount(gUPSDataArrayRef))) { res = kIOReturnBadArgument; } else { data = (CFMutableDataRef)CFArrayGetValueAtIndex(gUPSDataArrayRef, upsID); upsDataRef =(UPSDataRef)CFDataGetMutableBytePtr(data); if (upsDataRef && upsDataRef->upsPlugInInterface) res = (*upsDataRef->upsPlugInInterface)->sendCommand(upsDataRef->upsPlugInInterface, command); } } return res; } //--------------------------------------------------------------------------- // _io_ups_get_event // // This routine allow remote processes to issue commands to the UPS. It will // return a CFDictionaryRef that is serialized. //--------------------------------------------------------------------------- kern_return_t _io_ups_get_event( mach_port_t server, int upsID, void ** eventBufferPtr, IOByteCount * eventBufferSizePtr) { CFDictionaryRef event; CFMutableDataRef data; CFDataRef serializedData; UPSDataRef upsDataRef; IOReturn res = kIOReturnError; if (!eventBufferPtr || !eventBufferSizePtr || !gUPSDataArrayRef || (upsID >= CFArrayGetCount(gUPSDataArrayRef))) { return kIOReturnBadArgument; } data = (CFMutableDataRef)CFArrayGetValueAtIndex(gUPSDataArrayRef, upsID); upsDataRef = (UPSDataRef)CFDataGetMutableBytePtr(data); if (!upsDataRef || !upsDataRef->upsPlugInInterface) return kIOReturnBadArgument; res = (*upsDataRef->upsPlugInInterface)->getEvent(upsDataRef->upsPlugInInterface, &event); if ((res != kIOReturnSuccess) || !event) return kIOReturnError; serializedData = (CFDataRef)IOCFSerialize( event, kNilOptions ); if (!serializedData) return kIOReturnError; *eventBufferSizePtr = CFDataGetLength(serializedData); vm_allocate(mach_task_self(), eventBufferPtr, *eventBufferSizePtr, TRUE); if( *eventBufferPtr ) memcpy(*eventBufferPtr, CFDataGetBytePtr(serializedData), *eventBufferSizePtr); CFRelease( serializedData ); return res; } //--------------------------------------------------------------------------- // _io_ups_get_capabilities // // This routine allow remote processes to issue commands to the UPS. It will // return a CFSetRef that is serialized. //--------------------------------------------------------------------------- kern_return_t _io_ups_get_capabilities( mach_port_t server, int upsID, void ** capabilitiesBufferPtr, IOByteCount * capabilitiesBufferSizePtr) { CFSetRef capabilities; CFMutableDataRef data; CFDataRef serializedData; UPSDataRef upsDataRef; IOReturn res = kIOReturnError; if (!capabilitiesBufferPtr || !capabilitiesBufferSizePtr || !gUPSDataArrayRef || (upsID >= CFArrayGetCount(gUPSDataArrayRef))) { return kIOReturnBadArgument; } data = (CFMutableDataRef)CFArrayGetValueAtIndex(gUPSDataArrayRef, upsID); upsDataRef = (UPSDataRef)CFDataGetMutableBytePtr(data); if (!upsDataRef || !upsDataRef->upsPlugInInterface) return kIOReturnBadArgument; res = (*upsDataRef->upsPlugInInterface)->getCapabilities( upsDataRef->upsPlugInInterface, &capabilities); if ((res != kIOReturnSuccess) || !capabilities) return kIOReturnError; serializedData = (CFDataRef)IOCFSerialize( capabilities, kNilOptions ); if (!serializedData) return kIOReturnError; *capabilitiesBufferSizePtr = CFDataGetLength(serializedData); vm_allocate(mach_task_self(), capabilitiesBufferPtr, *capabilitiesBufferSizePtr, TRUE); if( *capabilitiesBufferPtr ) memcpy(*capabilitiesBufferPtr, CFDataGetBytePtr(serializedData), *capabilitiesBufferSizePtr); CFRelease( serializedData ); return res; }