|
|
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(), ¬ify_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,¶meterArray[EVSIOCWINFO_THRESH]); ! 422: nsecs_to_packed_ns(&waitSustain, ! 423: ¶meterArray[EVSIOCWINFO_SUSTAIN]); ! 424: nsecs_to_packed_ns(&waitFrameRate, ! 425: ¶meterArray[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,¶meterArray[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,¶meterArray[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,¶meterArray[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,¶meterArray[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:¶meterArray[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 *)¶ms ! 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 *)¶ms ! 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:
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.