IOServiceOpen returns kIOReturnUnsupported despite driver's user client instantiation

1.7k views Asked by At

I'm trying to write a very simple user client that - just for now - writes into the kernel log from user space. If the following code worked, it would write "Hello World" to the log.

I have verified that I've got the right IOService - com_soggywizards_Foo - with the call to IOObjectGetClass in the code below.

Always IOServiceOpen returns kIOReturnUnsupported. However when it is called, my user client then shows up in IORegistryExplorer. I can also see it in ioreg.

It appears as if IOServiceOpen is instantiating the user client but returning its result before that instantion is complete.

The call to IOServiceOpen is in the "doOpen" function:

int main(int argc, const char * argv[]) {
CFMutableDictionaryRef  dict = NULL;

dict = IOServiceMatching( "com_soggywizards_Foo" );

kern_return_t result;
io_iterator_t it = NULL;

result = IOServiceGetMatchingServices( kIOMasterPortDefault,
                                                   (CFDictionaryRef)dict,
                                                   &it);

if ( result != KERN_SUCCESS ){

    fprintf( stderr, "IOServiceGetMatchingServices failed 0x%x\n", result );
    exit( 1 );
}

io_service_t service = IOIteratorNext( it );
if ( service == (io_service_t)NULL ){
    fprintf( stderr, "IOIteratorNext cant find service\n " );
    exit( 1 );
}

char name[ 256 ];

result = IOObjectGetClass( service, name );

cout << "service: " << name << endl;  // prints "service: com_soggywizards_Foo"

io_connect_t connect;

result = doOpen( service, &connect );

if ( result != KERN_SUCCESS ) return 1;

result = logMessage( "Hello World\n", connect );
if ( result != KERN_SUCCESS ) return 1;

return 0;

}

kern_return_t doOpen( io_service_t service, io_connect_t *connect )
{
kern_return_t result = IOServiceOpen( service, mach_task_self(), 0, connect );  // returns 0xe00002c7

if ( result != KERN_SUCCESS ) fprintf( stderr, "IOServiceOpen failed: 0x%x\n", result );
else{
    result = openUserClient( *connect );
    if ( result != KERN_SUCCESS ) fprintf( stderr, "openUserClient failed: 0x%x\n", result );
}

return result;

}

the kernel log shows my user client's initWithTask being called, with super::initWithTask succeeding. Also my user client's start method is called.

I am unclear as to whether the user client needs to call registerService(). However, ioreg says its registered even if I don't call it.

1

There are 1 answers

0
pmdj On

Does your driver class, or one of its superclasses other than IOService itself, override the newUserClient() method? If a superclass overrides it, and you want to add an extra user client type, you'll need to override it yourself as well. If you're already overriding it, you'll need to show us its code as that's likely where your problem lies.

(Generally, it looks like your problem is kernel side, so if in doubt post that code.)

Regarding registerService(): You need to call this if you want your IOService object to be matched, and it is ready to accept clients that found by matching - i.e. found by IOServiceGetMatchingServices() or similar functions in either user or kernel space, including an IOKit personality of a kext.