771 lines
		
	
	
		
			24 KiB
		
	
	
	
		
			C
		
	
	
	
			
		
		
	
	
			771 lines
		
	
	
		
			24 KiB
		
	
	
	
		
			C
		
	
	
	
| /**************************************************************
 | |
|  *
 | |
|  * IOKit support for the Darwin X Server
 | |
|  *
 | |
|  * HISTORY:
 | |
|  * Original port to Mac OS X Server by John Carmack
 | |
|  * Port to Darwin 1.0 by Dave Zarzycki
 | |
|  * Significantly rewritten for XFree86 4.0.1 by Torrey Lyons
 | |
|  *
 | |
|  **************************************************************/
 | |
| /*
 | |
|  * Copyright (c) 2001-2004 Torrey T. Lyons. All Rights Reserved.
 | |
|  *
 | |
|  * Permission is hereby granted, free of charge, to any person obtaining a
 | |
|  * copy of this software and associated documentation files (the "Software"),
 | |
|  * to deal in the Software without restriction, including without limitation
 | |
|  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
 | |
|  * and/or sell copies of the Software, and to permit persons to whom the
 | |
|  * Software is furnished to do so, subject to the following conditions:
 | |
|  *
 | |
|  * The above copyright notice and this permission notice shall be included in
 | |
|  * all copies or substantial portions of the Software.
 | |
|  *
 | |
|  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 | |
|  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 | |
|  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
 | |
|  * THE ABOVE LISTED COPYRIGHT HOLDER(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
 | |
|  * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
 | |
|  * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
 | |
|  * DEALINGS IN THE SOFTWARE.
 | |
|  *
 | |
|  * Except as contained in this notice, the name(s) of the above copyright
 | |
|  * holders shall not be used in advertising or otherwise to promote the sale,
 | |
|  * use or other dealings in this Software without prior written authorization.
 | |
|  */
 | |
| 
 | |
| #include <X11/X.h>
 | |
| #include <X11/Xproto.h>
 | |
| #include "os.h"
 | |
| #include "servermd.h"
 | |
| #include "inputstr.h"
 | |
| #include "scrnintstr.h"
 | |
| #include "mi.h"
 | |
| #include "mibstore.h"
 | |
| #include "mipointer.h"
 | |
| #include "micmap.h"
 | |
| #include "shadow.h"
 | |
| 
 | |
| #include <sys/types.h>
 | |
| #include <sys/time.h>
 | |
| #include <unistd.h>
 | |
| #include <fcntl.h>
 | |
| #include <pthread.h>
 | |
| 
 | |
| #include <mach/mach_interface.h>
 | |
| 
 | |
| #define NO_CFPLUGIN
 | |
| #include <IOKit/IOKitLib.h>
 | |
| #include <IOKit/hidsystem/IOHIDShared.h>
 | |
| #include <IOKit/graphics/IOGraphicsLib.h>
 | |
| #include <drivers/event_status_driver.h>
 | |
| 
 | |
| // Define this to work around bugs in the display drivers for
 | |
| // older PowerBook G3's. If the X server starts without this
 | |
| // #define, you don't need it.
 | |
| #undef OLD_POWERBOOK_G3
 | |
| 
 | |
| #include "darwin.h"
 | |
| #include "xfIOKit.h"
 | |
| 
 | |
| // Globals
 | |
| int             xfIOKitScreenIndex = 0;
 | |
| io_connect_t    xfIOKitInputConnect = 0;
 | |
| 
 | |
| static pthread_t                inputThread;
 | |
| static EvGlobals *              evg;
 | |
| static mach_port_t              masterPort;
 | |
| static mach_port_t              notificationPort;
 | |
| static IONotificationPortRef    NotificationPortRef;
 | |
| static mach_port_t              pmNotificationPort;
 | |
| static io_iterator_t            fbIter;
 | |
| 
 | |
| 
 | |
| /*
 | |
|  * XFIOKitStoreColors
 | |
|  * This is a callback from X to change the hardware colormap
 | |
|  * when using PsuedoColor.
 | |
|  */
 | |
| static void XFIOKitStoreColors(
 | |
|     ColormapPtr     pmap,
 | |
|     int             numEntries,
 | |
|     xColorItem      *pdefs)
 | |
