move IOKIT power event code to bt_control_iphone.m

This commit is contained in:
matthias.ringwald 2011-01-08 22:45:27 +00:00
parent 0df774e2ac
commit 8ebcfd8dd8
3 changed files with 175 additions and 143 deletions

View File

@ -28,9 +28,10 @@ NEXT:
- DONE: Bluetooth is on iff at least one client did request it. delay off by 10 seconds
- DONE: add enum POWER_EVENTS {POWER_WILL_SLEEP, POWER_WILL_WAKE_UP);
- DONE: add register_for_power_management_notifictations( void (*callback)(POWER_EVENTS event)); to bt_control.h
- move core foundation power event code to bt_control_iphone.m
- add sleep() to bt_control.h (assumption: no off -> sleep transition)
- DONE: move core foundation power event code to bt_control_iphone.m
- DONE: add sleep() to bt_control.h (assumption: no off -> sleep transition)
- call control->sleep() instead of control->off()
- clean up components
- consolidate ios code in port_ios.m (bt_control_iphone.m, platform_iphone.m)
- consolidate cocoa/corefoundation code in port_corefoundation.c (remote_device_db)

View File

@ -72,15 +72,57 @@
#define IOKIT
#include <device/device_types.h>
#include <UIKit/UIKit.h>
// costants
#define sys_iokit err_system(0x38)
#define sub_iokit_common err_sub(0)
#define iokit_common_msg(message) (UInt32)(sys_iokit|sub_iokit_common|message)
#define kIOMessageCanDevicePowerOff iokit_common_msg(0x200)
#define kIOMessageDeviceWillPowerOff iokit_common_msg(0x210)
#define kIOMessageDeviceWillNotPowerOff iokit_common_msg(0x220)
#define kIOMessageDeviceHasPoweredOn iokit_common_msg(0x230)
#define kIOMessageCanSystemPowerOff iokit_common_msg(0x240)
#define kIOMessageSystemWillPowerOff iokit_common_msg(0x250)
#define kIOMessageSystemWillNotPowerOff iokit_common_msg(0x260)
#define kIOMessageCanSystemSleep iokit_common_msg(0x270)
#define kIOMessageSystemWillSleep iokit_common_msg(0x280)
#define kIOMessageSystemWillNotSleep iokit_common_msg(0x290)
#define kIOMessageSystemHasPoweredOn iokit_common_msg(0x300)
#define kIOMessageSystemWillRestart iokit_common_msg(0x310)
#define kIOMessageSystemWillPowerOn iokit_common_msg(0x320)
// types
typedef io_object_t io_connect_t;
typedef io_object_t io_service_t;
typedef kern_return_t IOReturn;
typedef struct IONotificationPort * IONotificationPortRef;
// prototypes
kern_return_t IOMasterPort( mach_port_t bootstrapPort, mach_port_t * masterPort );
CFMutableDictionaryRef IOServiceNameMatching(const char * name );
CFTypeRef IORegistryEntrySearchCFProperty(mach_port_t entry, const io_name_t plane,
CFStringRef key, CFAllocatorRef allocator, UInt32 options );
mach_port_t IOServiceGetMatchingService(mach_port_t masterPort, CFDictionaryRef matching );
kern_return_t IOObjectRelease(mach_port_t object);
typedef void (*IOServiceInterestCallback)(void * refcon, io_service_t service, uint32_t messageType, void * messageArgument);
io_connect_t IORegisterForSystemPower (void * refcon, IONotificationPortRef * thePortRef,
IOServiceInterestCallback callback, io_object_t * notifier );
IOReturn IODeregisterForSystemPower (io_object_t *notifier);
CFRunLoopSourceRef IONotificationPortGetRunLoopSource(IONotificationPortRef notify );
IOReturn IOAllowPowerChange ( io_connect_t kernelPort, long notificationID );
IOReturn IOCancelPowerChange ( io_connect_t kernelPort, long notificationID );
// local globals
static io_object_t notifier;
static io_connect_t root_port = 0; // a reference to the Root Power Domain IOService
#endif
#endif
int iphone_system_bt_enabled(){
return SBA_getBluetoothEnabled();
}
@ -93,6 +135,8 @@ void iphone_system_bt_set_enabled(int enabled)
#endif
static void (*power_notification_callback)(POWER_NOTIFICATION_t event) = NULL;
#define BUFF_LEN 80
static char buffer[BUFF_LEN+1];
@ -504,6 +548,103 @@ static int iphone_sleep(void *config){
return iphone_off(config);
}
#ifdef IOKIT
static void MySleepCallBack( void * refCon, io_service_t service, natural_t messageType, void * messageArgument ) {
printf( "messageType %08lx, arg %08lx\n", (long unsigned int)messageType, (long unsigned int)messageArgument);
switch ( messageType ) {
case kIOMessageCanSystemSleep:
/* Idle sleep is about to kick in. This message will not be sent for forced sleep.
Applications have a chance to prevent sleep by calling IOCancelPowerChange.
Most applications should not prevent idle sleep.
Power Management waits up to 30 seconds for you to either allow or deny idle sleep.
If you don't acknowledge this power change by calling either IOAllowPowerChange
or IOCancelPowerChange, the system will wait 30 seconds then go to sleep.
*/
// Uncomment to cancel idle sleep
// IOCancelPowerChange( root_port, (long)messageArgument );
// we will allow idle sleep
IOAllowPowerChange( root_port, (long)messageArgument );
break;
case kIOMessageSystemWillSleep:
/* The system WILL go to sleep. If you do not call IOAllowPowerChange or
IOCancelPowerChange to acknowledge this message, sleep will be
delayed by 30 seconds.
NOTE: If you call IOCancelPowerChange to deny sleep it returns kIOReturnSuccess,
however the system WILL still go to sleep.
*/
if (power_notification_callback){
(*power_notification_callback)(POWER_WILL_SLEEP);
}
// don't allow power change to get the 30 second delay
// IOAllowPowerChange( root_port, (long)messageArgument );
break;
case kIOMessageSystemWillPowerOn:
// System has started the wake up process...
if (power_notification_callback){
(*power_notification_callback)(POWER_WILL_WAKE_UP);
}
break;
case kIOMessageSystemHasPoweredOn:
//System has finished waking up...
break;
default:
break;
}
}
/** handle IOKIT power notifications - http://developer.apple.com/library/mac/#qa/qa2004/qa1340.html */
void iphone_register_for_power_notifications(void (*cb)(POWER_NOTIFICATION_t event)){
static IONotificationPortRef notifyPortRef = NULL; // notification port allocated by IORegisterForSystemPower
static io_object_t notifierObject = 0; // notifier object, used to deregister later
if (cb) {
if (!root_port) {
// register to receive system sleep notifications
root_port = IORegisterForSystemPower(NULL, &notifyPortRef, MySleepCallBack, &notifierObject);
if (!root_port) {
printf("IORegisterForSystemPower failed\n");
}
// add the notification port to the application runloop
CFRunLoopAddSource(CFRunLoopGetCurrent(), IONotificationPortGetRunLoopSource(notifyPortRef), kCFRunLoopCommonModes);
}
power_notification_callback = cb;
} else {
if (root_port) {
// we no longer want sleep notifications:
// remove the sleep notification port from the application runloop
CFRunLoopRemoveSource(CFRunLoopGetCurrent(), IONotificationPortGetRunLoopSource(notifyPortRef), kCFRunLoopCommonModes);
// deregister for system sleep notifications
IODeregisterForSystemPower(&notifierObject);
// IORegisterForSystemPower implicitly opens the Root Power Domain IOService
// so we close it here
IOServiceClose(root_port);
// destroy the notification port allocated by IORegisterForSystemPower
IONotificationPortDestroy(notifyPortRef);
root_port = 0;
}
power_notification_callback = NULL;
}
}
#endif
// single instance
bt_control_t bt_control_iphone = {
iphone_on,
@ -512,5 +653,9 @@ bt_control_t bt_control_iphone = {
iphone_valid,
iphone_name,
NULL, // custom init sequence
#ifdef IOKIT
iphone_register_for_power_notifications
#else
NULL // register_for_power_notifications
#endif
};

View File

@ -73,7 +73,6 @@
#define DAEMON_NO_ACTIVE_CLIENT_TIMEOUT 10000
#define HANDLE_POWER_NOTIFICATIONS
static hci_transport_t * transport;
@ -94,125 +93,6 @@ static void active_clients_add(connection_t *connection);
static void active_clients_start_power_off_timer();
static void active_clients_stop_power_off_timer();
#ifdef HANDLE_POWER_NOTIFICATIONS
#include <CoreFoundation/CoreFoundation.h>
// minimal IOKit
#include <Availability.h>
#if __IPHONE_OS_VERSION_MIN_REQUIRED >= __IPHONE_2_0
// compile issue fix with 4.2 headers
#undef NSEC_PER_USEC
#undef USEC_PER_SEC
#undef NSEC_PER_SEC
// end of fix
#include <mach/mach.h>
#define IOKIT
#include <device/device_types.h>
// costants
#define sys_iokit err_system(0x38)
#define sub_iokit_common err_sub(0)
#define iokit_common_msg(message) (UInt32)(sys_iokit|sub_iokit_common|message)
#define kIOMessageCanDevicePowerOff iokit_common_msg(0x200)
#define kIOMessageDeviceWillPowerOff iokit_common_msg(0x210)
#define kIOMessageDeviceWillNotPowerOff iokit_common_msg(0x220)
#define kIOMessageDeviceHasPoweredOn iokit_common_msg(0x230)
#define kIOMessageCanSystemPowerOff iokit_common_msg(0x240)
#define kIOMessageSystemWillPowerOff iokit_common_msg(0x250)
#define kIOMessageSystemWillNotPowerOff iokit_common_msg(0x260)
#define kIOMessageCanSystemSleep iokit_common_msg(0x270)
#define kIOMessageSystemWillSleep iokit_common_msg(0x280)
#define kIOMessageSystemWillNotSleep iokit_common_msg(0x290)
#define kIOMessageSystemHasPoweredOn iokit_common_msg(0x300)
#define kIOMessageSystemWillRestart iokit_common_msg(0x310)
#define kIOMessageSystemWillPowerOn iokit_common_msg(0x320)
// types
typedef io_object_t io_connect_t;
typedef io_object_t io_service_t;
typedef kern_return_t IOReturn;
typedef struct IONotificationPort * IONotificationPortRef;
typedef void
(*IOServiceInterestCallback)(
void * refcon,
io_service_t service,
uint32_t messageType,
void * messageArgument );
io_connect_t IORegisterForSystemPower (void * refcon,
IONotificationPortRef * thePortRef,
IOServiceInterestCallback callback,
io_object_t * notifier );
CFRunLoopSourceRef IONotificationPortGetRunLoopSource(IONotificationPortRef notify );
IOReturn IOAllowPowerChange ( io_connect_t kernelPort, long notificationID );
IOReturn IOCancelPowerChange ( io_connect_t kernelPort, long notificationID );
io_connect_t root_port;
io_object_t notifier;
io_connect_t root_port; // a reference to the Root Power Domain IOService
void MySleepCallBack( void * refCon, io_service_t service, natural_t messageType, void * messageArgument ) {
printf( "messageType %08lx, arg %08lx\n", (long unsigned int)messageType, (long unsigned int)messageArgument);
switch ( messageType ) {
case kIOMessageCanSystemSleep:
/* Idle sleep is about to kick in. This message will not be sent for forced sleep.
Applications have a chance to prevent sleep by calling IOCancelPowerChange.
Most applications should not prevent idle sleep.
Power Management waits up to 30 seconds for you to either allow or deny idle sleep.
If you don't acknowledge this power change by calling either IOAllowPowerChange
or IOCancelPowerChange, the system will wait 30 seconds then go to sleep.
*/
// Uncomment to cancel idle sleep
// IOCancelPowerChange( root_port, (long)messageArgument );
// we will allow idle sleep
IOAllowPowerChange( root_port, (long)messageArgument );
break;
case kIOMessageSystemWillSleep:
/* The system WILL go to sleep. If you do not call IOAllowPowerChange or
IOCancelPowerChange to acknowledge this message, sleep will be
delayed by 30 seconds.
NOTE: If you call IOCancelPowerChange to deny sleep it returns kIOReturnSuccess,
however the system WILL still go to sleep.
*/
// let's sleep
power_management_sleep = 1;
hci_power_control(HCI_POWER_SLEEP);
// power control only starts falling asleep, count on the 30 second delay
// IOAllowPowerChange( root_port, (long)messageArgument );
break;
case kIOMessageSystemWillPowerOn:
//System has started the wake up process...
// assume that all clients use Bluetooth -> if connection, start Bluetooth
power_management_sleep = 0;
if (!active_clients_empty()) {
hci_power_control(HCI_POWER_ON);
}
break;
case kIOMessageSystemHasPoweredOn:
//System has finished waking up...
break;
default:
break;
}
}
#endif
#endif
static void dummy_bluetooth_status_handler(BLUETOOTH_STATE state){
printf("Bluetooth status: %u\n", state);
};
@ -422,6 +302,25 @@ static void daemon_packet_handler(void * connection, uint8_t packet_type, uint16
}
}
static void power_notification_callback(POWER_NOTIFICATION_t notification){
switch (notification) {
case POWER_WILL_SLEEP:
// let's sleep
power_management_sleep = 1;
hci_power_control(HCI_POWER_SLEEP);
break;
case POWER_WILL_WAKE_UP:
// assume that all clients use Bluetooth -> if connection, start Bluetooth
power_management_sleep = 0;
if (!active_clients_empty()) {
hci_power_control(HCI_POWER_ON);
}
break;
default:
break;
}
}
static void daemon_sigint_handler(int param){
printf(" <= SIGINT received, shutting down..\n");
hci_power_control( HCI_POWER_OFF);
@ -529,11 +428,15 @@ int main (int argc, char * const * argv){
run_loop_init(RUN_LOOP_POSIX);
#endif
// init power management notifications
if (control->register_for_power_notifications){
control->register_for_power_notifications(power_notification_callback);
}
// use logger: format HCI_DUMP_PACKETLOGGER, HCI_DUMP_BLUEZ or HCI_DUMP_STDOUT
hci_dump_open("/tmp/hci_dump.pklg", HCI_DUMP_PACKETLOGGER);
hci_dump_set_max_packets(1000);
// hci_dump_open(NULL, HCI_DUMP_STDOUT);
// init HCI
hci_init(transport, &config, control, remote_device_db);
@ -559,24 +462,7 @@ int main (int argc, char * const * argv){
}
#endif
socket_connection_register_packet_callback(daemon_client_handler);
#ifdef HANDLE_POWER_NOTIFICATIONS
IONotificationPortRef notifyPortRef; // notification port allocated by IORegisterForSystemPower
io_object_t notifierObject; // notifier object, used to deregister later
void* refCon = NULL; // this parameter is passed to the callback
// register to receive system sleep notifications
root_port = IORegisterForSystemPower( refCon, &notifyPortRef, MySleepCallBack, &notifierObject );
if (!root_port)
{
printf("IORegisterForSystemPower failed\n");
return 1;
}
// add the notification port to the application runloop
CFRunLoopAddSource(CFRunLoopGetCurrent(), IONotificationPortGetRunLoopSource(notifyPortRef), kCFRunLoopCommonModes);
#endif
// go!
run_loop_execute();
return 0;