1/*
2 *
3 * @APPLE_LICENSE_HEADER_START@
4 *
5 * Copyright (c) 1999-2003 Apple Computer, Inc.  All Rights Reserved.
6 *
7 * This file contains Original Code and/or Modifications of Original Code
8 * as defined in and that are subject to the Apple Public Source License
9 * Version 2.0 (the 'License'). You may not use this file except in
10 * compliance with the License. Please obtain a copy of the License at
11 * http://www.opensource.apple.com/apsl/ and read it before using this
12 * 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, QUIET ENJOYMENT OR NON-INFRINGEMENT.
19 * Please see the License for the specific language governing rights and
20 * limitations under the License.
21 *
22 * @APPLE_LICENSE_HEADER_END@
23 */
24
25#include <IOKit/IOLib.h>
26
27#include "IOHIDKeyboardDevice.h"
28
29typedef struct __attribute__((packed)) GenericKeyboardRpt {
30    UInt8 modifiers;
31    UInt8 reserved;
32    UInt8 keys[6];
33} GenericKeyboardRpt;
34
35static UInt8 gGenLEDKeyboardDesc[] = {
36    0x05, 0x01,                               // Usage Page (Generic Desktop)
37    0x09, 0x06,                               // Usage (Keyboard)
38    0xA1, 0x01,                               // Collection (Application)
39    0x05, 0x07,                               //   Usage Page (Keyboard/Keypad)
40    0x19, 0xE0,                               //   Usage Minimum........... (224)
41    0x29, 0xE7,                               //   Usage Maximum........... (231)
42    0x15, 0x00,                               //   Logical Minimum......... (0)
43    0x25, 0x01,                               //   Logical Maximum......... (1)
44    0x75, 0x01,                               //   Report Size............. (1)
45    0x95, 0x08,                               //   Report Count............ (8)
46    0x81, 0x02,                               //   Input...................(Data, Variable, Absolute)
47    0x95, 0x01,                               //   Report Count............ (1)
48    0x75, 0x08,                               //   Report Size............. (8)
49    0x81, 0x01,                               //   Input...................(Constant)
50    0x95, 0x02,                               //   Report Count............ (2)
51    0x75, 0x01,                               //   Report Size............. (1)
52    0x05, 0x08,                               //   Usage Page (LED)
53    0x19, 0x01,                               //   Usage Minimum........... (1)
54    0x29, 0x02,                               //   Usage Maximum........... (2)
55    0x91, 0x02,                               //   Output..................(Data, Variable, Absolute)
56    0x95, 0x01,                               //   Report Count............ (1)
57    0x75, 0x06,                               //   Report Size............. (6)
58    0x91, 0x01,                               //   Output..................(Constant)
59    0x95, 0x06,                               //   Report Count............ (6)
60    0x75, 0x08,                               //   Report Size............. (8)
61    0x15, 0x00,                               //   Logical Minimum......... (0)
62    0x26, 0xFF, 0x00,                         //   Logical Maximum......... (255)
63    0x05, 0x07,                               //   Usage Page (Keyboard/Keypad)
64    0x19, 0x00,                               //   Usage Minimum........... (0)
65    0x29, 0xFF,                               //   Usage Maximum........... (255)
66    0x81, 0x00,                               //   Input...................(Data, Array, Absolute)
67    0xC0,                                     // End Collection
68};
69
70static UInt8 gGenKeyboardDesc[] = {
71    0x05, 0x01,                               // Usage Page (Generic Desktop)
72    0x09, 0x06,                               // Usage (Keyboard)
73    0xA1, 0x01,                               // Collection (Application)
74    0x05, 0x07,                               //   Usage Page (Keyboard/Keypad)
75    0x19, 0xE0,                               //   Usage Minimum........... (224)
76    0x29, 0xE7,                               //   Usage Maximum........... (231)
77    0x15, 0x00,                               //   Logical Minimum......... (0)
78    0x25, 0x01,                               //   Logical Maximum......... (1)
79    0x75, 0x01,                               //   Report Size............. (1)
80    0x95, 0x08,                               //   Report Count............ (8)
81    0x81, 0x02,                               //   Input...................(Data, Variable, Absolute)
82    0x95, 0x01,                               //   Report Count............ (1)
83    0x75, 0x08,                               //   Report Size............. (8)
84    0x81, 0x01,                               //   Input...................(Constant)
85    0x95, 0x06,                               //   Report Count............ (6)
86    0x75, 0x08,                               //   Report Size............. (8)
87    0x15, 0x00,                               //   Logical Minimum......... (0)
88    0x26, 0xFF, 0x00,                         //   Logical Maximum......... (255)
89    0x05, 0x07,                               //   Usage Page (Keyboard/Keypad)
90    0x19, 0x00,                               //   Usage Minimum........... (0)
91    0x29, 0xFF,                               //   Usage Maximum........... (255)
92    0x81, 0x00,                               //   Input...................(Data, Array, Absolute)
93    0xC0,                                     // End Collection
94};
95
96extern unsigned int hid_adb_2_usb_keymap[];  //In Cosmo_USB2ADB.cpp
97
98#define super IOHIDDeviceShim
99
100OSDefineMetaClassAndStructors( IOHIDKeyboardDevice, IOHIDDeviceShim )
101
102
103IOHIDKeyboardDevice *
104IOHIDKeyboardDevice::newKeyboardDeviceAndStart(IOService * owner, UInt32 location)
105{
106    IOService * provider = owner;
107
108    while ( NULL != (provider = provider->getProvider()) )
109    {
110	if(OSDynamicCast(IOHIDDevice, provider) || OSDynamicCast(IOHIDevice, provider))
111            return  0;
112    }
113
114
115    IOHIDKeyboardDevice * device = new IOHIDKeyboardDevice;
116
117    if (device)
118    {
119        if ( device->initWithLocation(location) && device->attach(owner) )
120        {
121            if (!device->start(owner))
122            {
123                device->detach(owner);
124                device->release();
125                device = 0;
126            }
127        }
128        else
129        {
130            device->release();
131            device = 0;
132        }
133    }
134
135    return device;
136}
137
138
139bool IOHIDKeyboardDevice::initWithLocation( UInt32 location )
140{
141    if (!super::initWithLocation(location))
142        return false;
143
144    _report 		= 0;
145    _cachedLEDState 	= 0;
146    _inputReportOnly 	= true;
147
148    return true;
149}
150
151void IOHIDKeyboardDevice::free()
152{
153    if (_report) _report->release();
154
155    super::free();
156}
157
158bool IOHIDKeyboardDevice::handleStart( IOService * provider )
159{
160    if (!super::handleStart(provider))
161        return false;
162
163    if ( (_keyboard = OSDynamicCast(IOHIKeyboard, provider)) )
164    {
165        _inputReportOnly = ((transport() == kIOHIDTransportADB) && (_keyboard->deviceType() >= 0xc3));
166        _cachedLEDState = _keyboard->getLEDStatus() & 0x3;
167    }
168
169    _report = IOBufferMemoryDescriptor::withCapacity(
170        sizeof(GenericKeyboardRpt), kIODirectionNone, true);
171
172    bzero(_report->getBytesNoCopy(), sizeof(GenericKeyboardRpt));
173
174    return (_report) ? true : false;
175}
176
177IOReturn IOHIDKeyboardDevice::newReportDescriptor(
178                        IOMemoryDescriptor ** descriptor ) const
179{
180    void  * desc;
181    UInt8 * descBytes;
182    UInt8 descSize;
183
184    if (!descriptor)
185        return kIOReturnBadArgument;
186
187    if (_inputReportOnly)
188    {
189        descSize = sizeof(gGenKeyboardDesc);
190        descBytes = gGenKeyboardDesc;
191    }
192    else
193    {
194        descSize = sizeof(gGenLEDKeyboardDesc);
195        descBytes = gGenLEDKeyboardDesc;
196    }
197
198    *descriptor = IOBufferMemoryDescriptor::withCapacity(
199        descSize,
200        kIODirectionNone,
201        true);
202
203    if (! *descriptor)
204        return kIOReturnNoMemory;
205
206    desc = ((IOBufferMemoryDescriptor *)(*descriptor))->getBytesNoCopy();
207    bcopy(descBytes, desc, descSize);
208
209    return kIOReturnSuccess;
210}
211
212IOReturn IOHIDKeyboardDevice::getReport(IOMemoryDescriptor  *report,
213                                        IOHIDReportType     reportType,
214                                        IOOptionBits        options __unused )
215{
216    if (!report)
217        return kIOReturnError;
218
219    if ( reportType != kIOHIDReportTypeInput)
220        return kIOReturnUnsupported;
221
222    report->writeBytes(0, _report->getBytesNoCopy(), min(report->getLength(), _report->getLength()));
223    return kIOReturnSuccess;
224}
225
226IOReturn IOHIDKeyboardDevice::setReport(IOMemoryDescriptor * report,
227                                        IOHIDReportType      reportType __unused,
228                                        IOOptionBits         options )
229{
230    UInt8 	ledState;
231    UInt8	mask;
232
233    if ((options & 0xff) || (_inputReportOnly) || !_keyboard)
234        return kIOReturnError;
235
236    report->readBytes( 0, (void *)&ledState, sizeof(UInt8) );
237
238    mask = (1 << (kHIDUsage_LED_NumLock - 1));
239    if ( (ledState & mask) && !(_cachedLEDState & mask) )
240    {
241        _keyboard->setNumLockFeedback(true);
242    }
243    else if ( !(ledState & mask) && (_cachedLEDState & mask) )
244    {
245        _keyboard->setNumLockFeedback(false);
246    }
247
248    mask = (1 << (kHIDUsage_LED_CapsLock - 1));
249    if ( (ledState & mask) && !(_cachedLEDState & mask) )
250    {
251        _keyboard->setAlphaLockFeedback(true);
252    }
253    else if ( !(ledState & mask) && (_cachedLEDState & mask) )
254    {
255        _keyboard->setAlphaLockFeedback(false);
256    }
257
258    _cachedLEDState = ledState;
259
260    return kIOReturnSuccess;
261}
262
263void IOHIDKeyboardDevice::setCapsLockLEDElement(bool state)
264{
265    UInt8	mask = (1 << (kHIDUsage_LED_CapsLock-1));
266
267    if (_inputReportOnly)
268        return;
269
270    if (state)
271        _cachedLEDState |=  mask;
272
273    else
274        _cachedLEDState &= ~mask;
275
276    *(UInt8 *)(_report->getBytesNoCopy()) = _cachedLEDState;
277
278    handleReport(_report, kIOHIDReportTypeOutput);
279}
280
281void IOHIDKeyboardDevice::setNumLockLEDElement(bool state)
282{
283    UInt8	mask = (1 << (kHIDUsage_LED_NumLock-1));
284
285    if (_inputReportOnly)
286        return;
287
288    if (state)
289        _cachedLEDState |= mask;
290
291    else
292        _cachedLEDState &= ~mask;
293
294    *(UInt8 *)(_report->getBytesNoCopy()) = _cachedLEDState;
295
296    handleReport(_report, kIOHIDReportTypeOutput);
297}
298
299#define SET_MODIFIER_BIT(bitField, key, down)	\
300    if (down) {bitField |= (1 << (key - 0xe0));}	\
301    else {bitField &= ~(1 << (key - 0xe0));}
302
303void IOHIDKeyboardDevice::postKeyboardEvent(UInt8 key, bool keyDown)
304{
305    GenericKeyboardRpt *report = (GenericKeyboardRpt *)_report->getBytesNoCopy();
306    UInt8		usbKey;
307
308    if (!report)
309        return;
310
311    // Convert ADB scan code to USB
312    if (! (usbKey = hid_adb_2_usb_keymap[key]))
313        return;
314
315    // Check if modifier
316    if ((usbKey >= 0xe0) && (usbKey <= 0xe7))
317    {
318	SET_MODIFIER_BIT(report->modifiers, usbKey, keyDown);
319    }
320    else
321    {
322        for (int i=0; i<6; i++)
323        {
324            if (report->keys[i] == usbKey)
325            {
326                if (keyDown) return;
327
328                for (int j=i; j<5; j++)
329                    report->keys[j] = report->keys[j+1];
330
331                report->keys[5] = 0;
332                break;
333            }
334
335            else if ((report->keys[i] == 0) && keyDown)
336            {
337                report->keys[i] = usbKey;
338                break;
339            }
340        }
341    }
342
343    handleReport(_report);
344}
345
346enum {
347    kUSB_LEFT_CONTROL_BIT = 0x01,
348    kUSB_LEFT_SHIFT_BIT = 0x02,
349    kUSB_LEFT_ALT_BIT = 0x04,
350    kUSB_LEFT_FLOWER_BIT = 0x08,
351
352    kUSB_RIGHT_CONTROL_BIT = 0x10,
353    kUSB_RIGHT_SHIFT_BIT = 0x20,
354    kUSB_RIGHT_ALT_BIT = 0x040,
355    kUSB_RIGHT_FLOWER_BIT = 0x80
356};
357
358void IOHIDKeyboardDevice::postFlagKeyboardEvent(UInt32 flags)
359{
360    GenericKeyboardRpt *report      = (GenericKeyboardRpt *)_report->getBytesNoCopy();
361    UInt32              flagDelta   = (flags ^ _lastFlags);
362
363    if (!flagDelta)
364        return;
365
366    report->modifiers = 0;
367    _lastFlags = flags;
368
369    if ( flagDelta & 0x0000ffff )
370    {
371        if( flags & NX_DEVICELSHIFTKEYMASK )
372            report->modifiers |= kUSB_LEFT_SHIFT_BIT;
373        if( flags & NX_DEVICELCTLKEYMASK )
374            report->modifiers |= kUSB_LEFT_CONTROL_BIT;
375        if( flags & NX_DEVICELALTKEYMASK )
376            report->modifiers |= kUSB_LEFT_ALT_BIT;
377        if( flags & NX_DEVICELCMDKEYMASK )
378            report->modifiers |= kUSB_LEFT_FLOWER_BIT;
379
380        if( flags & NX_DEVICERSHIFTKEYMASK )
381            report->modifiers |= kUSB_RIGHT_SHIFT_BIT;
382        if( flags & NX_DEVICERCTLKEYMASK )
383            report->modifiers |= kUSB_RIGHT_CONTROL_BIT;
384        if( flags & NX_DEVICERALTKEYMASK )
385            report->modifiers |= kUSB_RIGHT_ALT_BIT;
386        if( flags & NX_DEVICERCMDKEYMASK )
387            report->modifiers |= kUSB_RIGHT_FLOWER_BIT;
388    }
389    else if ( flagDelta & 0xffff0000 )
390    {
391        if( flags & NX_SHIFTMASK )
392            report->modifiers |= kUSB_LEFT_SHIFT_BIT;
393        if( flags & NX_CONTROLMASK )
394            report->modifiers |= kUSB_LEFT_CONTROL_BIT;
395        if( flags & NX_ALTERNATEMASK )
396            report->modifiers |= kUSB_LEFT_ALT_BIT;
397        if( flags & NX_COMMANDMASK )
398            report->modifiers |= kUSB_LEFT_FLOWER_BIT;
399    }
400
401    if ( flagDelta & NX_ALPHASHIFTMASK )
402    {
403        postKeyboardEvent(0x39, flags & NX_ALPHASHIFTMASK);
404        return;
405    }
406
407    handleReport(_report);
408}
409
410OSString * IOHIDKeyboardDevice::newProductString() const
411{
412    OSString * string = 0;
413
414    if ( !(string = super::newProductString()) )
415        string = OSString::withCString("Virtual Keyboard");
416
417    return string;
418}
419