|
|
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.