1/* 2 * Copyright (c) 1998-2000 Apple Computer, Inc. All rights reserved. 3 * 4 * @APPLE_LICENSE_HEADER_START@ 5 * 6 * The contents of this file constitute Original Code as defined in and 7 * are subject to the Apple Public Source License Version 1.1 (the 8 * "License"). You may not use this file except in compliance with the 9 * License. Please obtain a copy of the License at 10 * http://www.apple.com/publicsource and read it before using this file. 11 * 12 * This Original Code and all software distributed under the License are 13 * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER 14 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, 15 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, 16 * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the 17 * License for the specific language governing rights and limitations 18 * under the License. 19 * 20 * @APPLE_LICENSE_HEADER_END@ 21 */ 22 23#include <IOKit/IOLib.h> 24#include <IOKit/IOLocks.h> 25#include <IOKit/assert.h> 26#include <IOKit/IOKitKeys.h> 27 28#include <IOKit/graphics/IOAccelerator.h> 29#include <IOKit/graphics/IOGraphicsTypesPrivate.h> 30#include <IOKit/IOUserClient.h> 31 32 33OSDefineMetaClassAndStructors(IOAccelerator, IOService) 34 35/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ 36 37static IOLock * gLock; 38static queue_head_t gGlobalList; 39static UInt32 gTotalCount; 40static SInt32 gTweak; 41 42struct IOAccelIDRecord 43{ 44 IOAccelID id; 45 SInt32 retain; 46 queue_chain_t task_link; 47 queue_chain_t glob_link; 48}; 49 50enum { kTweakBits = 0x1f }; // sizeof(IOAccelIDRecord) == 24 51 52class IOAccelerationUserClient : public IOUserClient 53{ 54 /* 55 * Declare the metaclass information that is used for runtime 56 * typechecking of IOKit objects. 57 */ 58 59 OSDeclareDefaultStructors( IOAccelerationUserClient ); 60 61private: 62 task_t fTask; 63 queue_head_t fTaskList; 64 65 static void initialize(); 66 67public: 68 /* IOService overrides */ 69 virtual bool start( IOService * provider ); 70 virtual void stop( IOService * provider ); 71 72 /* IOUserClient overrides */ 73 virtual bool initWithTask( task_t owningTask, void * securityID, 74 UInt32 type, OSDictionary * properties ); 75 virtual IOReturn clientClose( void ); 76 77 virtual IOExternalMethod * getTargetAndMethodForIndex( 78 IOService ** targetP, UInt32 index ); 79 80 81 IOReturn extCreate(IOOptionBits options, 82 IOAccelID requestedID, IOAccelID * idOut); 83 IOReturn extDestroy(IOOptionBits options, IOAccelID id); 84 85}; 86 87#define super IOUserClient 88OSDefineMetaClassAndStructorsWithInit(IOAccelerationUserClient, IOUserClient, 89 IOAccelerationUserClient::initialize()); 90 91/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ 92 93void IOAccelerationUserClient::initialize() 94{ 95 if (!gLock) 96 { 97 gLock = IOLockAlloc(); 98 queue_init(&gGlobalList); 99 } 100} 101 102bool IOAccelerationUserClient::initWithTask( task_t owningTask, void * securityID, 103 UInt32 type, OSDictionary * properties ) 104{ 105 106 if ( properties != NULL ) 107 properties->setObject ( kIOUserClientCrossEndianCompatibleKey, kOSBooleanTrue ); 108 109 fTask = owningTask; 110 queue_init(&fTaskList); 111 112 return( super::initWithTask( owningTask, securityID, type, properties )); 113} 114 115bool IOAccelerationUserClient::start( IOService * provider ) 116{ 117 if( !super::start( provider )) 118 return( false ); 119 120 return (true); 121} 122 123IOReturn IOAccelerationUserClient::clientClose( void ) 124{ 125 if( !isInactive()) 126 terminate(); 127 128 return( kIOReturnSuccess ); 129} 130 131void IOAccelerationUserClient::stop( IOService * provider ) 132{ 133 IOAccelIDRecord * record; 134 135 IOLockLock(gLock); 136 137 while (!queue_empty( &fTaskList )) 138 { 139 queue_remove_first( &fTaskList, 140 record, 141 IOAccelIDRecord *, 142 task_link ); 143 144 if (--record->retain) 145 record->task_link.next = 0; 146 else 147 { 148 queue_remove(&gGlobalList, 149 record, 150 IOAccelIDRecord *, 151 glob_link); 152 gTotalCount--; 153 IODelete(record, IOAccelIDRecord, 1); 154 } 155 } 156 IOLockUnlock(gLock); 157 158 super::stop( provider ); 159} 160 161IOExternalMethod * IOAccelerationUserClient::getTargetAndMethodForIndex( 162 IOService ** targetP, UInt32 index ) 163{ 164 static const IOExternalMethod methodTemplate[] = 165 { 166 /* 0 */ { NULL, (IOMethod) &IOAccelerationUserClient::extCreate, 167 kIOUCScalarIScalarO, 2, 1 }, 168 /* 1 */ { NULL, (IOMethod) &IOAccelerationUserClient::extDestroy, 169 kIOUCScalarIScalarO, 2, 0 }, 170 }; 171 172 if (index > (sizeof(methodTemplate) / sizeof(methodTemplate[0]))) 173 return (NULL); 174 175 *targetP = this; 176 177 return ((IOExternalMethod *)(methodTemplate + index)); 178} 179 180/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ 181 182static 183IOReturn _CreateID(queue_head_t * taskList, IOOptionBits options, 184 IOAccelID requestedID, IOAccelID * idOut) 185{ 186 IOReturn err; 187 Boolean found; 188 IOAccelIDRecord * record; 189 IOAccelIDRecord * dup; 190 191 record = IONew(IOAccelIDRecord, 1); 192 record->retain = 1; 193 194 IOLockLock(gLock); 195 196 gTotalCount++; 197 198 do 199 { 200 if (kIOAccelSpecificID & options) 201 { 202 if ((requestedID > 4095) || (requestedID < -4096)) 203 { 204 err = kIOReturnExclusiveAccess; 205 break; 206 } 207 208 found = false; 209 queue_iterate(&gGlobalList, 210 dup, 211 IOAccelIDRecord *, 212 glob_link) 213 { 214 found = (dup->id == requestedID); 215 if (found) 216 break; 217 } 218 219 if (found) 220 { 221 err = kIOReturnExclusiveAccess; 222 break; 223 } 224 225 record->id = requestedID; 226 } 227 else 228 { 229 record->id = ((IOAccelID) (intptr_t) record) ^ (kTweakBits & gTweak++); 230 } 231 232 if (taskList) 233 { 234 queue_enter(taskList, record, 235 IOAccelIDRecord *, task_link); 236 } 237 else 238 record->task_link.next = 0; 239 240 queue_enter(&gGlobalList, record, 241 IOAccelIDRecord *, glob_link); 242 243 *idOut = record->id; 244 err = kIOReturnSuccess; 245 } 246 while (false); 247 248 if (kIOReturnSuccess != err) 249 gTotalCount--; 250 251 IOLockUnlock(gLock); 252 253 if (kIOReturnSuccess != err) 254 { 255 IODelete(record, IOAccelIDRecord, 1); 256 } 257 return (err); 258} 259 260IOReturn IOAccelerationUserClient::extCreate(IOOptionBits options, 261 IOAccelID requestedID, IOAccelID * idOut) 262{ 263 return (_CreateID(&fTaskList, options, requestedID, idOut)); 264} 265 266IOReturn IOAccelerationUserClient::extDestroy(IOOptionBits options, IOAccelID id) 267{ 268 IOAccelIDRecord * record; 269 bool found = false; 270 IOLockLock(gLock); 271 272 queue_iterate(&fTaskList, 273 record, 274 IOAccelIDRecord *, 275 task_link) 276 { 277 found = (record->id == id); 278 if (found) 279 { 280 queue_remove(&fTaskList, 281 record, 282 IOAccelIDRecord *, 283 task_link); 284 if (--record->retain) 285 record->task_link.next = 0; 286 else 287 { 288 queue_remove(&gGlobalList, 289 record, 290 IOAccelIDRecord *, 291 glob_link); 292 gTotalCount--; 293 IODelete(record, IOAccelIDRecord, 1); 294 } 295 break; 296 } 297 } 298 299 IOLockUnlock(gLock); 300 301 return (found ? kIOReturnSuccess : kIOReturnBadMessageID); 302} 303 304IOReturn 305IOAccelerator::createAccelID(IOOptionBits options, IOAccelID * identifier) 306{ 307 return (_CreateID(0, options, *identifier, identifier)); 308} 309 310IOReturn 311IOAccelerator::retainAccelID(IOOptionBits options, IOAccelID id) 312{ 313 IOAccelIDRecord * record; 314 bool found = false; 315 IOLockLock(gLock); 316 317 queue_iterate(&gGlobalList, 318 record, 319 IOAccelIDRecord *, 320 glob_link) 321 { 322 found = (record->id == id); 323 if (found) 324 { 325 record->retain++; 326 break; 327 } 328 } 329 330 IOLockUnlock(gLock); 331 332 return (found ? kIOReturnSuccess : kIOReturnBadMessageID); 333} 334 335IOReturn 336IOAccelerator::releaseAccelID(IOOptionBits options, IOAccelID id) 337{ 338 IOAccelIDRecord * record; 339 bool found = false; 340 IOLockLock(gLock); 341 342 queue_iterate(&gGlobalList, 343 record, 344 IOAccelIDRecord *, 345 glob_link) 346 { 347 found = (record->id == id); 348 if (found) 349 { 350 if (!--record->retain) 351 { 352 if (record->task_link.next) 353 panic("IOAccelerator::releaseID task_link"); 354 355 queue_remove(&gGlobalList, 356 record, 357 IOAccelIDRecord *, 358 glob_link); 359 gTotalCount--; 360 IODelete(record, IOAccelIDRecord, 1); 361 } 362 break; 363 } 364 } 365 366 IOLockUnlock(gLock); 367 368 return (found ? kIOReturnSuccess : kIOReturnBadMessageID); 369} 370 371