IOFramebufferUserClient.cpp [plain text]
#define IOFRAMEBUFFER_PRIVATE
#include <IOKit/graphics/IOFramebufferShared.h>
#include <IOKit/pwr_mgt/RootDomain.h>
#include <IOKit/IOLib.h>
#include <IOKit/IOMessage.h>
#include <libkern/c++/OSContainers.h>
#include <IOKit/IOBufferMemoryDescriptor.h>
#include <IOKit/IOPlatformExpert.h>
#include <IOKit/assert.h>
#include "IOFramebufferUserClient.h"
#include <IOKit/graphics/IOGraphicsEngine.h>
#undef super
#define super IOUserClient
OSDefineMetaClassAndStructors(IOFramebufferUserClient, IOUserClient)
static IOReturn myHandler(void *, void * , UInt32, IOService *, void *, unsigned int);
static IOLock * gSleepFramebuffersLock;
static OSOrderedSet * gSleepFramebuffers;
static UInt32 gWakeCount;
IOFramebufferUserClient * IOFramebufferUserClient::withTask( task_t owningTask )
{
IOFramebufferUserClient * inst;
if( 0 == gSleepFramebuffersLock) {
gSleepFramebuffersLock = IOLockAlloc();
gSleepFramebuffers = OSOrderedSet::withCapacity(6);
assert( gSleepFramebuffersLock && gSleepFramebuffers );
}
inst = new IOFramebufferUserClient;
if( inst && !inst->init()) {
inst->release();
inst = 0;
}
return( inst );
}
bool IOFramebufferUserClient::start( IOService * _owner )
{
static const IOExternalMethod methodTemplate[] = {
{ NULL, NULL, kIOUCScalarIScalarO, 3, 0 },
{ NULL, NULL, kIOUCScalarIStructO, 3, sizeof( IOPixelInformation) },
{ NULL, NULL, kIOUCScalarIScalarO, 0, 2 },
{ NULL, NULL, kIOUCScalarIScalarO, 2, 0 },
{ NULL, NULL, kIOUCScalarIScalarO, 2, 0 },
{ NULL, NULL, kIOUCScalarIStructO,
1, sizeof( IODisplayModeInformation) },
{ NULL, NULL, kIOUCScalarIScalarO, 0, 1 },
{ NULL, NULL, kIOUCStructIStructO, 0, 0xffffffff },
{ NULL, NULL, kIOUCScalarIScalarO, 1, 1 },
{ NULL, NULL, kIOUCStructIStructO, sizeof( Bounds), 0 },
{ NULL, NULL, kIOUCScalarIScalarO, 3, 0 },
{ NULL, NULL, kIOUCScalarIStructI, 3, 0xffffffff },
{ NULL, NULL, kIOUCScalarIScalarO, 1, 0 },
{ NULL, NULL, kIOUCScalarIScalarO, 2, 0 },
{ NULL, NULL, kIOUCScalarIScalarO, 0, 0 },
{ NULL, NULL, kIOUCScalarIStructI, 1, 0xffffffff },
{ NULL, NULL, kIOUCScalarIStructI, 2, 0xffffffff },
{ NULL, NULL, kIOUCStructIStructO, 0xffffffff, 0xffffffff },
};
if( !super::start( _owner ))
return( false);
owner = (IOFramebuffer *) _owner;
assert( sizeof( methodTemplate) == sizeof( externals));
bcopy( methodTemplate, externals, sizeof( externals ));
externals[0].object = owner;
externals[0].func = (IOMethod) &IOFramebuffer::createSharedCursor;
externals[1].object = owner;
externals[1].func = (IOMethod) &IOFramebuffer::getPixelInformation;
externals[2].object = owner;
externals[2].func = (IOMethod) &IOFramebuffer::getCurrentDisplayMode;
externals[3].object = owner;
externals[3].func = (IOMethod) &IOFramebuffer::setStartupDisplayMode;
externals[4].object = owner;
externals[4].func = (IOMethod) &IOFramebuffer::extSetDisplayMode;
externals[5].object = owner;
externals[5].func =
(IOMethod) &IOFramebuffer::extGetInformationForDisplayMode;
externals[6].object = owner;
externals[6].func = (IOMethod) &IOFramebuffer::extGetDisplayModeCount;
externals[7].object = owner;
externals[7].func = (IOMethod) &IOFramebuffer::extGetDisplayModes;
externals[8].object = owner;
externals[8].func = (IOMethod) &IOFramebuffer::extGetVRAMMapOffset;
externals[9].object = owner;
externals[9].func = (IOMethod) &IOFramebuffer::extSetBounds;
externals[10].object = owner;
externals[10].func = (IOMethod) &IOFramebuffer::extSetNewCursor;
externals[11].object = owner;
externals[11].func = (IOMethod) &IOFramebuffer::setGammaTable;
externals[12].object = owner;
externals[12].func = (IOMethod) &IOFramebuffer::extSetCursorVisible;
externals[13].object = owner;
externals[13].func = (IOMethod) &IOFramebuffer::extSetCursorPosition;
externals[14].object = this;
externals[14].func = (IOMethod) &IOFramebufferUserClient::acknowledgeNotification;
externals[15].object = owner;
externals[15].func = (IOMethod) &IOFramebuffer::extSetColorConvertTable;
externals[16].object = owner;
externals[16].func = (IOMethod) &IOFramebuffer::extSetCLUTWithEntries;
externals[17].object = owner;
externals[17].func = (IOMethod) &IOFramebuffer::extValidateDetailedTiming;
ackFrameBuffer = false;
ackRoot = false;
owner->serverConnect = this;
powerRootNotifier = registerSleepWakeInterest(myHandler, (void *) this);
frameBufferNotifier = owner->registerInterest( gIOGeneralInterest, myHandler, this, 0 );
return( true );
}
IOReturn
IOFramebufferUserClient::acknowledgeNotification( void )
{
if( ackFrameBuffer ) {
ackFrameBuffer = false;
owner->allowPowerChange((unsigned long)PMrefcon);
}
if( ackRoot ) {
ackRoot = false;
owner->beginSystemSleep(PMrefcon);
}
return IOPMNoErr;
}
static IOReturn
myHandler(void * us, void *, UInt32 messageType, IOService *, void * params, unsigned int)
{
kern_return_t r;
mach_msg_header_t *msgh;
IOFramebufferUserClient * self = (IOFramebufferUserClient *)us;
switch (messageType) {
case kIOMessageSystemWillSleep:
if ( !(self->WSKnowsWeAreOff) ) {
msgh = (mach_msg_header_t *)(self->notificationMsg);
if( msgh && (self->WSnotificationPort) ) {
msgh->msgh_id = 0;
self->WSKnowsWeAreOff = true;
self->ackRoot = true;
r = mach_msg_send_from_kernel( msgh, msgh->msgh_size);
if( KERN_SUCCESS == r) {
((sleepWakeNote *)params)->returnValue = 10000000;
self->PMrefcon = ((sleepWakeNote *)params)->powerRef;
IOLockLock( gSleepFramebuffersLock );
gSleepFramebuffers->setObject(self);
IOLockUnlock( gSleepFramebuffersLock );
return kIOReturnSuccess;
}
}
}
self->ackRoot = false;
((sleepWakeNote *)params)->returnValue = 0;
return kIOReturnSuccess;
case kIOMessageDeviceWillPowerOff:
if ( !self->WSKnowsWeAreOff ) {
msgh = (mach_msg_header_t *)(self->notificationMsg);
if( msgh && (self->WSnotificationPort) ) {
msgh->msgh_id = 0;
self->WSKnowsWeAreOff = true;
self->ackFrameBuffer = true;
r = mach_msg_send_from_kernel( msgh, msgh->msgh_size);
if( KERN_SUCCESS == r) {
((sleepWakeNote *)params)->returnValue = 10000000;
self->PMrefcon = ((sleepWakeNote *)params)->powerRef;
IOLockLock( gSleepFramebuffersLock );
gSleepFramebuffers->setObject(self);
IOLockUnlock( gSleepFramebuffersLock );
return kIOReturnSuccess;
}
}
}
((sleepWakeNote *)params)->returnValue = 0;
self->ackFrameBuffer = false;
return kIOReturnSuccess;
case kIOMessageDeviceHasPoweredOn:
IOLockLock( gSleepFramebuffersLock );
gWakeCount++;
if( gWakeCount == gSleepFramebuffers->getCount()) {
while( (self = (IOFramebufferUserClient *) gSleepFramebuffers->getFirstObject())) {
if ( self->WSKnowsWeAreOff ) {
msgh = (mach_msg_header_t *)(self->notificationMsg);
if( msgh && (self->WSnotificationPort)) {
msgh->msgh_id = 1;
self->WSKnowsWeAreOff = false;
r = mach_msg_send_from_kernel( msgh, msgh->msgh_size);
}
}
gSleepFramebuffers->removeObject( self );
}
gWakeCount = 0;
}
IOLockUnlock( gSleepFramebuffersLock );
return kIOReturnSuccess;
}
return kIOReturnUnsupported;
}
IOReturn IOFramebufferUserClient::registerNotificationPort(
mach_port_t port,
UInt32 type,
UInt32 refCon )
{
static mach_msg_header_t init_msg = {
MACH_MSGH_BITS(MACH_MSG_TYPE_COPY_SEND,0),
sizeof (mach_msg_header_t),
MACH_PORT_NULL,
MACH_PORT_NULL,
0,
0
};
if ( notificationMsg == NULL )
notificationMsg = IOMalloc( sizeof (mach_msg_header_t) );
*((mach_msg_header_t *)notificationMsg) = init_msg;
((mach_msg_header_t *)notificationMsg)->msgh_remote_port = port;
WSnotificationPort = port;
WSKnowsWeAreOff = false;
return( kIOReturnSuccess);
}
IOReturn IOFramebufferUserClient::getNotificationSemaphore(
UInt32 interruptType, semaphore_t * semaphore )
{
return( owner->getNotificationSemaphore(interruptType, semaphore) );
}
IOReturn IOFramebufferUserClient::clientClose( void )
{
owner->close();
if( owner->isConsoleDevice())
getPlatform()->setConsoleInfo( 0, kPEAcquireScreen);
if( powerRootNotifier) {
powerRootNotifier->remove();
powerRootNotifier = 0;
}
if( frameBufferNotifier) {
frameBufferNotifier->remove();
frameBufferNotifier = 0;
}
if( notificationMsg) {
IOFree( notificationMsg, sizeof (mach_msg_header_t));
notificationMsg = 0;
}
owner->serverConnect = 0;
WSnotificationPort = NULL;
detach( owner);
return( kIOReturnSuccess);
}
IOService * IOFramebufferUserClient::getService( void )
{
return( owner );
}
IOReturn IOFramebufferUserClient::clientMemoryForType( UInt32 type,
IOOptionBits * flags, IOMemoryDescriptor ** memory )
{
IOMemoryDescriptor * mem;
IOReturn err;
switch( type) {
case kIOFBCursorMemory:
mem = owner->sharedCursor;
mem->retain();
break;
case kIOFBVRAMMemory:
mem = owner->getVRAMRange();
break;
default:
mem = (IOMemoryDescriptor *) owner->userAccessRanges->getObject( type );
mem->retain();
break;
}
*memory = mem;
if( mem)
err = kIOReturnSuccess;
else
err = kIOReturnBadArgument;
return( err );
}
IOExternalMethod * IOFramebufferUserClient::getExternalMethodForIndex( UInt32 index )
{
if( index < (sizeof( externals) / sizeof( externals[0])))
return( externals + index);
else
return( NULL);
}
IOReturn IOFramebufferUserClient::setProperties( OSObject * properties )
{
OSDictionary * dict;
OSArray * array;
IOReturn kr = kIOReturnUnsupported;
if( !(dict = OSDynamicCast( OSDictionary, properties)))
return( kIOReturnBadArgument);
if( (array = OSDynamicCast(OSArray,
dict->getObject( kIOFBDetailedTimingsKey))))
kr = owner->setDetailedTimings( array );
else
kr = kIOReturnBadArgument;
return( kr );
}
OSDefineMetaClassAndStructors(IOGraphicsEngineClient, IOUserClient)
IOGraphicsEngineClient * IOGraphicsEngineClient::withTask( task_t owningTask )
{
IOGraphicsEngineClient * inst;
inst = new IOGraphicsEngineClient;
if( inst && !inst->init()) {
inst->release();
inst = 0;
}
if( inst)
inst->owningTask = owningTask;
return( inst );
}
bool IOGraphicsEngineClient::start( IOService * _owner )
{
static const IOExternalMethod methodTemplate[] = {
{ NULL, NULL, kIOUCScalarIScalarO, 3, 1 },
{ NULL, NULL, kIOUCScalarIScalarO, 2, 2 },
{ NULL, NULL, kIOUCScalarIScalarO, 3, 2 },
{ NULL, NULL, kIOUCScalarIScalarO, 1, 0 },
};
IOGraphicsEngineContext * mem;
IOByteCount size;
if( !super::start( _owner ))
return( false);
owner = (IOFramebuffer *) _owner;
agpDev = OSDynamicCast( IOAGPDevice, owner->getProvider());
descriptors = OSArray::withCapacity( 1 );
bcopy( methodTemplate, externals, sizeof( methodTemplate ));
externals[0].object = this;
externals[0].func = (IOMethod) &IOGraphicsEngineClient::addUserRange;
externals[1].object = this;
externals[1].func = (IOMethod) &IOGraphicsEngineClient::createAGPSpace;
externals[2].object = this;
externals[2].func = (IOMethod) &IOGraphicsEngineClient::commitAGPMemory;
externals[3].object = this;
externals[3].func = (IOMethod) &IOGraphicsEngineClient::releaseAGPMemory;
if( 0 == owner->engineContext) {
size = round_page( sizeof( IOGraphicsEngineContext));
owner->engineContext = IOBufferMemoryDescriptor::withCapacity(
size, kIODirectionNone, false );
if( !owner->engineContext)
return( kIOReturnNoMemory );
owner->engineContext->setLength( size );
mem = (IOGraphicsEngineContext *)
owner->engineContext->getBytesNoCopy();
memset((char *)mem, 0, size);
mem->version = kIOGraphicsEngineContextVersion;
mem->structSize = size;
}
return( true );
}
void IOGraphicsEngineClient::free()
{
if( descriptors)
descriptors->free();
if( agpDev && haveAGP)
agpDev->destroyAGPSpace();
super::free();
}
IOReturn IOGraphicsEngineClient::clientClose( void )
{
detach( owner );
return( kIOReturnSuccess);
}
IOService * IOGraphicsEngineClient::getService( void )
{
return( owner );
}
IOReturn IOGraphicsEngineClient::clientMemoryForType( UInt32 type,
IOOptionBits * options, IOMemoryDescriptor ** memory )
{
IOMemoryDescriptor * mem;
switch( type) {
case kIOGraphicsEngineContext:
mem = owner->engineContext;
break;
default:
mem = (IOMemoryDescriptor *) owner->engineAccessRanges->getObject( type );
break;
}
if( mem) {
mem->retain();
*memory = mem;
return( kIOReturnSuccess);
} else
return( kIOReturnBadArgument);
}
IOExternalMethod * IOGraphicsEngineClient::getExternalMethodForIndex( UInt32 index )
{
if( index < (sizeof( externals) / sizeof( externals[0])))
return( externals + index);
else
return( NULL);
}
IOReturn IOGraphicsEngineClient::addUserRange( vm_address_t start,
vm_size_t length, UInt32 apertureIndex, IOPhysicalAddress * phys )
{
IODeviceMemory * mem;
IOReturn err = kIOReturnSuccess;
OSArray * ranges;
int i;
IODeviceMemory * aperture
= owner->getProvider()->getDeviceMemoryWithIndex( apertureIndex );
if( 0 == aperture)
return( kIOReturnBadArgument );
ranges = owner->engineAccessRanges;
i = 0;
while( (mem = (IODeviceMemory *) ranges->getObject( i++ ))) {
if( (mem->getPhysicalAddress() ==
(start + aperture->getPhysicalAddress()))
&& (length <= mem->getLength()) )
break;
}
if( 0 == mem) {
mem = IODeviceMemory::withSubRange(
aperture, start, length );
if( mem) {
owner->engineAccessRanges->setObject( mem );
err = kIOReturnSuccess;
} else
err = kIOReturnNoResources;
}
if( kIOReturnSuccess == err)
*phys = mem->getPhysicalAddress();
return( err );
}
IOReturn IOGraphicsEngineClient::createAGPSpace( IOOptionBits options,
IOPhysicalLength length,
IOPhysicalAddress * address,
IOPhysicalLength * lengthOut )
{
IOReturn err;
if( !agpDev)
return( kIOReturnUnsupported );
*lengthOut = length;
err = agpDev->createAGPSpace( options, address, lengthOut );
haveAGP = (kIOReturnSuccess == err);
return( err );
}
class _IOGraphicsClientMemory : public OSObject {
OSDeclareDefaultStructors(_IOGraphicsClientMemory)
public:
IOMemoryDescriptor * memory;
IOAGPDevice * agpDev;
IOByteCount agpOffset;
virtual bool init();
virtual void free();
};
OSDefineMetaClassAndStructors(_IOGraphicsClientMemory, OSObject)
bool _IOGraphicsClientMemory::init()
{
return( OSObject::init());
}
void _IOGraphicsClientMemory::free()
{
if( memory) {
agpDev->getAGPRangeAllocator()->deallocate( agpOffset,
memory->getLength() );
memory->complete();
memory->release();
}
OSObject::free();
}
IOReturn IOGraphicsEngineClient::commitAGPMemory( vm_address_t start,
vm_size_t length, IOOptionBits options,
void ** ref, IOByteCount * offset )
{
_IOGraphicsClientMemory * graphicsMem;
IORangeAllocator * rangeAllocator;
IOByteCount agpOffset;
IOReturn err = kIOReturnNoMemory;
bool ok;
if( !agpDev)
return( kIOReturnUnsupported );
if( (!start) || (!length))
return( kIOReturnBadArgument );
rangeAllocator = agpDev->getAGPRangeAllocator();
if( !rangeAllocator)
return( kIOReturnUnsupported );
do {
graphicsMem = new _IOGraphicsClientMemory;
if( (!graphicsMem) || (!graphicsMem->init()))
continue;
ok = rangeAllocator->allocate( length, (IORangeScalar *) &agpOffset );
if( !ok) {
err = kIOReturnNoSpace;
continue;
}
graphicsMem->agpDev = agpDev;
graphicsMem->agpOffset = agpOffset;
graphicsMem->memory = IOMemoryDescriptor::withAddress( start, length,
kIODirectionOut, owningTask );
if( !graphicsMem->memory)
continue;
err = graphicsMem->memory->prepare();
if( err != kIOReturnSuccess)
continue;
err = agpDev->commitAGPMemory( graphicsMem->memory, agpOffset );
if( err != kIOReturnSuccess)
continue;
*ref = (void *) descriptors->getCount();
*offset = agpOffset;
descriptors->setObject( graphicsMem );
} while( false );
if( graphicsMem)
graphicsMem->release();
if( (kIOReturnSuccess != err) && (!graphicsMem))
rangeAllocator->deallocate( agpOffset, length );
return( err );
}
IOReturn IOGraphicsEngineClient::releaseAGPMemory( void * ref )
{
_IOGraphicsClientMemory * graphicsMem;
UInt32 index = (UInt32) ref;
if( 0 == (graphicsMem = (_IOGraphicsClientMemory *)
descriptors->getObject( index )))
return( kIOReturnBadArgument );
descriptors->removeObject( index );
return( kIOReturnSuccess );
}
OSDefineMetaClassAndStructors(IOFramebufferSharedUserClient, IOUserClient)
IOFramebufferSharedUserClient * IOFramebufferSharedUserClient::withTask(
task_t owningTask )
{
IOFramebufferSharedUserClient * inst;
inst = new IOFramebufferSharedUserClient;
if( inst && !inst->init()) {
inst->release();
inst = 0;
}
return( inst );
}
bool IOFramebufferSharedUserClient::start( IOService * _owner )
{
static const IOExternalMethod methodTemplate[] = {
};
if( !super::start( _owner ))
return( false);
owner = (IOFramebuffer *) _owner;
bcopy( methodTemplate, externals, sizeof( methodTemplate ));
return( true );
}
void IOFramebufferSharedUserClient::free( void )
{
retain(); retain();
owner->sharedConnect = 0;
detach( owner);
super::free();
}
void IOFramebufferSharedUserClient::release() const
{
super::release(2);
}
IOReturn IOFramebufferSharedUserClient::clientClose( void )
{
return( kIOReturnSuccess);
}
IOService * IOFramebufferSharedUserClient::getService( void )
{
return( owner );
}
IOReturn IOFramebufferSharedUserClient::clientMemoryForType( UInt32 type,
IOOptionBits * options, IOMemoryDescriptor ** memory )
{
IOMemoryDescriptor * mem = 0;
IOReturn err;
switch( type) {
case kIOFBCursorMemory:
mem = owner->sharedCursor;
mem->retain();
*options = kIOMapReadOnly;
break;
case kIOFBVRAMMemory:
mem = owner->getVRAMRange();
break;
}
*memory = mem;
if( mem)
err = kIOReturnSuccess;
else
err = kIOReturnBadArgument;
return( err );
}
IOReturn IOFramebufferSharedUserClient::getNotificationSemaphore(
UInt32 interruptType, semaphore_t * semaphore )
{
return( owner->getNotificationSemaphore(interruptType, semaphore) );
}
IOExternalMethod * IOFramebufferSharedUserClient::getExternalMethodForIndex( UInt32 index )
{
if( index < (sizeof( externals) / sizeof( externals[0])))
return( externals + index);
else
return( NULL);
}