| {
 | |
|     kern_return_t   kr;
 | |
|     int             i;
 | |
|     IOColorEntry    *newColors;
 | |
|     ScreenPtr       pScreen = pmap->pScreen;
 | |
|     XFIOKitScreenPtr iokitScreen = XFIOKIT_SCREEN_PRIV(pScreen);
 | |
| 
 | |
|     assert( newColors = (IOColorEntry *)
 | |
|                 xalloc( numEntries*sizeof(IOColorEntry) ));
 | |
| 
 | |
|     // Convert xColorItem values to IOColorEntry
 | |
|     // assume the colormap is PsuedoColor
 | |
|     // as we do not support DirectColor
 | |
|     for (i = 0; i < numEntries; i++) {
 | |
|         newColors[i].index = pdefs[i].pixel;
 | |
|         newColors[i].red =   pdefs[i].red;
 | |
|         newColors[i].green = pdefs[i].green;
 | |
|         newColors[i].blue =  pdefs[i].blue;
 | |
|     }
 | |
| 
 | |
|     kr = IOFBSetCLUT( iokitScreen->fbService, 0, numEntries,
 | |
|                       kSetCLUTByValue, newColors );
 | |
|     kern_assert( kr );
 | |
| 
 | |
|     xfree( newColors );
 | |
| }
 | |
| 
 | |
| 
 | |
| /*
 | |
|  * DarwinModeBell
 | |
|  *  FIXME
 | |
|  */
 | |
| void DarwinModeBell(
 | |
|     int             loud,
 | |
|     DeviceIntPtr    pDevice,
 | |
|     pointer         ctrl,
 | |
|     int             fbclass)
 | |
| {
 | |
| }
 | |
| 
 | |
| 
 | |
| /*
 | |
|  * DarwinModeGiveUp
 | |
|  *  Closes the connections to IOKit services
 | |
|  */
 | |
| void DarwinModeGiveUp( void )
 | |
| {
 | |
|     int i;
 | |
| 
 | |
|     // we must close the HID System first
 | |
|     // because it is a client of the framebuffer
 | |
|     NXCloseEventStatus( darwinParamConnect );
 | |
|     IOServiceClose( xfIOKitInputConnect );
 | |
|     for (i = 0; i < screenInfo.numScreens; i++) {
 | |
|         XFIOKitScreenPtr iokitScreen =
 | |
|                             XFIOKIT_SCREEN_PRIV(screenInfo.screens[i]);
 | |
|         IOServiceClose( iokitScreen->fbService );
 | |
|     }
 | |
| }
 | |
| 
 | |
| 
 | |
| /*
 | |
|  * ClearEvent
 | |
|  *  Clear an event from the HID System event queue
 | |
|  */
 | |
| static void ClearEvent(NXEvent * ep)
 | |
| {
 | |
|     static NXEvent nullEvent = {NX_NULLEVENT, {0, 0 }, 0, -1, 0 };
 | |
| 
 | |
|     *ep = nullEvent;
 | |
|     ep->data.compound.subType = ep->data.compound.misc.L[0] =
 | |
|                                 ep->data.compound.misc.L[1] = 0;
 | |
| }
 | |
| 
 | |
| 
 | |
| /*
 | |
|  * XFIOKitHIDThread
 | |
|  *  Read the HID System event queue, translate it to an X event,
 | |
|  *  and queue it for processing.
 | |
|  */
 | |
| static void *XFIOKitHIDThread(void *unused)
 | |
