1/*
2 * Copyright (c) 2008 Apple 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/*
24cc ionotifyCB.c -o /tmp/ion -Wall -Wno-four-char-constants -framework IOKit -undefined warning
25*/
26
27#include <ctype.h>
28#include <stdlib.h>
29#include <string.h>
30#include <assert.h>
31#include <limits.h>
32
33#include <mach/mach_interface.h>
34#include <IOKit/IOKitLib.h>
35#include <CoreFoundation/CFRunLoop.h>
36
37mach_port_t		masterPort;
38mach_port_t		notifyPort;
39CFRunLoopSourceRef	cfSource;
40
41void ServiceInterestCallback(void * refcon, io_service_t service,
42                            natural_t messageType, void * messageArgument )
43{
44    io_name_t	name;
45
46    assert( refcon == (void *) masterPort );
47
48    if( KERN_SUCCESS == IORegistryEntryGetName( service, name ))
49        printf(name);
50    else
51        printf("???");
52    printf(": messageType %08lx, arg %08lx\n",
53                   messageType, messageArgument);
54}
55
56void ServiceArrivalCallback( void * refcon, io_iterator_t iter )
57{
58    kern_return_t	kr;
59    io_object_t		obj;
60    io_name_t		name;
61    io_string_t		path;
62    mach_port_t		note;
63    CFDictionaryRef	dict;
64
65    IONotificationPortRef notify = (IONotificationPortRef) refcon;
66
67    while( (obj = IOIteratorNext( iter))) {
68        assert( KERN_SUCCESS == (
69        kr = IORegistryEntryGetName( obj, name )
70        ));
71	printf("name:%s(%d)\n", name, obj);
72
73
74	dict = IOCreateDisplayInfoDictionary( obj, kNilOptions );
75	if( dict) {
76	    CFShow( dict );
77	    CFRelease( dict );
78	}
79
80        kr = IORegistryEntryGetPath( obj, kIOServicePlane, path );
81        if( KERN_SUCCESS == kr) {
82
83	    // if the object is detached, getPath will fail
84            printf("path:%s\n", path);
85
86            // as will IOServiceAddInterestNotification
87            if( KERN_SUCCESS != (
88                    kr = IOServiceAddInterestNotification(
89                            notify,
90                            obj, kIOGeneralInterest,
91                            &ServiceInterestCallback, (void *) masterPort,
92                            &note )
93            )) printf("IOServiceAddInterestNotification(%lx)\n", kr);
94            // can compare two kernel objects with IOObjectIsEqualTo() if we keep the object,
95            // otherwise, release
96            IOObjectRelease( obj );
97        }
98    }
99}
100
101void notifyTest( char * arg )
102{
103    kern_return_t	kr;
104    io_iterator_t	note1, note2;
105    io_service_t	obj;
106    const char *	type;
107    IONotificationPortRef notify;
108
109    assert( 0 != (
110    notify = IONotificationPortCreate( masterPort )
111    ));
112
113    type = kIOMatchedNotification;// or kIOPublishNotification;
114    assert( KERN_SUCCESS == (
115    kr = IOServiceAddMatchingNotification(
116                        notify,
117                        type,
118                        IOServiceMatching( arg ),
119//                      IOBSDNameMatching( masterPort, 0, arg ),
120                        &ServiceArrivalCallback, (void *) notify,
121                        &note1 )
122    ));
123    printf("IOServiceAddMatchingNotification: %s: ", type );
124    // dumping the iterator gives us the current list
125    // and arms the notification for changes
126    ServiceArrivalCallback ( (void *) notify, note1 );
127    printf("\n");
128
129    type = kIOBusyInterest;
130    obj = IORegistryEntryFromPath( masterPort, kIOServicePlane ":/");
131    assert( obj );
132    assert( KERN_SUCCESS == (
133    kr = IOServiceAddInterestNotification(
134            notify,
135            obj, type,
136            &ServiceInterestCallback, (void *) masterPort,
137            &note2 )
138    ));
139
140    CFRunLoopAddSource(CFRunLoopGetCurrent(),
141                       IONotificationPortGetRunLoopSource(notify),
142                       kCFRunLoopDefaultMode);
143    printf("waiting...\n");
144    CFRunLoopRun();	// Start silly state machine
145
146    IOObjectRelease( note1 );
147    IOObjectRelease( note2 );
148}
149
150int
151main(int argc, char **argv)
152{
153	kern_return_t		kr;
154
155	/*
156	 * Get master device port
157	 */
158	assert( KERN_SUCCESS == (
159	kr = IOMasterPort(   bootstrap_port,
160			     &masterPort)
161	));
162
163	if( argc > 1)
164            notifyTest( argv[1] );
165	else
166	    printf("%s className\n", argv[0]);
167
168	printf("Exit\n");
169}
170
171