]> git.saurik.com Git - apple/xnu.git/blame - iokit/Families/IOHIDSystem/IOHIDSystem.cpp
xnu-124.13.tar.gz
[apple/xnu.git] / iokit / Families / IOHIDSystem / IOHIDSystem.cpp
CommitLineData
1c79356b
A
1/*
2 * Copyright (c) 1998-2000 Apple Computer, Inc. All rights reserved.
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
6 * The contents of this file constitute Original Code as defined in and
7 * are subject to the Apple Public Source License Version 1.1 (the
8 * "License"). You may not use this file except in compliance with the
9 * License. Please obtain a copy of the License at
10 * http://www.apple.com/publicsource and read it before using this file.
11 *
12 * This Original Code and all software distributed under the License are
13 * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
14 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
15 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
16 * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the
17 * License for the specific language governing rights and limitations
18 * under the License.
19 *
20 * @APPLE_LICENSE_HEADER_END@
21 */
22/* Copyright (c) 1992 NeXT Computer, Inc. All rights reserved.
23 *
24 * EventDriver.m - Event System module, ObjC implementation.
25 *
26 * The EventDriver is a pseudo-device driver.
27 *
28 * HISTORY
29 * 31-Mar-92 Mike Paquette at NeXT
30 * Created.
31 * 04-Aug-93 Erik Kay at NeXT
32 * minor API cleanup
33 * 12-Dec-00 bubba at Apple.
34 * Handle eject key cases on Pro Keyboard.
35*/
36
37#include <IOKit/system.h>
38#include <IOKit/assert.h>
39
40#include <libkern/c++/OSContainers.h>
41#include <libkern/c++/OSCollectionIterator.h>
42
43#include <IOKit/IOTimerEventSource.h>
44#include <IOKit/IOCommandQueue.h>
45#include <IOKit/IOMessage.h>
46#include <IOKit/IOWorkLoop.h>
47#include <IOKit/hidsystem/IOHIDevice.h>
48#include <IOKit/hidsystem/IOHIDShared.h>
49#include <IOKit/hidsystem/IOHIDSystem.h>
50#include <IOKit/hidsystem/IOHIKeyboard.h>
51#include <IOKit/hidsystem/IOHIPointing.h>
52#include <IOKit/hidsystem/IOHIDParameter.h>
53
54#include <IOKit/hidsystem/ev_private.h> /* Per-machine configuration info */
55#include "IOHIDUserClient.h"
56
57#include <sys/kdebug.h>
58
59#ifdef __cplusplus
60 extern "C"
61 {
62 #include <UserNotification/KUNCUserNotifications.h>
63 }
64#endif
65
66bool displayWranglerUp( OSObject *, void *, IOService * );
67
68static IOHIDSystem * evInstance = 0;
69MasterAudioFunctions *masterAudioFunctions = 0;
70
71#define xpr_ev_cursor(x, a, b, c, d, e)
72#define PtInRect(ptp,rp) \
73 ((ptp)->x >= (rp)->minx && (ptp)->x < (rp)->maxx && \
74 (ptp)->y >= (rp)->miny && (ptp)->y < (rp)->maxy)
75
76
77
78static inline unsigned AbsoluteTimeToTick( AbsoluteTime * ts )
79{
80 UInt64 nano;
81 absolutetime_to_nanoseconds(*ts, &nano);
82 return( nano >> 24 );
83}
84
85static inline void TickToAbsoluteTime( unsigned tick, AbsoluteTime * ts )
86{
87 UInt64 nano = ((UInt64) tick) << 24;
88 nanoseconds_to_absolutetime(nano, ts);
89}
90
91#define EV_NS_TO_TICK(ns) AbsoluteTimeToTick(ns)
92#define EV_TICK_TO_NS(tick,ns) TickToAbsoluteTime(tick,ns)
93
94
95#define super IOService
96OSDefineMetaClassAndStructors(IOHIDSystem, IOService);
97
98/* Return the current instance of the EventDriver, or 0 if none. */
99IOHIDSystem * IOHIDSystem::instance()
100{
101 return evInstance;
102}
103
104bool IOHIDSystem::init(OSDictionary * properties)
105{
106 if (!super::init(properties)) return false;
107
108 /*
109 * Initialize minimal state.
110 */
111
112 driverLock = NULL;
113 kickConsumerLock = NULL;
114 evScreen = NULL;
115 timerES = 0;
116 cmdQ = 0;
117 workLoop = 0;
118
119 return true;
120}
121
122IOHIDSystem * IOHIDSystem::probe(IOService * provider,
123 SInt32 * score)
124{
125 if (!super::probe(provider,score)) return 0;
126
127 return this;
128}
129
130/*
131 * Perform reusable initialization actions here.
132 */
133IOWorkLoop * IOHIDSystem::getWorkLoop() const
134{
135 return workLoop;
136}
137
138bool IOHIDSystem::start(IOService * provider)
139{
140 bool iWasStarted = false;
141
142 do {
143 if (!super::start(provider)) break;
144
145 evInstance = this;
146
147 driverLock = IOLockAlloc(); // Event driver data protection lock
148 kickConsumerLock = IOLockAlloc();
149
150 /* A few details to be set up... */
151 pointerLoc.x = INIT_CURSOR_X;
152 pointerLoc.y = INIT_CURSOR_Y;
153
154 pointerDelta.x = 0;
155 pointerDelta.y = 0;
156
157 evScreenSize = sizeof(EvScreen) * 6; // FIX
158 evScreen = (void *) IOMalloc(evScreenSize);
159
160 if (!driverLock ||
161 !kickConsumerLock ||
162 !evScreenSize) break;
163
164 IOLockInit(driverLock);
165 IOLockInit(kickConsumerLock);
166 bzero(evScreen, evScreenSize);
167
168 /*
169 * Start up the work loop
170 */
171 workLoop = IOWorkLoop::workLoop();
172 cmdQ = IOCommandQueue::commandQueue
173 (this, (IOCommandQueueAction) &_doPerformInIOThread );
174 timerES = IOTimerEventSource::timerEventSource
175 (this, (IOTimerEventSource::Action) &_periodicEvents );
176
177 if (!workLoop || !cmdQ || !timerES)
178 break;
179
180 if ((workLoop->addEventSource(cmdQ) != kIOReturnSuccess)
181 || (workLoop->addEventSource(timerES) != kIOReturnSuccess))
182 break;
183
184 publishNotify = addNotification(
185 gIOPublishNotification, serviceMatching("IOHIDevice"),
186 (IOServiceNotificationHandler) &publishNotificationHandler,
187 this, 0 );
188
189 if (!publishNotify) break;
190
191 /*
192 * IOHIDSystem serves both as a service and a nub (we lead a double
193 * life). Register ourselves as a nub to kick off matching.
194 */
195
196 registerService();
197
198 addNotification( gIOPublishNotification,serviceMatching("IODisplayWrangler"), // look for the display wrangler
199 (IOServiceNotificationHandler)displayWranglerUp, this, 0 );
200
201 iWasStarted = true;
202 } while(false);
203
204 if (!iWasStarted) evInstance = 0;
205
206 return iWasStarted;
207}
208
209// **********************************************************************************
210// displayWranglerUp
211//
212// The Display Wrangler has appeared. We will be calling its
213// activityTickle method when there is user activity.
214// **********************************************************************************
215bool displayWranglerUp( OSObject * us, void * ref, IOService * yourDevice )
216{
217 if ( yourDevice != NULL ) {
218 ((IOHIDSystem *)us)->displayManager = yourDevice;
219 ((IOHIDSystem *)us)->displayState = yourDevice->registerInterestedDriver((IOService *)us);
220 }
221 return true;
222}
223
224
225//*********************************************************************************
226// powerStateDidChangeTo
227//
228// The display wrangler has changed state, so the displays have changed
229// state, too. We save the new state.
230//*********************************************************************************
231
232IOReturn IOHIDSystem::powerStateDidChangeTo ( IOPMPowerFlags theFlags, unsigned long, IOService*)
233{
234 displayState = theFlags;
235 return IOPMNoErr;
236}
237
238
239
240bool IOHIDSystem::publishNotificationHandler(
241 IOHIDSystem * self,
242 void * /* ref */,
243 IOService * newService )
244{
245 self->attach( newService );
246
247// IOTakeLock( self->driverLock);
248 if( self->eventsOpen
249 && OSDynamicCast(IOHIDevice, newService)) {
250 self->registerEventSource((IOHIDevice *) newService);
251 }
252// IOUnlock( self->driverLock);
253
254 return true;
255}
256
257
258/*
259 * Free locally allocated resources, and then ourselves.
260 */
261void IOHIDSystem::free()
262{
263 /* Initiates a normal close if open & inited */
264 if( driverLock)
265 evClose();
266
267 if (evScreen) IOFree( (void *)evScreen, evScreenSize );
268 evScreen = (void *)0;
269 evScreenSize = 0;
270
271 if (timerES) timerES->release();
272 if (cmdQ) cmdQ->release();
273 if (workLoop) workLoop->release();
274 if (publishNotify) publishNotify->release();
275
276 /* Release locally allocated resources */
277 if (kickConsumerLock) IOLockFree( kickConsumerLock);
278 if (driverLock) IOLockFree( driverLock);
279
280 super::free();
281}
282
283
284
285/*
286 * Open the driver for business. This call must be made before
287 * any other calls to the Event driver. We can only be opened by
288 * one user at a time.
289 */
290IOReturn IOHIDSystem::evOpen(void)
291{
292 IOReturn r = kIOReturnSuccess;
293
294 if ( evOpenCalled == true )
295 {
296 r = kIOReturnBusy;
297 goto done;
298 }
299 evOpenCalled = true;
300
301 if (!evInitialized)
302 {
303 evInitialized = true;
304 curBright = EV_SCREEN_MAX_BRIGHTNESS; // FIXME: Set from NVRAM?
305 curVolume = EV_AUDIO_MAX_VOLUME / 2; // FIXME: Set from NVRAM?
306 // Put code here that is to run on the first open ONLY.
307 }
308
309done:
310 return r;
311}
312
313IOReturn IOHIDSystem::evClose(void)
314{
315 IOTakeLock( driverLock);
316 if ( evOpenCalled == false )
317 {
318 IOUnlock( driverLock);
319 return kIOReturnBadArgument;
320 }
321 // Early close actions here
322 forceAutoDimState(false);
323 if( cursorEnabled)
324 hideCursor();
325 cursorStarted = false;
326 cursorEnabled = false;
327 IOUnlock( driverLock);
328
329 // Release the input devices.
330 detachEventSources();
331
332 // Tear down the shared memory area if set up
333// if ( eventsOpen == true )
334// unmapEventShmem(eventPort);
335
336 IOTakeLock( driverLock);
337 // Clear screens registry and related data
338 if ( evScreen != (void *)0 )
339 {
340 screens = 0;
341 lastShmemPtr = (void *)0;
342 }
343 // Remove port notification for the eventPort and clear the port out
344 setEventPort(MACH_PORT_NULL);
345// ipc_port_release_send(event_port);
346
347 // Clear local state to shutdown
348 evOpenCalled = false;
349 eventsOpen = false;
350
351 IOUnlock( driverLock);
352
353 return kIOReturnSuccess;
354}
355
356//
357// Dispatch state to screens registered with the Event Driver
358// Pending state changes for a device may be coalesced.
359//
360//
361// On entry, the driverLock should be set.
362//
363void IOHIDSystem::evDispatch(
364 /* command */ EvCmd evcmd)
365{
366 Point p;
367
368 if( !eventsOpen)
369 return;
370
371 for( int i = 0; i < screens; i++ ) {
372
373 EvScreen *esp = &((EvScreen*)evScreen)[i];
374
375 if ( esp->instance )
376 {
377 p.x = evg->cursorLoc.x; // Copy from shmem.
378 p.y = evg->cursorLoc.y;
379
380 bool onscreen = (0 != (cursorScreens & (1 << i)));
381
382 switch ( evcmd )
383 {
384 case EVMOVE:
385 if (onscreen)
386 esp->instance->moveCursor(&p, evg->frame);
387 break;
388
389 case EVSHOW:
390 if (onscreen)
391 esp->instance->showCursor(&p, evg->frame);
392 break;
393
394 case EVHIDE:
395 if (onscreen)
396 esp->instance->hideCursor();
397 break;
398
399 case EVLEVEL:
400 case EVNOP:
401 /* lets keep that compiler happy */
402 break;
403 }
404 }
405 }
406}
407
408//
409// Dispatch mechanism for special key press. If a port has been registered,
410// a message is built to be sent out to that port notifying that the key has
411// changed state. A level in the range 0-64 is provided for convenience.
412//
413void IOHIDSystem::evSpecialKeyMsg(unsigned key,
414 /* direction */ unsigned dir,
415 /* flags */ unsigned f,
416 /* level */ unsigned l)
417{
418 mach_port_t dst_port;
419 struct evioSpecialKeyMsg *msg;
420
421 static const struct evioSpecialKeyMsg init_msg =
422 { { MACH_MSGH_BITS(MACH_MSG_TYPE_COPY_SEND, // mach3xxx, is the right?
423 MACH_MSG_TYPE_MAKE_SEND), // mach_msg_bits_t msgh_bits;
424 sizeof (struct evioSpecialKeyMsg), // mach_msg_size_t msgh_size;
425 MACH_PORT_NULL, // mach_port_t msgh_remote_port;
426 MACH_PORT_NULL, // mach_port_t msgh_local_port;
427 0, // mach_msg_size_t msgh_reserved;
428 EV_SPECIAL_KEY_MSG_ID // mach_msg_id_t msgh_id;
429 },
430 0, /* key */
431 0, /* direction */
432 0, /* flags */
433 0 /* level */
434 };
435
436 if ( (dst_port = specialKeyPort(key)) == MACH_PORT_NULL )
437 return;
438 msg = (struct evioSpecialKeyMsg *) IOMalloc(
439 sizeof (struct evioSpecialKeyMsg) );
440 if ( msg == NULL )
441 return;
442
443 // Initialize the message.
444 bcopy( &init_msg, msg, sizeof (struct evioSpecialKeyMsg) );
445 msg->Head.msgh_remote_port = dst_port;
446 msg->key = key;
447 msg->direction = dir;
448 msg->flags = f;
449 msg->level = l;
450
451 // Send the message out from the I/O thread.
452 sendWorkLoopCommand(this,(IOHIDAction)_performSpecialKeyMsg,(void*)msg);
453}
454
455//
456// Reset instance variables to their default state for mice/pointers
457//
458void IOHIDSystem::_resetMouseParameters()
459{
460
461 IOTakeLock( driverLock);
462 if ( eventsOpen == false )
463 {
464 IOUnlock( driverLock);
465 return;
466 }
467 nanoseconds_to_absolutetime( EV_DCLICKTIME, &clickTimeThresh);
468 clickSpaceThresh.x = clickSpaceThresh.y = EV_DCLICKSPACE;
469 AbsoluteTime_to_scalar( &clickTime) = 0;
470 clickLoc.x = clickLoc.y = -EV_DCLICKSPACE;
471 clickState = 1;
472 nanoseconds_to_absolutetime( DAUTODIMPERIOD, &autoDimPeriod);
473 clock_get_uptime( &autoDimTime);
474 ADD_ABSOLUTETIME( &autoDimTime, &autoDimPeriod);
475 dimmedBrightness = DDIMBRIGHTNESS;
476
477 IOUnlock( driverLock);
478}
479
480void IOHIDSystem::_resetKeyboardParameters()
481{
482}
483
484/*
485 * Methods exported by the EventDriver.
486 *
487 * The screenRegister protocol is used by frame buffer drivers to register
488 * themselves with the Event Driver. These methods are called in response
489 * to a registerSelf or unregisterSelf message received from the Event
490 * Driver.
491 */
492
493int IOHIDSystem::registerScreen(IOGraphicsDevice * instance,
494 /* bounds */ Bounds * bp)
495{
496 EvScreen *esp;
497
498 if( (false == eventsOpen) || (0 == bp) )
499 {
500 return -1;
501 }
502
503 if ( lastShmemPtr == (void *)0 )
504 lastShmemPtr = evs;
505
506 /* shmemSize and bounds already set */
507 esp = &((EvScreen*)evScreen)[screens];
508 esp->instance = instance;
509 esp->bounds = bp;
510 // Update our idea of workSpace bounds
511 if ( bp->minx < workSpace.minx )
512 workSpace.minx = bp->minx;
513 if ( bp->miny < workSpace.miny )
514 workSpace.miny = bp->miny;
515 if ( bp->maxx < workSpace.maxx )
516 workSpace.maxx = bp->maxx;
517 if ( esp->bounds->maxy < workSpace.maxy )
518 workSpace.maxy = bp->maxy;
519
520 return(SCREENTOKEN + screens++);
521}
522
523
524void IOHIDSystem::unregisterScreen(int index)
525{
526 index -= SCREENTOKEN;
527
528 IOTakeLock( driverLock);
529 if ( eventsOpen == false || index < 0 || index >= screens )
530 {
531 IOUnlock( driverLock);
532 return;
533 }
534 hideCursor();
535
536 // clear the state for the screen
537 ((EvScreen*)evScreen)[index].instance = 0;
538 // Put the cursor someplace reasonable if it was on the destroyed screen
539 cursorScreens &= ~(1 << index);
540 // This will jump the cursor back on screen
541 setCursorPosition((Point *)&evg->cursorLoc, true);
542
543 showCursor();
544
545 IOUnlock( driverLock);
546}
547
548/* Member of EventClient protocol
549 *
550 * Absolute position input devices and some specialized output devices
551 * may need to know the bounding rectangle for all attached displays.
552 * The following method returns a Bounds* for the workspace. Please note
553 * that the bounds are kept as signed values, and that on a multi-display
554 * system the minx and miny values may very well be negative.
555 */
556Bounds * IOHIDSystem::workspaceBounds()
557{
558 return &workSpace;
559}
560
561IOReturn IOHIDSystem::createShmem(void* p1, void*, void*, void*, void*, void*)
562{ // IOMethod
563 int shmemVersion = (int)p1;
564 IOByteCount size;
565
566 if( shmemVersion != kIOHIDCurrentShmemVersion)
567 return( kIOReturnUnsupported);
568
569 IOTakeLock( driverLock);
570
571 if( 0 == globalMemory) {
572
573 size = sizeof(EvOffsets) + sizeof(EvGlobals);
574 globalMemory = IOBufferMemoryDescriptor::withOptions(
575 kIODirectionNone | kIOMemoryKernelUserShared, size );
576
577 if( !globalMemory) {
578 IOUnlock( driverLock);
579 return( kIOReturnNoMemory );
580 }
581 shmem_addr = (vm_offset_t) globalMemory->getBytesNoCopy();
582 shmem_size = size;
583 }
584
585 initShmem();
586 IOUnlock( driverLock);
587
588 return kIOReturnSuccess;
589}
590
591
592// Initialize the shared memory area.
593//
594// On entry, the driverLock should be set.
595void IOHIDSystem::initShmem()
596{
597 int i;
598 EvOffsets *eop;
599
600 /* top of sharedMem is EvOffsets structure */
601 eop = (EvOffsets *) shmem_addr;
602
603 bzero( (void*)shmem_addr, shmem_size);
604
605 /* fill in EvOffsets structure */
606 eop->evGlobalsOffset = sizeof(EvOffsets);
607 eop->evShmemOffset = eop->evGlobalsOffset + sizeof(EvGlobals);
608
609 /* find pointers to start of globals and private shmem region */
610 evg = (EvGlobals *)((char *)shmem_addr + eop->evGlobalsOffset);
611 evs = (void *)((char *)shmem_addr + eop->evShmemOffset);
612
613 evg->version = kIOHIDCurrentShmemVersion;
614 evg->structSize = sizeof( EvGlobals);
615
616 /* Set default wait cursor parameters */
617 evg->waitCursorEnabled = TRUE;
618 evg->globalWaitCursorEnabled = TRUE;
619 evg->waitThreshold = (12 * EV_TICKS_PER_SEC) / 10;
620 clock_interval_to_absolutetime_interval(DefaultWCFrameRate, kNanosecondScale,
621 &waitFrameRate);
622 clock_interval_to_absolutetime_interval(DefaultWCSustain, kNanosecondScale,
623 &waitSustain);
624 AbsoluteTime_to_scalar(&waitSusTime) = 0;
625 AbsoluteTime_to_scalar(&waitFrameTime) = 0;
626
627 EV_TICK_TO_NS(10,&periodicEventDelta);
628
629 /* Set up low-level queues */
630 lleqSize = LLEQSIZE;
631 for (i=lleqSize; --i != -1; ) {
632 evg->lleq[i].event.type = 0;
633 AbsoluteTime_to_scalar(&evg->lleq[i].event.time) = 0;
634 evg->lleq[i].event.flags = 0;
635 ev_init_lock(&evg->lleq[i].sema);
636 evg->lleq[i].next = i+1;
637 }
638 evg->LLELast = 0;
639 evg->lleq[lleqSize-1].next = 0;
640 evg->LLEHead =
641 evg->lleq[evg->LLELast].next;
642 evg->LLETail =
643 evg->lleq[evg->LLELast].next;
644 evg->buttons = 0;
645 evg->eNum = INITEVENTNUM;
646 evg->eventFlags = 0;
647
648 AbsoluteTime ts;
649 unsigned tick;
650 clock_get_uptime( &ts);
651 tick = EV_NS_TO_TICK(&ts);
652 if ( tick == 0 )
653 tick = 1; // No zero values allowed!
654 evg->VertRetraceClock = tick;
655
656 evg->cursorLoc.x = pointerLoc.x;
657 evg->cursorLoc.y = pointerLoc.y;
658 evg->dontCoalesce = 0;
659 evg->dontWantCoalesce = 0;
660 evg->wantPressure = 0;
661 evg->wantPrecision = 0;
662 evg->mouseRectValid = 0;
663 evg->movedMask = 0;
664 ev_init_lock( &evg->cursorSema );
665 ev_init_lock( &evg->waitCursorSema );
666 // Set eventsOpen last to avoid race conditions.
667 eventsOpen = true;
668}
669
670//
671// Set the event port. The event port is both an ownership token
672// and a live port we hold send rights on. The port is owned by our client,
673// the WindowServer. We arrange to be notified on a port death so that
674// we can tear down any active resources set up during this session.
675// An argument of PORT_NULL will cause us to forget any port death
676// notification that's set up.
677//
678// The driverLock should be held on entry.
679//
680void IOHIDSystem::setEventPort(mach_port_t port)
681{
682 static struct _eventMsg init_msg = { {
683 // mach_msg_bits_t msgh_bits;
684 MACH_MSGH_BITS(MACH_MSG_TYPE_COPY_SEND,0),
685 // mach_msg_size_t msgh_size;
686 sizeof (struct _eventMsg),
687 // mach_port_t msgh_remote_port;
688 MACH_PORT_NULL,
689 // mach_port_t msgh_local_port;
690 MACH_PORT_NULL,
691 // mach_msg_size_t msgh_reserved;
692 0,
693 // mach_msg_id_t msgh_id;
694 0
695 } };
696
697 if ( eventMsg == NULL )
698 eventMsg = IOMalloc( sizeof (struct _eventMsg) );
699 eventPort = port;
700 // Initialize the events available message.
701 *((struct _eventMsg *)eventMsg) = init_msg;
702
703 ((struct _eventMsg *)eventMsg)->h.msgh_remote_port = port;
704}
705
706//
707// Set the port to be used for a special key notification. This could be more
708// robust about letting ports be set...
709//
710IOReturn IOHIDSystem::setSpecialKeyPort(
711 /* keyFlavor */ int special_key,
712 /* keyPort */ mach_port_t key_port)
713{
714 if ( special_key >= 0 && special_key < NX_NUM_SCANNED_SPECIALKEYS )
715 _specialKeyPort[special_key] = key_port;
716 return kIOReturnSuccess;
717}
718
719mach_port_t IOHIDSystem::specialKeyPort(int special_key)
720{
721 if ( special_key >= 0 && special_key < NX_NUM_SCANNED_SPECIALKEYS )
722 return _specialKeyPort[special_key];
723 return MACH_PORT_NULL;
724}
725
726//
727// Helper functions for postEvent
728//
729static inline int myAbs(int a) { return(a > 0 ? a : -a); }
730
731short IOHIDSystem::getUniqueEventNum()
732{
733 while (++evg->eNum == NULLEVENTNUM)
734 ; /* sic */
735 return(evg->eNum);
736}
737
738// postEvent
739//
740// This routine actually places events in the event queue which is in
741// the EvGlobals structure. It is called from all parts of the ev
742// driver.
743//
744// On entry, the driverLock should be set.
745//
746
747void IOHIDSystem::postEvent(int what,
748 /* at */ Point * location,
749 /* atTime */ AbsoluteTime ts,
750 /* withData */ NXEventData * myData)
751{
752 NXEQElement * theHead = (NXEQElement *) &evg->lleq[evg->LLEHead];
753 NXEQElement * theLast = (NXEQElement *) &evg->lleq[evg->LLELast];
754 NXEQElement * theTail = (NXEQElement *) &evg->lleq[evg->LLETail];
755 int wereEvents;
756 unsigned theClock = EV_NS_TO_TICK(&ts);
757
758 /* Some events affect screen dimming */
759 if (EventCodeMask(what) & NX_UNDIMMASK) {
760 autoDimTime = ts;
761 ADD_ABSOLUTETIME( &autoDimTime, &autoDimPeriod);
762 if (autoDimmed)
763 undoAutoDim();
764 }
765 // Update the PS VertRetraceClock off of the timestamp if it looks sane
766 if ( theClock > (unsigned)evg->VertRetraceClock
767 && theClock < (unsigned)(evg->VertRetraceClock + (20 * EV_TICK_TIME)) )
768 evg->VertRetraceClock = theClock;
769
770 wereEvents = EventsInQueue();
771
772 xpr_ev_post("postEvent: what %d, X %d Y %d Q %d, needKick %d\n",
773 what,location->x,location->y,
774 EventsInQueue(), needToKickEventConsumer);
775
776 if ((!evg->dontCoalesce) /* Coalescing enabled */
777 && (theHead != theTail)
778 && (theLast->event.type == what)
779 && (EventCodeMask(what) & COALESCEEVENTMASK)
780 && ev_try_lock(&theLast->sema)) {
781 /* coalesce events */
782 theLast->event.location.x = location->x;
783 theLast->event.location.y = location->y;
784 absolutetime_to_nanoseconds(ts, &theLast->event.time);
785 if (myData != NULL)
786 theLast->event.data = *myData;
787 ev_unlock(&theLast->sema);
788 } else if (theTail->next != evg->LLEHead) {
789 /* store event in tail */
790 theTail->event.type = what;
791 theTail->event.location.x = location->x;
792 theTail->event.location.y = location->y;
793 theTail->event.flags = evg->eventFlags;
794 absolutetime_to_nanoseconds(ts, &theLast->event.time);
795 theTail->event.window = 0;
796 if (myData != NULL)
797 theTail->event.data = *myData;
798 switch(what) {
799 case NX_LMOUSEDOWN:
800 theTail->event.data.mouse.eventNum =
801 leftENum = getUniqueEventNum();
802 break;
803 case NX_RMOUSEDOWN:
804 theTail->event.data.mouse.eventNum =
805 rightENum = getUniqueEventNum();
806 break;
807 case NX_LMOUSEUP:
808 theTail->event.data.mouse.eventNum = leftENum;
809 leftENum = NULLEVENTNUM;
810 break;
811 case NX_RMOUSEUP:
812 theTail->event.data.mouse.eventNum = rightENum;
813 rightENum = NULLEVENTNUM;
814 break;
815 }
816 if (EventCodeMask(what) & PRESSUREEVENTMASK) {
817 theTail->event.data.mouse.pressure = lastPressure;
818 }
819 if (EventCodeMask(what) & MOUSEEVENTMASK) { /* Click state */
820 AbsoluteTime delta = ts;
821 SUB_ABSOLUTETIME( &delta, &clickTime);
822 if ((CMP_ABSOLUTETIME(&delta, &clickTimeThresh) <= 0)
823 && (myAbs(location->x - clickLoc.x) <= clickSpaceThresh.x)
824 && (myAbs(location->y - clickLoc.y) <= clickSpaceThresh.y)) {
825 if ((what == NX_LMOUSEDOWN)||(what == NX_RMOUSEDOWN)) {
826 clickTime = ts;
827 theTail->event.data.mouse.click = ++clickState;
828 } else {
829 theTail->event.data.mouse.click = clickState;
830 }
831 } else if ((what == NX_LMOUSEDOWN)||(what == NX_RMOUSEDOWN)) {
832 clickLoc = *location;
833 clickTime = ts;
834 clickState = 1;
835 theTail->event.data.mouse.click = clickState;
836 } else
837 theTail->event.data.mouse.click = 0;
838 }
839#if PMON
840 pmon_log_event(PMON_SOURCE_EV,
841 KP_EV_POST_EVENT,
842 what,
843 evg->eventFlags,
844 theClock);
845#endif
846 evg->LLETail = theTail->next;
847 evg->LLELast = theLast->next;
848 if ( ! wereEvents ) // Events available, so wake event consumer
849 kickEventConsumer();
850 }
851 else
852 {
853 /*
854 * if queue is full, ignore event, too hard to take care of all cases
855 */
856 IOLog("%s: postEvent LLEventQueue overflow.\n", getName());
857 kickEventConsumer();
858#if PMON
859 pmon_log_event( PMON_SOURCE_EV,
860 KP_EV_QUEUE_FULL,
861 what,
862 evg->eventFlags,
863 theClock);
864#endif
865 }
866}
867
868/*
869 * - kickEventConsumer
870 *
871 * Try to send a message out to let the event consumer know that
872 * there are now events available for consumption.
873 */
874
875void IOHIDSystem::kickEventConsumer()
876{
877 IOReturn err;
878
879 IOTakeLock( kickConsumerLock);
880 xpr_ev_post("kickEventConsumer (need == %d)\n",
881 needToKickEventConsumer,2,3,4,5);
882 if ( needToKickEventConsumer == true )
883 {
884 IOUnlock( kickConsumerLock);
885 return; // Request is already pending
886 }
887 needToKickEventConsumer = true; // Posting a request now
888 IOUnlock( kickConsumerLock);
889
890 err = sendWorkLoopCommand(this, (IOHIDAction)_performKickEventConsumer,
891 NULL);
892
893 if( err)
894 IOLog("%s: cmdQ fail %d\n", getName(), err);
895}
896
897/*
898 * Event sources may need to use an I/O thread from time to time.
899 * Rather than have each instance running it's own thread, we provide
900 * a callback mechanism to let all the instances share a common Event I/O
901 * thread running in the IOTask space, and managed by the Event Driver.
902 */
903
904IOReturn IOHIDSystem::sendWorkLoopCommand(OSObject * target,
905 IOHIDAction action,
906 void * data)
907{
908 kern_return_t err;
909
910 err = cmdQ->enqueueCommand( /* sleep */ true,
911 /* field0 */ target,
912 /* field1 */ (void *) action,
913 /* field2 */ data );
914
915 return (err == KERN_SUCCESS) ? kIOReturnSuccess : kIOReturnNoMemory;
916}
917
918/*
919 * The following methods are executed from the I/O thread only.
920 */
921
922/*
923 * This routine is run within the I/O thread, on demand from the
924 * sendWorkLoopCommand method above. We attempt to dispatch a message
925 * to the specified selector and instance.
926 */
927void IOHIDSystem::_doPerformInIOThread(void* self,
928 void* target, /* IOCommandQueueAction */
929 void* action,
930 void* data,
931 void* /* unused */)
932{
933 (*((IOHIDAction)action))((OSObject *)target, data);
934}
935
936/*
937 * This is run in the I/O thread, to perform the actual message send operation.
938 */
939
940void IOHIDSystem::_performSpecialKeyMsg(IOHIDSystem * self,
941 struct evioSpecialKeyMsg *msg)
942 /* IOHIDAction */
943{
944 kern_return_t r;
945
946 xpr_ev_post("_performSpecialKeyMsg 0x%x\n", msg,2,3,4,5);
947
948
949 /* FIXME: Don't block */
950 r = mach_msg_send_from_kernel( &msg->Head, msg->Head.msgh_size);
951
952 xpr_ev_post("_performSpecialKeyMsg: msg_send() == %d\n",r,2,3,4,5);
953 if ( r != MACH_MSG_SUCCESS )
954 {
955 IOLog("%s: _performSpecialKeyMsg msg_send returned %d\n",
956 self->getName(), r);
957 }
958 if ( r == MACH_SEND_INVALID_DEST ) /* Invalidate the port */
959 {
960 self->setSpecialKeyPort(
961 /* keyFlavor */ msg->key,
962 /* keyPort */ MACH_PORT_NULL);
963 }
964 IOFree( (void *)msg, sizeof (struct evioSpecialKeyMsg) );
965}
966
967/*
968 * This is run in the I/O thread, to perform the actual message send operation.
969 * Note that we perform a non-blocking send. The Event port in the event
970 * consumer has a queue depth of 1 message. Once the consumer picks up that
971 * message, it runs until the event queue is exhausted before trying to read
972 * another message. If a message is pending,there is no need to enqueue a
973 * second one. This also keeps us from blocking the I/O thread in a msg_send
974 * which could result in a deadlock if the consumer were to make a call into
975 * the event driver.
976 */
977void IOHIDSystem::_performKickEventConsumer(IOHIDSystem * self, void *) /* IOHIDAction */
978{
979 kern_return_t r;
980 mach_msg_header_t *msgh
981
982 xpr_ev_post("_performKickEventConsumer\n", 1,2,3,4,5);
983 IOTakeLock( self->kickConsumerLock);
984 self->needToKickEventConsumer = false; // Request received and processed
985 IOUnlock( self->kickConsumerLock);
986
987 msgh = (mach_msg_header_t *)self->eventMsg;
988 if( msgh) {
989
990 r = mach_msg_send_from_kernel( msgh, msgh->msgh_size);
991 switch ( r )
992 {
993 case MACH_SEND_TIMED_OUT:/* Already has a message posted */
994 case MACH_MSG_SUCCESS: /* Message is posted */
995 break;
996 default: /* Log the error */
997 IOLog("%s: _performKickEventConsumer msg_send returned %d\n",
998 self->getName(), r);
999 break;
1000 }
1001 }
1002}
1003
1004//
1005// Schedule the next periodic event to be run, based on the current state of
1006// the event system. We have to consider things here such as when the last
1007// periodic event pass ran, if there is currently any mouse delta accumulated,
1008// and how long it has been since the last event was consumed by an app (for
1009// driving the wait cursor).
1010//
1011// This code should only be run from the periodicEvents method or
1012// _setCursorPosition.
1013//
1014void IOHIDSystem::scheduleNextPeriodicEvent()
1015{
1016 if (CMP_ABSOLUTETIME( &waitFrameTime, &thisPeriodicRun) > 0)
1017 {
1018 AbsoluteTime time_for_next_run;
1019
1020 clock_get_uptime(&time_for_next_run);
1021 ADD_ABSOLUTETIME( &time_for_next_run, &periodicEventDelta);
1022
1023 if (CMP_ABSOLUTETIME( &waitFrameTime, &time_for_next_run) < 0) {
1024 timerES->wakeAtTime(waitFrameTime);
1025 return;
1026 }
1027 }
1028
1029 timerES->setTimeout(periodicEventDelta);
1030}
1031
1032// Periodic events are driven from this method.
1033// After taking care of all pending work, the method
1034// calls scheduleNextPeriodicEvent to compute and set the
1035// next callout.
1036//
1037
1038void IOHIDSystem::_periodicEvents(IOHIDSystem * self,
1039 IOTimerEventSource *timer)
1040{
1041 self->periodicEvents(timer);
1042}
1043
1044void IOHIDSystem::periodicEvents(IOTimerEventSource * /* timer */)
1045 /* IOTimerEventSource::Action, IOHIDAction */
1046{
1047 unsigned int tick;
1048
1049 // If eventsOpen is false, then the driver shmem is
1050 // no longer valid, and it is in the process of shutting down.
1051 // We should give up without rescheduling.
1052 IOTakeLock( driverLock);
1053 if ( eventsOpen == false )
1054 {
1055 IOUnlock( driverLock);
1056 return;
1057 }
1058
1059 // Increment event time stamp last
1060 clock_get_uptime(&thisPeriodicRun);
1061
1062 // Temporary hack til we wean CGS off of VertRetraceClock
1063 tick = EV_NS_TO_TICK(&thisPeriodicRun);
1064 if ( tick == 0 )
1065 tick = 1;
1066 evg->VertRetraceClock = tick;
1067
1068 // Update cursor position if needed
1069 if ( needSetCursorPosition == true )
1070 _setCursorPosition(&pointerLoc, false);
1071
1072 // WAITCURSOR ACTION
1073 if ( ev_try_lock(&evg->waitCursorSema) )
1074 {
1075 if ( ev_try_lock(&evg->cursorSema) )
1076 {
1077 // See if the current context has timed out
1078 if ( (evg->AALastEventSent != evg->AALastEventConsumed)
1079 && ((evg->VertRetraceClock - evg->AALastEventSent >
1080 evg->waitThreshold)))
1081 evg->ctxtTimedOut = TRUE;
1082 // If wait cursor enabled and context timed out, do waitcursor
1083 if (evg->waitCursorEnabled && evg->globalWaitCursorEnabled &&
1084 evg->ctxtTimedOut)
1085 {
1086 /* WAIT CURSOR SHOULD BE ON */
1087 if (!evg->waitCursorUp)
1088 showWaitCursor();
1089 } else
1090 {
1091 /* WAIT CURSOR SHOULD BE OFF */
1092 if (evg->waitCursorUp &&
1093 CMP_ABSOLUTETIME(&waitSusTime, &thisPeriodicRun) <= 0)
1094 hideWaitCursor();
1095 }
1096 /* Animate cursor */
1097 if (evg->waitCursorUp &&
1098 CMP_ABSOLUTETIME(&waitFrameTime, &thisPeriodicRun) <= 0)
1099 animateWaitCursor();
1100 ev_unlock(&evg->cursorSema);
1101 if ((CMP_ABSOLUTETIME(&thisPeriodicRun, &autoDimTime) > 0)
1102 && (!autoDimmed))
1103 doAutoDim();
1104 }
1105 ev_unlock(&evg->waitCursorSema);
1106 }
1107
1108 scheduleNextPeriodicEvent();
1109 IOUnlock( driverLock);
1110
1111 return;
1112}
1113
1114//
1115// Start the cursor system running.
1116//
1117// At this point, the WindowServer is up, running, and ready to process events.
1118// We will attach the keyboard and mouse, if none are available yet.
1119//
1120
1121bool IOHIDSystem::resetCursor()
1122{
1123 volatile Point * p;
1124 UInt32 newScreens = 0;
1125 SInt32 pinScreen = -1L;
1126
1127 p = &evg->cursorLoc;
1128
1129 /* Get mask of screens on which the cursor is present */
1130 EvScreen *screen = (EvScreen *)evScreen;
1131 for (int i = 0; i < screens; i++ ) {
1132 if ((screen[i].instance) && PtInRect(p, screen[i].bounds)) {
1133 pinScreen = i;
1134 newScreens |= (1 << i);
1135 }
1136 }
1137
1138 if (newScreens == 0)
1139 pinScreen = 0;
1140
1141 // reset pin rect
1142 cursorPin = *(((EvScreen*)evScreen)[pinScreen].bounds);
1143 cursorPin.maxx--; /* Make half-open rectangle */
1144 cursorPin.maxy--;
1145 cursorPinScreen = pinScreen;
1146
1147 if (newScreens == 0) {
1148 /* Pin new cursor position to cursorPin rect */
1149 p->x = (p->x < cursorPin.minx) ?
1150 cursorPin.minx : ((p->x > cursorPin.maxx) ?
1151 cursorPin.maxx : p->x);
1152 p->y = (p->y < cursorPin.miny) ?
1153 cursorPin.miny : ((p->y > cursorPin.maxy) ?
1154 cursorPin.maxy : p->y);
1155
1156 /* regenerate mask for new position */
1157 for (int i = 0; i < screens; i++ ) {
1158 if ((screen[i].instance) && PtInRect(p, screen[i].bounds))
1159 newScreens |= (1 << i);
1160 }
1161 }
1162
1163 cursorScreens = newScreens;
1164
1165 pointerDelta.x += (evg->cursorLoc.x - pointerLoc.x);
1166 pointerDelta.y += (evg->cursorLoc.y - pointerLoc.y);
1167 pointerLoc.x = evg->cursorLoc.x;
1168 pointerLoc.y = evg->cursorLoc.y;
1169
1170 return( true );
1171}
1172
1173bool IOHIDSystem::startCursor()
1174{
1175 bool ok;
1176
1177 if (0 == screens) // no screens, no cursor
1178 return( false );
1179
1180 resetCursor();
1181 setBrightness();
1182 showCursor();
1183
1184 // Start the cursor control callouts
1185 ok = (kIOReturnSuccess ==
1186 sendWorkLoopCommand(this, (IOHIDAction)_periodicEvents, timerES));
1187
1188 cursorStarted = ok;
1189 return( ok );
1190}
1191
1192//
1193// Wait Cursor machinery. The driverLock should be held on entry to
1194// these methods, and the shared memory area must be set up.
1195//
1196void IOHIDSystem::showWaitCursor()
1197{
1198 xpr_ev_cursor("showWaitCursor\n",1,2,3,4,5);
1199 evg->waitCursorUp = true;
1200 hideCursor();
1201 evg->frame = EV_WAITCURSOR;
1202 showCursor();
1203 // Set animation and sustain absolute times.
1204
1205 waitSusTime = waitFrameTime = thisPeriodicRun;
1206 ADD_ABSOLUTETIME( &waitFrameTime, &waitFrameRate);
1207 ADD_ABSOLUTETIME( &waitSusTime, &waitSustain);
1208}
1209
1210void IOHIDSystem::hideWaitCursor()
1211{
1212 xpr_ev_cursor("hideWaitCursor\n",1,2,3,4,5);
1213 evg->waitCursorUp = false;
1214 hideCursor();
1215 evg->frame = EV_STD_CURSOR;
1216 showCursor();
1217 AbsoluteTime_to_scalar(&waitFrameTime) = 0;
1218 AbsoluteTime_to_scalar(&waitSusTime ) = 0;
1219}
1220
1221void IOHIDSystem::animateWaitCursor()
1222{
1223 xpr_ev_cursor("animateWaitCursor\n",1,2,3,4,5);
1224 changeCursor(evg->frame + 1);
1225 // Set the next animation time.
1226 waitFrameTime = thisPeriodicRun;
1227 ADD_ABSOLUTETIME( &waitFrameTime, &waitFrameRate);
1228}
1229
1230void IOHIDSystem::changeCursor(int frame)
1231{
1232 evg->frame =
1233 (frame > EV_MAXCURSOR) ? EV_WAITCURSOR : frame;
1234 xpr_ev_cursor("changeCursor %d\n",evg->frame,2,3,4,5);
1235 moveCursor();
1236}
1237
1238//
1239// Return the screen number in which point p lies. Return -1 if the point
1240// lies outside of all registered screens.
1241//
1242int IOHIDSystem::pointToScreen(Point * p)
1243{
1244 int i;
1245 EvScreen *screen = (EvScreen *)evScreen;
1246 for (i=screens; --i != -1; ) {
1247 if (screen[i].instance != 0
1248 && (p->x >= screen[i].bounds->minx)
1249 && (p->x < screen[i].bounds->maxx)
1250 && (p->y >= screen[i].bounds->miny)
1251 && (p->y < screen[i].bounds->maxy))
1252 return i;
1253 }
1254 return(-1); /* Cursor outside of known screen boundary */
1255}
1256
1257//
1258// API used to manipulate screen brightness
1259//
1260// On entry to each of these, the driverLock should be set.
1261//
1262// Set the current brightness
1263void IOHIDSystem::setBrightness(int b)
1264{
1265 if ( b < EV_SCREEN_MIN_BRIGHTNESS )
1266 b = EV_SCREEN_MIN_BRIGHTNESS;
1267 else if ( b > EV_SCREEN_MAX_BRIGHTNESS )
1268 b = EV_SCREEN_MAX_BRIGHTNESS;
1269 if ( b != curBright )
1270 {
1271 curBright = b;
1272 if ( autoDimmed == false )
1273 setBrightness();
1274 }
1275}
1276
1277int IOHIDSystem::brightness()
1278{
1279 return curBright;
1280}
1281
1282// Set the current brightness
1283void IOHIDSystem::setAutoDimBrightness(int b)
1284{
1285 if ( b < EV_SCREEN_MIN_BRIGHTNESS )
1286 b = EV_SCREEN_MIN_BRIGHTNESS;
1287 else if ( b > EV_SCREEN_MAX_BRIGHTNESS )
1288 b = EV_SCREEN_MAX_BRIGHTNESS;
1289 if ( b != dimmedBrightness )
1290 {
1291 dimmedBrightness = b;
1292 if ( autoDimmed == true )
1293 setBrightness();
1294 }
1295}
1296
1297int IOHIDSystem::autoDimBrightness()
1298{
1299 return dimmedBrightness;
1300}
1301
1302int IOHIDSystem::currentBrightness() // Return the current brightness
1303{
1304 if ( autoDimmed == true && dimmedBrightness < curBright )
1305 return dimmedBrightness;
1306 else
1307 return curBright;
1308}
1309
1310void IOHIDSystem::doAutoDim()
1311{
1312 autoDimmed = true;
1313 setBrightness();
1314}
1315
1316// Return display brightness to normal
1317void IOHIDSystem::undoAutoDim()
1318{
1319 autoDimmed = false;
1320 setBrightness();
1321}
1322
1323void IOHIDSystem::forceAutoDimState(bool dim)
1324{
1325 if ( dim == true )
1326 {
1327 if ( autoDimmed == false )
1328 {
1329 if ( eventsOpen == true )
1330 clock_get_uptime( &autoDimTime);
1331 doAutoDim();
1332 }
1333 }
1334 else
1335 {
1336 if ( autoDimmed == true )
1337 {
1338 if ( eventsOpen == true ) {
1339 clock_get_uptime( &autoDimTime);
1340 ADD_ABSOLUTETIME( &autoDimTime, &autoDimPeriod);
1341 }
1342 undoAutoDim();
1343 }
1344 }
1345}
1346
1347//
1348// API used to manipulate sound volume/attenuation
1349//
1350// Set the current brightness.
1351void IOHIDSystem::setAudioVolume(int v)
1352{
1353 if ( v < EV_AUDIO_MIN_VOLUME )
1354 v = EV_AUDIO_MIN_VOLUME;
1355 else if ( v > EV_AUDIO_MAX_VOLUME )
1356 v = EV_AUDIO_MAX_VOLUME;
1357 curVolume = v;
1358}
1359
1360//
1361// Volume set programatically, rather than from keyboard
1362//
1363void IOHIDSystem::setUserAudioVolume(int v)
1364{
1365 setAudioVolume(v);
1366 // Let sound driver know about the change
1367 evSpecialKeyMsg( NX_KEYTYPE_SOUND_UP,
1368 /* direction */ NX_KEYDOWN,
1369 /* flags */ 0,
1370 /* level */ curVolume);
1371}
1372
1373int IOHIDSystem::audioVolume()
1374{
1375 return curVolume;
1376}
1377
1378//
1379// API used to drive event state out to attached screens
1380//
1381// On entry to each of these, the driverLock should be set.
1382//
1383inline void IOHIDSystem::setBrightness() // Propagate state out to screens
1384{
1385 evDispatch(/* command */ EVLEVEL);
1386}
1387
1388inline void IOHIDSystem::showCursor()
1389{
1390 evDispatch(/* command */ EVSHOW);
1391}
1392inline void IOHIDSystem::hideCursor()
1393{
1394 evDispatch(/* command */ EVHIDE);
1395}
1396
1397inline void IOHIDSystem::moveCursor()
1398{
1399 evDispatch(/* command */ EVMOVE);
1400}
1401
1402//
1403// - attachDefaultEventSources
1404// Attach the default event sources.
1405//
1406void IOHIDSystem::attachDefaultEventSources()
1407{
1408 OSObject * source;
1409 OSIterator * sources;
1410
1411
1412 sources = getProviderIterator();
1413
1414 if (!sources) return;
1415
1416 while( (source = sources->getNextObject())) {
1417 if (OSDynamicCast(IOHIDevice, source)) {
1418
1419 registerEventSource((IOHIDevice *)source);
1420 }
1421 }
1422 sources->release();
1423}
1424
1425//
1426// - detachEventSources
1427// Detach all event sources
1428//
1429void IOHIDSystem::detachEventSources()
1430{
1431 OSIterator * iter;
1432 IOHIDevice * srcInstance;
1433
1434 iter = getOpenProviderIterator();
1435 if( iter) {
1436 while( (srcInstance = (IOHIDevice *) iter->getNextObject())) {
1437#ifdef DEBUG
1438 kprintf("detachEventSource:%s\n", srcInstance->getName());
1439#endif
1440 srcInstance->close(this);
1441 }
1442 iter->release();
1443 }
1444}
1445
1446//
1447// EventSrcClient implementation
1448//
1449
1450//
1451// A new device instance desires to be added to our list.
1452// Try to get ownership of the device. If we get it, add it to
1453// the list.
1454//
1455bool IOHIDSystem::registerEventSource(IOHIDevice * source)
1456{
1457 bool success = false;
1458
1459#ifdef DEBUG
1460 kprintf("registerEventSource:%s\n", ((IOHIDevice*)source)->getName());
1461#endif
1462
1463 if ( OSDynamicCast(IOHIKeyboard, source) ) {
1464 success = ((IOHIKeyboard*)source)->open(this, kIOServiceSeize,
1465 (KeyboardEventAction) _keyboardEvent,
1466 (KeyboardSpecialEventAction) _keyboardSpecialEvent,
1467 (UpdateEventFlagsAction) _updateEventFlags);
1468 } else if ( OSDynamicCast(IOHIPointing, source) ) {
1469 success = ((IOHIPointing*)source)->open(this, kIOServiceSeize,
1470 (RelativePointerEventAction) _relativePointerEvent,
1471 (AbsolutePointerEventAction) _absolutePointerEvent,
1472 (ScrollWheelEventAction) _scrollWheelEvent);
1473 }
1474
1475 if ( success == false )
1476 IOLog("%s: Seize of %s failed.\n", getName(), source->getName());
1477
1478 return success;
1479}
1480
1481IOReturn IOHIDSystem::message(UInt32 type, IOService * provider,
1482 void * argument)
1483{
1484 IOReturn status = kIOReturnSuccess;
1485
1486 switch (type)
1487 {
1488 case kIOMessageServiceIsTerminated:
1489#ifdef DEBUG
1490 kprintf("detachEventSource:%s\n", provider->getName());
1491#endif
1492 provider->close( this );
1493 case kIOMessageServiceWasClosed:
1494 break;
1495
1496 default:
1497 status = super::message(type, provider, argument);
1498 break;
1499 }
1500
1501 return status;
1502}
1503
1504//
1505// This will scale the point at location in the coordinate system represented by bounds
1506// to the coordinate system of the current screen.
1507// This is needed for absolute pointer events that come from devices with different bounds.
1508//
1509void IOHIDSystem::_scaleLocationToCurrentScreen(Point *location, Bounds *bounds)
1510{
1511 // We probably also need to look at current screen offsets as well
1512 // but that shouldn't matter until we provide tablets with a way to
1513 // switch screens...
1514 location->x = ((location->x - bounds->minx) * (cursorPin.maxx - cursorPin.minx + 1)
1515 / (bounds->maxx - bounds->minx)) + cursorPin.minx;
1516 location->y = ((location->y - bounds->miny) * (cursorPin.maxy - cursorPin.miny + 1)
1517 / (bounds->maxy - bounds->miny)) + cursorPin.miny;
1518
1519 return;
1520}
1521
1522
1523//
1524// Process a mouse status change. The driver should sign extend
1525// it's deltas and perform any bit flipping needed there.
1526//
1527// We take the state as presented and turn it into events.
1528//
1529void IOHIDSystem::_relativePointerEvent(IOHIDSystem * self,
1530 int buttons,
1531 /* deltaX */ int dx,
1532 /* deltaY */ int dy,
1533 /* atTime */ AbsoluteTime ts)
1534{
1535 self->relativePointerEvent(buttons, dx, dy, ts);
1536}
1537
1538void IOHIDSystem::relativePointerEvent(int buttons,
1539 /* deltaX */ int dx,
1540 /* deltaY */ int dy,
1541 /* atTime */ AbsoluteTime ts)
1542{
1543 AbsoluteTime nextVBL, vblDeltaTime, eventDeltaTime, moveDeltaTime;
1544
1545 if( displayManager != NULL ) // if there is a display manager, tell
1546 displayManager->activityTickle(0,0); // it there is user activity
1547
1548 IOTakeLock( driverLock);
1549 if( eventsOpen == false )
1550 {
1551 IOUnlock( driverLock);
1552 return;
1553 }
1554 // Fake up pressure changes from button state changes
1555 if( (buttons & EV_LB) != (evg->buttons & EV_LB) )
1556 {
1557 if ( buttons & EV_LB )
1558 lastPressure = MAXPRESSURE;
1559 else
1560 lastPressure = MINPRESSURE;
1561 }
1562 _setButtonState(buttons, /* atTime */ ts);
1563
1564 // figure cursor movement
1565 if( dx || dy )
1566 {
1567 eventDeltaTime = ts;
1568 SUB_ABSOLUTETIME( &eventDeltaTime, &lastEventTime );
1569 lastEventTime = ts;
1570
1571 IOGraphicsDevice * instance = ((EvScreen*)evScreen)[cursorPinScreen].instance;
1572 if( instance)
1573 instance->getVBLTime( &nextVBL, &vblDeltaTime );
1574 else
1575 nextVBL.hi = nextVBL.lo = vblDeltaTime.hi = vblDeltaTime.lo = 0;
1576
1577 if( dx && ((dx ^ accumDX) < 0))
1578 accumDX = 0;
1579 if( dy && ((dy ^ accumDY) < 0))
1580 accumDY = 0;
1581
1582 KERNEL_DEBUG(0x0c000060 | DBG_FUNC_NONE,
1583 nextVBL.hi, nextVBL.lo, postedVBLTime.hi, postedVBLTime.lo, 0);
1584
1585 if( (nextVBL.lo || nextVBL.hi)
1586 && (nextVBL.lo == postedVBLTime.lo) && (nextVBL.hi == postedVBLTime.hi)) {
1587 accumDX += dx;
1588 accumDY += dy;
1589
1590 } else {
1591 SInt32 num = 0, div = 0;
1592
1593 dx += accumDX;
1594 dy += accumDY;
1595
1596 moveDeltaTime = ts;
1597 SUB_ABSOLUTETIME( &moveDeltaTime, &lastMoveTime );
1598 lastMoveTime = ts;
1599
1600 if( (eventDeltaTime.lo < vblDeltaTime.lo) && (0 == eventDeltaTime.hi)
1601 && vblDeltaTime.lo && moveDeltaTime.lo) {
1602 num = vblDeltaTime.lo;
1603 div = moveDeltaTime.lo;
1604 dx = (num * dx) / div;
1605 dy = (num * dy) / div;
1606 }
1607
1608 KERNEL_DEBUG(0x0c000000 | DBG_FUNC_NONE,
1609 dx, dy, num, div, 0);
1610
1611 postedVBLTime = nextVBL; // we have posted for this vbl
1612 accumDX = accumDY = 0;
1613
1614 if( dx || dy ) {
1615 pointerLoc.x += dx;
1616 pointerLoc.y += dy;
1617 pointerDelta.x += dx;
1618 pointerDelta.y += dy;
1619 _setCursorPosition(&pointerLoc, false);
1620 }
1621 }
1622 }
1623 IOUnlock( driverLock);
1624}
1625
1626void IOHIDSystem::_absolutePointerEvent(IOHIDSystem * self,
1627 int buttons,
1628 /* at */ Point * newLoc,
1629 /* withBounds */ Bounds * bounds,
1630 /* inProximity */ bool proximity,
1631 /* withPressure */ int pressure,
1632 /* withAngle */ int stylusAngle,
1633 /* atTime */ AbsoluteTime ts)
1634{
1635 self->absolutePointerEvent(buttons, newLoc, bounds, proximity,
1636 pressure, stylusAngle, ts);
1637}
1638
1639void IOHIDSystem::absolutePointerEvent(int buttons,
1640 /* at */ Point * newLoc,
1641 /* withBounds */ Bounds * bounds,
1642 /* inProximity */ bool proximity,
1643 /* withPressure */ int pressure,
1644 /* withAngle */ int /* stylusAngle */,
1645 /* atTime */ AbsoluteTime ts)
1646
1647{
1648 /*
1649 * If you don't know what to pass for the following fields, pass the
1650 * default values below:
1651 * pressure = MINPRESSURE or MAXPRESSURE
1652 * stylusAngle = 90
1653 */
1654
1655 NXEventData outData; /* dummy data */
1656
1657 if ( displayManager != NULL ) { // if there is a display manager, tell
1658 displayManager->activityTickle(0,0); // it there is user activity
1659 }
1660
1661 IOTakeLock( driverLock);
1662 if ( eventsOpen == false )
1663 {
1664 IOUnlock( driverLock);
1665 return;
1666 }
1667
1668 lastPressure = pressure;
1669
1670 _scaleLocationToCurrentScreen(newLoc, bounds);
1671 if ( newLoc->x != pointerLoc.x || newLoc->y != pointerLoc.y )
1672 {
1673 pointerDelta.x += (newLoc->x - pointerLoc.x);
1674 pointerDelta.y += (newLoc->y - pointerLoc.y);
1675 pointerLoc = *newLoc;
1676 _setCursorPosition(&pointerLoc, false);
1677 }
1678 if ( lastProximity != proximity && proximity == true )
1679 {
1680 evg->eventFlags |= NX_STYLUSPROXIMITYMASK;
1681 bzero( (char *)&outData, sizeof outData );
1682 postEvent( NX_FLAGSCHANGED,
1683 /* at */ (Point *)&pointerLoc,
1684 /* atTime */ ts,
1685 /* withData */ &outData);
1686 }
1687 if ( proximity == true )
1688 _setButtonState(buttons, /* atTime */ ts);
1689 if ( lastProximity != proximity && proximity == false )
1690 {
1691 evg->eventFlags &= ~NX_STYLUSPROXIMITYMASK;
1692 bzero( (char *)&outData, sizeof outData );
1693 postEvent( NX_FLAGSCHANGED,
1694 /* at */ (Point *)&pointerLoc,
1695 /* atTime */ ts,
1696 /* withData */ &outData);
1697 }
1698 lastProximity = proximity;
1699 IOUnlock( driverLock);
1700}
1701
1702void IOHIDSystem::_scrollWheelEvent(IOHIDSystem * self,
1703 short deltaAxis1,
1704 short deltaAxis2,
1705 short deltaAxis3,
1706 /* atTime */ AbsoluteTime ts)
1707{
1708 self->scrollWheelEvent(deltaAxis1, deltaAxis2, deltaAxis3, ts);
1709}
1710
1711void IOHIDSystem::scrollWheelEvent(short deltaAxis1,
1712 short deltaAxis2,
1713 short deltaAxis3,
1714 /* atTime */ AbsoluteTime ts)
1715
1716{
1717 NXEventData wheelData;
1718
1719 if ((deltaAxis1 == 0) && (deltaAxis2 == 0) && (deltaAxis3 == 0)) {
1720 return;
1721 }
1722
1723 IOTakeLock( driverLock);
1724 if (!eventsOpen)
1725 {
1726 IOUnlock(driverLock);
1727 return;
1728 }
1729
1730 bzero((char *)&wheelData, sizeof wheelData);
1731 wheelData.scrollWheel.deltaAxis1 = deltaAxis1;
1732 wheelData.scrollWheel.deltaAxis2 = deltaAxis2;
1733 wheelData.scrollWheel.deltaAxis3 = deltaAxis3;
1734
1735 postEvent( NX_SCROLLWHEELMOVED,
1736 /* at */ (Point *)&evg->cursorLoc,
1737 /* atTime */ ts,
1738 /* withData */ &wheelData);
1739
1740 IOUnlock(driverLock);
1741 return;
1742}
1743
1744void IOHIDSystem::_tabletEvent(IOHIDSystem *self,
1745 NXEventData *tabletData,
1746 AbsoluteTime ts)
1747{
1748 self->tabletEvent(tabletData, ts);
1749}
1750
1751void IOHIDSystem::tabletEvent(NXEventData *tabletData,
1752 AbsoluteTime ts)
1753{
1754 IOTakeLock(driverLock);
1755
1756 if (eventsOpen) {
1757 postEvent(NX_TABLETPOINTER,
1758 (Point *)&evg->cursorLoc,
1759 ts,
1760 tabletData);
1761 }
1762
1763 IOUnlock(driverLock);
1764
1765 return;
1766}
1767
1768void IOHIDSystem::_proximityEvent(IOHIDSystem *self,
1769 NXEventData *proximityData,
1770 AbsoluteTime ts)
1771{
1772 self->proximityEvent(proximityData, ts);
1773}
1774
1775void IOHIDSystem::proximityEvent(NXEventData *proximityData,
1776 AbsoluteTime ts)
1777{
1778 IOTakeLock(driverLock);
1779
1780 if (eventsOpen) {
1781 postEvent(NX_TABLETPROXIMITY,
1782 (Point *)&evg->cursorLoc,
1783 ts,
1784 proximityData);
1785 }
1786
1787 IOUnlock(driverLock);
1788
1789 return;
1790}
1791
1792//
1793// Process a keyboard state change.
1794//
1795void IOHIDSystem::_keyboardEvent(IOHIDSystem * self,
1796 unsigned eventType,
1797 /* flags */ unsigned flags,
1798 /* keyCode */ unsigned key,
1799 /* charCode */ unsigned charCode,
1800 /* charSet */ unsigned charSet,
1801 /* originalCharCode */ unsigned origCharCode,
1802 /* originalCharSet */ unsigned origCharSet,
1803 /* keyboardType */ unsigned keyboardType,
1804 /* repeat */ bool repeat,
1805 /* atTime */ AbsoluteTime ts)
1806{
1807 self->keyboardEvent(eventType, flags, key, charCode, charSet,
1808 origCharCode, origCharSet, keyboardType, repeat, ts);
1809}
1810
1811void IOHIDSystem::keyboardEvent(unsigned eventType,
1812 /* flags */ unsigned flags,
1813 /* keyCode */ unsigned key,
1814 /* charCode */ unsigned charCode,
1815 /* charSet */ unsigned charSet,
1816 /* originalCharCode */ unsigned origCharCode,
1817 /* originalCharSet */ unsigned origCharSet,
1818 /* keyboardType */ unsigned keyboardType,
1819 /* repeat */ bool repeat,
1820 /* atTime */ AbsoluteTime ts)
1821{
1822 NXEventData outData;
1823
1824 if ( ! (displayState & IOPMDeviceUsable) ) { // display is off, consume the keystroke
1825 if ( eventType == NX_KEYDOWN ) {
1826 return;
1827 }
1828 if ( displayManager != NULL ) { // but if there is a display manager, tell
1829 displayManager->activityTickle(0,0); // it there is user activity
1830 }
1831 return;
1832 }
1833
1834 if ( displayManager != NULL ) { // if there is a display manager, tell
1835 displayManager->activityTickle(0,0); // it there is user activity
1836 }
1837
1838 outData.key.repeat = repeat;
1839 outData.key.keyCode = key;
1840 outData.key.charSet = charSet;
1841 outData.key.charCode = charCode;
1842 outData.key.origCharSet = origCharSet;
1843 outData.key.origCharCode = origCharCode;
1844 outData.key.keyboardType = keyboardType;
1845
1846 IOTakeLock( driverLock);
1847 if ( eventsOpen == false )
1848 {
1849 IOUnlock( driverLock);
1850 return;
1851 }
1852 evg->eventFlags = (evg->eventFlags & ~KEYBOARD_FLAGSMASK)
1853 | (flags & KEYBOARD_FLAGSMASK);
1854
1855 postEvent( eventType,
1856 /* at */ (Point *)&pointerLoc,
1857 /* atTime */ ts,
1858 /* withData */ &outData);
1859
1860 IOUnlock( driverLock);
1861}
1862
1863void IOHIDSystem::_keyboardSpecialEvent( IOHIDSystem * self,
1864 unsigned eventType,
1865 /* flags */ unsigned flags,
1866 /* keyCode */ unsigned key,
1867 /* specialty */ unsigned flavor,
1868 /* guid */ UInt64 guid,
1869 /* repeat */ bool repeat,
1870 /* atTime */ AbsoluteTime ts)
1871{
1872 self->keyboardSpecialEvent(eventType, flags, key, flavor, guid, repeat, ts);
1873}
1874
1875
1876void IOHIDSystem::keyboardSpecialEvent( unsigned eventType,
1877 /* flags */ unsigned flags,
1878 /* keyCode */ unsigned key,
1879 /* specialty */ unsigned flavor,
1880 /* guid */ UInt64 guid,
1881 /* repeat */ bool repeat,
1882 /* atTime */ AbsoluteTime ts)
1883{
1884 NXEventData outData;
1885 int level = -1;
1886
1887 bzero( (void *)&outData, sizeof outData );
1888
1889 IOTakeLock( driverLock);
1890 if ( eventsOpen == false )
1891 {
1892 IOUnlock( driverLock);
1893 return;
1894 }
1895
1896 // Update flags.
1897 evg->eventFlags = (evg->eventFlags & ~KEYBOARD_FLAGSMASK)
1898 | (flags & KEYBOARD_FLAGSMASK);
1899
1900 if ( eventType == NX_KEYDOWN )
1901 {
1902 switch ( flavor )
1903 {
1904 case NX_KEYTYPE_SOUND_UP:
1905 if ( (flags & SPECIALKEYS_MODIFIER_MASK) == 0 )
1906 {
1907 //level = IOAudioManager::sharedInstance()->incrementMasterVolume();
1908 if (masterAudioFunctions && masterAudioFunctions->incrementMasterVolume)
1909 {
1910 masterAudioFunctions->incrementMasterVolume();
1911 }
1912 }
1913 else
1914 {
1915 if( !(evg->eventFlags & NX_COMMANDMASK) &&
1916 !(evg->eventFlags & NX_CONTROLMASK) &&
1917 !(evg->eventFlags & NX_SHIFTMASK) &&
1918 (evg->eventFlags & NX_ALTERNATEMASK) )
1919 {
1920 // Open the sound preferences control panel.
1921 KUNCExecute( "Sound.preference", kOpenAppAsConsoleUser, kOpenPreferencePanel );
1922 }
1923 }
1924 break;
1925 case NX_KEYTYPE_SOUND_DOWN:
1926 if ( (flags & SPECIALKEYS_MODIFIER_MASK) == 0 )
1927 {
1928 //level = IOAudioManager::sharedInstance()->decrementMasterVolume();
1929 if (masterAudioFunctions && masterAudioFunctions->decrementMasterVolume)
1930 {
1931 masterAudioFunctions->decrementMasterVolume();
1932 }
1933 }
1934 else
1935 {
1936 if( !(evg->eventFlags & NX_COMMANDMASK) &&
1937 !(evg->eventFlags & NX_CONTROLMASK) &&
1938 !(evg->eventFlags & NX_SHIFTMASK) &&
1939 (evg->eventFlags & NX_ALTERNATEMASK) )
1940 {
1941 // Open the sound preferences control panel.
1942 KUNCExecute( "Sound.preference", kOpenAppAsConsoleUser, kOpenPreferencePanel );
1943 }
1944 }
1945 break;
1946 case NX_KEYTYPE_MUTE:
1947 if ( (flags & SPECIALKEYS_MODIFIER_MASK) == 0 )
1948 {
1949 //level = IOAudioManager::sharedInstance()->toggleMasterMute();
1950 if (masterAudioFunctions && masterAudioFunctions->toggleMasterMute)
1951 {
1952 masterAudioFunctions->toggleMasterMute();
1953 }
1954 }
1955 else
1956 {
1957 if( !(evg->eventFlags & NX_COMMANDMASK) &&
1958 !(evg->eventFlags & NX_CONTROLMASK) &&
1959 !(evg->eventFlags & NX_SHIFTMASK) &&
1960 (evg->eventFlags & NX_ALTERNATEMASK) )
1961 {
1962 // Open the sound preferences control panel.
1963 KUNCExecute( "Sound.preference", kOpenAppAsConsoleUser, kOpenPreferencePanel );
1964 }
1965 }
1966 break;
1967 case NX_KEYTYPE_EJECT:
1968
1969 // Special key handlers:
1970 //
1971 // Command = invoke macsbug
1972 // Command+option = sleep now
1973 // Command+option+control = shutdown now
1974 // Control = logout dialog
1975
1976 if( (evg->eventFlags & NX_COMMANDMASK) &&
1977 !(evg->eventFlags & NX_CONTROLMASK) &&
1978 !(evg->eventFlags & NX_SHIFTMASK) &&
1979 !(evg->eventFlags & NX_ALTERNATEMASK) )
1980 {
1981 // Post a power key event, Classic should pick this up and
1982 // drop into MacsBug.
1983 //
1984 outData.compound.subType = NX_SUBTYPE_POWER_KEY;
1985 postEvent( NX_SYSDEFINED,
1986 /* at */ (Point *)&pointerLoc,
1987 /* atTime */ ts,
1988 /* withData */ &outData);
1989 }
1990 else if( (evg->eventFlags & NX_COMMANDMASK) &&
1991 !(evg->eventFlags & NX_CONTROLMASK) &&
1992 !(evg->eventFlags & NX_SHIFTMASK) &&
1993 (evg->eventFlags & NX_ALTERNATEMASK) )
1994 {
1995 //IOLog( "IOHIDSystem -- sleep now!\n" );
1996
1997 // Post the sleep now event. Someone else will handle the actual call.
1998 //
1999 outData.compound.subType = NX_SUBTYPE_SLEEP_EVENT;
2000 postEvent( NX_SYSDEFINED,
2001 /* at */ (Point *)&pointerLoc,
2002 /* atTime */ ts,
2003 /* withData */ &outData);
2004 }
2005 else if( (evg->eventFlags & NX_COMMANDMASK) &&
2006 (evg->eventFlags & NX_CONTROLMASK) &&
2007 !(evg->eventFlags & NX_SHIFTMASK) &&
2008 (evg->eventFlags & NX_ALTERNATEMASK) )
2009 {
2010 //IOLog( "IOHIDSystem -- shutdown now!\n" );
2011
2012 // Post the shutdown now event. Someone else will handle the actual call.
2013 //
2014 outData.compound.subType = NX_SUBTYPE_SHUTDOWN_EVENT;
2015 postEvent( NX_SYSDEFINED,
2016 /* at */ (Point *)&pointerLoc,
2017 /* atTime */ ts,
2018 /* withData */ &outData);
2019 }
2020 else if( (evg->eventFlags & NX_COMMANDMASK) &&
2021 (evg->eventFlags & NX_CONTROLMASK) &&
2022 !(evg->eventFlags & NX_SHIFTMASK) &&
2023 !(evg->eventFlags & NX_ALTERNATEMASK) )
2024 {
2025 // Restart now!
2026 //IOLog( "IOHIDSystem -- Restart now!\n" );
2027
2028 // Post the Restart now event. Someone else will handle the actual call.
2029 //
2030 outData.compound.subType = NX_SUBTYPE_RESTART_EVENT;
2031 postEvent( NX_SYSDEFINED,
2032 /* at */ (Point *)&pointerLoc,
2033 /* atTime */ ts,
2034 /* withData */ &outData);
2035 }
2036 else if( !(evg->eventFlags & NX_COMMANDMASK) &&
2037 (evg->eventFlags & NX_CONTROLMASK) &&
2038 !(evg->eventFlags & NX_SHIFTMASK) &&
2039 !(evg->eventFlags & NX_ALTERNATEMASK) )
2040 {
2041 // Looks like we should put up the normal 'Power Key' dialog.
2042 //
2043 // Set the event flags to zero, because the system will not do the right
2044 // thing if we don't zero this out (it will ignore the power key event
2045 // we post, thinking that some modifiers are down).
2046 //
2047 evg->eventFlags = 0;
2048
2049 // Post the power keydown event.
2050 //
2051 outData.compound.subType = NX_SUBTYPE_POWER_KEY;
2052 postEvent( NX_SYSDEFINED,
2053 /* at */ (Point *)&pointerLoc,
2054 /* atTime */ ts,
2055 /* withData */ &outData);
2056 }
2057 else
2058 {
2059 // After all that checking, no modifiers are down, so let's pump up a
2060 // system defined eject event. This way we can have anyone who's watching
2061 // for this event (aka LoginWindow) route this event to the right target
2062 // (aka AutoDiskMounter).
2063
2064 //IOLog( "IOHIDSystem--Normal Eject action!\n" );
2065
2066 // Post the eject keydown event.
2067 //
2068 outData.compound.subType = NX_SUBTYPE_EJECT_KEY;
2069 postEvent( NX_SYSDEFINED,
2070 /* at */ (Point *)&pointerLoc,
2071 /* atTime */ ts,
2072 /* withData */ &outData);
2073 }
2074 break;
2075
2076 case NX_POWER_KEY:
2077 outData.compound.subType = NX_SUBTYPE_POWER_KEY;
2078 postEvent( NX_SYSDEFINED,
2079 /* at */ (Point *)&pointerLoc,
2080 /* atTime */ ts,
2081 /* withData */ &outData);
2082 break;
2083 }
2084 }
2085#if 0 /* So far, nothing to do on keyup */
2086 else if ( eventType == NX_KEYUP )
2087 {
2088 switch ( flavor )
2089 {
2090 case NX_KEYTYPE_SOUND_UP:
2091 break;
2092 case NX_KEYTYPE_SOUND_DOWN:
2093 break;
2094 case NX_KEYTYPE_MUTE:
2095 break;
2096 case NX_POWER_KEY:
2097 break;
2098 }
2099 }
2100#endif
2101 if( (0 == (flags & SPECIALKEYS_MODIFIER_MASK))
2102 && ((1 << flavor) & NX_SPECIALKEY_POST_MASK)) {
2103 outData.compound.subType = NX_SUBTYPE_AUX_CONTROL_BUTTONS;
2104 outData.compound.misc.S[0] = flavor;
2105 outData.compound.misc.C[2] = eventType;
2106 outData.compound.misc.C[3] = repeat;
2107 outData.compound.misc.L[1] = guid & 0xffffffff;
2108 outData.compound.misc.L[2] = guid >> 32;
2109
2110 postEvent( NX_SYSDEFINED,
2111 /* at */ (Point *)&pointerLoc,
2112 /* atTime */ ts,
2113 /* withData */ &outData);
2114 }
2115
2116 IOUnlock( driverLock);
2117 if ( level != -1 ) // An interesting special key event occurred
2118 {
2119 evSpecialKeyMsg( flavor,
2120 /* direction */ eventType,
2121 /* flags */ flags,
2122 /* level */ level);
2123 }
2124}
2125
2126/*
2127 * Update current event flags. Restricted to keyboard flags only, this
2128 * method is used to silently update the flags state for keys which both
2129 * generate characters and flag changes. The specs say we don't generate
2130 * a flags-changed event for such keys. This method is also used to clear
2131 * the keyboard flags on a keyboard subsystem reset.
2132 */
2133void IOHIDSystem::_updateEventFlags(IOHIDSystem * self, unsigned flags)
2134{
2135 self->updateEventFlags(flags);
2136}
2137
2138void IOHIDSystem::updateEventFlags(unsigned flags)
2139{
2140 IOTakeLock( driverLock);
2141 if ( eventsOpen )
2142 evg->eventFlags = (evg->eventFlags & ~KEYBOARD_FLAGSMASK)
2143 | (flags & KEYBOARD_FLAGSMASK);
2144 IOUnlock( driverLock);
2145}
2146
2147//
2148// - _setButtonState:(int)buttons atTime:(int)t
2149// Update the button state. Generate button events as needed
2150//
2151void IOHIDSystem::_setButtonState(int buttons,
2152 /* atTime */ AbsoluteTime ts)
2153{
2154 // Magic uber-mouse buttons changed event so we can get all of the buttons...
2155 if(evg->buttons ^ buttons)
2156 {
2157 NXEventData evData;
2158 unsigned long hwButtons, hwDelta, temp;
2159
2160 /* I'd like to keep the event button mapping linear, so
2161 I have to "undo" the LB/RB mouse bit numbering funkiness
2162 before I pass the information down to the app. */
2163 /* Ideally this would all go away if we fixed EV_LB and EV_RB
2164 to be bits 0 and 1 */
2165 hwButtons = buttons & ~7; /* Keep everything but bottom 3 bits. */
2166 hwButtons |= (buttons & 3) << 1; /* Map bits 01 to 12 */
2167 hwButtons |= (buttons & 4) >> 2; /* Map bit 2 back to bit 0 */
2168 temp = evg->buttons ^ buttons;
2169 hwDelta = temp & ~7;
2170 hwDelta |= (temp & 3) << 1; /* Map bits 01 to 12 */
2171 hwDelta |= (temp & 4) >> 2; /* Map bit 2 back to bit 0 */
2172
2173 evData.compound.reserved = 0;
2174 evData.compound.subType = NX_SUBTYPE_AUX_MOUSE_BUTTONS;
2175 evData.compound.misc.L[0] = hwDelta;
2176 evData.compound.misc.L[1] = hwButtons;
2177
2178 postEvent( NX_SYSDEFINED,
2179 /* at */ (Point *)&evg->cursorLoc,
2180 /* atTime */ ts,
2181 /* withData */ &evData);
2182 }
2183
2184 if ((evg->buttons & EV_LB) != (buttons & EV_LB))
2185 {
2186 if (buttons & EV_LB)
2187 {
2188 postEvent( NX_LMOUSEDOWN,
2189 /* at */ (Point *)&evg->cursorLoc,
2190 /* atTime */ ts,
2191 /* withData */ NULL);
2192 }
2193 else
2194 {
2195 postEvent( NX_LMOUSEUP,
2196 /* at */ (Point *)&evg->cursorLoc,
2197 /* atTime */ ts,
2198 /* withData */ NULL);
2199 }
2200 // After entering initial up/down event, set up
2201 // coalescing state so drags will behave correctly
2202 evg->dontCoalesce = evg->dontWantCoalesce;
2203 if (evg->dontCoalesce)
2204 evg->eventFlags |= NX_NONCOALSESCEDMASK;
2205 else
2206 evg->eventFlags &= ~NX_NONCOALSESCEDMASK;
2207 }
2208
2209 if ((evg->buttons & EV_RB) != (buttons & EV_RB)) {
2210 if (buttons & EV_RB) {
2211 postEvent( NX_RMOUSEDOWN,
2212 /* at */ (Point *)&evg->cursorLoc,
2213 /* atTime */ ts,
2214 /* withData */ NULL);
2215 } else {
2216 postEvent( NX_RMOUSEUP,
2217 /* at */ (Point *)&evg->cursorLoc,
2218 /* atTime */ ts,
2219 /* withData */ NULL);
2220 }
2221 }
2222
2223 evg->buttons = buttons;
2224}
2225//
2226// Sets the cursor position (evg->cursorLoc) to the new
2227// location. The location is clipped against the cursor pin rectangle,
2228// mouse moved/dragged events are generated using the given event mask,
2229// and a mouse-exited event may be generated. The cursor image is
2230// moved.
2231// On entry, the driverLock should be set.
2232//
2233void IOHIDSystem::setCursorPosition(Point * newLoc, bool external)
2234{
2235 if ( eventsOpen == true )
2236 {
2237 pointerDelta.x += (newLoc->x - pointerLoc.x);
2238 pointerDelta.y += (newLoc->y - pointerLoc.y);
2239 pointerLoc = *newLoc;
2240 _setCursorPosition(newLoc, external);
2241 }
2242}
2243
2244//
2245// This mechanism is used to update the cursor position, possibly generating
2246// messages to registered frame buffer devices and posting drag, tracking, and
2247// mouse motion events.
2248//
2249// On entry, the driverLock should be set.
2250// This can be called from setCursorPosition:(Point *)newLoc to set the
2251// position by a _IOSetParameterFromIntArray() call, directly from the absolute or
2252// relative pointer device routines, or on a timed event callback.
2253//
2254void IOHIDSystem::_setCursorPosition(Point * newLoc, bool external)
2255{
2256 bool cursorMoved = true;
2257
2258 if (!screens)
2259 return;
2260
2261 if( ev_try_lock(&evg->cursorSema) == 0 ) // host using shmem
2262 {
2263 needSetCursorPosition = true; // try again later
2264// scheduleNextPeriodicEvent();
2265 return;
2266 }
2267
2268 // Past here we hold the cursorSema lock. Make sure the lock is
2269 // cleared before returning or the system will be wedged.
2270
2271 needSetCursorPosition = false; // We WILL succeed
2272
2273 if (cursorCoupled || external)
2274 {
2275 UInt32 newScreens = 0;
2276 SInt32 pinScreen = -1L;
2277
2278 /* Get mask of screens on which the cursor is present */
2279 EvScreen *screen = (EvScreen *)evScreen;
2280 for (int i = 0; i < screens; i++ ) {
2281 if ((screen[i].instance) && PtInRect(newLoc, screen[i].bounds)) {
2282 pinScreen = i;
2283 newScreens |= (1 << i);
2284 }
2285 }
2286
2287 if (newScreens == 0) {
2288 /* At this point cursor has gone off all screens,
2289 just clip it to one of the previous screens. */
2290 newLoc->x = (newLoc->x < cursorPin.minx) ?
2291 cursorPin.minx : ((newLoc->x > cursorPin.maxx) ?
2292 cursorPin.maxx : newLoc->x);
2293 newLoc->y = (newLoc->y < cursorPin.miny) ?
2294 cursorPin.miny : ((newLoc->y > cursorPin.maxy) ?
2295 cursorPin.maxy : newLoc->y);
2296 /* regenerate mask for new position */
2297 for (int i = 0; i < screens; i++ ) {
2298 if ((screen[i].instance) && PtInRect(newLoc, screen[i].bounds)) {
2299 pinScreen = i;
2300 newScreens |= (1 << i);
2301 }
2302 }
2303 }
2304
2305 pointerLoc = *newLoc; // Sync up pointer with clipped cursor
2306 /* Catch the no-move case */
2307 if ((evg->cursorLoc.x == newLoc->x) && (evg->cursorLoc.y == newLoc->y)) {
2308 if ((pointerDelta.x == 0) && (pointerDelta.y == 0)) {
2309 ev_unlock(&evg->cursorSema);
2310 return;
2311 }
2312 cursorMoved = false; // mouse moved, but cursor didn't
2313 } else {
2314 evg->cursorLoc.x = newLoc->x;
2315 evg->cursorLoc.y = newLoc->y;
2316
2317 /* If cursor changed screens */
2318 if (newScreens != cursorScreens) {
2319 hideCursor(); /* hide cursor on old screens */
2320 cursorScreens = newScreens;
2321 cursorPin = *(((EvScreen*)evScreen)[pinScreen].bounds);
2322 cursorPin.maxx--; /* Make half-open rectangle */
2323 cursorPin.maxy--;
2324 cursorPinScreen = pinScreen;
2325 showCursor();
2326 } else {
2327 /* cursor moved on same screens */
2328 moveCursor();
2329 }
2330 }
2331 } else {
2332 /* cursor uncoupled */
2333 pointerLoc.x = evg->cursorLoc.x;
2334 pointerLoc.y = evg->cursorLoc.y;
2335 }
2336
2337 AbsoluteTime ts;
2338 clock_get_uptime(&ts);
2339
2340 /* See if anybody wants the mouse moved or dragged events */
2341 if (evg->movedMask) {
2342 if ((evg->movedMask&NX_LMOUSEDRAGGEDMASK)&&(evg->buttons& EV_LB)) {
2343 _postMouseMoveEvent(NX_LMOUSEDRAGGED, newLoc, ts);
2344 } else if ((evg->movedMask&NX_RMOUSEDRAGGEDMASK) && (evg->buttons & EV_RB)) {
2345 _postMouseMoveEvent(NX_RMOUSEDRAGGED, newLoc, ts);
2346 } else if (evg->movedMask & NX_MOUSEMOVEDMASK) {
2347 _postMouseMoveEvent(NX_MOUSEMOVED, newLoc, ts);
2348 }
2349 }
2350
2351 /* check new cursor position for leaving evg->mouseRect */
2352 if (cursorMoved && evg->mouseRectValid && (!PtInRect(newLoc, &evg->mouseRect)))
2353 {
2354 if (evg->mouseRectValid)
2355 {
2356 postEvent( NX_MOUSEEXITED,
2357 /* at */ newLoc,
2358 /* atTime */ ts,
2359 /* withData */ NULL);
2360 evg->mouseRectValid = 0;
2361 }
2362 }
2363 ev_unlock(&evg->cursorSema);
2364}
2365
2366void IOHIDSystem::_postMouseMoveEvent(int what,
2367 Point * location,
2368 AbsoluteTime ts)
2369{
2370 NXEventData data;
2371
2372 data.mouseMove.dx = pointerDelta.x;
2373 data.mouseMove.dy = pointerDelta.y;
2374
2375 pointerDelta.x = 0;
2376 pointerDelta.y = 0;
2377
2378 postEvent(what, location, ts, &data);
2379}
2380
2381/**
2382 ** IOUserClient methods
2383 **/
2384
2385IOReturn IOHIDSystem::newUserClient(task_t /* owningTask */,
2386 /* withToken */ void * /* security_id */,
2387 /* ofType */ UInt32 type,
2388 /* client */ IOUserClient ** handler)
2389{
2390 IOUserClient * newConnect = 0;
2391 IOReturn err = kIOReturnNoMemory;
2392
2393 IOTakeLock( driverLock);
2394
2395 do {
2396 if( type == kIOHIDParamConnectType) {
2397 if( paramConnect) {
2398 newConnect = paramConnect;
2399 newConnect->retain();
2400 } else if( eventsOpen) {
2401 newConnect = new IOHIDParamUserClient;
2402 } else {
2403 err = kIOReturnNotOpen;
2404 continue;
2405 }
2406
2407 } else if( type == kIOHIDServerConnectType) {
2408 newConnect = new IOHIDUserClient;
2409 } else
2410 err = kIOReturnUnsupported;
2411
2412 if( !newConnect)
2413 continue;
2414
2415 // initialization is getting out of hand
2416
2417 if( (newConnect != paramConnect) && (
2418 (false == newConnect->init())
2419 || (false == newConnect->attach( this ))
2420 || (false == newConnect->start( this ))
2421 || ((type == kIOHIDServerConnectType)
2422 && (err = evOpen()))
2423 )) {
2424 newConnect->detach( this );
2425 newConnect->release();
2426 newConnect = 0;
2427 continue;
2428 }
2429 if( type == kIOHIDParamConnectType)
2430 paramConnect = newConnect;
2431 err = kIOReturnSuccess;
2432
2433 } while( false );
2434
2435 IOUnlock( driverLock);
2436
2437 *handler = newConnect;
2438 return( err );
2439}
2440
2441
2442IOReturn IOHIDSystem::setEventsEnable(void*p1,void*,void*,void*,void*,void*)
2443{ // IOMethod
2444 bool enable = (bool)p1;
2445
2446 if( enable) {
2447 attachDefaultEventSources();
2448 _resetMouseParameters();
2449 _resetKeyboardParameters();
2450 }
2451 return( kIOReturnSuccess);
2452}
2453
2454IOReturn IOHIDSystem::setCursorEnable(void*p1,void*,void*,void*,void*,void*)
2455{ // IOMethod
2456 bool enable = (bool)p1;
2457 IOReturn err = kIOReturnSuccess;
2458
2459 IOTakeLock( driverLock);
2460 if ( eventsOpen == false ) {
2461 IOUnlock( driverLock);
2462 return( kIOReturnNotOpen );
2463 }
2464
2465 if( 0 == screens) { // Should be at least 1!
2466 IOUnlock( driverLock);
2467 return( kIOReturnNoDevice );
2468 }
2469
2470 if( enable) {
2471 if( cursorStarted) {
2472 hideCursor();
2473 cursorEnabled = resetCursor();
2474 showCursor();
2475 } else
2476 cursorEnabled = startCursor();
2477 } else
2478 cursorEnabled = enable;
2479
2480 cursorCoupled = cursorEnabled;
2481
2482 IOUnlock( driverLock);
2483
2484 return( err);
2485}
2486
2487IOReturn IOHIDSystem::extPostEvent(void*p1,void*,void*,void*,void*,void*)
2488{ // IOMethod
2489 struct evioLLEvent * event = (struct evioLLEvent *)p1;
2490
2491 IOTakeLock( driverLock);
2492
2493 if( event->setCursor)
2494 setCursorPosition(&event->location, true);
2495
2496 if( event->setFlags)
2497 evg->eventFlags = (evg->eventFlags & ~KEYBOARD_FLAGSMASK)
2498 | (event->flags & KEYBOARD_FLAGSMASK);
2499
2500 AbsoluteTime ts;
2501 clock_get_uptime(&ts);
2502 postEvent( event->type,
2503 /* at */ &event->location,
2504 /* atTime */ ts,
2505 /* withData */ &event->data);
2506
2507 IOUnlock( driverLock);
2508 return( kIOReturnSuccess);
2509}
2510
2511IOReturn IOHIDSystem::extSetMouseLocation(void*p1,void*,void*,void*,void*,void*)
2512{ // IOMethod
2513 Point * loc = (Point *)p1;
2514
2515 IOTakeLock( driverLock);
2516 setCursorPosition(loc, true);
2517 IOUnlock( driverLock);
2518 return( kIOReturnSuccess);
2519}
2520
2521IOReturn IOHIDSystem::extGetButtonEventNum(void*p1,void*p2,void*,void*,void*,void*)
2522{ // IOMethod
2523 NXMouseButton button = (NXMouseButton)(int)p1;
2524 int * eventNum = (int *)p2;
2525 IOReturn err = kIOReturnSuccess;
2526
2527 IOTakeLock( driverLock);
2528 switch( button) {
2529 case NX_LeftButton:
2530 *eventNum = leftENum;
2531 break;
2532 case NX_RightButton:
2533 *eventNum = rightENum;
2534 break;
2535 default:
2536 err = kIOReturnBadArgument;
2537 }
2538
2539 IOUnlock( driverLock);
2540 return( err);
2541}
2542
2543bool IOHIDSystem::updateProperties( void )
2544{
2545 UInt64 clickTimeThreshNano;
2546 UInt64 autoDimThresholdNano;
2547 UInt64 autoDimTimeNano;
2548 UInt64 idleTimeNano;
2549 AbsoluteTime time1, time2;
2550 bool ok;
2551
2552 absolutetime_to_nanoseconds( clickTimeThresh, &clickTimeThreshNano);
2553 absolutetime_to_nanoseconds( autoDimPeriod, &autoDimThresholdNano);
2554 if( eventsOpen) {
2555 clock_get_uptime( &time1);
2556 if( autoDimmed) {
2557 autoDimTimeNano = 0;
2558 // now - (autoDimTime - autoDimPeriod)
2559 SUB_ABSOLUTETIME( &time1, &autoDimTime);
2560 ADD_ABSOLUTETIME( &time1, &autoDimPeriod);
2561 absolutetime_to_nanoseconds( time1, &idleTimeNano);
2562 } else {
2563 // autoDimTime - now
2564 time2 = autoDimTime;
2565 SUB_ABSOLUTETIME( &time2, &time1);
2566 absolutetime_to_nanoseconds( time2, &autoDimTimeNano);
2567 // autoDimPeriod - (autoDimTime - evg->VertRetraceClock)
2568 time1 = autoDimPeriod;
2569 SUB_ABSOLUTETIME( &time1, &time2);
2570 absolutetime_to_nanoseconds( time1, &idleTimeNano);
2571 }
2572 } else {
2573 absolutetime_to_nanoseconds( autoDimPeriod, &autoDimTimeNano);
2574 idleTimeNano = 0; // user is active
2575 }
2576
2577 ok = setProperty( kIOHIDClickTimeKey, &clickTimeThreshNano,
2578 sizeof( UInt64))
2579 & setProperty( kIOHIDClickSpaceKey, &clickSpaceThresh,
2580 sizeof( clickSpaceThresh))
2581 & setProperty( kIOHIDAutoDimThresholdKey, &autoDimThresholdNano,
2582 sizeof( UInt64))
2583 & setProperty( kIOHIDAutoDimTimeKey, &autoDimTimeNano,
2584 sizeof( UInt64))
2585 & setProperty( kIOHIDIdleTimeKey, &idleTimeNano,
2586 sizeof( UInt64))
2587 & setProperty( kIOHIDAutoDimStateKey, &autoDimmed,
2588 sizeof( autoDimmed))
2589 & setProperty( kIOHIDBrightnessKey, &curBright,
2590 sizeof( curBright))
2591 & setProperty( kIOHIDAutoDimBrightnessKey, &dimmedBrightness,
2592 sizeof( dimmedBrightness));
2593
2594 return( ok );
2595}
2596
2597bool IOHIDSystem::serializeProperties( OSSerialize * s ) const
2598{
2599 ((IOHIDSystem *) this)->updateProperties();
2600
2601 return( super::serializeProperties( s ));
2602}
2603
2604IOReturn IOHIDSystem::setParamProperties( OSDictionary * dict )
2605{
2606 OSData * data;
2607 IOReturn err = kIOReturnSuccess;
2608
2609 IOTakeLock( driverLock);
2610 if( (data = OSDynamicCast( OSData, dict->getObject(kIOHIDClickTimeKey))))
2611 {
2612 UInt64 nano = *((UInt64 *)(data->getBytesNoCopy()));
2613 nanoseconds_to_absolutetime(nano, &clickTimeThresh);
2614 }
2615 if( (data = OSDynamicCast( OSData,
2616 dict->getObject(kIOHIDClickSpaceKey)))) {
2617 clickSpaceThresh.x = ((UInt32 *) (data->getBytesNoCopy()))[EVSIOSCS_X];
2618 clickSpaceThresh.y = ((UInt32 *) (data->getBytesNoCopy()))[EVSIOSCS_Y];
2619 }
2620
2621 if( (data = OSDynamicCast( OSData, dict->getObject(kIOHIDAutoDimThresholdKey)))) {
2622 AbsoluteTime oldPeriod = autoDimPeriod;
2623 UInt64 nano = *((UInt64 *)(data->getBytesNoCopy()));
2624 nanoseconds_to_absolutetime(nano, &autoDimPeriod);
2625 // autoDimTime = autoDimTime - oldPeriod + autoDimPeriod;
2626 SUB_ABSOLUTETIME( &autoDimTime, &oldPeriod);
2627 ADD_ABSOLUTETIME( &autoDimTime, &autoDimPeriod);
2628 }
2629
2630 if( (data = OSDynamicCast( OSData, dict->getObject(kIOHIDAutoDimStateKey))))
2631 forceAutoDimState( 0 != *((SInt32 *) (data->getBytesNoCopy())));
2632
2633 if( (data = OSDynamicCast( OSData, dict->getObject(kIOHIDBrightnessKey))))
2634 setBrightness( *((SInt32 *) (data->getBytesNoCopy())));
2635
2636 if( (data = OSDynamicCast( OSData, dict->getObject(kIOHIDAutoDimBrightnessKey))))
2637 setAutoDimBrightness( *((SInt32 *) (data->getBytesNoCopy())));
2638
2639 IOUnlock( driverLock);
2640
2641 return( err );
2642}
2643