| {
 | |
|     for (;;) {
 | |
|         NXEQElement             *oldHead;
 | |
|         mach_msg_return_t       kr;
 | |
|         mach_msg_empty_rcv_t    msg;
 | |
| 
 | |
|         kr = mach_msg((mach_msg_header_t*) &msg, MACH_RCV_MSG, 0,
 | |
|                       sizeof(msg), notificationPort, 0, MACH_PORT_NULL);
 | |
|         kern_assert(kr);
 | |
| 
 | |
|         while (evg->LLEHead != evg->LLETail) {
 | |
|             NXEvent ev;
 | |
|             xEvent xe;
 | |
| 
 | |
|             // Extract the next event from the kernel queue
 | |
|             oldHead = (NXEQElement*)&evg->lleq[evg->LLEHead];
 | |
|             ev_lock(&oldHead->sema);
 | |
|             ev = oldHead->event;
 | |
|             ClearEvent(&oldHead->event);
 | |
|             evg->LLEHead = oldHead->next;
 | |
|             ev_unlock(&oldHead->sema);
 | |
| 
 | |
|             memset(&xe, 0, sizeof(xe));
 | |
| 
 | |
|             // These fields should be filled in for every event
 | |
|             xe.u.keyButtonPointer.rootX = ev.location.x;
 | |
|             xe.u.keyButtonPointer.rootY = ev.location.y;
 | |
|             xe.u.keyButtonPointer.time = GetTimeInMillis();
 | |
| 
 | |
|             switch( ev.type ) {
 | |
|                 case NX_MOUSEMOVED:
 | |
|                     xe.u.u.type = MotionNotify;
 | |
|                     break;
 | |
| 
 | |
|                 case NX_LMOUSEDOWN:
 | |
|                     xe.u.u.type = ButtonPress;
 | |
|                     xe.u.u.detail = 1;
 | |
|                     break;
 | |
| 
 | |
|                 case NX_LMOUSEUP:
 | |
|                     xe.u.u.type = ButtonRelease;
 | |
|                     xe.u.u.detail = 1;
 | |
|                     break;
 | |
| 
 | |
|                 // A newer kernel generates multi-button events with
 | |
|                 // NX_SYSDEFINED. Button 2 isn't handled correctly by
 | |
|                 // older kernels anyway. Just let NX_SYSDEFINED events
 | |
|                 // handle these.
 | |
| #if 0
 | |
|                 case NX_RMOUSEDOWN:
 | |
|                     xe.u.u.type = ButtonPress;
 | |
|                     xe.u.u.detail = 2;
 | |
|                     break;
 | |
| 
 | |
|                 case NX_RMOUSEUP:
 | |
|                     xe.u.u.type = ButtonRelease;
 | |
|                     xe.u.u.detail = 2;
 | |
|                     break;
 | |
| #endif
 | |
| 
 | |
|                 case NX_KEYDOWN:
 | |
|                     xe.u.u.type = KeyPress;
 | |
|                     xe.u.u.detail = ev.data.key.keyCode;
 | |
|                     break;
 | |
| 
 | |
|                 case NX_KEYUP:
 | |
|                     xe.u.u.type = KeyRelease;
 | |
|                     xe.u.u.detail = ev.data.key.keyCode;
 | |
|                     break;
 | |
| 
 | |
|                 case NX_FLAGSCHANGED:
 | |
|                     xe.u.u.type = kXDarwinUpdateModifiers;
 | |
|                     xe.u.clientMessage.u.l.longs0 = ev.flags;
 | |
|                     break;
 | |
| 
 | |
|                 case NX_SYSDEFINED:
 | |
|                     if (ev.data.compound.subType == 7) {
 | |
|                         xe.u.u.type = kXDarwinUpdateButtons;
 | |
|                         xe.u.clientMessage.u.l.longs0 =
 | |
|                                         ev.data.compound.misc.L[0];
 | |
|                         xe.u.clientMessage.u.l.longs1 =
 | |
|                                         ev.data.compound.misc.L[1];
 | |
|                     } else {
 | |
|                         continue;
 | |
|                     }
 | |
|                     break;
 | |
| 
 | |
|                 case NX_SCROLLWHEELMOVED:
 | |
|                     xe.u.u.type = kXDarwinScrollWheel;
 | |
|                     xe.u.clientMessage.u.s.shorts0 =
 | |
|                                     ev.data.scrollWheel.deltaAxis1;
 | |
|                     break;
 | |
| 
 | |
|                 default:
 | |
|                     continue;
 | |
|             }
 | |
| 
 | |
|             DarwinEQEnqueue(&xe);
 | |
|         }
 | |
|     }
 | |
| 
 | |
|     return NULL;
 | |
| }
 | |
| 
 | |
| 
 | |
| /*
 | |
|  * XFIOKitPMThread
 | |
|  *  Handle power state notifications
 | |
|  */
 | |
| static void *XFIOKitPMThread(void *arg)
 | |
| {
 | |
|     ScreenPtr pScreen = (ScreenPtr)arg;
 | |
|     XFIOKitScreenPtr iokitScreen = XFIOKIT_SCREEN_PRIV(pScreen);
 | |
| 
 | |
|     for (;;) {
 | |
|         mach_msg_return_t       kr;
 | |
|         mach_msg_empty_rcv_t    msg;
 | |
| 
 | |
|         kr = mach_msg((mach_msg_header_t*) &msg, MACH_RCV_MSG, 0,
 | |
|                       sizeof(msg), pmNotificationPort, 0, MACH_PORT_NULL);
 | |
|         kern_assert(kr);
 | |
| 
 | |
|         // display is powering down
 | |
|         if (msg.header.msgh_id == 0) {
 | |
|             IOFBAcknowledgePM( iokitScreen->fbService );
 | |
|             xf86SetRootClip(pScreen, FALSE);
 | |
|         }
 | |
|         // display just woke up
 | |
|         else if (msg.header.msgh_id == 1) {
 | |
|             xf86SetRootClip(pScreen, TRUE);
 | |
|         }
 | |
|     }
 | |
|     return NULL;
 | |
| }
 | |
