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