|
|
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:
25: /* Copyright (c) 1992 NeXT Computer, Inc. All rights reserved.
26: *
27: * PPCKeyboard.m - Keyboard driver.
28: *
29: *
30: * HISTORY
31: * 11-Aug-92 Joe Pasqua at NeXT
32: * Created.
33: * 8-April-97 Simon Douglas
34: * Munged into ADB version. Remove mouse interface.
35: */
36:
37: // TO DO:
38: // Make this an indirect client of ADB. ADB should probe to create multiple
39: // event sources.
40: // Notes:
41: // * To find things that need to be fixed, search for FIX, to find questions
42: // to be resolved, search for ASK, to find stuff that still needs to be
43: // done, search for TO DO.
44:
45: #define MACH_USER_API 1
46: #undef KERNEL_PRIVATE
47:
48: #import <machkit/NXLock.h>
49: #import <driverkit/IODevice.h>
50: #import <driverkit/driverServer.h>
51: #import <driverkit/generalFuncs.h>
52: #import <driverkit/interruptMsg.h>
53: #import <bsd/dev/ppc/PPCKeyboardPriv.h>
54: #import <bsd/dev/ppc/PPCKeyboard.h>
55: #import <bsd/dev/ppc/PCKeyboardDefs.h>
56: #import <driverkit/ppc/directDevice.h>
57: #import <driverkit/ppc/driverTypes.h>
58: #import <bsd/dev/ev_types.h>
59: #import <bsd/dev/event.h>
60:
61: #import <kern/thread_call.h>
62:
63: #include <mach_kdb.h>
64: #include <mach/mach_types.h>
65: #include <sys/tty.h>
66: #include <sys/conf.h>
67: #include <machdep/ppc/mach_param.h>
68: #include <machine/machspl.h>
69:
70: #include <machdep/ppc/powermac.h>
71:
72: #include "busses.h"
73: #include "adb.h"
74: #import "IOADBBus.h"
75:
76: unsigned char extendCount;
77:
78: static int adbAsyncAvail = FALSE; /* can try async ADB */
79: static int keyboard_led_state; /* state of caps/num/scroll lock */
80: static id adb_driver; // pointer to adb indirect driver
81:
82: extern struct tty cons;
83:
84: void keyboard_updown(unsigned char key);
85: void keyboard_adbhandler(int number, unsigned char *buffer, int count, void * ssp);
86: void keyboard_init(void);
87: void keyboard_updown(unsigned char key);
88:
89: io_return_t keyboard_set_led_state(int state);
90: int keyboard_get_led_state(void);
91: void keyboard_initialize_led_state(void);
92:
93: boolean_t keyboard_initted = FALSE;
94: int keyboard_adb_addr = -1;
95:
96: #define KeyboardIPL 3
97: #define SAFE_IPL (KeyboardIPL + 1)
98:
99: #define MAX_PENDING_EVENTS 10
100:
101: #if KERNOBJC
102: static PPCKeyboard *_kbdObj;
103: #endif KERNOBJC
104:
105: static PCKeyboardEvent _pendingEvents[MAX_PENDING_EVENTS];
106: static int _eventIndex;
107: /* Forward declarations */
108: static inline PCKeyboardEvent *PPCScancodeToKeyEvent( unsigned char key);
109: static void EnqueueKey(int keyCode, ns_time_t stamp);
110:
111:
112: /* Forward declarations */
113: #define msg_printf null_printf
114: #define msg1_printf null_printf
115:
116: #define busywait(x) delay(x)
117:
118:
119: //
120: // BEGIN: Definitions used to keep track of key state
121: //
122: // NOTES: Key up/down state is tracked in a bit list. Bits are set
123: // for key-down, and cleared for key-up. The bit vector and
124: // macros for it's manipulation are defined here.
125: #define KBV_BITS_PER_UNIT 32
126: #define KBV_BITS_MASK 31
127: #define KBV_BITS_SHIFT 5 // 1<<5 == 32, for cheap divide
128: #define KBV_NUNITS ((128 + (KBV_BITS_PER_UNIT-1))/KBV_BITS_PER_UNIT)
129:
130: #define KBV_KEYDOWN(n, bits) \
131: (bits)[((n)>>KBV_BITS_SHIFT)] |= (1 << ((n) & KBV_BITS_MASK))
132:
133: #define KBV_KEYUP(n, bits) \
134: (bits)[((n)>>KBV_BITS_SHIFT)] &= ~(1 << ((n) & KBV_BITS_MASK))
135:
136: #define KBV_IS_KEYDOWN(n, bits) \
137: (((bits)[((n)>>KBV_BITS_SHIFT)] & (1 << ((n) & KBV_BITS_MASK))) != 0)
138:
139: static unsigned long _kbdBitVector[KBV_NUNITS];
140: //
141: // END: Definitions used to keep track of key state
142: //
143:
144:
145: #if KERNOBJC
146:
147: @implementation PPCKeyboard
148: + (IODeviceStyle) deviceStyle
149: {
150: return IO_IndirectDevice;
151: }
152:
153: static Protocol *protocols[] = {
154: @protocol(ADBprotocol),
155: nil
156: };
157:
158: + (Protocol **)requiredProtocols
159: {
160: return protocols;
161: }
162:
163:
164:
165: #endif
166:
167: //
168: // BEGIN: Impl. of internal methods for dealing w/ kbd controller
169: // NOTE: The following are utility procedures for dealing with
170: // The keyboard controller. They are called from the low
171: // level interrupt handler. Because of this, they can not be
172: // ObjC methods.
173: //
174:
175:
176: static void ADBKeyboardInit(void);
177:
178: static void
179: ADBKeyboardInit(void)
180: {
181: extern boolean_t adb_initted; //extern from adb.m
182: int i;
183: IOADBDeviceInfo table[IO_ADB_MAX_DEVICE];
184:
185: if (!keyboard_initted) {
186: //if early debugging mode, table[] is filled with trash, ADB not initialized
187: if (!adb_initted) //set in adb.m if ADB were instantiated
188: {
189: keyboard_initted = FALSE;
190: return;
191: }
192: [adb_driver GetTable: table: &i];
193: for (i = 0; i < ADB_DEVICE_COUNT; i++) {
194: if ((table[i].flags & ADB_FLAGS_PRESENT) == 0)
195: {
196: continue;
197: }
198: if (table[i].originalAddress == ADB_DEV_KEYBOARD) {
199: /* Find the first ADB keyboard device, and use that. */
200: keyboard_adb_addr = i;
201: break; //break out of for loop
202: }
203: }
204: keyboard_initted = TRUE;
205: /* Pickup all keyboard devices */
206: [adb_driver adb_register_handler:ADB_DEV_KEYBOARD: keyboard_adbhandler];
207: }
208: }
209:
210:
211: /* Called the first time the console is opened, can't be done
212: * above since it's too early
213: */
214: void
215: keyboard_initialize_led_state(void)
216: {
217: keyboard_led_state = keyboard_get_led_state();
218: }
219:
220: int
221: keyboard_get_led_state(void)
222: {
223: unsigned short lights = 0;
224: unsigned char buffer[8];
225: int length;
226:
227: if (keyboard_adb_addr == -1)
228: return 0;
229:
230: [adb_driver readADBDeviceRegister: keyboard_adb_addr: 2: buffer: &length];
231:
232: lights = buffer[0] << 8;
233: if (length > 1) {
234: lights |= buffer[1];
235: }
236:
237: return ~lights;
238: }
239:
240: int
241: keyboard_set_led_state(int lights)
242: {
243: unsigned char buffer[2];
244:
245: if (keyboard_adb_addr == -1)
246: return D_NO_SUCH_DEVICE;
247:
248: /* Inverse things for ADB */
249: lights = ~lights;
250: buffer[0] = lights >> 8;
251: buffer[1] = lights & 0xFF;
252:
253: [adb_driver writeADBDeviceRegister: keyboard_adb_addr: 2: buffer: 2];
254:
255: return D_SUCCESS;
256: }
257:
258:
259: #import <kern/kdp_internal.h>
260: #import <mach/exception.h>
261:
262: void
263: keyboard_adbhandler(int number, unsigned char *buffer, int count, void * ssp)
264: {
265: ns_time_t stamp;
266:
267: if ( (HasPMU() &&
268: (buffer[0] == ADBK_POWER2 || buffer[1] == ADBK_POWER2)) ||
269: (!HasPMU() &&
270: (buffer[0] == ADBK_POWER && buffer[1] == ADBK_POWER)) )
271: {
272: if (KBV_IS_KEYDOWN(ADBK_CONTROL, _kbdBitVector))
273: {
274: IOGetTimestamp(&stamp);
275:
276: if (KBV_IS_KEYDOWN(ADBK_OPTION, _kbdBitVector))
277: {
278: mini_mon("", "Kernel Debugger",ssp);
279: EnqueueKey(ADBK_OPTION, stamp);
280: }
281: else {
282: if( kdp.is_conn) {
283: #if 0
284: kdp_raise_exception( EXC_SOFTWARE, 0, 0, ssp);
285: #else
286: call_kdp();
287: #endif
288: } else {
289: mini_mon("restart", "Restart",ssp);
290: }
291: }
292: EnqueueKey(ADBK_CONTROL, stamp);
293: return;
294: }
295: keyboard_updown(ADBK_POWER);
296: keyboard_updown(ADBK_KEYUP(ADBK_POWER));
297: return;
298: }
299:
300: keyboard_updown(buffer[0]);
301: if (buffer[1] != 0xff)
302: keyboard_updown(buffer[1]);
303: }
304:
305:
306: #if KERNOBJC
307: void
308: KeyboardCallout()
309: {
310: [_kbdObj interruptHandler];
311: }
312: #else
313: void cDispatchKeyboardEvent( PCKeyboardEvent *event);
314: #endif KERNOBJC
315:
316: void
317: keyboard_updown(unsigned char key)
318: {
319: PCKeyboardEvent *event;
320: if ( (event = (PCKeyboardEvent *)PPCScancodeToKeyEvent(key)) )
321: {
322: // Add this event to the queue. If there is no room in the queue,
323: // we toss the event. TO DO: when we fill the last entry in the
324: // queue we should disable keyboard interrupts until the queue gets
325: // some free space.
326: if (_eventIndex == MAX_PENDING_EVENTS)
327: return;
328: _pendingEvents[_eventIndex++] = *event;
329:
330: // This call causes an interrupt message to be sent. Note that
331: // if a previous message is outstanding, this call does nothing.
332: // That is, no new message is queued.
333:
334: if( adbAsyncAvail)
335: {
336:
337: #if KERNOBJC
338: #if DRVRKITINTS
339: IOSendInterrupt(identity, state, IO_DEVICE_INTERRUPT_MSG);
340: #else
341: thread_call_func((thread_call_func_t)KeyboardCallout, 0, TRUE);
342: #endif DRVRKITINTS
343:
344: #else
345: cDispatchKeyboardEvent( event );
346: _eventIndex = 0;
347: #endif DRIVERKIT
348: }
349: }
350: }
351:
352: //
353: // END: Impl. of internal methods for dealing w/ kbd controller
354: //
355:
356: //
357: // BEGIN: Implementation of internal functions and methods
358: //
359: static void EnqueueKey(int keyCode, ns_time_t stamp)
360: // Description: Enqueue an event that corresponds to a key coming up
361: {
362: PCKeyboardEvent event;
363:
364: if (_eventIndex != MAX_PENDING_EVENTS)
365: {
366: event.keyCode = keyCode;
367: event.goingDown = 0;
368: event.timeStamp = stamp;
369: _pendingEvents[_eventIndex++] = event;
370: }
371: }
372:
373: static inline
374: PCKeyboardEvent *PPCScancodeToKeyEvent(
375: unsigned char key)
376: // Description: Take a scan code from the keyboard and package it up into
377: // a PCKeyboard event.
378: {
379: static PCKeyboardEvent event;
380:
381: event.keyCode = ADBK_KEYVAL(key);
382: IOGetTimestamp(&event.timeStamp);
383: event.goingDown = ADBK_PRESS(key);
384:
385: if (event.goingDown)
386: {
387: if (KBV_IS_KEYDOWN(event.keyCode, _kbdBitVector))
388: return (PCKeyboardEvent *)0;
389: else
390: KBV_KEYDOWN(event.keyCode, _kbdBitVector);
391: }
392: else
393: KBV_KEYUP(event.keyCode, _kbdBitVector);
394:
395: return (&event);
396: }
397:
398: #if KERNOBJC
399:
400: - (void)interruptHandler
401: // Description: This method is invoked by the I/O Thread when a keyboard
402: // interrupt message has been recieved. This method reads
403: // the keycode, processes it into a PCKeyboardEvent and
404: // sends it to our owner.
405: {
406: int oldIPL, nEvents, i;
407: PCKeyboardEvent events[MAX_PENDING_EVENTS];
408:
409: if (_owner == nil)
410: {
411: _eventIndex = 0; //bug 2228585
412: return; // After all that, no one is interested!
413: }
414:
415: // Safely copy the events from the pending queue
416: oldIPL = spltty();
417: if (_eventIndex == 1)
418: events[0] = _pendingEvents[0];
419: else
420: bcopy(_pendingEvents, events, sizeof(PCKeyboardEvent) * _eventIndex);
421: nEvents = _eventIndex;
422: _eventIndex = 0;
423: (void)splx(oldIPL);
424:
425: for (i = 0; i < nEvents; i++)
426: {
427: [_owner dispatchKeyboardEvent:&events[i]];
428: }
429: }
430:
431: #ifdef DRVRKITINTS
432:
433: static volatile void kbdThread(PPCKeyboard *_kbdObject)
434: // Description: This is the function which is executed as the I/O Thread.
435: // It waits for messages from driverkit and dispatches them
436: // as appropriate.
437: {
438: kern_return_t result;
439: msg_header_t msg, *msgPtr = &msg;
440:
441: /* For the time being;it is already init to false */
442:
443: //
444: // Main loop. Wait for incoming messages, dispatch as appropriate.
445: //
446: while (TRUE) {
447: msgPtr->msg_size = sizeof(msg);
448: msgPtr->msg_local_port = [_kbdObject interruptPort];
449:
450: result = msg_receive(msgPtr, MSG_OPTION_NONE, 0);
451: if (result != RCV_SUCCESS) {
452: IOLog("kbdThread: msg_receive() returned %d\n", result);
453: continue;
454: }
455:
456: if (msgPtr->msg_id == IO_DEVICE_INTERRUPT_MSG)
457: {
458: [_kbdObject interruptHandler];
459: } else
460: IOLog("kbdThread: non intr msg received %d\n", result);
461: }
462: }
463:
464: #endif DRVRKITINTS
465:
466: - (BOOL)kbdInit:(IODeviceDescription *)deviceDescription
467: // Description: Initialize the keyboard object. Returns NO on error.
468: {
469: char locationStr[ 24 ];
470: IOADBDeviceInfo deviceInfo;
471:
472: _owner = nil;
473: _desiredOwner = nil;
474: _ownerLock = [NXLock new];
475:
476: #ifdef DRVRKITINTS
477: [self enableAllInterrupts];
478: IOForkThread((IOThreadFunc)kbdThread, self);
479: #else
480: _kbdObj = self;
481: #endif DRVRKITINTS
482:
483: ADBKeyboardInit();
484: adbAsyncAvail = TRUE;
485:
486: interfaceId = NX_EVS_DEVICE_INTERFACE_ADB;
487:
488: [adb_driver getADBInfo: keyboard_adb_addr: &deviceInfo];
489: handlerId = 16 + (deviceInfo.handlerID);
490:
491: sprintf( locationStr, "handlerID %d", handlerId);
492: [self setLocation:locationStr];
493:
494: return YES;
495: }
496:
497: //
498: // END: Implementation of internal functions and methods
499: //
500:
501: //
502: // BEGIN: EXPORTED PPCKeyboard methods
503: //
504: + (BOOL)probe:deviceDescription
505: // Description: Bring a new instance into existance.
506: {
507: PPCKeyboard *inst;
508:
509: //
510: // Create an instance and initialize some basic instance variables.
511: //
512: inst = [[self alloc] initFromDeviceDescription:deviceDescription];
513:
514: [inst setUnit: 0];
515: [inst setName:"PPCKeyboard0"];
516: [inst setDeviceKind:"PPCKeyboard"];
517:
518: //
519: // Proceed with initialization.
520: //
521: if ([inst kbdInit:deviceDescription] == NO) {
522: IOLog("PPCKeyboard probe: kdbInit failed\n");
523: [inst free];
524: return NO;
525: }
526: else
527: [inst registerDevice];
528:
529: //IODelay(1000000);
530:
531: [inst setAlphaLockFeedback:NO];
532:
533: return YES;
534: }
535:
536: - initFromDeviceDescription:(IODeviceDescription *)deviceDescription
537: {
538:
539: adb_driver = [deviceDescription directDevice];
540:
541: return self;
542: }
543:
544: - (BOOL) getHandler:(IOPPCInterruptHandler *)handler
545: level:(unsigned int *) ipl
546: argument:(unsigned int *) arg
547: forInterrupt:(unsigned int) localInterrupt
548: {
549: #ifdef DRVRKITINTS
550: *handler = KbdIntHandler;
551: *ipl = 3;
552: *arg = 0xdeadbeef;
553: return YES;
554: #endif DRVRKITINTS
555: return NO;
556: }
557:
558: - free
559: // Description: Frees an instance.
560: {
561: [_ownerLock free];
562: return [super free];
563: }
564:
565:
566: - (int)interfaceId
567: // Description: return keyboard interface ID.
568: {
569: return interfaceId;
570: }
571:
572: - (int)handlerId
573: // Description: return keyboard handler ID.
574: {
575: return handlerId;
576: }
577:
578: - (void)setAlphaLockFeedback:(BOOL)locked
579: // Description: Set the keyboard LEDs to indicate the state of alpha lock
580: {
581: keyboard_set_led_state( locked ? ADBKS_LED_CAPSLOCK : 0 );
582: }
583:
584: #endif KERNOBJC
585:
586: static PCKeyboardEvent stolenEvent;
587:
588: PCKeyboardEvent *PPCStealKeyEvent()
589: // Description: Call this routine to steal a keyboard event directly
590: // from the hardware. Must be called from interrupt level.
591: {
592: ADBKeyboardInit();
593:
594: if (_eventIndex == 0) {
595: CheckADBPoll();
596: if (_eventIndex == 0)
597: return NULL;
598: }
599: // This sucks.
600: stolenEvent = _pendingEvents[0];
601: _eventIndex--;
602: bcopy( &_pendingEvents[1], &_pendingEvents[0], sizeof(PCKeyboardEvent) * _eventIndex);
603:
604: return( &stolenEvent );
605: }
606:
607: //
608: // END: EXPORTED PPCKeyboard methods
609: //
610:
611: #if KERNOBJC
612:
613: //
614: // BEGIN: Implementation of the PCKeyboardExported protocol
615: //
616: - (IOReturn)becomeOwner : client;
617: // Description: Register for event dispatch via device-specific protocol.
618: // (See the dispatchKeyboardEvent method)
619: // Returns IO_R_SUCCESS if successful, else IO_R_BUSY. The
620: // relinquishOwnershipRequest: method may be called on another
621: // client during the execution of this method.
622: {
623: IOReturn rtn;
624:
625: [_ownerLock lock];
626: if(_owner != nil) {
627: if([_owner respondsTo:@selector(relinquishOwnershipRequest:)])
628: {
629: rtn = [_owner relinquishOwnershipRequest:self];
630: }
631: else {
632: IOLog("%s: owner %s does not respond to "
633: "relinquishOwnershipRequest:\n",
634: [self name], [_owner name]);
635: rtn = IO_R_BUSY;
636: }
637:
638: if(rtn == IO_R_SUCCESS) {
639: _owner = client;
640: }
641: else {
642: // NEGOTIATION FAILED
643: }
644: }
645: else {
646: _owner = client;
647: rtn = IO_R_SUCCESS;
648: }
649:
650: [_ownerLock unlock];
651:
652: if( rtn == IO_R_SUCCESS) {
653: // Send the new owner a capslock down
654:
655: unsigned char read_buf[8];
656: int rcvd_length;
657: int s;
658:
659: [ adb_driver readADBDeviceRegister: keyboard_adb_addr: 2: read_buf: &rcvd_length];
660: if( (rcvd_length == 2) &&
661: (0 == (read_buf[0] & ADBKS_CAPSLOCK_short))) {
662: s = spltty();
663: KBV_KEYUP(ADBK_CAPSLOCK, _kbdBitVector);
664: keyboard_updown(ADBK_CAPSLOCK);
665: splx(s);
666: }
667: }
668: return rtn;
669: }
670:
671: - (IOReturn)relinquishOwnership : client;
672: // Description: Relinquish ownership. Returns IO_R_BUSY if caller is not
673: // current owner.
674: {
675: IOReturn rtn;
676:
677: [_ownerLock lock];
678: if(_owner == client) {
679: rtn = IO_R_SUCCESS;
680: _owner = nil;
681: }
682: else {
683: rtn = IO_R_BUSY;
684: }
685: [_ownerLock unlock];
686: if((rtn == IO_R_SUCCESS) &&
687: _desiredOwner &&
688: (_desiredOwner != client)) {
689: /*
690: * Notify this potential client that it can take over.
691: * We'll most likely be called back during this method,
692: * which is why we released _ownerLock.
693: */
694: if([_desiredOwner respondsTo:@selector(canBecomeOwner:)]) {
695: [_desiredOwner canBecomeOwner:self];
696: }
697: else {
698: IOLog("%s: desiredOwner does not respond to "
699: "canBecomeOwner:\n", [self name]);
700: }
701: }
702: return rtn;
703: }
704:
705:
706: - (IOReturn)desireOwnership : client;
707: // Description: Request notification (via canBecomeOwner:) when
708: // relinquishOwnership: is called. This allows one potential
709: // client to place itself "next in line" for ownership. The
710: // queue is only one deep.
711: {
712: IOReturn rtn;
713:
714: [_ownerLock lock];
715: if(_desiredOwner && (_desiredOwner != client)) {
716: rtn = IO_R_BUSY;
717: }
718: else {
719: _desiredOwner = client;
720: rtn = IO_R_SUCCESS;
721: }
722: [_ownerLock unlock];
723: return rtn;
724: }
725: //
726: // END: Implementation of the PCKeyboardExported protocol
727: //
728: @end
729:
730: #endif KERNOBJC
731:
732:
733:
734:
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.