Annotation of driverkit/libDriver/Kernel/EventDriver.m, revision 1.1

1.1     ! root        1: /*
        !             2:  * Copyright (c) 1999 Apple Computer, Inc. All rights reserved.
        !             3:  *
        !             4:  * @APPLE_LICENSE_HEADER_START@
        !             5:  * 
        !             6:  * Portions Copyright (c) 1999 Apple Computer, Inc.  All Rights
        !             7:  * Reserved.  This file contains Original Code and/or Modifications of
        !             8:  * Original Code as defined in and that are subject to the Apple Public
        !             9:  * Source License Version 1.1 (the "License").  You may not use this file
        !            10:  * except in compliance with the License.  Please obtain a copy of the
        !            11:  * License at http://www.apple.com/publicsource and read it before using
        !            12:  * this file.
        !            13:  * 
        !            14:  * The Original Code and all software distributed under the License are
        !            15:  * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
        !            16:  * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
        !            17:  * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
        !            18:  * FITNESS FOR A PARTICULAR PURPOSE OR NON- INFRINGEMENT.  Please see the
        !            19:  * License for the specific language governing rights and limitations
        !            20:  * under the License.
        !            21:  * 
        !            22:  * @APPLE_LICENSE_HEADER_END@
        !            23:  */
        !            24: /*     Copyright (c) 1992 NeXT Computer, Inc.  All rights reserved. 
        !            25:  *
        !            26:  * EventDriver.m - Event System module, ObjC implementation.
        !            27:  *
        !            28:  *             The EventDriver is a pseudo-device driver.
        !            29:  *
        !            30:  * HISTORY
        !            31:  * 31-Mar-92    Mike Paquette at NeXT 
        !            32:  *      Created. 
        !            33:  * 4  Aug 1993   Erik Kay at NeXT
        !            34:  *     minor API cleanup
        !            35:  */
        !            36: 
        !            37: #import <driverkit/generalFuncs.h>
        !            38: #import <machkit/NXLock.h>
        !            39: #import <driverkit/Device_ddm.h>
        !            40: #import <driverkit/kernelDriver.h>
        !            41: #import <mach/notify.h>
        !            42: #import <bsd/dev/evio.h>
        !            43: #import <kern/queue.h>
        !            44: #import <bsd/dev/machine/ev_private.h> /* Per-machine configuration info */
        !            45: #import <driverkit/EventDriver.h>
        !            46: #import <driverkit/EventInput.h>
        !            47: #import <bsd/dev/evsio.h>
        !            48: 
        !            49: #define EVSRC_PRINT    0
        !            50: #if    EVSRC_PRINT
        !            51: #undef xpr_evsrc
        !            52: #define xpr_evsrc(x,a,b,c,d,e) printf(x,a,b,c,d,e)
        !            53: #endif EVSRC_PRINT
        !            54: 
        !            55: static EventDriver *evInstance = (EventDriver *)nil;
        !            56: static volatile void EventListener(EventDriver *inst);
        !            57: 
        !            58: typedef void * kern_port_t;
        !            59: #define KERN_PORT_NULL ((kern_port_t) 0)
        !            60: 
        !            61: /*
        !            62:  * Template for evIoOpMsg.
        !            63:  */
        !            64: static evIoOpMsg opMsgTemplate = {
        !            65: 
        !            66:         {                                              // header 
        !            67:                 0,                                     // msg_unused 
        !            68:                 1,                                     // msg_simple 
        !            69:                 sizeof(evIoOpMsg),                     // msg_size 
        !            70:                 MSG_TYPE_NORMAL,                       // msg_type 
        !            71:                 PORT_NULL,                             // msg_local_port 
        !            72:                 PORT_NULL,                             // msg_remote_port - TO
        !            73:                                                         // BE FILLED IN 
        !            74:                 (int)EV_IO_OP_MSG_ID                   // msg_id 
        !            75:         },
        !            76:         {                                              // type 
        !            77:                 MSG_TYPE_UNSTRUCTURED,                 // msg_type_name 
        !            78:                 sizeof(evIoOpBuf) * 8,                 // msg_type_size 
        !            79:                 1,                                     // msg_type_number 
        !            80:                 1,                                     // msg_type_inline 
        !            81:                 0,                                     // msg_type_longform 
        !            82:                 0,                                     // msg_type_deallocate 
        !            83:                 0                                      // msg_type_unused
        !            84:         },
        !            85:         { 0 }                                          /* evIoOpBuf - TO BE 
        !            86:                                                         * FILLED IN */
        !            87: };
        !            88: 
        !            89: static void nsecs_to_packed_ns(ns_time_t *nsecs, unsigned int *pnsecs)
        !            90: {
        !            91:        _NX_packed_time_t data;
        !            92:        int i;
        !            93: 
        !            94:        data.tval = *nsecs;     // nsecs to ns_time_t
        !            95:        for ( i = 0; i < EVS_PACKED_TIME_SIZE; ++i )
        !            96:                pnsecs[i] = data.itval[i];
        !            97: }
        !            98: 
        !            99: static void packed_nsecs_to_nsecs(unsigned int *pnsecs, ns_time_t *nsecs)
        !           100: {
        !           101:        _NX_packed_time_t data;
        !           102:        int i;
        !           103: 
        !           104:        for ( i = 0; i < EVS_PACKED_TIME_SIZE; ++i )
        !           105:                data.itval[i] = pnsecs[i];
        !           106:        *nsecs = data.tval;
        !           107: }
        !           108: 
        !           109: @implementation EventDriver: IODevice
        !           110: 
        !           111: /* Probe routine for a pseudo-device driver. */
        !           112: + (BOOL)probe : deviceDescription
        !           113: {      
        !           114:        if ( evInstance != nil )
        !           115:                return YES;
        !           116: 
        !           117:        evInstance = [self alloc];
        !           118:        /*
        !           119:         * Take care of private stuff...
        !           120:         */
        !           121:        evInstance->devicePort = PORT_NULL;
        !           122:        [evInstance setUnit:0];
        !           123:        [evInstance setName:"event0"];
        !           124:        [evInstance setDeviceKind:"event"];
        !           125:        
        !           126:        return ([evInstance init] ? YES : NO);
        !           127: }
        !           128: 
        !           129: + (IODeviceStyle)deviceStyle
        !           130: {
        !           131:        return IO_PseudoDevice;
        !           132: }
        !           133: 
        !           134: /* subclass specific methods */
        !           135: 
        !           136: /* Return the current instance of the EventDriver, or nil if none. */
        !           137: + instance
        !           138: {
        !           139:        return (id)evInstance;
        !           140: }
        !           141: 
        !           142: /*
        !           143:  * Perform reusable initialization actions here.
        !           144:  */
        !           145: - init
        !           146: {
        !           147:        kern_return_t krtn;
        !           148:        IOReturn drtn;
        !           149:        IOThread thread;
        !           150: #ifdef KERNEL
        !           151:        extern kern_port_t ev_port_list[];
        !           152: #endif
        !           153:        
        !           154:        driverLock = [NXLock new];      // Event driver data protection lock
        !           155:        eventSrcListLock = [NXLock new];
        !           156:        kickConsumerLock = [NXLock new];
        !           157: 
        !           158:        /*
        !           159:         * Set up the ports we'll be using.
        !           160:         */
        !           161:        krtn = port_allocate(task_self(), &ev_port);
        !           162:        if(krtn) {
        !           163:                xpr_err("Ev init: port_allocate returned %d\n", krtn, 2,3,4,5);
        !           164:                return nil;
        !           165:        }
        !           166: 
        !           167:        krtn = port_allocate(task_self(), &evs_port);
        !           168:        if(krtn) {
        !           169:                xpr_err("Ev init: port_allocate returned %d\n", krtn, 2,3,4,5);
        !           170:                return nil;
        !           171:        }
        !           172:        krtn = port_allocate(task_self(), &notify_port);
        !           173:        if(krtn) {
        !           174:                xpr_err("Ev init: port_allocate returned %d\n", krtn, 2,3,4,5);
        !           175:                return nil;
        !           176:        }
        !           177: #ifdef KERNEL
        !           178:        /*
        !           179:         * Get a kern_port_t version of same for use with 
        !           180:         * msg_send_from_kernel().
        !           181:         */
        !           182:        ev_port_list[0] = (kern_port_t)IOGetKernPort(ev_port);
        !           183:        ev_port_list[1] = (kern_port_t)IOGetKernPort(evs_port);
        !           184:        notify_kern_port = IOGetKernPort(notify_port);
        !           185: #endif KERNEL
        !           186:        krtn = port_set_allocate(task_self(), &ev_port_set);
        !           187:        if(krtn) {
        !           188:                xpr_err("adbInit: port_set_allocate returned %d\n", 
        !           189:                        krtn, 2,3,4,5);
        !           190:                return nil;
        !           191:        }
        !           192:        krtn = port_set_add(task_self(), ev_port_set, ev_port);
        !           193:        if(krtn) {
        !           194:                xpr_err("Ev init: port_set_add returned %d\n", krtn, 2,3,4,5);
        !           195:                return nil;
        !           196:        }
        !           197:        krtn = port_set_add(task_self(), ev_port_set, evs_port);
        !           198:        if(krtn) {
        !           199:                xpr_err("Ev init: port_set_add returned %d\n", krtn, 2,3,4,5);
        !           200:                return nil;
        !           201:        }
        !           202:        krtn = port_set_add(task_self(), ev_port_set, notify_port);
        !           203:        if(krtn) {
        !           204:                xpr_err("Ev init: port_set_add returned %d\n", krtn, 2,3,4,5);
        !           205:                return nil;
        !           206:        }
        !           207:        
        !           208:        /*
        !           209:         * Initialize the eventSrc list.
        !           210:         */
        !           211:        queue_init(&eventSrcList);
        !           212: 
        !           213:        /*
        !           214:         * Have IODevice do its thing.
        !           215:         */
        !           216:        [super init];
        !           217: 
        !           218:        /* A few details to be set up... */
        !           219:        pointerLoc.x = INIT_CURSOR_X;
        !           220:        pointerLoc.y = INIT_CURSOR_Y;
        !           221: 
        !           222:        /*
        !           223:         * Start up the I/O thread and wait for it to finish 
        !           224:         * initialization via an AIO_PING command.
        !           225:         */
        !           226:        thread = IOForkThread((IOThreadFunc)EventListener, self);
        !           227:        (void) IOSetThreadPolicy(thread, POLICY_FIXEDPRI);
        !           228:        (void) IOSetThreadPriority(thread, 28); /* XXX */
        !           229: 
        !           230:        if ( ! hasRegistered )
        !           231:        {
        !           232:                [self registerDevice];
        !           233:                hasRegistered = YES;
        !           234:        }
        !           235:        return self;
        !           236: }
        !           237: 
        !           238: /*
        !           239:  * Free locally allocated resources, and then ourselves.
        !           240:  */
        !           241: - free
        !           242: {
        !           243:        /* Initiates a normal close if open */
        !           244:        [self evClose:ev_port token:eventPort];
        !           245: 
        !           246:        /*
        !           247:         * Destroy the ports and port set listenerThread is using.
        !           248:         * This will cause it to return from msg_receive() with an
        !           249:         * error.  It should take this as a clue to exit.
        !           250:         */
        !           251:        port_deallocate(task_self(), ev_port);
        !           252:        port_deallocate(task_self(), evs_port);
        !           253:        port_deallocate(task_self(), notify_port);
        !           254:        port_set_deallocate(task_self(), ev_port_set);
        !           255: 
        !           256:        /* Release locally allocated resources */
        !           257:        [eventSrcListLock free];
        !           258:        [driverLock free];
        !           259:        return [super free];
        !           260: }
        !           261: 
        !           262: /*
        !           263:  * Open the driver for business.  This call must be made before
        !           264:  * any other calls to the Event driver.  We can only be opened by
        !           265:  * one user at a time.
        !           266:  */
        !           267: - (IOReturn)evOpen:(port_t)dev_port token:(port_t)event_port
        !           268: {
        !           269:        IOReturn r = IO_R_SUCCESS;
        !           270: 
        !           271:        if ( dev_port != ev_port )
        !           272:                return IO_R_INVALID_ARG;
        !           273: 
        !           274:        [driverLock lock];
        !           275:        
        !           276:        if ( evOpenCalled == YES )
        !           277:        {
        !           278:                r = IO_R_BUSY;
        !           279:                goto done;
        !           280:        }
        !           281:        evOpenCalled = YES;
        !           282: 
        !           283:        if (!evInitialized)
        !           284:        {
        !           285:            evInitialized = YES;
        !           286:            curBright = EV_SCREEN_MAX_BRIGHTNESS; // FIXME: Set from NVRAM?
        !           287:            curVolume = EV_AUDIO_MAX_VOLUME / 2; // FIXME: Set from NVRAM?
        !           288:            // Put code here that is to run on the first open ONLY.
        !           289:        }
        !           290: 
        !           291:        [self setEventPort:event_port];
        !           292:        // Init local state
        !           293:        // IODDMMasks[XPR_EVENTDRIVER_INDEX] |= XPR_EVSRC;
        !           294:        // IODDMMasks[XPR_IODEVICE_INDEX] |= XPR_ADB;
        !           295: done:
        !           296:        [driverLock unlock];
        !           297:        return r;
        !           298: }
        !           299: 
        !           300: - (IOReturn)evClose:(port_t)dev_port token:(port_t)event_port
        !           301: {
        !           302:        [driverLock lock];
        !           303:        if ( evOpenCalled == NO || event_port != eventPort )
        !           304:        {
        !           305:                [driverLock unlock];
        !           306:                return IO_R_INVALID_ARG;
        !           307:        }
        !           308:        // Early close actions here
        !           309:        [self forceAutoDimState:NO];
        !           310:        [self hideCursor];
        !           311: 
        !           312:        [driverLock unlock];
        !           313: 
        !           314:        // Release the input devices.
        !           315:        [self detachEventSources];
        !           316: 
        !           317:        // Tear down the shared memory area if set up
        !           318:        if ( eventsOpen == YES )
        !           319:            [self unmapEventShmem:eventPort];
        !           320: 
        !           321:        [driverLock lock];
        !           322:        // Clear screens registry and related data
        !           323:        if ( evScreen != (void *)0 )
        !           324:        {
        !           325:            IOFree( (void *)evScreen, evScreenSize );
        !           326:            evScreen = (void *)0;
        !           327:            evScreenSize = 0;
        !           328:            screens = 0;
        !           329:            lastShmemPtr = (void *)0;
        !           330:        }
        !           331:        // Remove port notification for the eventPort and clear the port out
        !           332:        [self setEventPort:PORT_NULL];
        !           333: 
        !           334:        // Clear local state to shutdown
        !           335:        evOpenCalled = NO;
        !           336:        [driverLock unlock];
        !           337: 
        !           338:        return IO_R_SUCCESS;
        !           339: }
        !           340: 
        !           341: - (IOReturn)evFrameBufferDevicePort:(port_t)event_port
        !           342:                  unitName:(IOString)name
        !           343:                  unitClass:(IOString)class
        !           344:                  unitPort:(port_t *)port
        !           345: {
        !           346:        id instance;
        !           347:        IOReturn r;
        !           348: 
        !           349:        *port = PORT_NULL;
        !           350:        if ( evOpenCalled == NO || event_port != eventPort )
        !           351:                return IO_R_INVALID_ARG;
        !           352: 
        !           353:        if ( (r = IOGetObjectForDeviceName( name, &instance )) != IO_R_SUCCESS )
        !           354:        {       // Not checked in yet.  Lookup class and force a probe
        !           355:                if ( (instance = objc_getClass(class)) == nil )
        !           356:                    return r;
        !           357:                if ( [instance respondsTo:@selector(probe)] == NO )
        !           358:                    return r;
        !           359:                if ( (instance = [instance probe]) == nil )
        !           360:                    return r;
        !           361:        }
        !           362: 
        !           363:        if ( [instance respondsTo:@selector(devicePort)] == NO )
        !           364:                return IO_R_PRIVILEGE;
        !           365: 
        !           366:        *port = [instance devicePort];
        !           367:        return IO_R_SUCCESS;
        !           368: }
        !           369: 
        !           370: /*
        !           371:  * General get/set parameter methods for use with the
        !           372:  * event system.  These replace the old evs ioctl calls.
        !           373:  *
        !           374:  *     We could wind up not needing any of these, in which case we should
        !           375:  *     toss them out and let inheritance take care of the messages.
        !           376:  */
        !           377: - (IOReturn)getIntValues               : (unsigned *)parameterArray
        !           378:                           forParameter : (IOParameterName)parameterName
        !           379:                                  count : (unsigned *)count;    // in/out
        !           380: {
        !           381:        IOReturn r = IO_R_INVALID_ARG;
        !           382:        IOReturn retval;
        !           383:        attachedEventSrc *device;
        !           384:        id      srcInstance;
        !           385:        ns_time_t       nst;
        !           386:        unsigned        maxCount = *count;
        !           387:        unsigned        returnedCount = 0;
        !           388:        
        !           389:        // Report the ID for the last left/right button down event
        !           390:        if (   strcmp( parameterName, EVIOEVNUM ) == 0 )
        !           391:        {
        !           392:            if ( maxCount >= EVIOEVNUM_SIZE )
        !           393:            {
        !           394:                returnedCount = EVIOEVNUM_SIZE;
        !           395:                [driverLock lock];
        !           396:                parameterArray[EVIOEVNUM_LEFT] = leftENum;
        !           397:                parameterArray[EVIOEVNUM_RIGHT] = rightENum;
        !           398:                [driverLock unlock];
        !           399:                r = IO_R_SUCCESS;
        !           400:            }
        !           401:        }
        !           402:        else if ( strcmp( parameterName, EVIOSHMEMSIZE ) == 0 )
        !           403:        {
        !           404:            if ( maxCount >= EVIOSHMEMSIZE_SIZE )
        !           405:            {
        !           406:                returnedCount = EVIOSHMEMSIZE_SIZE;
        !           407:                parameterArray[0] = shmem_size;
        !           408:                r = IO_R_SUCCESS;
        !           409:            }
        !           410:        }
        !           411:        else if (   strcmp( parameterName, EVSIOCWINFO ) == 0 )
        !           412:        {
        !           413:            if ( maxCount >= EVSIOCWINFO_SIZE )
        !           414:            {
        !           415:                returnedCount = EVSIOCWINFO_SIZE;
        !           416:                [driverLock lock];
        !           417:                if ( eventsOpen == YES )
        !           418:                    nst = EV_TICK_TO_NS(((EvGlobals*)evg)->waitThreshold);
        !           419:                else
        !           420:                    nst = 0ULL;
        !           421:                nsecs_to_packed_ns(&nst,&parameterArray[EVSIOCWINFO_THRESH]);
        !           422:                nsecs_to_packed_ns(&waitSustain,
        !           423:                                &parameterArray[EVSIOCWINFO_SUSTAIN]);
        !           424:                nsecs_to_packed_ns(&waitFrameRate,
        !           425:                                &parameterArray[EVSIOCWINFO_FINTERVAL]);
        !           426:                [driverLock unlock];
        !           427:                r = IO_R_SUCCESS;
        !           428:            }
        !           429:        }
        !           430:        else if (   strcmp( parameterName, EVSIO_DCTLINFO ) == 0 )
        !           431:        {
        !           432:            if ( maxCount >= EVSIO_DCTLINFO_SIZE )
        !           433:            {
        !           434:                returnedCount = EVSIO_DCTLINFO_SIZE;
        !           435:                [driverLock lock];
        !           436:                parameterArray[EVSIO_DCTLINFO_BRIGHT] =
        !           437:                        [self brightness];
        !           438:                // EVSIO_DCTLINFO_ATTEN obsolete once libc-67 is released
        !           439:                parameterArray[EVSIO_DCTLINFO_ATTEN] = curVolume;
        !           440:                parameterArray[EVSIO_DCTLINFO_AUTODIMBRIGHT] =
        !           441:                        [self autoDimBrightness];
        !           442:                [driverLock unlock];
        !           443:                r = IO_R_SUCCESS;
        !           444:            }
        !           445:        }
        !           446:        else if (   strcmp( parameterName, EVSIOCCT ) == 0 )
        !           447:        {
        !           448:            if ( maxCount >= EVSIOCCT_SIZE )
        !           449:            {
        !           450:                returnedCount = EVSIOCCT_SIZE;
        !           451:                [driverLock lock];
        !           452:                nst = EV_TICK_TO_NS(clickTimeThresh);
        !           453:                nsecs_to_packed_ns(&nst,&parameterArray[0]);
        !           454:                [driverLock unlock];
        !           455:                r = IO_R_SUCCESS;
        !           456:            }
        !           457:        }
        !           458:        else if (   strcmp( parameterName, EVSIOCADT ) == 0 )
        !           459:        {
        !           460:            if ( maxCount >= EVSIOCADT_SIZE )
        !           461:            {
        !           462:                returnedCount = EVSIOCADT_SIZE;
        !           463:                [driverLock lock];
        !           464:                nst = EV_TICK_TO_NS(autoDimPeriod);
        !           465:                nsecs_to_packed_ns(&nst,&parameterArray[0]);
        !           466:                [driverLock unlock];
        !           467:                r = IO_R_SUCCESS;
        !           468:            }
        !           469:        }
        !           470:        else if (   strcmp( parameterName, EVSIOGDADT ) == 0 )
        !           471:        {
        !           472:            if ( maxCount >= EVSIOGDADT_SIZE )
        !           473:            {
        !           474:                returnedCount = EVSIOGDADT_SIZE;
        !           475:                [driverLock lock];
        !           476:                if ( eventsOpen == YES )
        !           477:                {
        !           478:                    if ( autoDimmed )
        !           479:                        nst = EV_TICK_TO_NS(0);
        !           480:                    else
        !           481:                        nst = EV_TICK_TO_NS(autoDimTime -
        !           482:                                        ((EvGlobals*)evg)->VertRetraceClock);
        !           483:                }
        !           484:                else
        !           485:                    nst = EV_TICK_TO_NS(autoDimPeriod);
        !           486:                nsecs_to_packed_ns(&nst,&parameterArray[0]);
        !           487:                [driverLock unlock];
        !           488:                r = IO_R_SUCCESS;
        !           489:            }
        !           490:        }
        !           491:        // added april 7, 1994 EK - to fix bug 41768
        !           492:        else if (   strcmp( parameterName, EVSIOIDLE ) == 0 )
        !           493:        {
        !           494:            if (maxCount >= EVSIOIDLE_SIZE)
        !           495:            {
        !           496:                returnedCount = EVSIOIDLE_SIZE;
        !           497:                [driverLock lock];
        !           498:                if (eventsOpen == YES)
        !           499:                {
        !           500:                    if (autoDimmed)
        !           501:                        nst = EV_TICK_TO_NS(((EvGlobals*)evg)->VertRetraceClock 
        !           502:                                        - (autoDimTime - autoDimPeriod));
        !           503:                    else
        !           504:                        nst = EV_TICK_TO_NS(autoDimPeriod - (autoDimTime -
        !           505:                                        ((EvGlobals*)evg)->VertRetraceClock));
        !           506:                }
        !           507:                else
        !           508:                    nst = EV_TICK_TO_NS(0); // user is active
        !           509:                nsecs_to_packed_ns(&nst,&parameterArray[0]);
        !           510:                [driverLock unlock];
        !           511:                r = IO_R_SUCCESS;
        !           512:            }
        !           513:        }
        !           514:        else if (   strcmp( parameterName, EVSIOCCS ) == 0 )
        !           515:        {
        !           516:            if ( maxCount >= EVSIOCCS_SIZE )
        !           517:            {
        !           518:                returnedCount = EVSIOCCS_SIZE;
        !           519:                [driverLock lock];
        !           520:                parameterArray[EVSIOCCS_X] = clickSpaceThresh.x;
        !           521:                parameterArray[EVSIOCCS_Y] = clickSpaceThresh.y;
        !           522:                [driverLock unlock];
        !           523:                r = IO_R_SUCCESS;
        !           524:            }
        !           525:        }
        !           526:        else if (   strcmp( parameterName, EVSIOCADS ) == 0 )
        !           527:        {
        !           528:            if ( maxCount >= EVSIOCADS_SIZE )
        !           529:            {
        !           530:                returnedCount = EVSIOCADS_SIZE;
        !           531:                [driverLock lock];
        !           532:                parameterArray[0] = autoDimmed;
        !           533:                [driverLock unlock];
        !           534:                r = IO_R_SUCCESS;
        !           535:            }
        !           536:        }
        !           537:        else if (   strcmp( parameterName, EVSIOINFO ) == 0 )
        !           538:        {
        !           539:            NXEventSystemDevice dp;
        !           540:            unsigned int cnt;
        !           541: 
        !           542:            [eventSrcListLock lock];
        !           543:            device = (attachedEventSrc *)queue_first(&eventSrcList);
        !           544:            while( ! queue_end(&eventSrcList, (queue_t)device)
        !           545:                  && maxCount >= (sizeof(NXEventSystemDevice) / sizeof(int)) )
        !           546:            {
        !           547:                srcInstance = device->info.eventSrc;
        !           548:                device = (attachedEventSrc *)device->link.next;
        !           549:                cnt = 0;
        !           550:                retval = [srcInstance 
        !           551:                            getIntValues:&parameterArray[returnedCount]
        !           552:                           forParameter : parameterName
        !           553:                                  count : &cnt];
        !           554:                if ( retval == IO_R_SUCCESS )
        !           555:                {
        !           556:                        maxCount -= cnt;
        !           557:                        returnedCount += cnt;
        !           558:                }
        !           559:            }
        !           560:            [eventSrcListLock unlock];
        !           561:            r = IO_R_SUCCESS;
        !           562: 
        !           563:        }
        !           564:        else
        !           565:        {
        !           566:            // Try sending the operation out to the attached
        !           567:            // event sources.
        !           568:            returnedCount = *count;
        !           569:            [eventSrcListLock lock];
        !           570:            device = (attachedEventSrc *)queue_first(&eventSrcList);
        !           571:            while(!queue_end(&eventSrcList, (queue_t)device))
        !           572:            {
        !           573:                srcInstance = device->info.eventSrc;
        !           574:                device = (attachedEventSrc *)device->link.next;
        !           575:                retval = [srcInstance getIntValues:parameterArray
        !           576:                                    forParameter:parameterName
        !           577:                                    count:&returnedCount];
        !           578:                if ( retval != IO_R_INVALID_ARG )
        !           579:                {
        !           580:                    r = retval;
        !           581:                    break;
        !           582:                }
        !           583:            }
        !           584:            [eventSrcListLock unlock];
        !           585: 
        !           586:            if ( r == IO_R_INVALID_ARG )
        !           587:            {
        !           588:                r = [super getIntValues:parameterArray
        !           589:                           forParameter : parameterName
        !           590:                                  count : &returnedCount];
        !           591:            }
        !           592:        }
        !           593:        *count = returnedCount;
        !           594:        return r;
        !           595: }
        !           596: 
        !           597: - (IOReturn)getCharValues              : (unsigned char *)parameterArray
        !           598:                           forParameter : (IOParameterName)parameterName
        !           599:                                  count : (unsigned *)count
        !           600: {
        !           601:        IOReturn r = IO_R_INVALID_ARG;
        !           602:        IOReturn retval;
        !           603:        attachedEventSrc *device;
        !           604:        id      srcInstance;
        !           605:        unsigned maxCount = *count;
        !           606:        unsigned returnedCount = 0;
        !           607:        
        !           608:        if ( 0 )
        !           609:        {
        !           610:        }
        !           611:        else
        !           612:        {
        !           613:                // Try sending the operation out to the attached
        !           614:                // event sources.
        !           615:                returnedCount = *count;
        !           616:                [eventSrcListLock lock];
        !           617:                device = (attachedEventSrc *)queue_first(&eventSrcList);
        !           618:                while(!queue_end(&eventSrcList, (queue_t)device))
        !           619:                {
        !           620:                        srcInstance = device->info.eventSrc;
        !           621:                        device = (attachedEventSrc *)device->link.next;
        !           622:                        retval = [srcInstance getCharValues:parameterArray
        !           623:                                            forParameter:parameterName
        !           624:                                            count:&returnedCount];
        !           625:                        if ( retval != IO_R_INVALID_ARG )
        !           626:                        {
        !           627:                                r = retval;
        !           628:                                break;
        !           629:                        }
        !           630:                }
        !           631:                [eventSrcListLock unlock];
        !           632: 
        !           633:                if ( r == IO_R_INVALID_ARG )
        !           634:                {
        !           635:                        r = [super getCharValues:parameterArray
        !           636:                           forParameter : parameterName
        !           637:                                  count : &returnedCount];
        !           638:                }
        !           639:        }
        !           640:        *count = returnedCount;
        !           641:        return r;
        !           642: }
        !           643: 
        !           644:                
        !           645: - (IOReturn)setIntValues               : (unsigned *)parameterArray
        !           646:                           forParameter : (IOParameterName)parameterName
        !           647:                                  count : (unsigned)count;
        !           648: {
        !           649:        IOReturn r = IO_R_INVALID_ARG;
        !           650:        IOReturn retval;
        !           651:        attachedEventSrc *device;
        !           652:        id      srcInstance;
        !           653:        Point           p;
        !           654:        _NX_packed_event_t event;
        !           655:        ns_time_t nst;
        !           656: 
        !           657:        if ( strcmp( parameterName, EVIOSETSCREEN ) == 0 )
        !           658:        {
        !           659:                if ( count == EVIOSETSCREEN_SIZE )
        !           660:                    r = [self evSetScreen:parameterArray];
        !           661:        }
        !           662:        else if ( strcmp( parameterName, EVIOST ) == 0 )
        !           663:        {
        !           664:                [self startCursor];
        !           665:                r = IO_R_SUCCESS;
        !           666:        }
        !           667:        else if ( strcmp( parameterName, EVIOSM ) == 0 )
        !           668:        {
        !           669:                if ( count == EVIOSM_SIZE )
        !           670:                {
        !           671:                        p.x = parameterArray[EVIOSM_LOC_X];
        !           672:                        p.y = parameterArray[EVIOSM_LOC_Y];
        !           673:                        [driverLock lock];
        !           674:                        [self setCursorPosition:&p];
        !           675:                        [driverLock unlock];
        !           676:                        r = IO_R_SUCCESS;
        !           677:                }
        !           678:        }
        !           679:        else if ( strcmp( parameterName, EVSIOSWT ) == 0 )
        !           680:        {
        !           681:                packed_nsecs_to_nsecs(parameterArray, &nst);            
        !           682:                [driverLock lock];
        !           683:                if ( eventsOpen )
        !           684:                        ((EvGlobals*)evg)->waitThreshold = EV_NS_TO_TICK(nst);
        !           685:                [driverLock unlock];
        !           686:                r = IO_R_SUCCESS;
        !           687:        }
        !           688:        else if ( strcmp( parameterName, EVSIOSWS ) == 0 )
        !           689:        {
        !           690:                [driverLock lock];
        !           691:                packed_nsecs_to_nsecs(parameterArray, &waitSustain);            
        !           692:                [driverLock unlock];
        !           693:                r = IO_R_SUCCESS;
        !           694:        }
        !           695:        else if ( strcmp( parameterName, EVSIOSWFI ) == 0 )
        !           696:        {
        !           697:                [driverLock lock];
        !           698:                packed_nsecs_to_nsecs(parameterArray, &waitFrameRate);          
        !           699:                [driverLock unlock];
        !           700:                r = IO_R_SUCCESS;
        !           701:        }
        !           702:        else if ( strcmp( parameterName, EVSIOSB ) == 0 )
        !           703:        {
        !           704:                [driverLock lock];
        !           705:                [self setBrightness:parameterArray[0]];
        !           706:                [driverLock unlock];
        !           707:                r = IO_R_SUCCESS;
        !           708:        }
        !           709:        else if ( strcmp( parameterName, EVSIOSA ) == 0 )
        !           710:        {       // Obsolete once libc-67 is released
        !           711:                [driverLock lock];
        !           712:                [self setUserAudioVolume:parameterArray[0]];
        !           713:                [driverLock unlock];
        !           714:                r = IO_R_SUCCESS;
        !           715:        }
        !           716:        else if ( strcmp( parameterName, EVSIOSADB ) == 0 )
        !           717:        {
        !           718:                [driverLock lock];
        !           719:                [self setAutoDimBrightness:parameterArray[0]];
        !           720:                [driverLock unlock];
        !           721:                r = IO_R_SUCCESS;
        !           722:        }
        !           723:        else if ( strcmp( parameterName, EVSIOSCT ) == 0 )
        !           724:        {
        !           725:                packed_nsecs_to_nsecs(parameterArray, &nst);            
        !           726:                [driverLock lock];
        !           727:                clickTimeThresh = EV_NS_TO_TICK(nst);
        !           728:                [driverLock unlock];
        !           729:                r = IO_R_SUCCESS;
        !           730:        }
        !           731:        else if ( strcmp( parameterName, EVSIOSCS ) == 0 )
        !           732:        {
        !           733:                [driverLock lock];
        !           734:                clickSpaceThresh.x = parameterArray[EVSIOSCS_X];
        !           735:                clickSpaceThresh.y = parameterArray[EVSIOSCS_Y];
        !           736:                [driverLock unlock];
        !           737:                r = IO_R_SUCCESS;
        !           738:        }
        !           739:        else if ( strcmp( parameterName, EVSIOSADT ) == 0 )
        !           740:        {
        !           741:                packed_nsecs_to_nsecs(parameterArray, &nst);            
        !           742:                [driverLock lock];
        !           743:                autoDimTime = autoDimTime - autoDimPeriod + EV_NS_TO_TICK(nst);
        !           744:                autoDimPeriod = EV_NS_TO_TICK(nst);
        !           745:                [driverLock unlock];
        !           746:                r = IO_R_SUCCESS;
        !           747:        }
        !           748:        else if ( strcmp( parameterName, EVSIOSADS ) == 0 )
        !           749:        {
        !           750:                [driverLock lock];
        !           751:                [self forceAutoDimState:parameterArray[0]];
        !           752:                [driverLock unlock];
        !           753:                r = IO_R_SUCCESS;
        !           754:        }
        !           755:        else if ( strcmp( parameterName, EVSIORMS ) == 0 )
        !           756:        {
        !           757:                [self _resetMouseParameters];
        !           758:                r = IO_R_SUCCESS;
        !           759:        }
        !           760:        else if ( strcmp( parameterName, EVSIORKBD ) == 0 )
        !           761:        {
        !           762:                [self _resetKeyboardParameters];
        !           763:                r = IO_R_SUCCESS;
        !           764:        }
        !           765:        else if (  strcmp( parameterName, EVIOLLPE ) == 0 
        !           766:                || strcmp( parameterName, EVIOPTRLLPE ) == 0 )
        !           767:        {
        !           768:                if ( count == EVIOLLPE_SIZE )
        !           769:                {
        !           770:                        p.x = parameterArray[EVIOLLPE_LOC_X];
        !           771:                        p.y = parameterArray[EVIOLLPE_LOC_Y];
        !           772:                        event.idata[0] = parameterArray[EVIOLLPE_DATA0];
        !           773:                        event.idata[1] = parameterArray[EVIOLLPE_DATA1];
        !           774:                        event.idata[2] = parameterArray[EVIOLLPE_DATA2];
        !           775:                        [driverLock lock];
        !           776:                        if ( strcmp( parameterName, EVIOPTRLLPE ) == 0 )
        !           777:                                [self setCursorPosition:&p];
        !           778:                        [self postEvent:parameterArray[EVIOLLPE_TYPE]
        !           779:                                at:&p
        !           780:                                atTime:EvTickTimeValue()
        !           781:                                withData:&event.data];          
        !           782:                        [driverLock unlock];
        !           783:                        r = IO_R_SUCCESS;
        !           784:                }
        !           785:        }
        !           786:        else
        !           787:        {
        !           788:                // Try sending the operation out to the attached
        !           789:                // event sources.
        !           790:                [eventSrcListLock lock];
        !           791:                device = (attachedEventSrc *)queue_first(&eventSrcList);
        !           792:                while(!queue_end(&eventSrcList, (queue_t)device))
        !           793:                {
        !           794:                        srcInstance = device->info.eventSrc;
        !           795:                        device = (attachedEventSrc *)device->link.next;
        !           796:                        retval = [srcInstance setIntValues:parameterArray
        !           797:                                            forParameter:parameterName
        !           798:                                            count:count];
        !           799:                        if ( retval != IO_R_INVALID_ARG )
        !           800:                                r = retval;
        !           801:                }
        !           802:                [eventSrcListLock unlock];
        !           803: 
        !           804:                // Nobody wants it?  Kick the message upstairs.
        !           805:                if ( r == IO_R_INVALID_ARG )
        !           806:                {
        !           807:                        r = [super setIntValues:parameterArray
        !           808:                                            forParameter:parameterName
        !           809:                                            count:count];
        !           810:                }
        !           811:        }
        !           812:        return r;
        !           813: }
        !           814: 
        !           815: - (IOReturn)setCharValues              : (unsigned char *)parameterArray
        !           816:                           forParameter : (IOParameterName)parameterName
        !           817:                                  count : (unsigned)count;
        !           818: {
        !           819:        IOReturn r = IO_R_INVALID_ARG;
        !           820:        IOReturn retval;
        !           821:        attachedEventSrc *device;
        !           822:        id      srcInstance;
        !           823: 
        !           824:        if ( 0 )
        !           825:        {
        !           826:        }
        !           827:        else
        !           828:        {
        !           829:                // Try sending the operation out to the attached
        !           830:                // event sources.
        !           831:                [eventSrcListLock lock];
        !           832:                device = (attachedEventSrc *)queue_first(&eventSrcList);
        !           833:                while(!queue_end(&eventSrcList, (queue_t)device))
        !           834:                {
        !           835:                        srcInstance = device->info.eventSrc;
        !           836:                        device = (attachedEventSrc *)device->link.next;
        !           837:                        retval = [srcInstance setCharValues:parameterArray
        !           838:                                                forParameter:parameterName
        !           839:                                                count:count];
        !           840:                        if ( retval != IO_R_INVALID_ARG )
        !           841:                                r = retval;
        !           842:                }
        !           843:                [eventSrcListLock unlock];
        !           844: 
        !           845:                if ( r == IO_R_INVALID_ARG )
        !           846:                {
        !           847:                        r = [super setCharValues: parameterArray
        !           848:                                        forParameter:parameterName
        !           849:                                        count:count];
        !           850:                }
        !           851:        }
        !           852:        return r;
        !           853: }
        !           854: 
        !           855: //
        !           856: // Reset instance variables to their default state for mice/pointers
        !           857: //
        !           858: - _resetMouseParameters
        !           859: {
        !           860:        attachedEventSrc *device;
        !           861:        id      srcInstance;
        !           862:        unsigned int parameterArray[EVSIORMS_SIZE];
        !           863: 
        !           864:        [driverLock lock];
        !           865:        if ( eventsOpen == NO )
        !           866:        {
        !           867:            [driverLock unlock];
        !           868:            return self;
        !           869:        }
        !           870:        clickTimeThresh = EV_DCLICKTIME;
        !           871:        clickSpaceThresh.x = clickSpaceThresh.y = EV_DCLICKSPACE;
        !           872:        clickTime = -EV_DCLICKTIME;
        !           873:        clickLoc.x = clickLoc.y = -EV_DCLICKSPACE;
        !           874:        clickState = 1;
        !           875:        autoDimTime = ((EvGlobals*)evg)->VertRetraceClock + DAUTODIMPERIOD;
        !           876:        autoDimPeriod = DAUTODIMPERIOD;
        !           877:        dimmedBrightness = DDIMBRIGHTNESS;
        !           878: 
        !           879:        [driverLock unlock];
        !           880:        // Go down the Event Src list looking for devices which respond to
        !           881:        // a EVSIORMS message.  Ping these.
        !           882:        [eventSrcListLock lock];
        !           883:        device = (attachedEventSrc *)queue_first(&eventSrcList);
        !           884:        while(!queue_end(&eventSrcList, (queue_t)device))
        !           885:        {
        !           886:                srcInstance = device->info.eventSrc;
        !           887:                device = (attachedEventSrc *)device->link.next;
        !           888:                [srcInstance setIntValues:parameterArray
        !           889:                                    forParameter:EVSIORMS
        !           890:                                    count:EVSIORMS_SIZE];
        !           891:        }
        !           892:        [eventSrcListLock unlock];
        !           893: 
        !           894:        return self;
        !           895: }
        !           896: 
        !           897: - _resetKeyboardParameters
        !           898: {
        !           899:        attachedEventSrc *device;
        !           900:        id      srcInstance;
        !           901:        unsigned int parameterArray[EVSIORKBD_SIZE];
        !           902: 
        !           903:        // Go down the Event Src list looking for devices which respond to
        !           904:        // a EVSIORKBD message.  Ping these.
        !           905:        [eventSrcListLock lock];
        !           906:        device = (attachedEventSrc *)queue_first(&eventSrcList);
        !           907:        while(!queue_end(&eventSrcList, (queue_t)device))
        !           908:        {
        !           909:                srcInstance = device->info.eventSrc;
        !           910:                device = (attachedEventSrc *)device->link.next;
        !           911:                [srcInstance setIntValues:parameterArray
        !           912:                                    forParameter:EVSIORKBD
        !           913:                                    count:EVSIORKBD_SIZE];
        !           914:        }
        !           915:        [eventSrcListLock unlock];
        !           916:        return self;
        !           917: }
        !           918: 
        !           919: /*
        !           920:  * Methods exported by the EventDriver.
        !           921:  *
        !           922:  *     The screenRegister protocol is used by frame buffer drivers to register
        !           923:  *     themselves with the Event Driver.  These methods are called in response
        !           924:  *     to a registerSelf or unregisterSelf message received from the Event
        !           925:  *     Driver.
        !           926:  */
        !           927: /* @protocol screenRegister */
        !           928: 
        !           929: - (int) registerScreen:        (id)instance
        !           930:                bounds:(Bounds *)bp
        !           931:                shmem:(void **)addr
        !           932:                size:(int *)size
        !           933: {
        !           934:     EvScreen *esp;
        !           935: 
        !           936:     if ( eventsOpen == NO )
        !           937:     {
        !           938:        *addr = (void *)0;
        !           939:        *size = 0;
        !           940:        return -1;
        !           941:     }
        !           942:     if ( lastShmemPtr == (void *)0 )
        !           943:        lastShmemPtr = evs;
        !           944:     
        !           945:     /* shmemSize and bounds already set */
        !           946:     esp = &((EvScreen*)evScreen)[screens];
        !           947:     esp->instance = instance;
        !           948:     /* If this driver wants private shmem, then set its shmemPtr */
        !           949:     if (esp->shmemSize)
        !           950:        esp->shmemPtr = lastShmemPtr;
        !           951:     lastShmemPtr += esp->shmemSize;
        !           952:     /* Fill in parameters for the requesting instance */
        !           953:     *addr = esp->shmemPtr;
        !           954:     *size = esp->shmemSize;
        !           955:     bcopy( (char *)&esp->bounds, (char *)bp, sizeof (Bounds) );
        !           956:     return(SCREENTOKEN + screens++);
        !           957: }
        !           958: 
        !           959: 
        !           960: - (void) unregisterScreen:(int)index
        !           961: {
        !           962:     int i;
        !           963: 
        !           964:     index -= SCREENTOKEN;
        !           965: 
        !           966:     [driverLock lock];
        !           967:     if ( eventsOpen == NO || index < 0 || index >= screens )
        !           968:     {
        !           969:        [driverLock unlock];
        !           970:        return;
        !           971:     }
        !           972:     [self hideCursor];
        !           973:     // clear the state for the screen
        !           974:     ((EvScreen*)evScreen)[index].instance = nil;
        !           975:     // Put the cursor someplace reasonable if it was on the destroyed screen
        !           976:     if ( currentScreen == index )      // Uh oh...
        !           977:     {
        !           978:        for ( i = screens; --i != -1; ) // Pick a new currentScreen
        !           979:        {
        !           980:            if ( ((EvScreen*)evScreen)[i].instance != nil )
        !           981:            {
        !           982:                currentScreen = i;
        !           983:                break;
        !           984:            }
        !           985:        }
        !           986:        // This will jump the cursor back on screen
        !           987:        [self setCursorPosition:(Point *)&((EvGlobals*)evg)->cursorLoc];
        !           988:     }
        !           989:     else
        !           990:        [self showCursor];
        !           991:     [driverLock unlock];
        !           992:     return;
        !           993: }
        !           994: 
        !           995: /* @end screenRegister */
        !           996: 
        !           997: /* Private methods specific to this driver */   
        !           998: 
        !           999: #if KERNEL
        !          1000: //
        !          1001: // Allocate a private array of EvScreen structures based on the screen count
        !          1002: // passed in by PostScript and copy in each screen's bounds and shmemSize.
        !          1003: // Also calculate the total size of shared memory and return it to PostScript.
        !          1004: // PostScript will later call mapEventShmem to map in the page(s) at which
        !          1005: // point the ev driver will fill out the EvOffsets structure partly
        !          1006: // based on each driver's shmemSize.  NOTE: Can't access evg pointer yet!
        !          1007: //
        !          1008: 
        !          1009: - (IOReturn)evSetScreen:(unsigned int *)parameterArray
        !          1010: {
        !          1011:     int i = parameterArray[EVIOSETSCREEN_INDEX];
        !          1012:     EvScreen * screen;
        !          1013: 
        !          1014:     if ( evOpenCalled == NO )  // Try to screen out cruft...
        !          1015:        return IO_R_PRIVILEGE;
        !          1016: 
        !          1017:     if (!evScreen) {
        !          1018:        /* if first time through, allocate screen array */
        !          1019:        evScreenSize = sizeof(EvScreen)
        !          1020:                        * parameterArray[EVIOSETSCREEN_TOTALSCREENS];
        !          1021:        evScreen = (void *) IOMalloc(evScreenSize);
        !          1022:        bzero(evScreen, evScreenSize);
        !          1023:        /* The following initial shmem size can change in the kernel if
        !          1024:         * more space is required.  This lets the kernel shmem structure
        !          1025:         * expand if needed without breaking PostScript.
        !          1026:         */
        !          1027:        shmem_size = sizeof(EvGlobals) + sizeof(EvOffsets);
        !          1028:        // Set up screen registration variables
        !          1029:        lastShmemPtr = (void *)0;
        !          1030:        screens = 0;
        !          1031:        workSpace.minx = workSpace.miny = workSpace.maxx = workSpace.maxy = 0;
        !          1032:     }
        !          1033:     if ( i < 0 || i >= (evScreenSize / sizeof(EvScreen)) )     // Sanity check
        !          1034:        return IO_R_INVALID_ARG;
        !          1035:     screen = &((EvScreen*)evScreen)[i];
        !          1036:     screen->bounds.minx = parameterArray[EVIOSETSCREEN_MINX];
        !          1037:     screen->bounds.maxx = parameterArray[EVIOSETSCREEN_MAXX];
        !          1038:     screen->bounds.miny = parameterArray[EVIOSETSCREEN_MINY];
        !          1039:     screen->bounds.maxy = parameterArray[EVIOSETSCREEN_MAXY];
        !          1040:     screen->shmemSize = parameterArray[EVIOSETSCREEN_SHMEMSIZE];
        !          1041:     shmem_size += parameterArray[EVIOSETSCREEN_SHMEMSIZE];
        !          1042:     // Update our idea of workSpace bounds
        !          1043:     if ( screen->bounds.minx < workSpace.minx )
        !          1044:        workSpace.minx = screen->bounds.minx;
        !          1045:     if ( screen->bounds.miny < workSpace.miny )
        !          1046:        workSpace.miny = screen->bounds.miny;
        !          1047:     if ( screen->bounds.maxx < workSpace.maxx )
        !          1048:        workSpace.maxx = screen->bounds.maxx;
        !          1049:     if ( screen->bounds.maxy < workSpace.maxy )
        !          1050:        workSpace.maxy = screen->bounds.maxy;
        !          1051:     return IO_R_SUCCESS;
        !          1052: }
        !          1053: 
        !          1054: /* Member of EventClient protocol 
        !          1055:  *
        !          1056:  * Absolute position input devices and some specialized output devices
        !          1057:  * may need to know the bounding rectangle for all attached displays.
        !          1058:  * The following method returns a Bounds* for the workspace.  Please note
        !          1059:  * that the bounds are kept as signed values, and that on a multi-display
        !          1060:  * system the minx and miny values may very well be negative.
        !          1061:  */
        !          1062: - (Bounds *)workspaceBounds
        !          1063: {
        !          1064:        return &workSpace;
        !          1065: }
        !          1066: 
        !          1067: /*
        !          1068:  * Set up the shared memory area between the Window Server and the kernel.
        !          1069:  *
        !          1070:  *     Obtain page aligned wired kernel memory for 'size' bytes using
        !          1071:  *     kmem_alloc().
        !          1072:  *     Find a similar sized region in the Window Server task VM map using
        !          1073:  *     vm_map_find().  This function will find an appropriately sized region,
        !          1074:  *     create a memory object, and insert it in the VM map.
        !          1075:  *     For each physical page in the kernel's wired memory we got from
        !          1076:  *     kmem_alloc(), enter that page at the appropriate location in the page
        !          1077:  *     map for the Window Server, in the address range we allocated using
        !          1078:  *     vm_map_find().  
        !          1079:  */
        !          1080: - (IOReturn) mapEventShmem : (port_t) event_port
        !          1081:                   task : (port_t)task                  // in
        !          1082:                   size : (vm_size_t)size               // in
        !          1083:                   at : (vm_offset_t *)addr             // out
        !          1084: {
        !          1085:        vm_offset_t     off;
        !          1086:        vm_offset_t     phys_addr;
        !          1087:        IOReturn        krtn;
        !          1088:        void *          task_map;
        !          1089:        vm_offset_t     task_addr;
        !          1090:        
        !          1091:        if ( event_port != eventPort || evOpenCalled == NO )
        !          1092:            return IO_R_PRIVILEGE;
        !          1093:        if ( task == PORT_NULL || size == 0 )   // malformed request
        !          1094:            return IO_R_INVALID_ARG;
        !          1095:        if ( owner_task != PORT_NULL || owner != NULL )
        !          1096:            return IO_R_INVALID_ARG;    // Mapping set up already
        !          1097: 
        !          1098:        krtn = createEventShmem(task,size,&task_map,&task_addr,&shmem_addr);
        !          1099:        if ( krtn != KERN_SUCCESS )
        !          1100:        {
        !          1101:            IOLog("%s: createEventShmem fails (%d).\n",[self name],krtn);
        !          1102:            return krtn;
        !          1103:        }
        !          1104: 
        !          1105:        [driverLock lock];
        !          1106:        shmem_size = size;
        !          1107:        owner_task = task;
        !          1108:        owner_addr = task_addr;
        !          1109:        *addr = task_addr;
        !          1110:        owner = task_map;
        !          1111:        [self initShmem];
        !          1112:        [driverLock unlock];
        !          1113: 
        !          1114:        [self _resetMouseParameters];
        !          1115:        [self _resetKeyboardParameters];
        !          1116:        // Start the cursor control callouts
        !          1117:        [driverLock lock];
        !          1118:        [self scheduleNextPeriodicEvent];
        !          1119:        [driverLock unlock];
        !          1120: 
        !          1121:        return IO_R_SUCCESS;
        !          1122: }
        !          1123: 
        !          1124: // 
        !          1125: // Unmap the shared memory area and release the wired memory.
        !          1126: //
        !          1127: - (IOReturn) unmapEventShmem : (port_t)event_port;
        !          1128: {
        !          1129:        vm_offset_t off;
        !          1130:        IOReturn r;
        !          1131: 
        !          1132:        // Since the shared memory area is being torn down, set eventsOpen
        !          1133:        // to NO to keep the cursor thread from futzing with the shared area.
        !          1134:        // We need to implement a lock to guard the shmem, and acquire the
        !          1135:        // lock before tearing the area down.
        !          1136:        xpr_ev_shmemlock("unmapEventShmem: will lock %x\n",
        !          1137:                        driverLock, 3, 4, 5, 6);
        !          1138:        [driverLock lock];
        !          1139:        xpr_ev_shmemlock("unmapEventShmem: did lock %x\n",
        !          1140:                        driverLock, 3, 4, 5, 6);
        !          1141: 
        !          1142:        if (event_port != eventPort || evOpenCalled == NO || eventsOpen == NO)
        !          1143:        {
        !          1144:            [driverLock unlock];
        !          1145:            return IO_R_PRIVILEGE;
        !          1146:        }
        !          1147:        eventsOpen = NO;
        !          1148: 
        !          1149:        r=destroyEventShmem(owner_task,owner,shmem_size,owner_addr,shmem_addr);
        !          1150:        if ( r != KERN_SUCCESS )
        !          1151:        {
        !          1152:            IOLog("%s: destroyEventShmem fails (%d).\n", [self name], r);
        !          1153:        }
        !          1154:        shmem_addr = owner_addr = (vm_offset_t)0;
        !          1155:        shmem_size = 0;
        !          1156:        owner = NULL;
        !          1157:        owner_task = PORT_NULL;
        !          1158:        [driverLock unlock];
        !          1159:        xpr_ev_shmemlock("unmapEventShmem: did unlock %x\n",
        !          1160:                        driverLock, 3, 4, 5, 6);
        !          1161:        return r;
        !          1162: }
        !          1163: #endif
        !          1164: 
        !          1165: // Initialize the shared memory area.
        !          1166: //
        !          1167: // On entry, the driverLock should be set.
        !          1168: - initShmem
        !          1169: {
        !          1170:        int             i;
        !          1171:        EvOffsets       *eop;
        !          1172:        EvGlobals       *glob;
        !          1173: 
        !          1174:        pointerLoc.x = INIT_CURSOR_X;
        !          1175:        pointerLoc.y = INIT_CURSOR_Y;
        !          1176: 
        !          1177:        /* top of sharedMem is EvOffsets structure */
        !          1178:        eop = (EvOffsets *) shmem_addr;
        !          1179:        
        !          1180:        /* fill in EvOffsets structure */
        !          1181:        eop->evGlobalsOffset = sizeof(EvOffsets);
        !          1182:        eop->evShmemOffset = eop->evGlobalsOffset + sizeof(EvGlobals);
        !          1183:     
        !          1184:        /* find pointers to start of globals and private shmem region */
        !          1185:        glob = (EvGlobals *) ((char *)shmem_addr + eop->evGlobalsOffset);
        !          1186:        evs = (void *)((char *)shmem_addr + eop->evShmemOffset);
        !          1187:     
        !          1188:        /* Set default wait cursor parameters */
        !          1189:        glob->waitCursorEnabled = TRUE;
        !          1190:        glob->globalWaitCursorEnabled = TRUE;
        !          1191:        glob->waitThreshold = EV_NS_TO_TICK(DefaultWCThreshold);
        !          1192:        waitFrameRate = DefaultWCFrameRate;
        !          1193:        waitSustain = DefaultWCSustain; 
        !          1194:        waitSusTime = 0ULL;
        !          1195:        waitFrameTime = 0ULL;
        !          1196: 
        !          1197:        /* Set up low-level queues */
        !          1198:        lleqSize = LLEQSIZE;
        !          1199:        for (i=lleqSize; --i != -1; ) {
        !          1200:            glob->lleq[i].event.type = 0;
        !          1201:            glob->lleq[i].event.time = 0;
        !          1202:            glob->lleq[i].event.flags = 0;
        !          1203:            ev_init_lock(&glob->lleq[i].sema);
        !          1204:            glob->lleq[i].next = i+1;
        !          1205:        }
        !          1206:        glob->LLELast = 0;
        !          1207:        glob->lleq[lleqSize-1].next = 0;
        !          1208:        glob->LLEHead =
        !          1209:            glob->lleq[glob->LLELast].next;
        !          1210:        glob->LLETail =
        !          1211:            glob->lleq[glob->LLELast].next;
        !          1212:        glob->buttons = 0;
        !          1213:        glob->eNum = INITEVENTNUM;
        !          1214:        glob->eventFlags = 0;
        !          1215:        glob->VertRetraceClock = EvTickTimeValue();
        !          1216:        glob->cursorLoc = pointerLoc;
        !          1217:        glob->dontCoalesce = 0;
        !          1218:        glob->dontWantCoalesce = 0;
        !          1219:        glob->wantPressure = 0;
        !          1220:        glob->wantPrecision = 0;
        !          1221:        glob->mouseRectValid = 0;
        !          1222:        glob->movedMask = 0;
        !          1223:        ev_init_lock( &glob->cursorSema );
        !          1224:        ev_init_lock( &glob->waitCursorSema );
        !          1225:        evg = (void *)glob;
        !          1226:        // Set eventsOpen last to avoid race conditions.
        !          1227:        eventsOpen = YES;
        !          1228:        
        !          1229:        return self;
        !          1230: }
        !          1231: 
        !          1232: //
        !          1233: // Set the event port.  The event port is both an ownership token
        !          1234: // and a live port we hold send rights on.  The port is owned by our client,
        !          1235: // the WindowServer.  We arrange to be notified on a port death so that
        !          1236: // we can tear down any active resources set up during this session.
        !          1237: // An argument of PORT_NULL will cause us to forget any port death
        !          1238: // notification that's set up.
        !          1239: //
        !          1240: // The driverLock should be held on entry.
        !          1241: //
        !          1242: - setEventPort:(port_t)port
        !          1243: {
        !          1244:        static struct _eventMsg init_msg =
        !          1245:                        { { 0, 1, sizeof(msg_header_t)+sizeof(msg_type_t), 
        !          1246:                           MSG_TYPE_NORMAL, (port_t)0, (port_t)0, 0 },
        !          1247:                          { MSG_TYPE_UNSTRUCTURED, 0, 0, 1, 0, 0 } };
        !          1248:        if ( port == PORT_NULL )
        !          1249:        {
        !          1250:                event_kern_port = (port_t)KERN_PORT_NULL;
        !          1251:        }
        !          1252:        else if ( port != eventPort )   // Set up a new notification
        !          1253:        {
        !          1254:                event_kern_port = IOGetKernPort(port);
        !          1255:                port_request_notification((kern_port_t)event_kern_port, 
        !          1256:                        (kern_port_t)notify_kern_port);
        !          1257:        }
        !          1258:        if ( eventMsg == NULL )
        !          1259:                eventMsg = IOMalloc( sizeof (struct _eventMsg) );
        !          1260:        eventPort = port;
        !          1261:        // Initialize the events available message.
        !          1262:        *((struct _eventMsg *)eventMsg) = init_msg;
        !          1263: 
        !          1264:        ((struct _eventMsg *)eventMsg)->h.msg_remote_port = port;
        !          1265:        return self;
        !          1266: }
        !          1267: 
        !          1268: //
        !          1269: // Set the port to be used for a special key notification.  This could be more
        !          1270: // robust about letting ports be set...
        !          1271: //
        !          1272: - (IOReturn)   setSpecialKeyPort       : (port_t)dev_port
        !          1273:                                keyFlavor       : (int)special_key
        !          1274:                                keyPort         : (port_t)key_port
        !          1275: {
        !          1276:        if ( dev_port != ev_port )
        !          1277:            return IO_R_PRIVILEGE;
        !          1278:        
        !          1279:        if ( special_key >= 0 && special_key < NX_NUM_SCANNED_SPECIALKEYS )
        !          1280:                specialKeyPort[special_key] = key_port;
        !          1281:        return IO_R_SUCCESS;
        !          1282: }
        !          1283: 
        !          1284: - (port_t)specialKeyPort: (int)special_key
        !          1285: {
        !          1286:        if ( special_key >= 0 && special_key < NX_NUM_SCANNED_SPECIALKEYS )
        !          1287:                return specialKeyPort[special_key];
        !          1288:        return PORT_NULL;
        !          1289: }
        !          1290: 
        !          1291: //     Return ports used for Mach interface
        !          1292: - (port_t)ev_port
        !          1293: { 
        !          1294:        return ev_port;
        !          1295: }
        !          1296: 
        !          1297: - (port_t)evs_port
        !          1298: {
        !          1299:        return evs_port;
        !          1300: }
        !          1301: 
        !          1302: //
        !          1303: // Dispatch mechanism for special key press.  If a port has been registered,
        !          1304: // a message is built to be sent out to that port notifying that the key has
        !          1305: // changed state.  A level in the range 0-64 is provided for convenience.
        !          1306: //
        !          1307: - evSpecialKeyMsg:     (unsigned)key
        !          1308:                        direction:(unsigned)dir
        !          1309:                        flags:(unsigned)f
        !          1310:                        level:(unsigned)l
        !          1311: {
        !          1312:        port_t dst_port;
        !          1313:        struct evioSpecialKeyMsg *msg;
        !          1314:        static const struct evioSpecialKeyMsg init_msg =
        !          1315:                        { { 0, 1, sizeof (struct evioSpecialKeyMsg), 
        !          1316:                           MSG_TYPE_NORMAL, (port_t)0, (port_t)0,
        !          1317:                          EV_SPECIAL_KEY_MSG_ID },
        !          1318:                          { MSG_TYPE_INTEGER_32, 32, 1, TRUE, FALSE, FALSE },
        !          1319:                          0,    /* key */
        !          1320:                          { MSG_TYPE_INTEGER_32, 32, 1, TRUE, FALSE, FALSE },
        !          1321:                          0,    /* direction */
        !          1322:                          { MSG_TYPE_INTEGER_32, 32, 1, TRUE, FALSE, FALSE },
        !          1323:                          0,    /* flags */
        !          1324:                          { MSG_TYPE_INTEGER_32, 32, 1, TRUE, FALSE, FALSE },
        !          1325:                          0     /* level */
        !          1326:                        };
        !          1327: 
        !          1328:        if ( (dst_port = [self specialKeyPort:key]) == PORT_NULL )
        !          1329:                return self;
        !          1330:        msg = (struct evioSpecialKeyMsg *) IOMalloc(
        !          1331:                                sizeof (struct evioSpecialKeyMsg) );
        !          1332:        if ( msg == NULL )
        !          1333:                return self;
        !          1334:        
        !          1335:        // Initialize the message.
        !          1336:        bcopy( &init_msg, msg, sizeof (struct evioSpecialKeyMsg) );
        !          1337:        msg->Head.msg_remote_port = dst_port;
        !          1338:        msg->key = key;
        !          1339:        msg->direction = dir;
        !          1340:        msg->flags = f;
        !          1341:        msg->level = l;
        !          1342: 
        !          1343:        // Send the message out from the I/O thread.
        !          1344:        [self sendIOThreadAsyncMsg      :@selector(_performSpecialKeyMsg:)
        !          1345:                        to              :self
        !          1346:                        with            :(void *)msg];
        !          1347: 
        !          1348:        return self;
        !          1349: }
        !          1350: 
        !          1351: /*
        !          1352:  * This is run in the I/O thread, to perform the actual message send operation.
        !          1353:  */
        !          1354: - _performSpecialKeyMsg:(id)data
        !          1355: {
        !          1356:        kern_return_t r;
        !          1357:        struct evioSpecialKeyMsg *msg;
        !          1358: 
        !          1359:        msg = (struct evioSpecialKeyMsg *)data;
        !          1360:        xpr_ev_post("_performSpecialKeyMsg 0x%x\n", msg,2,3,4,5);
        !          1361: 
        !          1362:        r = msg_send( &msg->Head, SEND_TIMEOUT, 0 );    /* Don't block */
        !          1363:        xpr_ev_post("_performSpecialKeyMsg: msg_send() == %d\n",
        !          1364:                r,2,3,4,5);
        !          1365:        if ( r != SEND_SUCCESS )
        !          1366:        {
        !          1367:                IOLog("%s: _performSpecialKeyMsg msg_send returned %d\n",
        !          1368:                        [self name], r);
        !          1369:        }
        !          1370:        if ( r == SEND_INVALID_PORT )   /* Invalidate the port */
        !          1371:        {
        !          1372:                [self setSpecialKeyPort         : ev_port
        !          1373:                                keyFlavor       : msg->key
        !          1374:                                keyPort         : PORT_NULL];
        !          1375:        }
        !          1376:        IOFree( (void *)msg, sizeof (struct evioSpecialKeyMsg) );
        !          1377:        return self;
        !          1378: }
        !          1379: 
        !          1380: //
        !          1381: // Dispatch state to screens registered with the Event Driver
        !          1382: // Pending state changes for a device may be coalesced.
        !          1383: //
        !          1384: //
        !          1385: // On entry, the  driverLock should be set.
        !          1386: //
        !          1387: - evDispatch:(int)screen command:(EvCmd)evcmd
        !          1388: {
        !          1389:     Point p;
        !          1390:     EvScreen *esp = &((EvScreen*)evScreen)[screen];
        !          1391: 
        !          1392:     if ( eventsOpen == NO )
        !          1393:        return self;
        !          1394: 
        !          1395:     p = ((EvGlobals*)evg)->cursorLoc;  // Copy from shmem.
        !          1396:     if ( esp->instance != nil )
        !          1397:     {
        !          1398:        switch ( evcmd )
        !          1399:        {
        !          1400:            case EVMOVE:
        !          1401:                [esp->instance  moveCursor:&p
        !          1402:                                frame:((EvGlobals*)evg)->frame
        !          1403:                                token:(screen + SCREENTOKEN)];
        !          1404:                break;
        !          1405: 
        !          1406:            case EVSHOW:
        !          1407:                [esp->instance  showCursor:&p
        !          1408:                                frame:((EvGlobals*)evg)->frame
        !          1409:                                token:(screen + SCREENTOKEN)];
        !          1410:                break;
        !          1411: 
        !          1412:            case EVHIDE:
        !          1413:                [esp->instance hideCursor:(screen + SCREENTOKEN)];
        !          1414:                break;
        !          1415: 
        !          1416:            case EVLEVEL:
        !          1417:                [esp->instance  setBrightness:[self currentBrightness]
        !          1418:                                token:(screen + SCREENTOKEN)];
        !          1419:        }
        !          1420:     }
        !          1421:     return self;
        !          1422: }
        !          1423: 
        !          1424: //
        !          1425: // Helper functions for postEvent
        !          1426: //
        !          1427: static inline int myAbs(int a) { return(a > 0 ? a : -a); }
        !          1428: 
        !          1429: static inline short UniqueEventNum(EventDriver * instance)
        !          1430: {
        !          1431:    EvGlobals *evg = (EvGlobals *)instance->evg;
        !          1432:     while (++evg->eNum == NULLEVENTNUM)
        !          1433:        ; /* sic */
        !          1434:     return(evg->eNum);
        !          1435: }
        !          1436: 
        !          1437: // postEvent 
        !          1438: //
        !          1439: // This routine actually places events in the event queue which is in
        !          1440: // the EvGlobals structure.  It is called from all parts of the ev
        !          1441: // driver.
        !          1442: //
        !          1443: // On entry, the driverLock should be set.
        !          1444: //
        !          1445: 
        !          1446: - postEvent:(int)what
        !          1447:        at:(Point *)location
        !          1448:        atTime:(unsigned)theClock
        !          1449:        withData:(NXEventData *)myData
        !          1450: {
        !          1451:     EvGlobals *glob = (EvGlobals *)evg;
        !          1452:     NXEQElement        *theHead = (NXEQElement *) &glob->lleq[glob->LLEHead];
        !          1453:     NXEQElement        *theLast = (NXEQElement *) &glob->lleq[glob->LLELast];
        !          1454:     NXEQElement        *theTail = (NXEQElement *) &glob->lleq[glob->LLETail];
        !          1455:     int                wereEvents;
        !          1456: 
        !          1457:     /* Some events affect screen dimming */
        !          1458:     if (EventCodeMask(what) & NX_UNDIMMASK) {
        !          1459:        autoDimTime = theClock + autoDimPeriod;
        !          1460:        if (autoDimmed)
        !          1461:            [self undoAutoDim];
        !          1462:     }
        !          1463:     // Update the PS VertRetraceClock off of the timestamp if it looks sane
        !          1464:     if (   theClock > glob->VertRetraceClock
        !          1465:        && theClock < (glob->VertRetraceClock + (20 * EV_TICK_TIME)) )
        !          1466:        glob->VertRetraceClock = theClock;
        !          1467: 
        !          1468:     wereEvents = EventsInQueue();
        !          1469: 
        !          1470:     xpr_ev_post("postEvent: what %d, X %d Y %d Q %d, needKick %d\n",
        !          1471:                what,location->x,location->y,
        !          1472:                EventsInQueue(), needToKickEventConsumer);
        !          1473: 
        !          1474:     if ((!glob->dontCoalesce)  /* Coalescing enabled */
        !          1475:     && (theHead != theTail)
        !          1476:     && (theLast->event.type == what)
        !          1477:     && (EventCodeMask(what) & COALESCEEVENTMASK)
        !          1478:     && ev_try_lock(&theLast->sema)) {
        !          1479:     /* coalesce events */
        !          1480:        theLast->event.location.x = location->x;
        !          1481:        theLast->event.location.y = location->y;
        !          1482:        theLast->event.time = theClock;
        !          1483:        if (myData != NULL)
        !          1484:            theLast->event.data = *myData;
        !          1485:        ev_unlock(&theLast->sema);
        !          1486:     } else if (theTail->next != glob->LLEHead) {
        !          1487:        /* store event in tail */
        !          1488:        theTail->event.type = what;
        !          1489:        theTail->event.location.x = location->x;
        !          1490:        theTail->event.location.y = location->y;
        !          1491:        theTail->event.flags = glob->eventFlags;
        !          1492:        theTail->event.time = theClock;
        !          1493:        theTail->event.window = 0;
        !          1494:        if (myData != NULL)
        !          1495:            theTail->event.data = *myData;
        !          1496:        switch(what) {
        !          1497:        case NX_LMOUSEDOWN:
        !          1498:            theTail->event.data.mouse.eventNum =
        !          1499:                leftENum = UniqueEventNum(self);
        !          1500:            break;
        !          1501:        case NX_RMOUSEDOWN:
        !          1502:            theTail->event.data.mouse.eventNum =
        !          1503:                rightENum = UniqueEventNum(self);
        !          1504:            break;
        !          1505:        case NX_LMOUSEUP:
        !          1506:            theTail->event.data.mouse.eventNum = leftENum;
        !          1507:            leftENum = NULLEVENTNUM;
        !          1508:            break;
        !          1509:        case NX_RMOUSEUP:
        !          1510:            theTail->event.data.mouse.eventNum = rightENum;
        !          1511:            rightENum = NULLEVENTNUM;
        !          1512:            break;
        !          1513:        }
        !          1514:        if (EventCodeMask(what) & PRESSUREEVENTMASK) {
        !          1515:            theTail->event.data.mouse.pressure = lastPressure;
        !          1516:        }
        !          1517:        if (EventCodeMask(what) & MOUSEEVENTMASK) { /* Click state */
        !          1518:            if (((theClock - clickTime) <= clickTimeThresh)
        !          1519:            && (myAbs(location->x - clickLoc.x) <= clickSpaceThresh.x)
        !          1520:            && (myAbs(location->y - clickLoc.y) <= clickSpaceThresh.y)) {
        !          1521:                theTail->event.data.mouse.click = 
        !          1522:                    ((what == NX_LMOUSEDOWN)||(what == NX_RMOUSEDOWN)) ?
        !          1523:                    (clickTime=theClock,++clickState) : clickState ;
        !          1524:            } else if ((what == NX_LMOUSEDOWN)||(what == NX_RMOUSEDOWN)) {
        !          1525:                clickLoc = *location;
        !          1526:                clickTime = theClock;
        !          1527:                clickState = 1;
        !          1528:                theTail->event.data.mouse.click = clickState;
        !          1529:            } else
        !          1530:                theTail->event.data.mouse.click = 0;
        !          1531:        }
        !          1532: #if PMON
        !          1533:        pmon_log_event(PMON_SOURCE_EV,
        !          1534:                       KP_EV_POST_EVENT,
        !          1535:                       what,
        !          1536:                       glob->eventFlags,
        !          1537:                       theClock);
        !          1538: #endif
        !          1539:        glob->LLETail = theTail->next;
        !          1540:        glob->LLELast = theLast->next;
        !          1541:        if ( ! wereEvents )     // Events available, so wake event consumer
        !          1542:            [self kickEventConsumer];
        !          1543:     }
        !          1544:     else
        !          1545:     {
        !          1546:        /*
        !          1547:         * if queue is full, ignore event, too hard to take care of all cases 
        !          1548:         */
        !          1549:        IOLog("%s: postEvent LLEventQueue overflow.\n", [self name]);
        !          1550:        [self kickEventConsumer];
        !          1551: #if PMON
        !          1552:        pmon_log_event( PMON_SOURCE_EV,
        !          1553:                        KP_EV_QUEUE_FULL,
        !          1554:                        what,
        !          1555:                        glob->eventFlags,
        !          1556:                        theClock);
        !          1557: #endif
        !          1558:     }
        !          1559: }
        !          1560: 
        !          1561: /*
        !          1562:  * - kickEventConsumer
        !          1563:  *
        !          1564:  *     Try to send a message out to let the event consumer know that
        !          1565:  *     there are now events available for consumption.
        !          1566:  */
        !          1567: - kickEventConsumer
        !          1568: {
        !          1569:        [kickConsumerLock lock];
        !          1570:        xpr_ev_post("kickEventConsumer (need == %d)\n",
        !          1571:                needToKickEventConsumer,2,3,4,5);
        !          1572:        if ( needToKickEventConsumer == YES )
        !          1573:        {
        !          1574:                [kickConsumerLock unlock];
        !          1575:                return self;            // Request is already pending
        !          1576:        }
        !          1577:        needToKickEventConsumer = YES;  // Posting a request now
        !          1578:        [kickConsumerLock unlock];
        !          1579:        [self sendIOThreadAsyncMsg      :@selector(_performKickEventConsumer:)
        !          1580:                        to              :self
        !          1581:                        with            :(void *)0];
        !          1582: 
        !          1583:        return self;
        !          1584: }
        !          1585: 
        !          1586: /*
        !          1587:  * This is run in the I/O thread, to perform the actual message send operation.
        !          1588:  * Note that we perform a non-blocking send.  The Event port in the event
        !          1589:  * consumer has a queue depth of 1 message.  Once the consumer picks up that
        !          1590:  * message, it runs until the event queue is exhausted before trying to read
        !          1591:  * another message.  If a message is pending,there is no need to enqueue a
        !          1592:  * second one.  This also keeps us from blocking the I/O thread in a msg_send
        !          1593:  * which could result in a deadlock if the consumer were to make a call into
        !          1594:  * the event driver.
        !          1595:  */
        !          1596: - _performKickEventConsumer:(id)data
        !          1597: {
        !          1598:        kern_return_t r;
        !          1599: 
        !          1600:        xpr_ev_post("_performKickEventConsumer\n", 1,2,3,4,5);
        !          1601:        [kickConsumerLock lock];
        !          1602:        needToKickEventConsumer = NO;   // Request received and processed
        !          1603:        [kickConsumerLock unlock];
        !          1604: 
        !          1605:        r = msg_send( (msg_header_t *)eventMsg, SEND_TIMEOUT, 0 );
        !          1606:        xpr_ev_post("_performKickEventConsumer: msg_send() == %d\n",
        !          1607:                r,2,3,4,5);
        !          1608:        switch ( r )
        !          1609:        {
        !          1610:            case SEND_TIMED_OUT:        /* Already has a message posted */
        !          1611:            case SEND_SUCCESS:          /* Message is posted */
        !          1612:                break;
        !          1613:            default:                    /* Log the error */
        !          1614:                IOLog("%s: _performKickEventConsumer msg_send returned %d\n",
        !          1615:                        [self name], r);
        !          1616:                break;
        !          1617:        }
        !          1618:        return self;
        !          1619: }
        !          1620: 
        !          1621: /* 
        !          1622:  * Event sources may need to use an I/O thread from time to time.
        !          1623:  * Rather than have each instance running it's own thread, we provide
        !          1624:  * a callback mechanism to let all the instances share a common Event I/O
        !          1625:  * thread running in the IOTask space, and managed by the Event Driver.
        !          1626:  * Returns self, or nil on error.
        !          1627:  */
        !          1628: - (IOReturn)sendIOThreadMsg:   (SEL)selector   // Selector to call back on
        !          1629:        to              :       (id)instance    // Instance to call back
        !          1630:        with            :       (id)data;       // Data to pass back
        !          1631: {
        !          1632:        evIoOpParams params;
        !          1633: 
        !          1634:        params.callback.instance = instance;
        !          1635:        params.callback.selector = selector;
        !          1636:        params.callback.data = data;
        !          1637: 
        !          1638:        return [self    _threadOpCommon : EVENT_LISTENER_CALLBACK
        !          1639:                        opParams : (void *)&params
        !          1640:                        async : NO];
        !          1641: }
        !          1642: 
        !          1643: - sendIOThreadAsyncMsg:                (SEL)selector   // Selector to call back on
        !          1644:        to              :       (id)instance    // Instance to call back
        !          1645:        with            :       (id)data;       // Data to pass back
        !          1646: {
        !          1647:        evIoOpParams params;
        !          1648: 
        !          1649:        params.callback.instance = instance;
        !          1650:        params.callback.selector = selector;
        !          1651:        params.callback.data = data;
        !          1652: 
        !          1653:        [self   _threadOpCommon : EVENT_LISTENER_CALLBACK
        !          1654:                opParams : (void *)&params
        !          1655:                async : YES];
        !          1656:        return self;
        !          1657: }
        !          1658: 
        !          1659: /*
        !          1660:  * This routine is run within the I/O thread, on demand from the
        !          1661:  * sendIOThreadMsg::: methods above.  We attempt to dispatch a message
        !          1662:  * to the specified selector and instance.
        !          1663:  */
        !          1664: - (IOReturn) _doPerformInIOThread:(void *)data
        !          1665: {
        !          1666:        IOReturn ret;
        !          1667:        evCallback *msg = data;
        !          1668:        if ( [msg->instance respondsTo:msg->selector] )
        !          1669:        {
        !          1670:            [msg->instance perform:msg->selector with:msg->data];
        !          1671:            ret = IO_R_SUCCESS;
        !          1672:        }
        !          1673:        else
        !          1674:        {
        !          1675:            IOLog("%s: _doPerformInIOThread: [%s] does not respond to SEL [%s]\n",
        !          1676:                        [self name],
        !          1677:                        object_getClassName(msg->instance),
        !          1678:                        sel_getName(msg->selector) );
        !          1679:            ret = IO_R_IPC_FAILURE;
        !          1680:        }
        !          1681:        return ret;
        !          1682: }
        !          1683: 
        !          1684: /*
        !          1685:  * Common thread dispatch code used to drive
        !          1686:  * I/O operations.  The operation to be performed is encoded
        !          1687:  * in a Mach message, which we send to our I/O thread.  This
        !          1688:  * thread then performs the requested operations, returning a
        !          1689:  * status
        !          1690:  */
        !          1691: - (IOReturn)_threadOpCommon : (int)op
        !          1692:                             opParams : (void *)data
        !          1693:                             async : (BOOL)async
        !          1694: {
        !          1695:        evIoOpParams *  opParams = data;
        !          1696:        evIoOpMsg opMsg;
        !          1697:        kern_return_t krtn;
        !          1698:        IOReturn rtn;
        !          1699: #ifdef KERNEL
        !          1700:        extern kern_port_t ev_port_list[];
        !          1701: #endif
        !          1702:        
        !          1703:        xpr_ev_post("_threadOpCommon: op %d\n",op , 2,3,4,5);
        !          1704:                
        !          1705:        /*
        !          1706:         * First, an evIoOpMsg.
        !          1707:         */
        !          1708:        opMsg = opMsgTemplate;
        !          1709:        opMsg.header.msg_local_port = PORT_NULL;
        !          1710:        
        !          1711:        /*
        !          1712:         * Next, the evIoOpBuf.
        !          1713:         */
        !          1714:        opMsg.opBuf.op = op;
        !          1715:        if ( async == NO )
        !          1716:        {
        !          1717:            opMsg.opBuf.cmdLock = [NXConditionLock alloc];
        !          1718:            [opMsg.opBuf.cmdLock initWith:CMD_INPROGRESS];
        !          1719:            opMsg.opBuf.status = &rtn;
        !          1720:            rtn = IO_R_INVALID_ARG;
        !          1721:        }
        !          1722:        opMsg.opBuf.params = *opParams;
        !          1723:        
        !          1724:        /*
        !          1725:         * Go for it. Send the message to the I/O thread and wait for
        !          1726:         * I/O complete. We use msg_send_from_kernel becuase this is called
        !          1727:         * from exported methods; we could be in a user task.
        !          1728:         */
        !          1729: #ifdef KERNEL
        !          1730:        opMsg.header.msg_remote_port = (port_t)ev_port_list[0];
        !          1731:        krtn = msg_send_from_kernel(&opMsg.header, MSG_OPTION_NONE, 0);
        !          1732: #else  KERNEL
        !          1733:        opMsg.header.msg_remote_port = ev_port;
        !          1734:        krtn = msg_send(&opMsg.header, MSG_OPTION_NONE, 0);
        !          1735: #endif KERNEL
        !          1736:        if(krtn) {
        !          1737:                IOLog("%s: _threadOpCommon msg_send returned %d\n",
        !          1738:                        [self name], krtn);
        !          1739:                rtn = IO_R_IPC_FAILURE;
        !          1740:                goto out;
        !          1741:        }
        !          1742:        if ( async == NO )
        !          1743:        {
        !          1744:            [opMsg.opBuf.cmdLock lockWhen:CMD_DONE];    // Wait for completion
        !          1745:        }
        !          1746:        else
        !          1747:            rtn = IO_R_SUCCESS;
        !          1748: out:
        !          1749:        if ( async == NO )
        !          1750:            [opMsg.opBuf.cmdLock free];
        !          1751:        xpr_ev_post("_threadOpCommon: status %s\n", 
        !          1752:                [self stringFromReturn:rtn], 2,3,4,5);
        !          1753:        return rtn;
        !          1754: }
        !          1755: 
        !          1756: 
        !          1757: /*
        !          1758:  * The following methods are executed from the I/O thread only.
        !          1759:  */
        !          1760: 
        !          1761: /*
        !          1762:  * Service incoming client evIoOp.
        !          1763:  */
        !          1764: - (void)_ioOpHandler   : (void *)data
        !          1765: {
        !          1766:        IOReturn ret;
        !          1767:        evIoOpBuf *opBuf = data;
        !          1768: 
        !          1769:        xpr_ev_post("_ioOpHandler: op %d\n",opBuf->op, 2,3,4,5);
        !          1770: 
        !          1771:        if ( opBuf->status != NULL )
        !          1772:            *opBuf->status = IO_R_SUCCESS;
        !          1773:        switch(opBuf->op) {
        !          1774:                 
        !          1775:            case EVENT_LISTENER_PING:
        !          1776:                /*
        !          1777:                 * This is just used for the init thread to know when we've
        !          1778:                 * come this far.
        !          1779:                 */
        !          1780:                break;
        !          1781:                
        !          1782:            case EVENT_LISTENER_EXIT:
        !          1783:                /* 
        !          1784:                 * First I/O complete this request, then terminate.
        !          1785:                 */
        !          1786:                [opBuf->cmdLock unlockWith:CMD_DONE];
        !          1787:                IOExitThread();
        !          1788: 
        !          1789:            case EVENT_LISTENER_CALLBACK:
        !          1790:                ret = [self _doPerformInIOThread:&(opBuf->params.callback)];
        !          1791:                if ( opBuf->status != NULL )
        !          1792:                    *opBuf->status = ret;
        !          1793:                break;
        !          1794: 
        !          1795:            default:
        !          1796:                IOPanic("EventDriver: Bogus opBuf.op");
        !          1797:        }
        !          1798:        
        !          1799:        /*
        !          1800:         * Release caller for synchronous operations.
        !          1801:         */
        !          1802:        if ( opBuf->cmdLock != nil )
        !          1803:            [opBuf->cmdLock unlockWith:CMD_DONE];
        !          1804: }
        !          1805: 
        !          1806: /*
        !          1807:  * Listen for and dispatch messages for the ev and evs clients
        !          1808:  * Messages received on these ports are used to control input devices, the
        !          1809:  * display, and the cursor.
        !          1810:  *
        !          1811:  * These ports replace the old /dev/ev0 and /dev/evs0 devices.
        !          1812:  * Programs which use the published event status driver API in
        !          1813:  * Release 3.0 will continue to work.  Programs which directly manipulated
        !          1814:  * /dev/ev0 and /dev/evs0 are out of luck.
        !          1815:  *
        !          1816:  * Message buffers:  The reply buffer is allocated when an RPC is generated,
        !          1817:  * and is freed after we have sent the reply out.  While this may seem
        !          1818:  * expensive, we normally only have between 4 and 12 RPCs in a session, with
        !          1819:  * almost all occuring at WindowServer startup and login time.  IOMalloc()
        !          1820:  * is fast enough to prevent any detectable delay.  The design opts to reduce
        !          1821:  * wired memory at the cost of a few extra lines of code.
        !          1822:  */
        !          1823: static volatile void EventListener(EventDriver *inst)
        !          1824: {
        !          1825:        msg_header_t    *in;
        !          1826:        int             in_size;
        !          1827:        msg_header_t    *out;
        !          1828:        int             out_size;
        !          1829:        msg_return_t    r;
        !          1830:        boolean_t       result;
        !          1831:        boolean_t       ok = TRUE;
        !          1832:        EvInMsg         in_msg;                 // Big enough for most input
        !          1833:        extern boolean_t Event_server();
        !          1834:        extern boolean_t EventStatus_server();
        !          1835:        
        !          1836:        in_size = sizeof in_msg;
        !          1837:        in = &in_msg.hdr;
        !          1838:        out_size = 0;
        !          1839:        out = (msg_header_t *)NULL;             // Dynamically alloc as needed
        !          1840: 
        !          1841:        while ( ok )
        !          1842:        {
        !          1843:            in->msg_local_port = inst->ev_port_set;
        !          1844:            in->msg_size = in_size;
        !          1845:            
        !          1846:            r = msg_receive( in, RCV_LARGE, 0 );
        !          1847:            switch( r )
        !          1848:            {
        !          1849:                case RCV_SUCCESS:
        !          1850:                        break;
        !          1851: 
        !          1852:                case RCV_TOO_LARGE:
        !          1853:                        /* If we already grew it, free grown buffer */
        !          1854:                        if ( in_size > (sizeof in_msg) )
        !          1855:                            IOFree( (void *)in, in_size );
        !          1856:                        /* Get a new buffer of an appropriate size. */
        !          1857:                        in_size = in->msg_size;
        !          1858:                        in = (msg_header_t *)IOMalloc( in_size );
        !          1859:                        xpr_ev_post(
        !          1860:                                "EventListener: msg ID %d insize %d: 0x%x\n",
        !          1861:                                in->msg_id, in_size,in,4,5);
        !          1862:                        continue;
        !          1863: 
        !          1864:                case RCV_INVALID_PORT:  /* Driver is being freed */
        !          1865:                        ok = FALSE;
        !          1866:                        continue;
        !          1867: 
        !          1868:                default:
        !          1869:                        IOLog("%s: error on msg_receive (%d)\n",
        !          1870:                                [inst name], r);
        !          1871:                        continue;
        !          1872:            }
        !          1873:            xpr_ev_post("EventListener: msg ID %d size %d\n",
        !          1874:                        in->msg_id, in->msg_size,3,4,5);
        !          1875:            /*
        !          1876:             * We have arranged for notification when the WindowServer
        !          1877:             * dies.  The eventPort, owned by the WindowServer, has been
        !          1878:             * checked in for port death notification.
        !          1879:             * In the event of it's death, we assume that the WindowServer
        !          1880:             * has met an unfortunate fate, and invoke our device close
        !          1881:             * actions.
        !          1882:             */
        !          1883:            if ( in->msg_local_port == inst->notify_port )
        !          1884:            {
        !          1885:                notification_t *nmsg = (notification_t *)in;
        !          1886:        
        !          1887:                if ( nmsg->notify_port == inst->event_kern_port &&
        !          1888:                     inst->event_kern_port!= (port_t)KERN_PORT_NULL )
        !          1889:                {
        !          1890:                    [inst evClose:inst->ev_port token:inst->eventPort];
        !          1891: #ifdef DEBUG
        !          1892:                    IOLog("%s: client token invalidated\n", [inst name]);
        !          1893: #endif
        !          1894:                }
        !          1895:                continue;
        !          1896:            }
        !          1897:            /*
        !          1898:             * We got a request.  If it's on the privileged ev_port, 
        !          1899:             * test the message to see if it's a control message for us.
        !          1900:             * If it's not a control message, try passing it to the
        !          1901:             * Event_server.
        !          1902:             */
        !          1903:            result = FALSE;
        !          1904:            switch( in->msg_id )
        !          1905:            {
        !          1906:                case EV_IO_OP_MSG_ID:
        !          1907:                    if ( in->msg_local_port == inst->ev_port )
        !          1908:                    {
        !          1909:                        [inst _ioOpHandler:&((evIoOpMsg *)in)->opBuf];
        !          1910:                        result = TRUE;
        !          1911:                    }
        !          1912:                    break;
        !          1913: 
        !          1914:                default:
        !          1915:                    /* A real RPC needs a reply buffer.  Make one. */
        !          1916:                    if ( out == (msg_header_t *)NULL )
        !          1917:                    {
        !          1918:                            out_size = sizeof (EvOutMsg);
        !          1919:                            out = (msg_header_t *)IOMalloc( out_size );
        !          1920:                            xpr_ev_post(
        !          1921:                              "EventListener: msg ID %d replysize %d: 0x%x\n",
        !          1922:                                        in->msg_id, out_size,out,4,5);
        !          1923:                    }
        !          1924:                    result = Event_server( in, out );
        !          1925:                    break;
        !          1926:            }
        !          1927: 
        !          1928:            if ( result == FALSE )
        !          1929:            {
        !          1930:                IOLog("%s: invalid message ID %d\n",
        !          1931:                        [inst name], in->msg_id );
        !          1932:            }
        !          1933:            else        /* result == TRUE */
        !          1934:            {
        !          1935:                if(in->msg_remote_port!=PORT_NULL && out!=(msg_header_t*)NULL)
        !          1936:                {
        !          1937:                    /*
        !          1938:                     * We were passed a reply port.  Set up and send a
        !          1939:                     * reply message.  If this fails, it's because of
        !          1940:                     * a MiG error.  No big deal. Just log it and try to go on.
        !          1941:                     */
        !          1942:                    if ( out->msg_size > out_size ) /* Mem smasher? panic? */
        !          1943:                        IOLog("%s: reply msg overflow (%d > %d)\n",
        !          1944:                                [inst name], out->msg_size, out_size);
        !          1945:                    r = msg_send(out, MSG_OPTION_NONE, 0);
        !          1946:                    xpr_ev_post("EventListener: msg ID %d reply stat %d\n",
        !          1947:                                in->msg_id, r,3,4,5);
        !          1948:                    if ( r != SEND_SUCCESS )
        !          1949:                        IOLog("%s: error on msg_send (%d)\n",
        !          1950:                                [inst name], r);
        !          1951:                }
        !          1952:            }
        !          1953:            /*
        !          1954:             * Done with messages.  Free the reply buffer, and shrink the
        !          1955:             * input buffer as needed.
        !          1956:             */
        !          1957:            if ( out != (msg_header_t *)NULL )
        !          1958:            {
        !          1959:                IOFree( (void *)out, out_size );
        !          1960:                out = (msg_header_t *)NULL;
        !          1961:                out_size = 0;
        !          1962:            }
        !          1963:            if ( in_size > (sizeof in_msg) )
        !          1964:            {
        !          1965:                IOFree( (void *)in, in_size );
        !          1966:                in_size = sizeof in_msg;
        !          1967:                in = &in_msg.hdr;
        !          1968:            }
        !          1969:        }
        !          1970: 
        !          1971:        (volatile void) IOExitThread();
        !          1972: }
        !          1973: 
        !          1974: @end
        !          1975: 

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.