| 
 | |
| 
 | |
| /*
 | |
|  * SetupFBandHID
 | |
|  *  Setup an IOFramebuffer service and connect the HID system to it.
 | |
|  */
 | |
| static Bool SetupFBandHID(
 | |
|     int                    index,
 | |
|     DarwinFramebufferPtr   dfb,
 | |
|     XFIOKitScreenPtr       iokitScreen)
 | |
| {
 | |
|     kern_return_t           kr;
 | |
|     io_service_t            service;
 | |
|     io_connect_t            fbService;
 | |
|     vm_address_t            vram;
 | |
|     vm_size_t               shmemSize;
 | |
|     int                     i;
 | |
|     UInt32                  numModes;
 | |
|     IODisplayModeInformation modeInfo;
 | |
|     IODisplayModeID         displayMode, *allModes;
 | |
|     IOIndex                 displayDepth;
 | |
|     IOFramebufferInformation fbInfo;
 | |
|     IOPixelInformation      pixelInfo;
 | |
|     StdFBShmem_t            *cshmem;
 | |
| 
 | |
|     // find and open the IOFrameBuffer service
 | |
|     service = IOIteratorNext(fbIter);
 | |
|     if (service == 0)
 | |
|         return FALSE;
 | |
| 
 | |
|     kr = IOServiceOpen( service, mach_task_self(),
 | |
|                         kIOFBServerConnectType, &iokitScreen->fbService );
 | |
|     IOObjectRelease( service );
 | |
|     if (kr != KERN_SUCCESS) {
 | |
|         ErrorF("Failed to connect as window server to screen %i.\n", index);
 | |
|         return FALSE;
 | |
|     }
 | |
|     fbService = iokitScreen->fbService;
 | |
| 
 | |
|     // create the slice of shared memory containing cursor state data
 | |
|     kr = IOFBCreateSharedCursor( fbService,
 | |
|                                  kIOFBCurrentShmemVersion,
 | |
|                                  32, 32 );
 | |
|     if (kr != KERN_SUCCESS)
 | |
|         return FALSE;
 | |
| 
 | |
|     // Register for power management events for the framebuffer's device
 | |
|     kr = IOCreateReceivePort(kOSNotificationMessageID, &pmNotificationPort);
 | |
|     kern_assert(kr);
 | |
|     kr = IOConnectSetNotificationPort( fbService, 0,
 | |
|                                        pmNotificationPort, 0 );
 | |
|     if (kr != KERN_SUCCESS) {
 | |
|         ErrorF("Power management registration failed.\n");
 | |
|     }
 | |
| 
 | |
|     // SET THE SCREEN PARAMETERS
 | |
|     // get the current screen resolution, refresh rate and depth
 | |
|     kr = IOFBGetCurrentDisplayModeAndDepth( fbService,
 | |
|                                             &displayMode,
 | |
|                                             &displayDepth );
 | |
|     if (kr != KERN_SUCCESS)
 | |
|         return FALSE;
 | |
| 
 | |
|     // use the current screen resolution if the user
 | |
|     // only wants to change the refresh rate
 | |
|     if (darwinDesiredRefresh != -1 && darwinDesiredWidth == 0) {
 | |
|         kr = IOFBGetDisplayModeInformation( fbService,
 | |
|                                             displayMode,
 | |
|                                             &modeInfo );
 | |
|         if (kr != KERN_SUCCESS)
 | |
|             return FALSE;
 | |
|         darwinDesiredWidth = modeInfo.nominalWidth;
 | |
|         darwinDesiredHeight = modeInfo.nominalHeight;
 | |
|     }
 | |
| 
 | |
|     // use the current resolution and refresh rate
 | |
|     // if the user doesn't have a preference
 | |
|     if (darwinDesiredWidth == 0) {
 | |
| 
 | |
|         // change the pixel depth if desired
 | |
|         if (darwinDesiredDepth != -1) {
 | |
|             kr = IOFBGetDisplayModeInformation( fbService,
 | |
|                                                 displayMode,
 | |
|                                                 &modeInfo );
 | |
|             if (kr != KERN_SUCCESS)
 | |
|                 return FALSE;
 | |
|             if (modeInfo.maxDepthIndex < darwinDesiredDepth) {
 | |
|                 ErrorF("Discarding screen %i:\n", index);
 | |
|                 ErrorF("Current screen resolution does not support desired pixel depth.\n");
 | |
|                 return FALSE;
 | |
|             }
 | |
| 
 | |
|             displayDepth = darwinDesiredDepth;
 | |
|             kr = IOFBSetDisplayModeAndDepth( fbService, displayMode,
 | |
|                                              displayDepth );
 | |
|             if (kr != KERN_SUCCESS)
 | |
|                 return FALSE;
 | |
|         }
 | |
| 
 | |
|     // look for display mode with correct resolution and refresh rate
 | |
|     } else {
 | |
| 
 | |
|         // get an array of all supported display modes
 | |
|         kr = IOFBGetDisplayModeCount( fbService, &numModes );
 | |
|         if (kr != KERN_SUCCESS)
 | |
|             return FALSE;
 | |
|         assert(allModes = (IODisplayModeID *)
 | |
|                 xalloc( numModes * sizeof(IODisplayModeID) ));
 | |
|         kr = IOFBGetDisplayModes( fbService, numModes, allModes );
 | |
|         if (kr != KERN_SUCCESS)
 | |
|             return FALSE;
 | |
| 
 | |
|         for (i = 0; i < numModes; i++) {
 | |
|             kr = IOFBGetDisplayModeInformation( fbService, allModes[i],
 | |
|                                                 &modeInfo );
 | |
|             if (kr != KERN_SUCCESS)
 | |
|                 return FALSE;
 | |
| 
 | |
|             if (modeInfo.flags & kDisplayModeValidFlag &&
 | |
|                 modeInfo.nominalWidth == darwinDesiredWidth &&
 | |
|                 modeInfo.nominalHeight == darwinDesiredHeight) {
 | |
| 
 | |
|                 if (darwinDesiredDepth == -1)
 | |
|                     darwinDesiredDepth = modeInfo.maxDepthIndex;
 | |
|                 if (modeInfo.maxDepthIndex < darwinDesiredDepth) {
 | |
|                     ErrorF("Discarding screen %i:\n", index);
 | |
|                     ErrorF("Desired screen resolution does not support desired pixel depth.\n");
 | |
|                     return FALSE;
 | |
|                 }
 | |
| 
 | |
|                 if ((darwinDesiredRefresh == -1 ||
 | |
|                     (darwinDesiredRefresh << 16) == modeInfo.refreshRate)) {
 | |
|                     displayMode = allModes[i];
 | |
|                     displayDepth = darwinDesiredDepth;
 | |
|                     kr = IOFBSetDisplayModeAndDepth(fbService,
 | |
|                                                     displayMode,
 | |
|                                                     displayDepth);
 | |
|                     if (kr != KERN_SUCCESS)
 | |
|                         return FALSE;
 | |
|                     break;
 | |
|                 }
 | |
|             }
 | |
|         }
 | |
| 
 | |
|         xfree( allModes );
 | |
|         if (i >= numModes) {
 | |
|             ErrorF("Discarding screen %i:\n", index);
 | |
|             ErrorF("Desired screen resolution or refresh rate is not supported.\n");
 | |
|             return FALSE;
 | |
|         }
 | |
|     }
 | |
| 
 | |
|     kr = IOFBGetPixelInformation( fbService, displayMode, displayDepth,
 | |
|                                   kIOFBSystemAperture, &pixelInfo );
 | |
|     if (kr != KERN_SUCCESS)
 | |
|         return FALSE;
 | |
| 
 | |
| #ifdef __i386__
 | |
|     /* x86 in 8bit mode currently needs fixed color map... */
 | |
|     if (pixelInfo.bitsPerComponent == 8 &&
 | |
|         pixelInfo.componentCount == 1)
 | |
|     {
 | |
|         pixelInfo.pixelType = kIOFixedCLUTPixels;
 | |
|     }
 | |
| #endif
 | |
| 
 | |
| #ifdef OLD_POWERBOOK_G3
 | |
|     if (pixelInfo.pixelType == kIOCLUTPixels)
 | |
|         pixelInfo.pixelType = kIOFixedCLUTPixels;
 | |
| #endif
 | |
| 
 | |
|     kr = IOFBGetFramebufferInformationForAperture( fbService,
 | |
|                                                    kIOFBSystemAperture,
 | |
|                                                    &fbInfo );
 | |
|     if (kr != KERN_SUCCESS)
 | |
|         return FALSE;
 | |
| 
 | |
|     // FIXME: 1x1 IOFramebuffers are sometimes used to indicate video
 | |
|     // outputs without a monitor connected to them. Since IOKit Xinerama
 | |
|     // does not really work, this often causes problems on PowerBooks.
 | |
|     // For now we explicitly check and ignore these screens.
 | |
|     if (fbInfo.activeWidth <= 1 || fbInfo.activeHeight <= 1) {
 | |
|         ErrorF("Discarding screen %i:\n", index);
 | |
|         ErrorF("Invalid width or height.\n");
 | |
|         return FALSE;
 | |
|     }
 | |
| 
 | |
|     kr = IOConnectMapMemory( fbService, kIOFBCursorMemory,
 | |
|                              mach_task_self(), (vm_address_t *) &cshmem,
 | |
|                              &shmemSize, kIOMapAnywhere );
 | |
|     if (kr != KERN_SUCCESS)
 | |
|         return FALSE;
 | |
|     iokitScreen->cursorShmem = cshmem;
 | |
| 
 | |
|     kr = IOConnectMapMemory( fbService, kIOFBSystemAperture,
 | |
|                              mach_task_self(), &vram, &shmemSize,
 | |
|                              kIOMapAnywhere );
 | |
|     if (kr != KERN_SUCCESS)
 | |
|         return FALSE;
 | |
| 
 | |
|     iokitScreen->framebuffer = (void*)vram;
 | |
|     dfb->x = cshmem->screenBounds.minx;
 | |
|     dfb->y = cshmem->screenBounds.miny;
 | |
|     dfb->width = fbInfo.activeWidth;
 | |
|     dfb->height = fbInfo.activeHeight;
 | |
|     dfb->pitch = fbInfo.bytesPerRow;
 | |
|     dfb->bitsPerPixel = fbInfo.bitsPerPixel;
 | |
|     dfb->colorBitsPerPixel = pixelInfo.componentCount *
 | |
|                              pixelInfo.bitsPerComponent;
 | |
|     dfb->bitsPerComponent = pixelInfo.bitsPerComponent;
 | |
| 
 | |
|     // allocate shadow framebuffer
 | |
|     iokitScreen->shadowPtr = xalloc(dfb->pitch * dfb->height);
 | |
|     dfb->framebuffer = iokitScreen->shadowPtr;
 | |
| 
 | |
|     // Note: Darwin kIORGBDirectPixels = X TrueColor, not DirectColor
 | |
|     if (pixelInfo.pixelType == kIORGBDirectPixels) {
 | |
|         dfb->colorType = TrueColor;
 | |
|     } else if (pixelInfo.pixelType == kIOCLUTPixels) {
 | |
|         dfb->colorType = PseudoColor;
 | |
|     } else if (pixelInfo.pixelType == kIOFixedCLUTPixels) {
 | |
|         dfb->colorType = StaticColor;
 | |
|     }
 | |
| 
 | |
|     // Inform the HID system that the framebuffer is also connected to it.
 | |
|     kr = IOConnectAddClient( xfIOKitInputConnect, fbService );
 | |
|     kern_assert( kr );
 | |
| 
 | |
|     // We have to have added at least one screen
 | |
|     // before we can enable the cursor.
 | |
|     kr = IOHIDSetCursorEnable(xfIOKitInputConnect, TRUE);
 | |
|     kern_assert( kr );
 | |
| 
 | |
|     return TRUE;
 | |
| }
 | |
