|
|
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: /* ! 26: File: KBDHIDEmulation.c ! 27: ! 28: Contains: Keyboard Emulation code ! 29: ! 30: Version: xxx put version here xxx ! 31: ! 32: Copyright: � 1998 by Apple Computer, Inc., all rights reserved. ! 33: ! 34: File Ownership: ! 35: ! 36: DRI: Craig Keithley ! 37: ! 38: Other Contact: xxx put other contact here xxx ! 39: ! 40: Technology: USB ! 41: ! 42: Writers: ! 43: ! 44: (BWS) Brent Schorsch ! 45: (BG) Bill Galcher ! 46: (CJK) Craig Keithley ! 47: ! 48: Change History (most recent first): ! 49: ! 50: <USB32> 6/20/98 CJK Expand on Brent's comments... It wasn't a "fix" of the refcon, ! 51: it was the addition of a new getinfo selector so that an ! 52: InputSprocket can ask the Keyboard HID Module to pass back it's ! 53: refcon to the caller. There was nothing "broken" in the original ! 54: code. ! 55: <USB31> 6/18/98 BWS fix interrupt refcon support ! 56: <USB30> 6/18/98 CJK update to use modified HID dispatch table (passing in refcon) ! 57: <USB29> 6/5/98 CJK remove pragma unused from GetKeysPressed ! 58: <USB28> 5/28/98 CJK add HID GetInfo Selector to get notification proc address ! 59: <USB27> 5/20/98 CJK change driver name from USBKeyboardModule to ! 60: USBHIDKeyboardModule ! 61: <USB26> 5/20/98 CJK add check for 'DDKBuild' define. If it's not defined then it's ! 62: okay to include USBPriv.h and use the USL's DoneQueue API. ! 63: <USB25> 5/19/98 CJK remove include of USBPriv.h. This file should not be included, ! 64: as the DDK will not supply it. If there are prototypes needed by ! 65: this file, they should be moved to USB.h (usb.i). ! 66: <USB24> 5/19/98 BG Add includes of <USBPriv.h> and "UIMPriv.h" to bring in needed ! 67: prototypes. ! 68: <USB23> 5/18/98 CJK remove the breaks... ! 69: <USB22> 5/18/98 CJK Add support for 'GetCurrentKeyboardState' getinfo selector ! 70: <USB21> 4/30/98 CJK fix break statements. ! 71: <USB20> 4/30/98 CJK handle keyreleasedflag slightly differently ! 72: <USB19> 4/30/98 CJK add a "send raw report" mode. rework so that the old hid report ! 73: and initialized flags are kept in the keyboard data structure ! 74: (rather than in static vars.) ! 75: <USB18> 4/27/98 CJK correct zero'ing of non-relevant hid report bytes. ! 76: <USB17> 4/27/98 CJK Add handling of key rollover errors. No longer sends already ! 77: down keys when the rollover error is removed. ! 78: <USB16> 4/26/98 CJK update to match reworked keyboard interface driver. ! 79: Restructured user notification routine. ! 80: <USB15> 4/14/98 CJK change call to USBIdleTask to UIMProcessDoneQueue ! 81: <USB14> 4/9/98 CJK remove include of USBDeviceDefines.h ! 82: <13> 4/8/98 CJK add enable/disable of emulation code ! 83: <12> 3/26/98 CJK remove debugstr ! 84: <11> 3/17/98 CJK change }; to just }. MetroWerks has a problem with };. Also ! 85: added parens around pragma unused's variable name. ! 86: <10> 3/12/98 CJK Don't worry about initializing the shim keyboard paramblock. ! 87: That's done in the keyboard initialize routine. ! 88: <9> 3/2/98 CJK remove include of KBDHIDEmulation.h ! 89: <8> 3/2/98 CJK change to use USBHIDModule hid data structure (rather than the ! 90: keyboard data structure). ! 91: <7> 2/27/98 CJK add check for keycount growing too large. Add include of ! 92: USBHIDModules.h. Change LED control selector to be "by bit" (as ! 93: opposed to by ID, which is probably how things will ultimately ! 94: work). ! 95: <6> 2/26/98 CJK Add USBHIDControlDevice functionality. All it does (right now) ! 96: is set the LEDs. ! 97: <5> 2/17/98 CJK Integrate Ferg's changes. ! 98: <4*> 2/16/98 DKF Add keyposting if there is no shim registered ! 99: <4> 2/16/98 CJK remove write of $00 keycodes into the keycode array. Streamline ! 100: old vs. new keycode detection (hopefully faster than before). ! 101: <3> 2/16/98 CJK Improve check of modifier key changes (shouldn't need to scan ! 102: through each bit to determine if any modifiers changed. Just check ! 103: the changed bits. If any changed, then look through each bit individually. ! 104: <2> 2/10/98 CJK Correct change history (to reflect the keyboard module changes) ! 105: <1> 2/10/98 CJK First time checkin. Cloned from Mouse HID Module. ! 106: */ ! 107: ! 108: //#include <Types.h> ! 109: //#include <Devices.h> ! 110: #include "../driverservices.h" ! 111: #include "../USB.h" ! 112: #ifndef DDKBuild ! 113: #include "../USBpriv.h" ! 114: #endif ! 115: ! 116: #include "KeyboardModule.h" ! 117: //prototype from PPCKeyboard.m ! 118: void keyboard_adbhandler(int number, unsigned char *buffer, int count, void * ssp); ! 119: ! 120: ! 121: extern usbKeyboardPBStruct myKeyboardPB; ! 122: extern usbKeyboardPBStruct shimKeyboardPB; ! 123: extern UInt8 usb_2_adb_keymap[]; ! 124: ! 125: void GetKeysPressed(USBHIDData * pKeysPressed); ! 126: ! 127: OSStatus kbd_USBHIDInstallInterrupt(HIDInterruptProcPtr HIDInterruptFunction, UInt32 refcon) ! 128: { ! 129: myKeyboardPB.interruptRefcon = refcon; ! 130: myKeyboardPB.pSHIMInterruptRoutine = HIDInterruptFunction; ! 131: return 0; ! 132: } ! 133: ! 134: OSStatus kbd_USBHIDControlDevice(UInt32 theControlSelector, void * theControlData) ! 135: { ! 136: switch (theControlSelector) ! 137: { ! 138: case kHIDSetLEDStateByBits: ! 139: shimKeyboardPB.hidReport[0] = *(UInt8*)theControlData; ! 140: ! 141: shimKeyboardPB.retryCount = kKeyboardRetryCount; ! 142: shimKeyboardPB.delayLevel = 0; ! 143: shimKeyboardPB.transDepth = 0; ! 144: ! 145: shimKeyboardPB.pb.usbRefcon = kSetKeyboardLEDs; /* Start with setting the interface protocol */ ! 146: KeyboardModuleInitiateTransaction(&shimKeyboardPB.pb); ! 147: break; ! 148: ! 149: case kHIDRemoveInterruptHandler: ! 150: myKeyboardPB.interruptRefcon = nil; ! 151: myKeyboardPB.pSavedInterruptRoutine = nil; ! 152: myKeyboardPB.pSHIMInterruptRoutine = nil; ! 153: break; ! 154: ! 155: case kHIDEnableDemoMode: ! 156: USBExpertStatus(myKeyboardPB.deviceRef, "USBHIDKeyboardModule: Demo Mode Enabled", myKeyboardPB.deviceRef); ! 157: myKeyboardPB.pSavedInterruptRoutine = myKeyboardPB.pSHIMInterruptRoutine; ! 158: myKeyboardPB.pSHIMInterruptRoutine = USBDemoKeyIn; ! 159: break; ! 160: ! 161: case kHIDDisableDemoMode: ! 162: USBExpertStatus(myKeyboardPB.deviceRef, "USBHIDKeyboardModule: Demo Mode Disabled", myKeyboardPB.deviceRef); ! 163: myKeyboardPB.pSHIMInterruptRoutine = myKeyboardPB.pSavedInterruptRoutine; ! 164: break; ! 165: ! 166: default: ! 167: return paramErr; ! 168: } ! 169: return 0; ! 170: } ! 171: ! 172: void GetKeysPressed(USBHIDDataPtr pKeysPressed) ! 173: { ! 174: UInt8 i,keycount; ! 175: ! 176: keycount = 0; ! 177: for (i = 0; i < kKeyboardModifierBits; i++) ! 178: { ! 179: if (myKeyboardPB.oldHIDReport[0] & (1 << i)) ! 180: { ! 181: pKeysPressed->kbd.usbkeycode[keycount++] = (0xe0 + i); ! 182: } ! 183: } ! 184: ! 185: if ((myKeyboardPB.oldHIDReport[kKeyboardOffsetToKeys] == 0) || (myKeyboardPB.oldHIDReport[kKeyboardOffsetToKeys] > 0x03)) ! 186: { ! 187: for (i = kKeyboardOffsetToKeys; i < (kKeyboardOffsetToKeys + kKeyboardReportKeys); i++) ! 188: { ! 189: if (myKeyboardPB.oldHIDReport[i] > 0x03) ! 190: { ! 191: pKeysPressed->kbd.usbkeycode[keycount++] = myKeyboardPB.oldHIDReport[i]; ! 192: } ! 193: } ! 194: } ! 195: pKeysPressed->kbd.keycount = keycount; ! 196: } ! 197: ! 198: ! 199: OSStatus kbd_USBHIDGetDeviceInfo(UInt32 theInfoSelector, void * theInfo) ! 200: { ! 201: HIDInterruptProcPtr * pHIDIntProcPtr; ! 202: UInt32 * pInterruptRefcon; ! 203: ! 204: switch (theInfoSelector) ! 205: { ! 206: case kHIDGetCurrentKeys: ! 207: GetKeysPressed((USBHIDDataPtr)theInfo); ! 208: break; ! 209: ! 210: case kHIDGetInterruptHandler: ! 211: pHIDIntProcPtr = (HIDInterruptProcPtr *)theInfo; ! 212: *pHIDIntProcPtr = myKeyboardPB.pSHIMInterruptRoutine; ! 213: break; ! 214: ! 215: case kHIDGetInterruptRefcon: ! 216: pInterruptRefcon = (UInt32 *)theInfo; ! 217: *pInterruptRefcon = myKeyboardPB.interruptRefcon; ! 218: break; ! 219: ! 220: default: ! 221: return paramErr; ! 222: } ! 223: return 0; ! 224: } ! 225: ! 226: OSStatus kbd_USBHIDPollDevice(void) ! 227: { ! 228: #ifndef DDKBuild ! 229: USLPolledProcessDoneQueue(); ! 230: #endif ! 231: return kUSBNoErr; ! 232: } ! 233: ! 234: OSStatus kbd_USBHIDEnterPolledMode(void) ! 235: { ! 236: return unimpErr; ! 237: } ! 238: ! 239: OSStatus kbd_USBHIDExitPolledMode(void) ! 240: { ! 241: return unimpErr; ! 242: } ! 243: ! 244: void kbd_NotifyRegisteredHIDUser(UInt32 devicetype, UInt8 hidReport[]) ! 245: { ! 246: #pragma unused (devicetype) ! 247: ! 248: UInt8 i, j, newkey, oldkey, deltas; ! 249: ! 250: UInt8 changedmodifiers, keycount; ! 251: USBHIDData theKeyboardData; ! 252: Boolean keypressedflag, keyreleasedflag; ! 253: char adb_data[8]; ! 254: ! 255: deltas = 0; ! 256: if (myKeyboardPB.hidEmulationInit == false) ! 257: { ! 258: myKeyboardPB.hidEmulationInit = true; ! 259: for (i = 0; i < kKeyboardReportSize; i++) ! 260: myKeyboardPB.oldHIDReport[i] = 0; ! 261: }; ! 262: ! 263: myKeyboardPB.oldHIDReport[1] = 0x0; ! 264: hidReport[1] = 0x0; ! 265: ! 266: for (i = 0; i < kKeyboardReportSize; i++) ! 267: { ! 268: if (hidReport[i] != myKeyboardPB.oldHIDReport[i]) ! 269: { ! 270: deltas++; ! 271: } ! 272: } ! 273: ! 274: if ((myKeyboardPB.sendRawReportFlag) && deltas) ! 275: { ! 276: (*myKeyboardPB.pSHIMInterruptRoutine)(0xff, (void *)&hidReport[0]); ! 277: } ! 278: else ! 279: { ! 280: if (deltas) ! 281: { ! 282: keycount = 0; ! 283: changedmodifiers = hidReport[0] ^ myKeyboardPB.oldHIDReport[0]; ! 284: ! 285: if (changedmodifiers) ! 286: { ! 287: for (i = 0; i < kKeyboardModifierBits; i++) ! 288: { ! 289: if (changedmodifiers & (1 << i)) ! 290: { ! 291: if (hidReport[0] & (1 << i)) ! 292: { ! 293: theKeyboardData.kbd.usbkeycode[keycount++] = (0xe0 + i); ! 294: } ! 295: else ! 296: { ! 297: theKeyboardData.kbd.usbkeycode[keycount++] = (0x80e0 + i); ! 298: } ! 299: } ! 300: } ! 301: myKeyboardPB.oldHIDReport[0] = hidReport[0]; ! 302: } ! 303: ! 304: if ((hidReport[kKeyboardOffsetToKeys] == 0) || (hidReport[kKeyboardOffsetToKeys] > 0x03)) ! 305: { ! 306: // While this double loop may look strange, I refer you to appendix C, of the HID Devices specification. ! 307: // pp. 73 & 74 clearly state that report order is abitrary and does not reflect the order of events. ! 308: // to quote: "The order of keycodes in array fields has no significance. Order determination is done ! 309: // by the host software comparing the contents of the previous report to the current report. If two or ! 310: // more keys are pressed in one report, their order is indeterminate. Keyboards may buffer events that ! 311: // would have otherwise resulted in multiple events in a single report". ! 312: ! 313: // Because this specification (or lack thereof) states that the order is indeterminant, we have to ! 314: // check all the old keys against all the new keys... ! 315: ! 316: for (i = kKeyboardOffsetToKeys; i < (kKeyboardOffsetToKeys + kKeyboardReportKeys); i++) ! 317: { ! 318: keypressedflag = true; ! 319: newkey = hidReport[i]; ! 320: ! 321: keyreleasedflag = true; ! 322: oldkey = myKeyboardPB.oldHIDReport[i]; ! 323: for (j = kKeyboardOffsetToKeys; j < (kKeyboardOffsetToKeys + kKeyboardReportKeys); j++) // then look through all the keys that were previously and are currently reported as pressed ! 324: { ! 325: if (newkey == myKeyboardPB.oldHIDReport[j]) // was this new key already pressed? ! 326: { ! 327: keypressedflag = false; // if it was, then don't report it as being pressed. ! 328: } ! 329: ! 330: if (oldkey == hidReport[j]) // Is the old key still pressed? ! 331: { ! 332: keyreleasedflag = false; // If yes, then don't report it as being released ! 333: } ! 334: } ! 335: if ((newkey > 0x03) && keypressedflag) ! 336: { ! 337: theKeyboardData.kbd.usbkeycode[keycount++] = newkey; ! 338: } ! 339: ! 340: if ((oldkey > 0x03) && keyreleasedflag) ! 341: { ! 342: theKeyboardData.kbd.usbkeycode[keycount++] = (oldkey + 0x8000); ! 343: } ! 344: ! 345: if (keycount > 20) // a worse case scenario is: ! 346: { // 4 modifier keys up ! 347: break; // the other 4 modifier keys down ! 348: } // 6 previously reported keys up ! 349: } // 6 newly reported keys down ! 350: // 6 + 6 + 4 + 4 = 20 ! 351: for (i = 0; i<kKeyboardReportSize; i++) ! 352: { ! 353: myKeyboardPB.oldHIDReport[i] = hidReport[i]; ! 354: }; ! 355: } ! 356: ! 357: //Now we map to ADB from USB ! 358: //Adam Wang 12/2/98 ! 359: adb_data[1] = 0xff; ! 360: for(i=0;i<keycount;++i) ! 361: { ! 362: static char caps_lock_state = 1; ! 363: unsigned char newLEDState; ! 364: //Special handling of USB caps-lock-that-doesn't-lock 12/8/98 ! 365: if ( theKeyboardData.kbd.usbkeycode[i] == 0x0039) //00 = going down, 39 = caps lock ! 366: { ! 367: newLEDState = 2; ! 368: //This call to set LED will hang on Yosemite ! 369: kbd_USBHIDControlDevice(1, &newLEDState); ! 370: } ! 371: if ( theKeyboardData.kbd.usbkeycode[i] == 0x8039) //80 = going up, 39 = caps lock ! 372: { ! 373: caps_lock_state ^= 1; //toggle bit ! 374: if (caps_lock_state == 0) ! 375: continue; //naga changed break to continue ! 376: //The logic is, ignore first caps-up on iMac keyboards ! 377: newLEDState = 0; ! 378: kbd_USBHIDControlDevice(1, &newLEDState); ! 379: } ! 380: ! 381: adb_data[0] = usb_2_adb_keymap[(theKeyboardData.kbd.usbkeycode[i] & 0x00ff)]; ! 382: ! 383: if ((theKeyboardData.kbd.usbkeycode[i] & 0x8000) == 0x8000) // key is on its way up ! 384: adb_data[0] |= 0x80; //Set ADB most significant bit ! 385: ! 386: //Special handling needed for ADB POWER key ! 387: if (adb_data[0] == 0x7f) ! 388: { ! 389: adb_data[1] = 0x7f; //ADB power scan code is 7f 7f ! 390: } ! 391: ! 392: keyboard_adbhandler(2, adb_data, 2, (void *) 0); ! 393: } ! 394: ! 395: ! 396: /* ! 397: if ((myKeyboardPB.pSHIMInterruptRoutine) && keycount) ! 398: { ! 399: theKeyboardData.kbd.keycount = keycount; ! 400: (*myKeyboardPB.pSHIMInterruptRoutine)(myKeyboardPB.interruptRefcon, (void *)&theKeyboardData); ! 401: } ! 402: */ ! 403: } ! 404: } ! 405: } ! 406: ! 407: ! 408: USBHIDModuleDispatchTable kbd_TheHIDModuleDispatchTable = ! 409: { ! 410: (UInt32)0, ! 411: (USBHIDInstallInterruptProcPtr)kbd_USBHIDInstallInterrupt, ! 412: (USBHIDPollDeviceProcPtr)kbd_USBHIDPollDevice, ! 413: (USBHIDControlDeviceProcPtr)kbd_USBHIDControlDevice, ! 414: (USBHIDGetDeviceInfoProcPtr)kbd_USBHIDGetDeviceInfo, ! 415: (USBHIDEnterPolledModeProcPtr)kbd_USBHIDEnterPolledMode, ! 416: (USBHIDExitPolledModeProcPtr)kbd_USBHIDExitPolledMode, ! 417: };
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.