1/*
2 * Copyright (c) 2000 Apple Computer, 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
24#include <CoreFoundation/CoreFoundation.h>
25
26#include <IOKit/IOKitLib.h>
27#include <IOKit/graphics/IOAccelSurfaceControl.h>
28#include <IOKit/graphics/IOGraphicsLib.h>
29#include <stdlib.h>
30
31
32#define arrayCnt(var) (sizeof(var)/sizeof(var[0]))
33#define regionSize(rgn) ((size_t) IOACCEL_SIZEOF_DEVICE_REGION(rgn))
34
35IOReturn IOAccelFindAccelerator( io_service_t framebuffer,
36                                io_service_t * pAccelerator, UInt32 * pFramebufferIndex )
37{
38    IOReturn      kr;
39    io_service_t  accelerator = MACH_PORT_NULL;
40
41    mach_port_t            masterPort;
42    CFMutableDictionaryRef props = 0;
43    CFStringRef            cfStr;
44    CFNumberRef            cfNum;
45    const char *           cStr;
46    char *                 buffer = NULL;
47
48    *pAccelerator = MACH_PORT_NULL;
49    *pFramebufferIndex = 0;
50
51    do {
52
53        IOMasterPort(MACH_PORT_NULL, &masterPort);
54
55        kr = IORegistryEntryCreateCFProperties( framebuffer, &props,
56                                                kCFAllocatorDefault, kNilOptions);
57        if( kr != kIOReturnSuccess)
58            continue;
59        kr = kIOReturnError;
60        cfStr = CFDictionaryGetValue( props, CFSTR(kIOAccelTypesKey) );
61        if( !cfStr)
62            continue;
63
64        cStr = CFStringGetCStringPtr( cfStr, kCFStringEncodingMacRoman);
65        if( !cStr) {
66            CFIndex bufferSize = CFStringGetMaximumSizeForEncoding( CFStringGetLength(cfStr),
67                    kCFStringEncodingMacRoman) + sizeof('\0');
68            buffer = malloc( bufferSize);
69            if( buffer && CFStringGetCString( cfStr, buffer, bufferSize, kCFStringEncodingMacRoman))
70                cStr = buffer;
71        }
72        if( !cStr)
73            continue;
74
75        accelerator = IORegistryEntryFromPath( masterPort, cStr );
76        if( !accelerator)
77            continue;
78        if( !IOObjectConformsTo( accelerator, kIOAcceleratorClassName )) {
79            IOObjectRelease( accelerator );
80            accelerator = MACH_PORT_NULL;
81            continue;
82        }
83
84        cfNum = CFDictionaryGetValue( props, CFSTR(kIOAccelIndexKey) );
85        if( cfNum)
86            CFNumberGetValue( cfNum, kCFNumberSInt32Type, pFramebufferIndex );
87
88        kr = kIOReturnSuccess;
89
90    } while( false );
91
92    if( buffer)
93        free( buffer);
94    if( props)
95        CFRelease( props);
96
97    *pAccelerator = accelerator;
98
99    return( kr );
100}
101
102static io_connect_t idConnect;
103enum { kAlloc, kFree };
104
105IOReturn IOAccelCreateAccelID(IOOptionBits options, IOAccelID * identifier)
106{
107    IOReturn err;
108
109    if (!idConnect)
110    {
111        io_service_t
112        service = IORegistryEntryFromPath(kIOMasterPortDefault,
113                                        kIOServicePlane ":/IOResources/IODisplayWrangler");
114        if (service)
115        {
116            err = IOServiceOpen(service, mach_task_self(), 0, &idConnect);
117            IOObjectRelease(service);
118        }
119    }
120
121    if (!idConnect)
122        return (kIOReturnNotReady);
123
124    uint64_t inData[] = { options, *identifier };
125    uint64_t outData;
126    uint32_t outLen = 1;
127    err = IOConnectCallScalarMethod(idConnect, kAlloc,
128                                 inData,   arrayCnt(inData),
129                                &outData,  &outLen);
130    *identifier = (IOAccelID) outData;
131
132    return (err);
133}
134
135IOReturn IOAccelDestroyAccelID(IOOptionBits options, IOAccelID identifier)
136{
137    IOReturn err;
138
139    if (!idConnect)
140        return (kIOReturnNotReady);
141
142    uint64_t inData[] = { options, identifier };
143    err = IOConnectCallScalarMethod(idConnect, kFree,
144                                 inData, arrayCnt(inData), NULL, NULL);
145
146    return (err);
147}
148
149IOReturn IOAccelCreateSurface( io_service_t accelerator, UInt32 wID, eIOAccelSurfaceModeBits modebits,
150                                IOAccelConnect *connect )
151{
152        IOReturn        kr;
153        io_connect_t    window = MACH_PORT_NULL;
154
155        *connect = NULL;
156
157        /* Create a context */
158        kr = IOServiceOpen( accelerator,
159                    mach_task_self(),
160                    kIOAccelSurfaceClientType,
161                    &window );
162
163        if( kr != kIOReturnSuccess)
164        {
165                return kr;
166        }
167
168        /* Set the window id */
169        uint64_t data[] = { wID, modebits };
170        kr = IOConnectCallScalarMethod(window, kIOAccelSurfaceSetIDMode,
171                                   data, arrayCnt(data), NULL, NULL);
172        if(kr != kIOReturnSuccess)
173        {
174                IOServiceClose(window);
175                return kr;
176        }
177
178        *connect = (IOAccelConnect) (uintptr_t) window;
179
180        return kIOReturnSuccess;
181}
182
183IOReturn IOAccelDestroySurface( IOAccelConnect connect )
184{
185        IOReturn kr;
186
187        if(!connect)
188                return kIOReturnError;
189
190        kr = IOServiceClose((io_connect_t) (uintptr_t) connect);
191
192        return kr;
193}
194
195IOReturn IOAccelSetSurfaceScale( IOAccelConnect connect, IOOptionBits options,
196                                    IOAccelSurfaceScaling * scaling, UInt32 scalingSize )
197{
198        uint64_t inData = options;
199        IOReturn result;
200
201        result = IOConnectCallMethod((io_connect_t) (uintptr_t) connect,
202                                kIOAccelSurfaceSetScale,
203                                &inData, 1,
204                                scaling, (size_t) scalingSize,
205                            NULL, NULL, NULL, NULL); // no output
206
207        return result;
208}
209
210
211IOReturn IOAccelSetSurfaceFramebufferShape( IOAccelConnect connect, IOAccelDeviceRegion *rgn,
212                                            eIOAccelSurfaceShapeBits options, UInt32 framebufferIndex )
213{
214        uint64_t inData[] = { options, framebufferIndex };
215        IOReturn result;
216        size_t   rgnSize = regionSize(rgn);
217
218        result = IOConnectCallMethod((io_connect_t) (uintptr_t) connect, kIOAccelSurfaceSetShape,
219                                inData, arrayCnt(inData), rgn, rgnSize,
220                                NULL, NULL, NULL, NULL); // no output
221        return result;
222}
223
224IOReturn IOAccelSetSurfaceFramebufferShapeWithBacking( IOAccelConnect connect, IOAccelDeviceRegion *rgn,
225                                            eIOAccelSurfaceShapeBits options, UInt32 framebufferIndex,
226                                            IOVirtualAddress backing, UInt32 rowbytes )
227{
228        IOReturn err;
229
230        err = IOAccelSetSurfaceFramebufferShapeWithBackingAndLength(connect, rgn, options,
231                        framebufferIndex, backing, rowbytes, rgn->bounds.h * rowbytes);
232
233        return (err);
234}
235
236IOReturn IOAccelSetSurfaceFramebufferShapeWithBackingAndLength( IOAccelConnect connect, IOAccelDeviceRegion *rgn,
237                                            eIOAccelSurfaceShapeBits options, UInt32 framebufferIndex,
238                                            IOVirtualAddress backing, UInt32 rowbytes, UInt32 backingLength )
239{
240    IOReturn err;
241    uint64_t inData[] =
242                { options, framebufferIndex, backing, rowbytes, backingLength };
243    size_t   rgnSize = regionSize(rgn);
244
245    err =  IOConnectCallMethod((io_connect_t) (uintptr_t) connect, kIOAccelSurfaceSetShapeBackingAndLength,
246            inData, arrayCnt(inData), rgn, rgnSize,
247            NULL, NULL, NULL, NULL); // no output
248
249        return (err);
250}
251
252IOReturn IOAccelSurfaceControl( IOAccelConnect connect,
253                                    UInt32 selector, UInt32 arg, UInt32 * result)
254{
255        uint64_t inData[] = { selector, arg };
256        uint64_t outData;
257        uint32_t outSize = 1;
258
259        IOReturn err =  IOConnectCallScalarMethod((io_connect_t) (uintptr_t)connect, kIOAccelSurfaceControl,
260                inData, arrayCnt(inData), &outData, &outSize);
261        *result = (UInt32) outData;
262
263        return( err );
264}
265
266IOReturn IOAccelReadLockSurface( IOAccelConnect connect, IOAccelSurfaceInformation * info, UInt32 infoSize )
267{
268        size_t size = (size_t) infoSize;
269        IOReturn ret =  IOConnectCallStructMethod((io_connect_t) (uintptr_t)connect, kIOAccelSurfaceReadLock,
270                                              NULL, 0, info, &size);
271
272        return ret;
273}
274
275IOReturn IOAccelReadLockSurfaceWithOptions( IOAccelConnect connect, IOOptionBits options,
276                                            IOAccelSurfaceInformation * info, UInt32 infoSize )
277{
278        uint64_t inData = options;
279        size_t size = (size_t) infoSize;
280        IOReturn ret =  IOConnectCallMethod((io_connect_t) (uintptr_t) connect, kIOAccelSurfaceReadLockOptions,
281                                        &inData, 1,             // in scalar
282                                        NULL,    0,             // in struct
283                                        NULL,    NULL,          // out scalar
284                                        info,    &size);        // out struct
285
286        return ret;
287}
288
289IOReturn IOAccelWriteLockSurface( IOAccelConnect connect, IOAccelSurfaceInformation * info, UInt32 infoSize )
290{
291        size_t size = (size_t) infoSize;
292        IOReturn ret =  IOConnectCallStructMethod((io_connect_t) (uintptr_t) connect, kIOAccelSurfaceWriteLock,
293                                              NULL, 0, info, &size);
294        return ret;
295}
296
297IOReturn IOAccelWriteLockSurfaceWithOptions( IOAccelConnect connect, IOOptionBits options,
298                                             IOAccelSurfaceInformation * info, UInt32 infoSize )
299{
300        uint64_t inData = options;
301        size_t size = (size_t) infoSize;
302        IOReturn ret =  IOConnectCallMethod((io_connect_t) (uintptr_t) connect, kIOAccelSurfaceWriteLockOptions,
303                                        &inData, 1,             // in scalar
304                                        NULL,    0,             // in struct
305                                        NULL,    NULL,          // out scalar
306                                        info,    &size);        // out struct
307        return ret;
308}
309
310IOReturn IOAccelReadUnlockSurface( IOAccelConnect connect )
311{
312        return IOConnectCallMethod((io_connect_t) (uintptr_t) connect, kIOAccelSurfaceReadUnlock,
313                               NULL, 0,    NULL, 0,     // input
314                               NULL, NULL, NULL, NULL); // output
315}
316
317IOReturn IOAccelReadUnlockSurfaceWithOptions( IOAccelConnect connect, IOOptionBits options )
318{
319        uint64_t inData = options;
320        return IOConnectCallMethod((io_connect_t) (uintptr_t) connect, kIOAccelSurfaceReadUnlockOptions,
321                               &inData, 1, NULL, 0,     // input
322                               NULL, NULL, NULL, NULL); // output
323}
324
325IOReturn IOAccelWriteUnlockSurface( IOAccelConnect connect )
326{
327        return IOConnectCallMethod((io_connect_t) (uintptr_t) connect, kIOAccelSurfaceWriteUnlock,
328                               NULL, 0,    NULL, 0,     // input
329                               NULL, NULL, NULL, NULL); // output
330}
331
332IOReturn IOAccelWriteUnlockSurfaceWithOptions( IOAccelConnect connect, IOOptionBits options )
333{
334        uint64_t inData = options;
335        return IOConnectCallMethod((io_connect_t) (uintptr_t) connect, kIOAccelSurfaceWriteUnlockOptions,
336                               &inData, 1, NULL, 0,     // input
337                               NULL, NULL, NULL, NULL); // output
338}
339
340IOReturn IOAccelWaitForSurface( IOAccelConnect connect __unused )
341{
342        return kIOReturnSuccess;
343}
344
345IOReturn IOAccelQueryLockSurface( IOAccelConnect connect )
346{
347        return IOConnectCallMethod((io_connect_t) (uintptr_t) connect, kIOAccelSurfaceQueryLock,
348                               NULL, 0,    NULL, 0,     // input
349                               NULL, NULL, NULL, NULL); // output
350}
351
352/* Flush surface to visible region */
353IOReturn IOAccelFlushSurfaceOnFramebuffers( IOAccelConnect connect, IOOptionBits options, UInt32 framebufferMask )
354{
355        uint64_t inData[] = { framebufferMask, options };
356        return IOConnectCallMethod((io_connect_t) (uintptr_t) connect, kIOAccelSurfaceFlush,
357                               inData, arrayCnt(inData), NULL, 0,// input
358                                NULL, NULL, NULL, NULL);         // output
359}
360
361IOReturn IOAccelReadSurface( IOAccelConnect connect, IOAccelSurfaceReadData * parameters )
362{
363        IOReturn result;
364
365        result = IOConnectCallMethod((io_connect_t) (uintptr_t) connect, kIOAccelSurfaceRead,
366               NULL, 0, parameters, sizeof( IOAccelSurfaceReadData), // input
367               NULL, NULL, NULL, NULL); // no output
368
369        return result;
370}
371
372