| 
 | |
| 
 | |
| /*
 | |
|  * DarwinModeAddScreen
 | |
|  *  IOKit specific initialization for each screen.
 | |
|  */
 | |
| Bool DarwinModeAddScreen(
 | |
|     int index,
 | |
|     ScreenPtr pScreen)
 | |
| {
 | |
|     DarwinFramebufferPtr dfb = SCREEN_PRIV(pScreen);
 | |
|     XFIOKitScreenPtr iokitScreen;
 | |
| 
 | |
|     // allocate space for private per screen storage
 | |
|     iokitScreen = xalloc(sizeof(XFIOKitScreenRec));
 | |
|     XFIOKIT_SCREEN_PRIV(pScreen) = iokitScreen;
 | |
| 
 | |
|     // setup hardware framebuffer
 | |
|     iokitScreen->fbService = 0;
 | |
|     if (! SetupFBandHID(index, dfb, iokitScreen)) {
 | |
|         if (iokitScreen->fbService) {
 | |
|             IOServiceClose(iokitScreen->fbService);
 | |
|         }
 | |
|         return FALSE;
 | |
|     }
 | |
| 
 | |
|     return TRUE;
 | |
| }
 | |
| 
 | |
| 
 | |
| /*
 | |
|  * XFIOKitShadowUpdate
 | |
|  *  Update the damaged regions of the shadow framebuffer on the screen.
 | |
|  */
 | |
