1/*
2 * Copyright (c) 1991 NeXT Computer, Inc.
3 * Copyright (c) 1996-2000 Apple Computer, Inc. All rights reserved.
4 *
5 * @APPLE_LICENSE_HEADER_START@
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	event_status_driver_api.c
26	API for the events status driver.
27	This file implements public API.
28	mpaque 11Oct91
29
30	Modified:
31	29 June 1992 Mike Paquette at NeXT
32		Implemented API for the new Mach based Event Driver.
33
34******************************************************************************/
35
36#include <mach/mach.h>
37
38#include <CoreFoundation/CoreFoundation.h>
39
40#include <IOKit/hidsystem/event_status_driver.h>
41#include <IOKit/IOKitLib.h>
42#include <IOKit/hidsystem/IOHIDLib.h>
43#include <IOKit/hidsystem/IOHIDParameter.h>
44
45#include <math.h>
46#include <limits.h>
47
48/* Definitions specific to the Mach based event driver */
49#define BRIGHT_MAX 64
50
51static void secs_to_packed_nsecs(double secs, UInt64 *nsecs)
52{
53    *nsecs = (1000.0 * 1000.0 * 1000.0 * secs);
54}
55
56static double packed_nsecs_to_secs(UInt64 nsecs)
57{
58    return( ((double)nsecs) / 1000.0 / 1000.0 / 1000.0);
59}
60
61/* Open and Close */
62NXEventHandle NXOpenEventStatus(void)
63{
64    NXEventHandle 		handle = MACH_PORT_NULL;
65    register kern_return_t	kr;
66    io_service_t		service = MACH_PORT_NULL;
67    mach_port_t			masterPort;
68
69    do {
70
71	kr = IOMasterPort( MACH_PORT_NULL, &masterPort );
72	if( kr != KERN_SUCCESS)
73	    break;
74
75        service = IORegistryEntryFromPath( masterPort,
76                    kIOServicePlane ":/IOResources/IOHIDSystem" );
77	if( !service)
78	    break;
79
80        kr = IOServiceOpen( service,
81			mach_task_self(),
82			kIOHIDParamConnectType,
83			&handle);
84
85        IOObjectRelease( service );
86
87    } while( false );
88
89    return( handle );
90}
91
92void NXCloseEventStatus(NXEventHandle handle)
93{
94    IOServiceClose( handle );
95}
96
97/* Status query */
98NXEventSystemInfoType NXEventSystemInfo(NXEventHandle handle,
99					char *flavor,
100					NXEventSystemInfoType evs_info,
101					unsigned int *evs_info_cnt)
102{
103    kern_return_t kr;
104    NXEventSystemDevice * info = (NXEventSystemDevice *) evs_info;
105    int	maxDeviceCount = (*evs_info_cnt) * sizeof( int) / sizeof( NXEventSystemDevice);
106    int deviceCount = 0;
107    int i;
108
109    io_registry_entry_t hidsystem;
110
111    CFArrayRef	array;
112    CFDictionaryRef dict;
113    CFNumberRef		num;
114    SInt32		val;
115
116    // Translate the one existing old case to new format
117    if ( ((uintptr_t) flavor) == __OLD_NX_EVS_DEVICE_INFO )
118            flavor = NX_EVS_DEVICE_INFO;
119
120    if( strcmp( flavor, NX_EVS_DEVICE_INFO))
121        kr = kIOReturnUnsupported;
122
123   do {
124	kr = IOConnectGetService( handle, &hidsystem );
125	if( KERN_SUCCESS != kr )
126	    break;
127
128    array = IORegistryEntryCreateCFProperty(hidsystem, CFSTR("NXSystemInfo"),
129                                kCFAllocatorDefault, kNilOptions);
130
131    IOObjectRelease( hidsystem );
132
133	if( !array )
134	    break;
135
136    deviceCount = CFArrayGetCount(array);
137
138    if ( deviceCount > maxDeviceCount )
139        deviceCount = maxDeviceCount;
140
141    for ( i=0; i<deviceCount; i++) {
142        dict = CFArrayGetValueAtIndex(array, i);
143
144        if( !dict )
145            continue;
146
147	    if( (num = CFDictionaryGetValue( dict, CFSTR(kIOHIDKindKey )))) {
148
149		CFNumberGetValue( num, kCFNumberSInt32Type, &val );
150                info[ i ].dev_type = val;
151
152                if( (num = CFDictionaryGetValue( dict, CFSTR(kIOHIDInterfaceIDKey ))))
153                    CFNumberGetValue( num, kCFNumberSInt32Type, &val );
154		else
155		    val = 0;
156                info[ i ].interface = val;
157
158                if( (num = CFDictionaryGetValue( dict, CFSTR(kIOHIDSubinterfaceIDKey ))))
159                    CFNumberGetValue( num, kCFNumberSInt32Type, &val );
160		else
161		    val = 0;
162                info[ i ].id = val;
163
164                info[ i ].interface_addr = 0;
165
166	    }
167	}
168    CFRelease(array);
169
170    } while( false );
171
172    if ( kr == KERN_SUCCESS )
173	*evs_info_cnt = (deviceCount * sizeof( NXEventSystemDevice) / sizeof( int));
174    else
175	evs_info = (NXEventSystemInfoType) 0;
176
177    return evs_info;
178}
179
180kern_return_t IOHIDSetParameter( io_connect_t handle, CFStringRef key,
181                const void * bytes, IOByteCount size )
182{
183    kern_return_t		kr = kIOReturnNoMemory;
184    CFNumberType		numberType;
185    CFNumberRef			numberRef;
186
187    if (!bytes || !size)
188        return kIOReturnError;
189
190    switch ( size )
191    {
192        case sizeof(UInt64):
193            numberType = kCFNumberSInt64Type;
194            break;
195        case sizeof(UInt32):
196            numberType = kCFNumberSInt32Type;
197            break;
198        case sizeof(UInt16):
199            numberType = kCFNumberSInt16Type;
200            break;
201        case sizeof(UInt8):
202            numberType = kCFNumberSInt8Type;
203            break;
204        default:
205            numberType = kCFNumberSInt32Type;
206            break;
207    }
208
209    numberRef = CFNumberCreate(kCFAllocatorDefault, numberType, bytes);
210    if( numberRef)
211    {
212        kr = IOConnectSetCFProperty( handle, key, numberRef );
213        CFRelease(numberRef);
214    }
215
216
217    return( kr );
218}
219
220kern_return_t IOHIDSetCFTypeParameter( io_connect_t handle, CFStringRef key, CFTypeRef parameter)
221{
222    kern_return_t		kr = kIOReturnError;
223
224    if ( parameter )
225        kr = IOConnectSetCFProperty( handle, key, parameter );
226    else
227        kr = kIOReturnBadArgument;
228
229    return( kr );
230}
231
232#ifndef kIOHIDParametersKey
233#define kIOHIDParametersKey		"HIDParameters"
234#endif
235
236kern_return_t IOHIDGetParameter( io_connect_t handle, CFStringRef key,
237                IOByteCount maxSize, void * bytes, IOByteCount * actualSize )
238{
239    kern_return_t	kr;
240    // io_service_t	hidsystem;
241    CFDataRef		data;
242    CFNumberRef		number;
243    CFNumberType	numberType;
244    CFTypeRef		typeRef = NULL;
245    IOByteCount		copySize;
246
247    if (!bytes || !maxSize)
248        return kIOReturnBadArgument;
249
250    kr = IOHIDCopyCFTypeParameter(handle, key, &typeRef);
251
252    if ( kr != kIOReturnSuccess )
253        return kr;
254
255    if( !typeRef )
256        return kIOReturnBadArgument;
257
258    if (CFGetTypeID(typeRef) == CFDataGetTypeID())
259    {
260        data = (CFDataRef)typeRef;
261        copySize = CFDataGetLength(data);
262        *actualSize = copySize;
263        if( maxSize < copySize)
264            copySize = maxSize;
265        bcopy( CFDataGetBytePtr(data), bytes, copySize );
266    }
267    else if (CFGetTypeID(typeRef) == CFNumberGetTypeID())
268    {
269        number = (CFNumberRef)typeRef;
270        copySize = CFNumberGetByteSize(number);
271        *actualSize = copySize;
272        if( maxSize < copySize)
273            copySize = maxSize;
274
275        switch ( copySize )
276        {
277            case sizeof(UInt64):
278                numberType = kCFNumberSInt64Type;
279                break;
280            case sizeof(UInt32):
281                numberType = kCFNumberSInt32Type;
282                break;
283            case sizeof(UInt16):
284                numberType = kCFNumberSInt16Type;
285                break;
286            case sizeof(UInt8):
287                numberType = kCFNumberSInt8Type;
288                break;
289            default:
290                numberType = kCFNumberSInt32Type;
291                break;
292        }
293
294        CFNumberGetValue( number, numberType, bytes );
295    }
296    else
297    {
298        kr = kIOReturnBadArgument;
299    }
300
301    CFRelease(typeRef);
302
303    return( kr );
304
305}
306
307kern_return_t IOHIDCopyCFTypeParameter( io_connect_t handle, CFStringRef key, CFTypeRef * parameter )
308{
309    kern_return_t	kr;
310    io_service_t	hidsystem;
311    CFDictionaryRef	paramDict;
312    CFTypeRef		tempParameter = NULL;
313
314    if (!parameter)
315        return kIOReturnError;
316
317    kr = IOConnectGetService( handle, &hidsystem );
318    if( KERN_SUCCESS != kr )
319        return( kr );
320
321    if( (paramDict = IORegistryEntryCreateCFProperty( hidsystem, CFSTR(kIOHIDParametersKey), kCFAllocatorDefault, kNilOptions)))
322    {
323        if ( (tempParameter = CFDictionaryGetValue( paramDict, key)) )
324            CFRetain(tempParameter);
325
326        CFRelease(paramDict);
327    }
328
329    if ( !tempParameter )
330        tempParameter = IORegistryEntryCreateCFProperty( hidsystem, key, kCFAllocatorDefault, kNilOptions);
331
332    if ( !tempParameter )
333        kr = kIOReturnBadArgument;
334
335    *parameter = tempParameter;
336
337    IOObjectRelease( hidsystem );
338
339    return( kr );
340}
341
342
343#define NXEvGetParameterChar( h,n,mx,p,sz ) IOHIDGetParameter( h, n,mx,p,sz )
344
345static inline int NXEvSetParameterChar( io_connect_t 	handle,
346                                 CFStringRef 	key,
347                                 const void * 	bytes,
348                                 IOByteCount 	size )
349{
350    kern_return_t		kr = kIOReturnNoMemory;
351    CFDataRef			data;
352
353    do {
354        data = CFDataCreate( kCFAllocatorDefault, bytes, size );
355        if( !data)
356            continue;
357        kr = IOHIDSetCFTypeParameter( handle, key, data );
358        CFRelease(data);
359
360    } while( false );
361
362    return( kr );
363}
364
365static inline int NXEvSetParameterInt(	NXEventHandle handle,
366                                CFStringRef parameterName,
367                                unsigned int *parameterArray,
368                                unsigned int count)
369{
370
371    CFMutableArrayRef 	arrayRef;
372    CFNumberRef 	numberRef;
373    IOReturn		ret = kIOReturnNoMemory;
374    unsigned int	i;
375
376
377    if (!parameterArray || !count)
378        return kIOReturnError;
379
380    if (count > 1)
381    {
382        arrayRef = CFArrayCreateMutable(kCFAllocatorDefault, count, &kCFTypeArrayCallBacks);
383        if ( !arrayRef )
384            return kIOReturnNoMemory;
385
386        for (i=0; i<count; i++)
387        {
388            numberRef = CFNumberCreate(kCFAllocatorDefault, kCFNumberSInt32Type, &(parameterArray[i]));
389
390            if (numberRef)
391            {
392                CFArraySetValueAtIndex(arrayRef, i, numberRef);
393                CFRelease(numberRef);
394            }
395        }
396
397        ret = IOHIDSetCFTypeParameter(handle, parameterName, arrayRef);
398
399        CFRelease(arrayRef);
400    }
401    else
402    {
403        numberRef = CFNumberCreate(kCFAllocatorDefault, kCFNumberIntType, &(parameterArray[0]));
404
405        if (numberRef)
406        {
407            ret = IOHIDSetCFTypeParameter(handle, parameterName, numberRef);
408            CFRelease(numberRef);
409        }
410
411    }
412    return ret;
413}
414
415static inline int NXEvGetParameterInt(	NXEventHandle handle,
416                                CFStringRef parameterName,
417                                unsigned int maxCount,
418                                unsigned int *parameterArray,
419                                unsigned int *returnedCount)
420{
421
422    CFArrayRef 		arrayRef;
423    CFNumberRef 	numberRef;
424    CFTypeRef		typeRef;
425    IOReturn		ret;
426    unsigned int	i;
427
428
429    ret = IOHIDCopyCFTypeParameter(handle, parameterName, &typeRef);
430
431    if ( ret != kIOReturnSuccess )
432        return ret;
433
434    if ( !typeRef || (CFGetTypeID(typeRef) != CFArrayGetTypeID()) || !parameterArray || !maxCount)
435        return kIOReturnBadArgument;
436
437    arrayRef = (CFArrayRef)typeRef;
438
439    *returnedCount = CFArrayGetCount(arrayRef);
440
441    if( maxCount < *returnedCount)
442        *returnedCount = maxCount;
443
444    for (i=0; i<*returnedCount; i++)
445    {
446        numberRef = CFArrayGetValueAtIndex(arrayRef, i);
447
448        if (numberRef)
449            CFNumberGetValue(numberRef, kCFNumberIntType, &(parameterArray[i]));
450    }
451
452    CFRelease(arrayRef);
453
454    return ret;
455}
456
457
458/* Keyboard */
459
460void NXResetKeyboard(NXEventHandle handle)
461{
462	unsigned int params[EVSIORKBD_SIZE];
463
464	NXEvSetParameterInt( handle, CFSTR(EVSIORKBD), params, EVSIORKBD_SIZE);
465}
466
467void NXSetKeyRepeatInterval(NXEventHandle handle, double rate)
468{
469	UInt64 params;
470	secs_to_packed_nsecs( rate, &params );
471	IOHIDSetParameter(	handle, CFSTR(EVSIOSKR), &params, sizeof(UInt64));
472}
473
474double NXKeyRepeatInterval(NXEventHandle handle)
475{
476	UInt64 params;
477	IOByteCount rcnt = EVSIOCKR_SIZE;
478	int r;
479
480        r = IOHIDGetParameter( handle, CFSTR(EVSIOSKR), sizeof(params),
481				&params, &rcnt );
482	if ( r != kIOReturnSuccess )
483		return 0.0;
484
485	return packed_nsecs_to_secs( params );
486}
487
488void NXSetKeyRepeatThreshold(NXEventHandle handle, double threshold)
489{
490        UInt64 params;
491        secs_to_packed_nsecs( threshold, &params );
492        IOHIDSetParameter( handle, CFSTR(EVSIOSIKR), &params, sizeof(params));
493}
494
495double NXKeyRepeatThreshold(NXEventHandle handle)
496{
497	UInt64 params;
498	IOByteCount rcnt = EVSIOCKR_SIZE;
499	int r;
500
501	r = IOHIDGetParameter( handle, CFSTR(EVSIOSIKR), sizeof(UInt64),
502				&params, &rcnt );
503	if ( r != kIOReturnSuccess )
504		return 0.0;
505	return packed_nsecs_to_secs( params );
506}
507
508NXKeyMapping * NXSetKeyMapping(NXEventHandle handle, NXKeyMapping *keymap)
509{
510	int r;
511
512	if ( keymap->size > EVSIOSKM_SIZE )
513	    	return (NXKeyMapping *)0;
514	r = NXEvSetParameterChar(handle, CFSTR(EVSIOSKM),
515				(unsigned char *) keymap->mapping,
516				keymap->size);
517	if ( r != kIOReturnSuccess )
518	    return (NXKeyMapping *)0;
519	return keymap;
520}
521
522int NXKeyMappingLength(NXEventHandle handle)
523{
524	int r;
525	IOByteCount size;
526
527	r = NXEvGetParameterChar( handle, CFSTR(EVSIOCKM), 0,
528				(unsigned char *) 0,
529				&size );
530	if ( r != kIOReturnSuccess )
531		size = 0;
532	return size;
533}
534
535NXKeyMapping * NXGetKeyMapping(NXEventHandle handle, NXKeyMapping *keymap)
536{
537	int r;
538
539	r = NXEvGetParameterChar( handle, CFSTR(EVSIOCKM), keymap->size,
540				(unsigned char *) keymap->mapping,
541				(IOByteCount *) &keymap->size );
542	if ( r != kIOReturnSuccess )
543    		return (NXKeyMapping *)0;
544	return keymap;
545}
546
547/* Mouse */
548
549void NXResetMouse(NXEventHandle handle)
550{
551	unsigned int params[EVSIORMS_SIZE];
552
553	NXEvSetParameterInt(handle, CFSTR(EVSIORMS), params, EVSIORMS_SIZE);
554}
555
556void NXSetClickTime(NXEventHandle handle, double secs)
557{
558	UInt64 params;
559
560	secs_to_packed_nsecs( secs, &params );
561        IOHIDSetParameter(handle, CFSTR(EVSIOSCT), &params, sizeof(params));
562}
563
564double NXClickTime(NXEventHandle handle)
565{
566	UInt64 params;
567	IOByteCount rcnt = EVSIOCCT_SIZE;
568	int r;
569
570	r = IOHIDGetParameter(handle, CFSTR(EVSIOCCT), sizeof(UInt64),
571				&params, &rcnt );
572	if ( r != kIOReturnSuccess )
573		return 0.0;
574	return packed_nsecs_to_secs( params );
575}
576
577void NXSetClickSpace(NXEventHandle handle, _NXSize_ *area)
578{
579	unsigned int params[EVSIOSCS_SIZE];
580
581	params[EVSIOSCS_X] = (unsigned int)(area->width);
582	params[EVSIOSCS_Y] = (unsigned int)(area->height);
583
584	NXEvSetParameterInt(handle, CFSTR(EVSIOSCS), params, EVSIOSCS_SIZE);
585}
586
587void NXGetClickSpace(NXEventHandle handle, _NXSize_ *area)
588{
589	unsigned int params[EVSIOCCS_SIZE];
590	unsigned int rcnt = EVSIOCCS_SIZE;
591
592	NXEvGetParameterInt(handle, CFSTR(EVSIOCCS), EVSIOCCS_SIZE,
593				params, &rcnt );
594	area->width = params[EVSIOCCS_X];
595	area->height = params[EVSIOCCS_Y];
596}
597
598kern_return_t IOHIDGetScrollAcceleration( io_connect_t handle, double * acceleration )
599{
600    kern_return_t	kr;
601    unsigned int	fixed;
602    IOByteCount	rsize;
603
604    kr = IOHIDGetParameter( handle, CFSTR(kIOHIDScrollAccelerationKey),
605                            sizeof( fixed), (unsigned char *) &fixed, &rsize );
606
607    if( kr == kIOReturnSuccess)
608        *acceleration = ((double) fixed) / 65536.0;
609
610    return( kr );
611}
612
613kern_return_t IOHIDSetScrollAcceleration( io_connect_t handle, double acceleration )
614{
615    unsigned int	fixed;
616
617    fixed = (unsigned int) (acceleration * 65536.0);
618
619    return( IOHIDSetParameter(handle, CFSTR(kIOHIDScrollAccelerationKey),
620                            (unsigned char *) &fixed, sizeof(fixed)) );
621}
622
623kern_return_t IOHIDGetMouseButtonMode( io_connect_t handle, int * mode )
624{
625    IOByteCount	rsize;
626
627    return( IOHIDGetParameter( handle, CFSTR(kIOHIDPointerButtonMode),
628                            sizeof( *mode), (unsigned char *) mode, &rsize ));
629}
630
631kern_return_t IOHIDSetMouseButtonMode( io_connect_t handle, int mode )
632{
633    return( IOHIDSetParameter(handle, CFSTR(kIOHIDPointerButtonMode),
634                            (unsigned char *) &mode, sizeof(mode)) );
635}
636
637kern_return_t IOHIDGetMouseAcceleration( io_connect_t handle, double * acceleration )
638{
639	kern_return_t	kr;
640	unsigned int	fixed;
641	IOByteCount	rsize;
642
643	kr = IOHIDGetParameter( handle, CFSTR(kIOHIDPointerAccelerationKey),
644				sizeof( fixed), (unsigned char *) &fixed, &rsize );
645
646	if( kr == kIOReturnSuccess)
647            *acceleration = ((double) fixed) / 65536.0;
648
649        return( kr );
650}
651
652kern_return_t IOHIDSetMouseAcceleration( io_connect_t handle, double acceleration )
653{
654	unsigned int	fixed;
655
656	fixed = (unsigned int) (acceleration * 65536.0);
657
658	return( IOHIDSetParameter(handle, CFSTR(kIOHIDPointerAccelerationKey),
659				(unsigned char *) &fixed, sizeof( fixed)) );
660}
661
662kern_return_t IOHIDGetAccelerationWithKey( io_connect_t handle, CFStringRef key, double * acceleration )
663{
664	kern_return_t	kr;
665	unsigned int	fixed;
666	IOByteCount	rsize;
667
668	kr = IOHIDGetParameter( handle, key,
669				sizeof( fixed), (unsigned char *) &fixed, &rsize );
670
671	if( kr == kIOReturnSuccess)
672            *acceleration = ((double) fixed) / 65536.0;
673
674        return( kr );
675}
676
677kern_return_t IOHIDSetAccelerationWithKey( io_connect_t handle, CFStringRef key, double acceleration )
678{
679	unsigned int	fixed;
680
681	fixed = (unsigned int) (acceleration * 65536.0);
682
683	return( IOHIDSetParameter(handle, key,
684				(unsigned char *) &fixed, sizeof( fixed)) );
685}
686