|
|
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: * kmDevice.m - kernel keyboard/monitor module, ObjC implementation. ! 28: * ! 29: * HISTORY ! 30: * 21 Sep 92 Joe Pasqua ! 31: * Created i386 version based on m88k version. ! 32: */ ! 33: ! 34: #import <driverkit/generalFuncs.h> ! 35: #import <machkit/NXLock.h> ! 36: #import <driverkit/ppc/driverTypesPrivate.h> ! 37: #import <driverkit/kernelDriver.h> ! 38: #import <bsd/sys/types.h> ! 39: #import <bsd/sys/tty.h> ! 40: #import <bsd/dev/ppc/cons.h> ! 41: #import <bsd/sys/conf.h> ! 42: #import <bsd/sys/fcntl.h> ! 43: #import <bsd/sys/errno.h> ! 44: #import <bsd/sys/msgbuf.h> ! 45: #import <bsd/dev/ppc/FBConsole.h> ! 46: #import <bsd/dev/ppc/SerialConsole.h> ! 47: #import <bsd/dev/ppc/kmDevice.h> ! 48: #import <bsd/dev/kmreg_com.h> ! 49: #import <bsd/sys/reboot.h> ! 50: #import <kernserv/prototypes.h> ! 51: #import <driverkit/IODisplay.h> ! 52: #import <driverkit/IOFrameBufferDisplay.h> ! 53: #import <driverkit/IODisplayPrivate.h> ! 54: #import <driverkit/IOConfigTable.h> ! 55: #import <bsd/dev/ppc/kmWaitCursor.h> ! 56: #import <bsd/sys/proc.h> ! 57: #import <bsd/sys/systm.h> ! 58: ! 59: #import <kern/assert.h> ! 60: #import <machdep/ppc/boot.h> ! 61: ! 62: #import "PCKeyboardDefs.h" ! 63: #import "PPCKeyboardPriv.h" ! 64: #import "ConsoleSupport.h" ! 65: #import "km.h" ! 66: ! 67: IODisplayInfo bootDisplayInfo; ! 68: ! 69: static IOConsoleInfo *serialConsole; ! 70: static int bootGraphicsMode = NO; ! 71: static short prettyShutdown = 0; ! 72: ! 73: // Title strings for the various windows ! 74: const char *mach_title = "Mac OS X Server Operating System"; // Used by km.m also ! 75: static const char *alert_title = "Alert"; ! 76: ! 77: ! 78: #if KERNOBJC ! 79: // Module Globals ! 80: static int kmUnit; // Incremented to keep track of what unit we're on ! 81: static id display; ! 82: // display == nil means that we do not have a display object around ! 83: // yet. In this case we use the basicConsole. When display != nil ! 84: // we can use it's console support mechanism to do our displaying. ! 85: ! 86: // The following function pointers are used by DoAlert and DoRestore. They ! 87: // get called at interrupt level and can't execute ObjC code. To avoid doing ! 88: // so we bind the lock and unlock methods that are used and call them thru ! 89: // these pointers. ! 90: static id (*lockProc)(), (*unlockProc)(); ! 91: ! 92: #define AllocConsole() \ ! 93: AllocDisplayConsole(display) ! 94: ! 95: LANG_TYPE glLanguage; ! 96: ! 97: #else ! 98: ! 99: #define AllocConsole() basicConsole ! 100: ! 101: #endif KERNOBJC ! 102: ! 103: ! 104: static IOConsoleInfo * ! 105: AllocDisplayConsole( id display ) ! 106: { ! 107: IOConsoleInfo * consoleInfo = NULL; ! 108: ! 109: if( display) ! 110: consoleInfo = [display allocateConsoleInfo]; ! 111: if( NULL == consoleInfo) ! 112: consoleInfo = basicConsole; ! 113: return( consoleInfo); ! 114: } ! 115: ! 116: ! 117: // Used for putting up alert panels very early, before kmId is valid. ! 118: IOConsoleInfo *kmAlertConsole; ! 119: ! 120: /* ! 121: * Calculate incremented index for inBuf. ! 122: */ ! 123: static inline int ! 124: inbuf_incr(int x) ! 125: { ! 126: if(++x == INBUF_SIZE) { ! 127: return 0; ! 128: } ! 129: else { ! 130: return x; ! 131: } ! 132: } ! 133: ! 134: /* ! 135: * Initialize the console enough for printf's to work via kmputc. No ! 136: * text window will be created if booting in icon mode. Keyboard is ! 137: * not enabled. ! 138: */ ! 139: ! 140: void ! 141: initialize_screen(void * args) ! 142: { ! 143: extern int initialized; ! 144: Boot_Video * framebufferArgs = (Boot_Video *) args; ! 145: ! 146: cons.t_dev = makedev(12, 0); /* point the cons device to cdevsw's km dev */ ! 147: ! 148: serialConsole = SerialAllocateConsole(); ! 149: ! 150: if( framebufferArgs->v_baseAddr) { ! 151: /* ! 152: * Initialize the OpenFirmware based framebuffer console. ! 153: */ ! 154: static char * ofPixelEncoding = "PPPPPPPP"; ! 155: ! 156: bzero(&bootDisplayInfo, sizeof(bootDisplayInfo)); ! 157: bootDisplayInfo.width = framebufferArgs->v_width; ! 158: bootDisplayInfo.height = framebufferArgs->v_height; ! 159: bootDisplayInfo.totalWidth = framebufferArgs->v_rowBytes; ! 160: bootDisplayInfo.rowBytes = framebufferArgs->v_rowBytes; ! 161: bootDisplayInfo.refreshRate = 75; // very approx ! 162: bootDisplayInfo.frameBuffer = (void *)framebufferArgs->v_baseAddr; ! 163: bootDisplayInfo.bitsPerPixel = IO_8BitsPerPixel; ! 164: bootDisplayInfo.colorSpace = IO_RGBColorSpace; ! 165: strcpy( bootDisplayInfo.pixelEncoding, ofPixelEncoding); ! 166: basicConsole = BasicAllocateConsole(&bootDisplayInfo); ! 167: } ! 168: if( basicConsole == NULL) ! 169: basicConsole = serialConsole; ! 170: ! 171: if( framebufferArgs->v_display & 1) ! 172: bootGraphicsMode = YES; ! 173: ! 174: basicConsoleMode = bootGraphicsMode ? SCM_GRAPHIC : SCM_TEXT; ! 175: (*basicConsole->Init)( ! 176: basicConsole, basicConsoleMode, (bootGraphicsMode == NO), (bootGraphicsMode == NO), mach_title); ! 177: ! 178: initialized = TRUE; ! 179: } ! 180: ! 181: #if KERNOBJC ! 182: ! 183: @implementation kmDevice ! 184: ! 185: - (void)registerDisplay:newDisplay ! 186: { ! 187: IOConsoleInfo * newConsole; ! 188: ! 189: if (display == nil) { ! 190: display = newDisplay; ! 191: ! 192: if( NO == probed) { ! 193: newConsole = AllocDisplayConsole( newDisplay); ! 194: if( newConsole) { ! 195: (*newConsole->Init)( ! 196: newConsole, fbMode, YES, fbMode == SCM_TEXT, mach_title); ! 197: fbp[FB_DEV_NORMAL] = newConsole; ! 198: if( fbMode == SCM_TEXT) ! 199: kmdumplog(); ! 200: else { ! 201: kmDrawString( newConsole, "Starting Mac OS X Server"); ! 202: [self animationCtl: KM_ANIM_RESUME]; ! 203: } ! 204: } ! 205: newConsole = AllocDisplayConsole( newDisplay); ! 206: if( newConsole) ! 207: fbp[FB_DEV_ALERT] = newConsole; ! 208: ! 209: } else { ! 210: // somebody like the window server has changed modes, ! 211: // but we still own the display! ! 212: fbMode = SCM_OTHER; ! 213: [self animationCtl: KM_ANIM_STOP]; ! 214: ! 215: fbp[FB_DEV_NORMAL] = AllocDisplayConsole( newDisplay); ! 216: fbp[FB_DEV_ALERT] = AllocDisplayConsole( newDisplay); ! 217: } ! 218: } ! 219: } ! 220: ! 221: - (void)unregisterDisplay:oldDisplay ! 222: { ! 223: if (display == oldDisplay) { ! 224: [self animationCtl: KM_ANIM_SUSPEND]; ! 225: basicConsole = serialConsole; ! 226: display = nil; ! 227: ! 228: if( fbp[FB_DEV_NORMAL]) ! 229: (*fbp[FB_DEV_NORMAL]->Free) (fbp[FB_DEV_NORMAL]); ! 230: if( fbp[FB_DEV_ALERT]) ! 231: (*fbp[FB_DEV_ALERT]->Free) (fbp[FB_DEV_ALERT]); ! 232: ! 233: fbp[FB_DEV_NORMAL] = serialConsole; ! 234: fbp[FB_DEV_ALERT] = serialConsole; ! 235: } ! 236: } ! 237: ! 238: ! 239: /* Probe routine for a pseudo-device driver. */ ! 240: + (BOOL)probe : deviceDescription ! 241: { ! 242: // Proceed with keyboard initialization. ! 243: ! 244: if ([kmId init:YES fb_mode: ! 245: bootGraphicsMode ? SCM_GRAPHIC : SCM_TEXT] == nil) ! 246: { ! 247: IOLog("kmDevice: continuing with bad kmDevice instance\n"); ! 248: [kmId free]; ! 249: kmId = nil; ! 250: return NO; ! 251: } else ! 252: kmId->probed = YES; ! 253: ! 254: return YES; ! 255: } ! 256: ! 257: + (IODeviceStyle)deviceStyle ! 258: { ! 259: return IO_PseudoDevice; ! 260: } ! 261: ! 262: /* ! 263: * Can't put this in the kmDevice object because we might need it ! 264: * before kmId is initialized. ! 265: */ ! 266: static int kmDeviceAnimationState = -1; ! 267: static simple_lock_data_t kmDeviceAnimationLock; ! 268: ! 269: /* ! 270: * Create a kmDevice. This should only be called once in the lifetime of ! 271: * the system. It can be called from kmDevice's probe:, or from km.m's ! 272: * alert() (if alert is called before IOTask autoconf). ! 273: */ ! 274: + new ! 275: { ! 276: char name[20]; ! 277: kmDevice *km_id; ! 278: int i; ! 279: ! 280: simple_lock_init(&kmDeviceAnimationLock); ! 281: ! 282: km_id = [self alloc]; ! 283: km_id->kmOpenLock = [NXLock new]; ! 284: (IMP)lockProc = [km_id->kmOpenLock methodFor:@selector(lock)]; ! 285: (IMP)unlockProc = [km_id->kmOpenLock methodFor:@selector(unlock)]; ! 286: km_id->kbId = nil; ! 287: ! 288: for(i=0; i<NUM_FB_DEVS; i++) { ! 289: km_id->fbp[i] = NULL; ! 290: } ! 291: ! 292: /* ! 293: * Global kmId is id of first kmDevice created. ! 294: */ ! 295: if(kmUnit == 0) { ! 296: ASSERT(kmId == nil); ! 297: kmId = km_id; ! 298: } ! 299: ! 300: /* ! 301: * Special case for this one, it's hard coded - there is always ! 302: * at least one of these, and it's created before autoconf. ! 303: */ ! 304: km_id->fbp[FB_DEV_NORMAL] = basicConsole; ! 305: km_id->fbp[FB_DEV_ALERT] = basicConsole; ! 306: [kmId setUnit:kmUnit]; ! 307: sprintf(name, "kmDevice%d", kmUnit++); ! 308: [kmId setName:name]; ! 309: [kmId setDeviceKind:"kmDevice"]; ! 310: [kmId setLocation:NULL]; ! 311: return km_id; ! 312: } ! 313: ! 314: /* ! 315: * Reusable initialization method. kmOpenLock must already have been ! 316: * initialized. initKb enables initialiation of keyboard. ! 317: */ ! 318: - init : (BOOL)initKb ! 319: fb_mode : (ScreenMode)fb_mode ! 320: { ! 321: id rtn = self; ! 322: ! 323: [kmOpenLock lock]; ! 324: ! 325: /* ! 326: * Init local instance variables. ! 327: */ ! 328: inDex = outDex = 0; ! 329: blockIn = 0; ! 330: alertRefCount = 0; ! 331: fbMode = fb_mode; ! 332: simple_lock_init(&inBufLock); ! 333: ! 334: if(initKb) { ! 335: /* ! 336: * connect to Keyboard. ! 337: */ ! 338: if([self initKb] == nil) { ! 339: IOLog("kmDevice: No Keyboard Found\n"); ! 340: /* but continue anyway... */ ! 341: } ! 342: } ! 343: [super init]; ! 344: if( (!hasRegistered) && initKb) { ! 345: [self registerDevice]; ! 346: hasRegistered = YES; ! 347: } ! 348: ! 349: [kmOpenLock unlock]; ! 350: return rtn; ! 351: } ! 352: ! 353: - initKb ! 354: // Description: Initialize connection with PCKeyboard object ! 355: { ! 356: IOReturn drtn; ! 357: ! 358: drtn = IOGetObjectForDeviceName("PPCKeyboard0", &kbId); ! 359: if(drtn) { ! 360: IOLog("km init: Can't find PPCKeyboard0 (%s)\n", ! 361: [self stringFromReturn:drtn]); ! 362: return nil; ! 363: } ! 364: ! 365: drtn = [kbId becomeOwner:self]; ! 366: if(drtn) { ! 367: IOLog("km init: becomeOwner failed (%s)\n", ! 368: [self stringFromReturn:drtn]); ! 369: return nil; ! 370: } ! 371: ! 372: /* ! 373: * Also register to be notified if anyone else relinquishes ! 374: * ownership after we give it up. This allows us to take over ! 375: * the frame buffer and keyboard when the window server exits. ! 376: */ ! 377: drtn = [kbId desireOwnership:self]; ! 378: if(drtn) { ! 379: IOLog("km init: desireOwnership failed (%s)\n", ! 380: [self stringFromReturn:drtn]); ! 381: return nil; ! 382: } ! 383: return self; ! 384: } ! 385: ! 386: /* ! 387: * Interface to bsd code. ! 388: */ ! 389: - (int)kmOpen : (int)flag ! 390: { ! 391: int rtn = 0; ! 392: ! 393: [kmOpenLock lock]; ! 394: if(flag & ( O_POPUP | O_ALERT)) { ! 395: switch(fbMode) { ! 396: case SCM_TEXT: ! 397: /* ! 398: * Easy case, we already have a place to do putc()'s. ! 399: * Note for SCM_TEXT case, alert text just goes to ! 400: * the normal console. ! 401: */ ! 402: break; ! 403: case SCM_ALERT: ! 404: alertRefCount++; ! 405: break; ! 406: ! 407: default: ! 408: /* ! 409: * Create an alert window. ! 410: * ! 411: * We only want to allow this for ! 412: * programs during system startup (eg. ! 413: * they must be run as root, and PostScript ! 414: * must not be running. ! 415: */ ! 416: if(suser(current_proc()->p_ucred, ! 417: ¤t_proc()->p_acflag)) { ! 418: rtn = EACCES; ! 419: goto out; ! 420: } ! 421: if(fbMode == SCM_OTHER) { ! 422: rtn = EBUSY; ! 423: goto out; ! 424: } ! 425: ! 426: /* ! 427: * Dropping to single user mode => O_POPUP, ! 428: * so make the console text mode. ! 429: */ ! 430: if( flag & O_POPUP) { ! 431: fbMode = SCM_TEXT; ! 432: (*fbp[FB_DEV_NORMAL]->Init)( ! 433: fbp[FB_DEV_NORMAL], SCM_TEXT, TRUE, TRUE, mach_title ); ! 434: ! 435: } else { ! 436: /* ! 437: * Jump into "alert mode". Note that alertRefCount ! 438: * doesn't get decremented in close; the user has ! 439: * to do an explicit KMIOCRESTORE. ! 440: */ ! 441: alertRefCount++; ! 442: savedFbMode = fbMode; ! 443: fbMode = SCM_ALERT; ! 444: (*fbp[FB_DEV_ALERT]->Init)( ! 445: fbp[FB_DEV_ALERT], fbMode, TRUE, TRUE, alert_title ); ! 446: } ! 447: } ! 448: } ! 449: ! 450: /* ! 451: * km.m takes care of Unix-y tty stuff. ! 452: */ ! 453: out: ! 454: [kmOpenLock unlock]; ! 455: return rtn; ! 456: } ! 457: ! 458: - (int)kmPutc : (int)c ! 459: { ! 460: switch(fbMode) { ! 461: case SCM_TEXT: ! 462: (*fbp[FB_DEV_NORMAL]->PutC)(fbp[FB_DEV_NORMAL], c); ! 463: return 0; ! 464: ! 465: case SCM_ALERT: ! 466: ASSERT(fbp[FB_DEV_ALERT] != NULL); ! 467: (*fbp[FB_DEV_ALERT]->PutC)(fbp[FB_DEV_ALERT], c); ! 468: return 0; ! 469: ! 470: default: ! 471: /* ! 472: * No place to put this text. This is not an error. ! 473: */ ! 474: return 0; ! 475: } ! 476: } ! 477: ! 478: /* ! 479: * Blocking read routine. This assumes that interrupts and threads are ! 480: * working, since keyboard driver will need that functionality...OK? ! 481: */ ! 482: ! 483: - (int)kmGetc ! 484: { ! 485: int c; ! 486: ! 487: simple_lock(&inBufLock); ! 488: blockIn = 1; ! 489: while(inDex == outDex) { ! 490: /* ! 491: * Just wait for something to show up... ! 492: */ ! 493: thread_sleep((void *)inBuf, &inBufLock, TRUE); ! 494: simple_lock(&inBufLock); ! 495: } ! 496: c = inBuf[outDex]; ! 497: outDex = inbuf_incr(outDex); ! 498: blockIn = 0; ! 499: simple_unlock(&inBufLock); ! 500: return c; ! 501: } ! 502: ! 503: #endif //KERNOBJC ! 504: ! 505: /* ! 506: * ioctl equivalents. All return an errno. ! 507: */ ! 508: ! 509: /* ! 510: * Client finished with alert panel. Called from ioctl and from inside the ! 511: * kernel via alert_done(). ! 512: */ ! 513: int DoRestore(void) ! 514: { ! 515: int rtn = 0; ! 516: ! 517: #if KERNOBJC ! 518: ! 519: if (kmAlertConsole) { // No kmDevice yet! ! 520: (*kmAlertConsole->Restore)(kmAlertConsole); ! 521: (*kmAlertConsole->Free)(kmAlertConsole); ! 522: kmAlertConsole = NULL; ! 523: return 0; ! 524: } ! 525: ! 526: if (kmId == nil) ! 527: return 0; ! 528: ! 529: ! 530: /* ! 531: * Have to protect with kmOpenLock since we may alter frame buffer ! 532: * context. ! 533: */ ! 534: (*lockProc)(kmId->kmOpenLock, @selector(lock)); ! 535: if(kmId->fbMode == SCM_ALERT) { ! 536: if(kmId->alertRefCount == 0) { ! 537: /* ! 538: * No can do. I'm not sure when this could ! 539: * ever happen... ! 540: */ ! 541: rtn = EBUSY; ! 542: goto out; ! 543: } ! 544: if(--kmId->alertRefCount != 0) { ! 545: ! 546: /* ! 547: * Not out of the woods yet, other user(s) of alert ! 548: * panel still active. ! 549: */ ! 550: goto out; ! 551: } ! 552: ! 553: /* ! 554: * Last user of alert/popup window. ! 555: */ ! 556: kmId->fbMode = kmId->savedFbMode; ! 557: if(kmId->fbMode != SCM_ALERT) { ! 558: rtn = (*kmId->fbp[FB_DEV_ALERT]->Restore)( ! 559: kmId->fbp[FB_DEV_ALERT]); ! 560: } ! 561: else { ! 562: IOLog("kmDevice: Recursive SCM_ALERT in restore!\n"); ! 563: } ! 564: goto out; ! 565: } else { ! 566: /* ! 567: * Not in alert mode, this is a nop (and it's also somewhat ! 568: * unexpected...). ! 569: */ ! 570: rtn = EINVAL; ! 571: } ! 572: out: ! 573: (*unlockProc)(kmId->kmOpenLock, @selector(unlock)); ! 574: ! 575: #endif // KERNOBJC ! 576: ! 577: return rtn; ! 578: } ! 579: ! 580: #if KERNOBJC ! 581: ! 582: - (int)restore ! 583: { ! 584: return DoRestore(); ! 585: } ! 586: ! 587: - (int)drawRect : (const struct km_drawrect *)kmRect ! 588: { ! 589: struct km_drawrect rect = *kmRect; ! 590: int size, ret; ! 591: ! 592: if(fbMode != SCM_GRAPHIC) { ! 593: /* ! 594: * No can do. ! 595: */ ! 596: return EBUSY; ! 597: } ! 598: /* ! 599: * Copy in user data so the console DrawRect routine ! 600: * doesn't have to. ! 601: */ ! 602: ! 603: if( (rect.x & 3) == 3) { ! 604: size = rect.width * rect.height; // size in bytes, 8bit src ! 605: ! 606: } else { ! 607: rect.width = (rect.width + 3) & ~3; // Round up to 4 pixel boundary ! 608: size = (rect.width >> 2) * rect.height; // size in bytes ! 609: } ! 610: rect.data.bits = (unsigned char *)kalloc( size ); ! 611: if (copyin(kmRect->data.bits, rect.data.bits, size)) { ! 612: ret = -1; ! 613: goto out; ! 614: } ! 615: ! 616: ret = (*fbp[FB_DEV_NORMAL]->DrawRect)(fbp[FB_DEV_NORMAL], &rect); ! 617: ! 618: out: ! 619: kfree( rect.data.bits, size ); ! 620: return ret; ! 621: } ! 622: ! 623: - (int)eraseRect : (const struct km_drawrect *)kmRect ! 624: { ! 625: if(fbMode != SCM_GRAPHIC) { ! 626: /* ! 627: * No can do. ! 628: */ ! 629: return EBUSY; ! 630: } ! 631: return (*fbp[FB_DEV_NORMAL]->EraseRect)(fbp[FB_DEV_NORMAL], kmRect); ! 632: } ! 633: ! 634: - (int)disableCons ! 635: { ! 636: /* ! 637: * This means that tty code has detected a "console ! 638: * now invalid" situation. ! 639: */ ! 640: #if 0 ! 641: if(fbMode == SCM_TEXT) { ! 642: fbMode = SCM_OTHER; ! 643: } ! 644: #endif ! 645: return 0; ! 646: } ! 647: ! 648: #endif // KERNOBJC ! 649: ! 650: static void ! 651: kmDeviceDrawCursor() ! 652: { ! 653: IOConsoleInfo *device; ! 654: ! 655: simple_lock(&kmDeviceAnimationLock); ! 656: ! 657: if (kmDeviceAnimationState > 0) { ! 658: device = kmId->fbp[FB_DEV_NORMAL]; ! 659: if (device && (kmId->fbMode == SCM_GRAPHIC)) { ! 660: (void)(*device->DrawRect)(device, ! 661: &kmDeviceWaitCursor[kmDeviceAnimationState - 1]); ! 662: } ! 663: if (++kmDeviceAnimationState > KM_DEVICE_WAITCURSOR_NSTATES) ! 664: kmDeviceAnimationState = 1; ! 665: ns_timeout((func)kmDeviceDrawCursor, 0, KM_DEVICE_WAITCURSOR_DELAY, ! 666: CALLOUT_PRI_THREAD); ! 667: } ! 668: simple_unlock(&kmDeviceAnimationLock); ! 669: } ! 670: ! 671: /* Called once and only once from main(), ! 672: */ ! 673: void ! 674: kmEnableAnimation(void) ! 675: { ! 676: if( kmId == nil) { ! 677: kmId = [kmDevice new]; ! 678: [kmId init:NO fb_mode: ! 679: bootGraphicsMode ? SCM_GRAPHIC : SCM_TEXT]; ! 680: } ! 681: [kmId animationCtl:KM_ANIM_RESUME]; ! 682: } ! 683: ! 684: void ! 685: kmDisableAnimation(void) ! 686: { ! 687: if (kmId != nil) ! 688: [kmId animationCtl:KM_ANIM_STOP]; ! 689: } ! 690: ! 691: #if KERNOBJC ! 692: ! 693: - (int)animationCtl : (km_anim_ctl_t)ctl ! 694: { ! 695: int doAnimation = 0; ! 696: int ret = 0; ! 697: ! 698: if (fbMode != SCM_GRAPHIC) ! 699: return 0; ! 700: ! 701: simple_lock(&kmDeviceAnimationLock); ! 702: switch(ctl) { ! 703: case KM_ANIM_STOP: ! 704: case KM_ANIM_SUSPEND: ! 705: if (kmDeviceAnimationState > 0) { ! 706: kmDeviceAnimationState = -kmDeviceAnimationState; ! 707: (void)(*fbp[FB_DEV_NORMAL]->DrawRect) ! 708: (fbp[FB_DEV_NORMAL], &kmDeviceBlankCursor); ! 709: } ! 710: ns_untimeout((func)kmDeviceDrawCursor, 0); ! 711: if( ctl == KM_ANIM_STOP) ! 712: kmDeviceAnimationState = 0; ! 713: break; ! 714: case KM_ANIM_RESUME: ! 715: if (kmDeviceAnimationState < 0) { ! 716: kmDeviceAnimationState = -kmDeviceAnimationState; ! 717: doAnimation = 1; ! 718: } ! 719: break; ! 720: default: ! 721: ret = EINVAL; ! 722: break; ! 723: } ! 724: simple_unlock(&kmDeviceAnimationLock); ! 725: if (doAnimation) ! 726: kmDeviceDrawCursor(); ! 727: return ret; ! 728: } ! 729: ! 730: - (int)getStatus : (unsigned *)statusp ! 731: { ! 732: unsigned status = KMS_SEE_MSGS; ! 733: ! 734: if(fbMode == SCM_GRAPHIC) { ! 735: status = 0; ! 736: } ! 737: *statusp = status; ! 738: return 0; ! 739: } ! 740: ! 741: - (int)getScreenSize : (struct ConsoleSize *)size ! 742: { ! 743: if (fbp[FB_DEV_NORMAL] == 0) ! 744: return EINVAL; ! 745: ! 746: (*fbp[FB_DEV_NORMAL]->GetSize)(fbp[FB_DEV_NORMAL], size); ! 747: return 0; ! 748: } ! 749: ! 750: #endif KERNOBJC ! 751: ! 752: #import <bsd/dev/ppc/keycodes.h> ! 753: ! 754: int ProcessKbdEvent(PCKeyboardEvent *ke) ! 755: { ! 756: // State of the modifier keys: ! 757: static boolean_t control_left, control_right, ! 758: shift_left, shift_right, caps_lock, ! 759: alt_left, alt_right, ! 760: cmd_left, cmd_right; ! 761: boolean_t valid, shift, control, cmd, c; ! 762: ! 763: valid = FALSE; ! 764: switch (ke->keyCode) { ! 765: case ADBK_CONTROL: ! 766: control_left = ke->goingDown; ! 767: break; ! 768: ! 769: case ADBK_CONTROL_R: ! 770: control_right = ke->goingDown; ! 771: break; ! 772: ! 773: case ADBK_SHIFT: ! 774: shift_left = ke->goingDown; ! 775: break; ! 776: ! 777: case ADBK_SHIFT_R: ! 778: shift_right = ke->goingDown; ! 779: break; ! 780: ! 781: case ADBK_CAPSLOCK: ! 782: caps_lock = ke->goingDown; ! 783: break; ! 784: ! 785: case ADBK_OPTION: ! 786: alt_left = ke->goingDown; ! 787: break; ! 788: ! 789: case ADBK_OPTION_R: ! 790: alt_right = ke->goingDown; ! 791: break; ! 792: ! 793: case ADBK_FLOWER: ! 794: cmd_left = ke->goingDown; ! 795: break; ! 796: ! 797: default: ! 798: valid = TRUE; ! 799: } ! 800: ! 801: if (!valid) ! 802: return inv; ! 803: ! 804: // caps lock is just a pain at this point ! 805: shift = shift_right || shift_left; // || caps_lock; ! 806: ! 807: control = (control_left || control_right) ? (_N_KEYCODES * 2) : 0; ! 808: c = keycodeToAscii[((ke->keyCode << 1) | shift) + control]; ! 809: ! 810: cmd = (cmd_right || cmd_left) ? 0x80 : 0; ! 811: ! 812: switch (c) { ! 813: case dim: ! 814: case bright: ! 815: case loud: ! 816: case quiet: ! 817: case up: ! 818: case down: ! 819: break; ! 820: ! 821: default: ! 822: c |= cmd; ! 823: break; ! 824: } ! 825: ! 826: //printf("{raw:%lx, ascii:%lx}",ke->keyCode,c); ! 827: ! 828: if (!ke->goingDown) // Ignore keys coming up ! 829: return(inv); ! 830: return(c); ! 831: } ! 832: ! 833: #if KERNOBJC ! 834: ! 835: - (void)dispatchKeyboardEvent:(PCKeyboardEvent *)event; ! 836: // Description: Called when the keyboard object receives a new keyboard ! 837: // Event. Don't free the event object. ! 838: { ! 839: register int c; ! 840: ! 841: if ((c = ProcessKbdEvent(event)) == inv) ! 842: return; ! 843: ! 844: // Normal ASCII data. pass it up. ! 845: if(blockIn) { ! 846: // ! 847: // We're in 'blocking input' mode; add this to ! 848: // the input buffer if there is room. ! 849: // ! 850: simple_lock(&inBufLock); ! 851: if(inbuf_incr(inDex) == outDex) { ! 852: // ! 853: // Overflow. Oh well. ! 854: // ! 855: simple_unlock(&inBufLock); ! 856: return; ! 857: } ! 858: inBuf[inDex] = c; ! 859: inDex = inbuf_incr(inDex); ! 860: thread_wakeup((void *)inBuf); ! 861: simple_unlock(&inBufLock); ! 862: } ! 863: else { ! 864: // ! 865: // Normal console input. ! 866: // ! 867: struct tty *tp = &cons; ! 868: ! 869: (*linesw[tp->t_line].l_rint) (c, tp); ! 870: } ! 871: return; ! 872: } ! 873: ! 874: #else ! 875: ! 876: void ! 877: cDispatchKeyboardEvent(PCKeyboardEvent *event) ! 878: { ! 879: register int c; ! 880: struct tty *tp = &cons; ! 881: ! 882: if ((c = ProcessKbdEvent(event)) == inv) ! 883: return; ! 884: #if 0 ! 885: cnputc(c); ! 886: #else ! 887: (*linesw[tp->t_line].l_rint) (c, tp); ! 888: #endif ! 889: ! 890: return; ! 891: } ! 892: ! 893: #endif KERNOBJC ! 894: ! 895: #if KERNOBJC ! 896: ! 897: /* ! 898: * ev driver (or DPS or ...) is taking over the screen and keyboard. ! 899: * This should always succeed. ! 900: */ ! 901: - (IOReturn)relinquishOwnershipRequest : device ! 902: { ! 903: [self animationCtl: KM_ANIM_STOP]; ! 904: ! 905: fbMode = SCM_OTHER; ! 906: /* ! 907: * FIXME - notify parent of SCM_UNINIT. ! 908: */ ! 909: return IO_R_SUCCESS; ! 910: } ! 911: ! 912: /* ! 913: * Called when ev/DPS, which has been the owner of Keyboard, relinquishes ! 914: * ownership. I think this means that we unconditionally go to SCM_TEXT ! 915: * mode... ! 916: */ ! 917: ! 918: static char *k_languages[L_NUM_LANGUAGE] = { ! 919: "English", ! 920: "French", ! 921: "German", ! 922: "Spanish", ! 923: "Italian", ! 924: "Swedish", ! 925: "Japanese", ! 926: }; ! 927: ! 928: ! 929: - (IOReturn)canBecomeOwner : device ! 930: { ! 931: IOReturn drtn; ! 932: static short checkedSystemConfig = 0; ! 933: static short preventPrettyShutdown = 0; ! 934: ! 935: /* ! 936: * Regain control of keyboard. ! 937: */ ! 938: if((drtn = [kbId becomeOwner:self])) { ! 939: IOLog("km canBecomeOwner: becomeOwner failed (%s)\n", ! 940: [self stringFromReturn:drtn]); ! 941: /* ! 942: * But continue, although we have no keyboard... ! 943: */ ! 944: } ! 945: ! 946: if (!checkedSystemConfig) { ! 947: IOConfigTable *configTable; ! 948: const char *val; ! 949: ! 950: checkedSystemConfig = 1; ! 951: configTable = [IOConfigTable newFromSystemConfig]; ! 952: val = [configTable valueForStringKey:"Shutdown Graphics"]; ! 953: if (val) { ! 954: if (!strcmp(val,"No")) ! 955: preventPrettyShutdown = 1; ! 956: [IOConfigTable freeString:val]; ! 957: } ! 958: ! 959: val = [configTable valueForStringKey:"Language"]; ! 960: if (val) { ! 961: int i; ! 962: ! 963: for (i=0; i<L_NUM_LANGUAGE; i++) { ! 964: if (!strcmp(val, k_languages[i])) { ! 965: glLanguage = i; ! 966: break; ! 967: } ! 968: } ! 969: [IOConfigTable freeString:val]; ! 970: } ! 971: ! 972: [configTable free]; ! 973: } ! 974: ! 975: if (preventPrettyShutdown) ! 976: prettyShutdown = 0; ! 977: ! 978: if (prettyShutdown) ! 979: fbMode = SCM_GRAPHIC; ! 980: else ! 981: fbMode = SCM_TEXT; ! 982: ! 983: (*fbp[FB_DEV_NORMAL]->Init)( ! 984: fbp[FB_DEV_NORMAL], fbMode, TRUE, TRUE, mach_title); ! 985: ! 986: if (prettyShutdown) { ! 987: [self drawGraphicPanel: KM_PANEL_NS]; ! 988: ! 989: switch(prettyShutdown) { ! 990: case 1: ! 991: [self graphicPanelString: "Restarting the computer...\n"]; ! 992: break; ! 993: case 2: ! 994: [self graphicPanelString: "Shutting down the computer...\n"]; ! 995: break; ! 996: default: ! 997: [self graphicPanelString: "Please wait..."]; ! 998: } ! 999: ! 1000: kmDeviceAnimationState = -1; ! 1001: [self animationCtl: KM_ANIM_RESUME]; ! 1002: } ! 1003: ! 1004: return IO_R_SUCCESS; ! 1005: } ! 1006: ! 1007: #endif // KERNOBJC ! 1008: ! 1009: /* ! 1010: * Kernel internal alert panel support. ! 1011: */ ! 1012: ! 1013: void DoSafeAlert(const char *windowTitle, const char *msg, boolean_t saveUnder ) ! 1014: { ! 1015: #if KERNOBJC ! 1016: if (kmId == nil) ! 1017: #endif ! 1018: { ! 1019: // We haven't created a kmDevice yet! We can't put up a panel or ! 1020: // call ObjC stuff. Create an alert console. ! 1021: #if KERNOBJC ! 1022: if (kmAlertConsole) ! 1023: return; ! 1024: #endif ! 1025: // ...unless we already have basicConsole in a text mode. ! 1026: if (basicConsoleMode == SCM_ALERT || ! 1027: basicConsoleMode == SCM_TEXT) { ! 1028: if (basicConsole) ! 1029: while (*msg) ! 1030: (basicConsole->PutC)(basicConsole, *msg++); ! 1031: return; ! 1032: } ! 1033: kmAlertConsole = basicConsole; ! 1034: if (kmAlertConsole) { ! 1035: (*kmAlertConsole->Init)( ! 1036: kmAlertConsole, SCM_ALERT, FALSE, TRUE, windowTitle); ! 1037: while(*msg) ! 1038: (kmAlertConsole->PutC)(kmAlertConsole, *msg++); ! 1039: } ! 1040: return; ! 1041: } ! 1042: ! 1043: #if KERNOBJC ! 1044: /* ! 1045: * Create alert panel if necessary ! 1046: */ ! 1047: (*lockProc)(kmId->kmOpenLock, @selector(lock)); ! 1048: switch(kmId->fbMode) { ! 1049: case SCM_TEXT: ! 1050: /* ! 1051: * Easy case, we already have a place to do putc()'s. ! 1052: * Note for SCM_TEXT case, alert text just goes to ! 1053: * the normal console. ! 1054: */ ! 1055: break; ! 1056: ! 1057: /* ! 1058: * FIXME - maybe do a case for SCM_UNINIT, do allow printfs ! 1059: * via alert() very early in boot. ! 1060: */ ! 1061: default: ! 1062: /* ! 1063: * Jump into "alert mode". ! 1064: */ ! 1065: ! 1066: kmId->savedFbMode = kmId->fbMode; ! 1067: kmId->fbMode = SCM_ALERT; ! 1068: ! 1069: /* ! 1070: * Create an alert window. ! 1071: */ ! 1072: (*kmId->fbp[FB_DEV_ALERT]->Init)( ! 1073: kmId->fbp[FB_DEV_ALERT], SCM_ALERT, saveUnder, TRUE, windowTitle); ! 1074: ! 1075: /* fall through */ ! 1076: ! 1077: case SCM_ALERT: ! 1078: kmId->alertRefCount++; ! 1079: break; ! 1080: } ! 1081: (*unlockProc)(kmId->kmOpenLock, @selector(unlock)); ! 1082: ! 1083: /* ! 1084: * Print alert message. ! 1085: */ ! 1086: { ! 1087: IOConsoleInfo *cons; ! 1088: ! 1089: if (kmId->fbMode == SCM_ALERT) ! 1090: cons = kmId->fbp[FB_DEV_ALERT]; ! 1091: else ! 1092: cons = kmId->fbp[FB_DEV_NORMAL]; ! 1093: while(*msg) ! 1094: (*cons->PutC)(cons, *msg++); ! 1095: } ! 1096: #endif // KERNOBJC ! 1097: ! 1098: return; ! 1099: } ! 1100: ! 1101: extern int scc_getc(int unit, int line, boolean_t wait, boolean_t raw); ! 1102: extern PCKeyboardEvent * PPCStealKeyEvent(); ! 1103: ! 1104: // This gets called from interrupt level by kdp ! 1105: ! 1106: int kmtrygetc() ! 1107: { ! 1108: int c = -1; ! 1109: PCKeyboardEvent * event; ! 1110: ! 1111: event = PPCStealKeyEvent(); ! 1112: if(event) ! 1113: c = ProcessKbdEvent(event); ! 1114: ! 1115: if( (c != -1) && ( c != inv)) { ! 1116: return(c); ! 1117: } else { ! 1118: /* modem port is 1, printer port is 0 */ ! 1119: #define LINE 1 ! 1120: return( scc_getc(0 /* ignored */, LINE, 0, 0)); ! 1121: } ! 1122: } ! 1123: ! 1124: void DoAlert(const char *windowTitle, const char *msg) ! 1125: { ! 1126: DoSafeAlert(windowTitle, msg, TRUE); ! 1127: } ! 1128: ! 1129: #if KERNOBJC ! 1130: ! 1131: - (void)doAlert : (const char *)windowTitle ! 1132: msg : (const char *)msg ! 1133: { ! 1134: DoSafeAlert(windowTitle, msg, TRUE); ! 1135: } ! 1136: ! 1137: ! 1138: - (IOReturn)setIntValues : (unsigned *)parameterArray ! 1139: forParameter : (IOParameterName)parameterName ! 1140: count : (unsigned)count ! 1141: { ! 1142: if(!strcmp(parameterName, "prettyShutdown")) ! 1143: { ! 1144: prettyShutdown = (short)(*parameterArray); ! 1145: return IO_R_SUCCESS; ! 1146: } ! 1147: else ! 1148: { ! 1149: /* Pass parameters we don't recognize to our superclass. */ ! 1150: return [super setIntValues:parameterArray ! 1151: forParameter:parameterName count:count]; ! 1152: } ! 1153: } ! 1154: ! 1155: @end ! 1156: ! 1157: #endif // KERNOBJC ! 1158: ! 1159: /* end of kmDevice.m */ ! 1160: ! 1161:
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.