| static void XFIOKitShadowUpdate(ScreenPtr pScreen,
 | |
|                                 shadowBufPtr pBuf)
 | |
| {
 | |
|     DarwinFramebufferPtr dfb = SCREEN_PRIV(pScreen);
 | |
|     XFIOKitScreenPtr iokitScreen = XFIOKIT_SCREEN_PRIV(pScreen);
 | |
|     RegionPtr damage = &pBuf->damage;
 | |
|     int numBox = REGION_NUM_RECTS(damage);
 | |
|     BoxPtr pBox = REGION_RECTS(damage);
 | |
|     int pitch = dfb->pitch;
 | |
|     int bpp = dfb->bitsPerPixel/8;
 | |
| 
 | |
|     // Loop through all the damaged boxes
 | |
|     while (numBox--) {
 | |
|         int width, height, offset;
 | |
|         unsigned char *src, *dst;
 | |
| 
 | |
|         width = (pBox->x2 - pBox->x1) * bpp;
 | |
|         height = pBox->y2 - pBox->y1;
 | |
|         offset = (pBox->y1 * pitch) + (pBox->x1 * bpp);
 | |
|         src = iokitScreen->shadowPtr + offset;
 | |
|         dst = iokitScreen->framebuffer + offset;
 | |
| 
 | |
|         while (height--) {
 | |
|             memcpy(dst, src, width);
 | |
|             dst += pitch;
 | |
|             src += pitch;
 | |
|         }
 | |
| 
 | |
|         // Get the next box
 | |
|         pBox++;
 | |
|     }
 | |
| }
 | |
