+IOReturn IOUserClient::externalMethod( uint32_t selector, IOExternalMethodArguments * args,
+ IOExternalMethodDispatch * dispatch, OSObject * target, void * reference )
+{
+ IOReturn err;
+ IOService * object;
+ IOByteCount structureOutputSize;
+
+ if (dispatch)
+ {
+ uint32_t count;
+ count = dispatch->checkScalarInputCount;
+ if ((kIOUCVariableStructureSize != count) && (count != args->scalarInputCount))
+ {
+ return (kIOReturnBadArgument);
+ }
+
+ count = dispatch->checkStructureInputSize;
+ if ((kIOUCVariableStructureSize != count)
+ && (count != ((args->structureInputDescriptor)
+ ? args->structureInputDescriptor->getLength() : args->structureInputSize)))
+ {
+ return (kIOReturnBadArgument);
+ }
+
+ count = dispatch->checkScalarOutputCount;
+ if ((kIOUCVariableStructureSize != count) && (count != args->scalarOutputCount))
+ {
+ return (kIOReturnBadArgument);
+ }
+
+ count = dispatch->checkStructureOutputSize;
+ if ((kIOUCVariableStructureSize != count)
+ && (count != ((args->structureOutputDescriptor)
+ ? args->structureOutputDescriptor->getLength() : args->structureOutputSize)))
+ {
+ return (kIOReturnBadArgument);
+ }
+
+ if (dispatch->function)
+ err = (*dispatch->function)(target, reference, args);
+ else
+ err = kIOReturnNoCompletion; /* implementator can dispatch */
+
+ return (err);
+ }
+
+
+ // pre-Leopard API's don't do ool structs
+ if (args->structureInputDescriptor || args->structureOutputDescriptor)
+ {
+ err = kIOReturnIPCError;
+ return (err);
+ }
+
+ structureOutputSize = args->structureOutputSize;
+
+ if (args->asyncWakePort)
+ {
+ IOExternalAsyncMethod * method;
+
+ if( !(method = getAsyncTargetAndMethodForIndex(&object, selector)) )
+ return (kIOReturnUnsupported);
+
+ switch (method->flags & kIOUCTypeMask)
+ {
+ case kIOUCScalarIStructI:
+ err = shim_io_async_method_scalarI_structureI( method, object,
+ args->asyncWakePort, args->asyncReference, args->asyncReferenceCount,
+ args->scalarInput, args->scalarInputCount,
+ (char *)args->structureInput, args->structureInputSize );
+ break;
+
+ case kIOUCScalarIScalarO:
+ err = shim_io_async_method_scalarI_scalarO( method, object,
+ args->asyncWakePort, args->asyncReference, args->asyncReferenceCount,
+ args->scalarInput, args->scalarInputCount,
+ args->scalarOutput, &args->scalarOutputCount );
+ break;
+
+ case kIOUCScalarIStructO:
+ err = shim_io_async_method_scalarI_structureO( method, object,
+ args->asyncWakePort, args->asyncReference, args->asyncReferenceCount,
+ args->scalarInput, args->scalarInputCount,
+ (char *) args->structureOutput, &args->structureOutputSize );
+ break;
+
+
+ case kIOUCStructIStructO:
+ err = shim_io_async_method_structureI_structureO( method, object,
+ args->asyncWakePort, args->asyncReference, args->asyncReferenceCount,
+ (char *)args->structureInput, args->structureInputSize,
+ (char *) args->structureOutput, &args->structureOutputSize );
+ break;
+
+ default:
+ err = kIOReturnBadArgument;
+ break;
+ }
+ }
+ else
+ {
+ IOExternalMethod * method;
+
+ if( !(method = getTargetAndMethodForIndex(&object, selector)) )
+ return (kIOReturnUnsupported);
+
+ switch (method->flags & kIOUCTypeMask)
+ {
+ case kIOUCScalarIStructI:
+ err = shim_io_connect_method_scalarI_structureI( method, object,
+ args->scalarInput, args->scalarInputCount,
+ (char *) args->structureInput, args->structureInputSize );
+ break;
+
+ case kIOUCScalarIScalarO:
+ err = shim_io_connect_method_scalarI_scalarO( method, object,
+ args->scalarInput, args->scalarInputCount,
+ args->scalarOutput, &args->scalarOutputCount );
+ break;
+
+ case kIOUCScalarIStructO:
+ err = shim_io_connect_method_scalarI_structureO( method, object,
+ args->scalarInput, args->scalarInputCount,
+ (char *) args->structureOutput, &structureOutputSize );
+ break;
+
+
+ case kIOUCStructIStructO:
+ err = shim_io_connect_method_structureI_structureO( method, object,
+ (char *) args->structureInput, args->structureInputSize,
+ (char *) args->structureOutput, &structureOutputSize );
+ break;
+
+ default:
+ err = kIOReturnBadArgument;
+ break;
+ }
+ }
+
+ args->structureOutputSize = structureOutputSize;
+
+ return (err);
+}
+
+