SDL-1.2.14
[sdl_omap.git] / src / joystick / darwin / SDL_sysjoystick.c
CommitLineData
e14743d1 1/*
2 SDL - Simple DirectMedia Layer
3 Copyright (C) 1997-2009 Sam Lantinga
4
5 This library is free software; you can redistribute it and/or
6 modify it under the terms of the GNU Library General Public
7 License as published by the Free Software Foundation; either
8 version 2 of the License, or (at your option) any later version.
9
10 This library is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Library General Public License for more details.
14
15 You should have received a copy of the GNU Library General Public
16 License along with this library; if not, write to the Free
17 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
18
19 Sam Lantinga
20 slouken@libsdl.org
21*/
22#include "SDL_config.h"
23
24#ifdef SDL_JOYSTICK_IOKIT
25
26/* SDL joystick driver for Darwin / Mac OS X, based on the IOKit HID API */
27/* Written 2001 by Max Horn */
28
29#include <unistd.h>
30#include <ctype.h>
31#include <sysexits.h>
32#include <mach/mach.h>
33#include <mach/mach_error.h>
34#include <IOKit/IOKitLib.h>
35#include <IOKit/IOCFPlugIn.h>
36#ifdef MACOS_10_0_4
37#include <IOKit/hidsystem/IOHIDUsageTables.h>
38#else
39/* The header was moved here in Mac OS X 10.1 */
40#include <Kernel/IOKit/hidsystem/IOHIDUsageTables.h>
41#endif
42#if MAC_OS_X_VERSION_MIN_REQUIRED == 1030
43#include "10.3.9-FIX/IOHIDLib.h"
44#else
45#include <IOKit/hid/IOHIDLib.h>
46#endif
47#include <IOKit/hid/IOHIDKeys.h>
48#include <CoreFoundation/CoreFoundation.h>
49#include <Carbon/Carbon.h> /* for NewPtrClear, DisposePtr */
50
51#include "SDL_joystick.h"
52#include "../SDL_sysjoystick.h"
53#include "../SDL_joystick_c.h"
54
55struct recElement
56{
57 IOHIDElementCookie cookie; /* unique value which identifies element, will NOT change */
58 long min; /* reported min value possible */
59 long max; /* reported max value possible */
60#if 0
61 /* TODO: maybe should handle the following stuff somehow? */
62
63 long scaledMin; /* reported scaled min value possible */
64 long scaledMax; /* reported scaled max value possible */
65 long size; /* size in bits of data return from element */
66 Boolean relative; /* are reports relative to last report (deltas) */
67 Boolean wrapping; /* does element wrap around (one value higher than max is min) */
68 Boolean nonLinear; /* are the values reported non-linear relative to element movement */
69 Boolean preferredState; /* does element have a preferred state (such as a button) */
70 Boolean nullState; /* does element have null state */
71#endif /* 0 */
72
73 /* runtime variables used for auto-calibration */
74 long minReport; /* min returned value */
75 long maxReport; /* max returned value */
76
77 struct recElement * pNext; /* next element in list */
78};
79typedef struct recElement recElement;
80
81struct joystick_hwdata
82{
83 IOHIDDeviceInterface ** interface; /* interface to device, NULL = no interface */
84
85 char product[256]; /* name of product */
86 long usage; /* usage page from IOUSBHID Parser.h which defines general usage */
87 long usagePage; /* usage within above page from IOUSBHID Parser.h which defines specific usage */
88
89 long axes; /* number of axis (calculated, not reported by device) */
90 long buttons; /* number of buttons (calculated, not reported by device) */
91 long hats; /* number of hat switches (calculated, not reported by device) */
92 long elements; /* number of total elements (shouldbe total of above) (calculated, not reported by device) */
93
94 recElement* firstAxis;
95 recElement* firstButton;
96 recElement* firstHat;
97
98 int removed;
99 int uncentered;
100
101 struct joystick_hwdata* pNext; /* next device */
102};
103typedef struct joystick_hwdata recDevice;
104
105
106/* Linked list of all available devices */
107static recDevice *gpDeviceList = NULL;
108
109
110static void HIDReportErrorNum (char * strError, long numError)
111{
112 SDL_SetError(strError);
113}
114
115static void HIDGetCollectionElements (CFMutableDictionaryRef deviceProperties, recDevice *pDevice);
116
117/* returns current value for element, polling element
118 * will return 0 on error conditions which should be accounted for by application
119 */
120
121static SInt32 HIDGetElementValue (recDevice *pDevice, recElement *pElement)
122{
123 IOReturn result = kIOReturnSuccess;
124 IOHIDEventStruct hidEvent;
125 hidEvent.value = 0;
126
127 if (NULL != pDevice && NULL != pElement && NULL != pDevice->interface)
128 {
129 result = (*(pDevice->interface))->getElementValue(pDevice->interface, pElement->cookie, &hidEvent);
130 if (kIOReturnSuccess == result)
131 {
132 /* record min and max for auto calibration */
133 if (hidEvent.value < pElement->minReport)
134 pElement->minReport = hidEvent.value;
135 if (hidEvent.value > pElement->maxReport)
136 pElement->maxReport = hidEvent.value;
137 }
138 }
139
140 /* auto user scale */
141 return hidEvent.value;
142}
143
144static SInt32 HIDScaledCalibratedValue (recDevice *pDevice, recElement *pElement, long min, long max)
145{
146 float deviceScale = max - min;
147 float readScale = pElement->maxReport - pElement->minReport;
148 SInt32 value = HIDGetElementValue(pDevice, pElement);
149 if (readScale == 0)
150 return value; /* no scaling at all */
151 else
152 return ((value - pElement->minReport) * deviceScale / readScale) + min;
153}
154
155
156static void HIDRemovalCallback(void * target,
157 IOReturn result,
158 void * refcon,
159 void * sender)
160{
161 recDevice *device = (recDevice *) refcon;
162 device->removed = 1;
163 device->uncentered = 1;
164}
165
166
167
168/* Create and open an interface to device, required prior to extracting values or building queues.
169 * Note: appliction now owns the device and must close and release it prior to exiting
170 */
171
172static IOReturn HIDCreateOpenDeviceInterface (io_object_t hidDevice, recDevice *pDevice)
173{
174 IOReturn result = kIOReturnSuccess;
175 HRESULT plugInResult = S_OK;
176 SInt32 score = 0;
177 IOCFPlugInInterface ** ppPlugInInterface = NULL;
178
179 if (NULL == pDevice->interface)
180 {
181 result = IOCreatePlugInInterfaceForService (hidDevice, kIOHIDDeviceUserClientTypeID,
182 kIOCFPlugInInterfaceID, &ppPlugInInterface, &score);
183 if (kIOReturnSuccess == result)
184 {
185 /* Call a method of the intermediate plug-in to create the device interface */
186 plugInResult = (*ppPlugInInterface)->QueryInterface (ppPlugInInterface,
187 CFUUIDGetUUIDBytes (kIOHIDDeviceInterfaceID), (void *) &(pDevice->interface));
188 if (S_OK != plugInResult)
189