| 
 | |
| 
 | |
| /*
 | |
|  * DarwinModeSetupScreen
 | |
|  *  Finalize IOKit specific initialization of each screen.
 | |
|  */
 | |
| Bool DarwinModeSetupScreen(
 | |
|     int index,
 | |
|     ScreenPtr pScreen)
 | |
| {
 | |
|     DarwinFramebufferPtr dfb = SCREEN_PRIV(pScreen);
 | |
|     pthread_t pmThread;
 | |
| 
 | |
|     // initalize cursor support
 | |
|     if (! XFIOKitInitCursor(pScreen)) {
 | |
|         return FALSE;
 | |
|     }
 | |
| 
 | |
|     // initialize shadow framebuffer support
 | |
|     if (! shadowInit(pScreen, XFIOKitShadowUpdate, NULL)) {
 | |
|         ErrorF("Failed to initalize shadow framebuffer for screen %i.\n",
 | |
|                index);
 | |
|         return FALSE;
 | |
|     }
 | |
| 
 | |
|     // initialize colormap handling as needed
 | |
|     if (dfb->colorType == PseudoColor) {
 | |
|         pScreen->StoreColors = XFIOKitStoreColors;
 | |
|     }
 | |
| 
 | |
|     // initialize power manager handling
 | |
|     pthread_create( &pmThread, NULL, XFIOKitPMThread,
 | |
|                     (void *) pScreen );
 | |
| 
 | |
|     return TRUE;
 | |
| }
 | |
| 
 | |
| 
 | |
| /*
 | |
|  * DarwinModeInitOutput
 | |
|  *  One-time initialization of IOKit output support.
 | |
|  */
 | |
| void DarwinModeInitOutput(
 | |
|     int argc,
 | |
|     char **argv)
 | |
| {
 | |
|     static unsigned long    generation = 0;
 | |
|     kern_return_t           kr;
 | |
|     io_iterator_t           iter;
 | |
|     io_service_t            service;
 | |
|     vm_address_t            shmem;
 | |
|     vm_size_t               shmemSize;
 | |
| 
 | |
|     ErrorF("Display mode: IOKit\n");
 | |
| 
 | |
|     // Allocate private storage for each screen's IOKit specific info
 | |
|     if (generation != serverGeneration) {
 | |
|         xfIOKitScreenIndex = AllocateScreenPrivateIndex();
 | |
|         generation = serverGeneration;
 | |
|     }
 | |
| 
 | |
|     kr = IOMasterPort(bootstrap_port, &masterPort);
 | |
|     kern_assert( kr );
 | |
| 
 | |
|     // Find and open the HID System Service
 | |
|     // Do this now to be sure the Mac OS X window server is not running.
 | |
|     kr = IOServiceGetMatchingServices( masterPort,
 | |
|                                        IOServiceMatching( kIOHIDSystemClass ),
 | |
|                                        &iter );
 | |
|     kern_assert( kr );
 | |
| 
 | |
|     assert( service = IOIteratorNext( iter ) );
 | |
| 
 | |
|     kr = IOServiceOpen( service, mach_task_self(), kIOHIDServerConnectType,
 | |
|                         &xfIOKitInputConnect );
 | |
|     if (kr != KERN_SUCCESS) {
 | |
|         ErrorF("Failed to connect to the HID System as the window server!\n");
 | |
| #ifdef DARWIN_WITH_QUARTZ
 | |
|         FatalError("Quit the Mac OS X window server or use the -quartz option.\n");
 | |
| #else
 | |
|         FatalError("Make sure you have quit the Mac OS X window server.\n");
 | |
| #endif
 | |
|     }
 | |
| 
 | |
|     IOObjectRelease( service );
 | |
|     IOObjectRelease( iter );
 | |
| 
 | |
|     // Setup the event queue in memory shared by the kernel and X server
 | |
|     kr = IOHIDCreateSharedMemory( xfIOKitInputConnect,
 | |
|                                   kIOHIDCurrentShmemVersion );
 | |
|     kern_assert( kr );
 | |
| 
 | |
|     kr = IOConnectMapMemory( xfIOKitInputConnect, kIOHIDGlobalMemory,
 | |
|                              mach_task_self(), &shmem, &shmemSize,
 | |
|                              kIOMapAnywhere );
 | |
|     kern_assert( kr );
 | |
| 
 | |
|     evg = (EvGlobals *)(shmem + ((EvOffsets *)shmem)->evGlobalsOffset);
 | |
| 
 | |
|     assert(sizeof(EvGlobals) == evg->structSize);
 | |
| 
 | |
|     NotificationPortRef = IONotificationPortCreate( masterPort );
 | |
| 
 | |
|     notificationPort = IONotificationPortGetMachPort(NotificationPortRef);
 | |
| 
 | |
|     kr = IOConnectSetNotificationPort( xfIOKitInputConnect,
 | |
|                                        kIOHIDEventNotification,
 | |
|                                        notificationPort, 0 );
 | |
|     kern_assert( kr );
 | |
| 
 | |
|     evg->movedMask |= NX_MOUSEMOVEDMASK;
 | |
| 
 | |
|     // find number of framebuffers
 | |
|     kr = IOServiceGetMatchingServices( masterPort,
 | |
|                         IOServiceMatching( IOFRAMEBUFFER_CONFORMSTO ),
 | |
|                         &fbIter );
 | |
|     kern_assert( kr );
 | |
| 
 | |
|     darwinScreensFound = 0;
 | |
|     while ((service = IOIteratorNext(fbIter))) {
 | |
|         IOObjectRelease( service );
 | |
|         darwinScreensFound++;
 | |
|     }
 | |
|     IOIteratorReset(fbIter);
 | |
| }
 | |
| 
 | |
| 
 | |
| /*
 | |
|  * DarwinModeInitInput
 | |
|  *  One-time initialization of IOKit input support.
 | |
|  */
 | |
| void DarwinModeInitInput(
 | |
|     int argc,
 | |
|     char **argv)
 | |
| {
 | |
|     kern_return_t           kr;
 | |
|     int                     fd[2];
 | |
| 
 | |
|     kr = IOHIDSetEventsEnable(xfIOKitInputConnect, TRUE);
 | |
|     kern_assert( kr );
 | |
| 
 | |
|     // Start event passing thread
 | |
|     assert( pipe(fd) == 0 );
 | |
|     darwinEventReadFD = fd[0];
 | |
|     darwinEventWriteFD = fd[1];
 | |
|     fcntl(darwinEventReadFD, F_SETFL, O_NONBLOCK);
 | |
|     pthread_create(&inputThread, NULL,
 | |
|                    XFIOKitHIDThread, NULL);
 | |
| 
 | |
| }
 | |
| 
 | |
| 
 | |
| /*
 | |
|  * DarwinModeProcessEvent
 | |
|  *  Process IOKit specific events.
 | |
|  */
 | |
| void DarwinModeProcessEvent(
 | |
|     xEvent *xe)
 | |
| {
 | |
|     // No mode specific events
 | |
|     ErrorF("Unknown X event caught: %d\n", xe->u.u.type);
 | |
| }
 |