1 /*
2 * Copyright 2007-2008 by Sascha Hlusiak. <saschahlusiak@freedesktop.org>
3 *
4 * Permission to use, copy, modify, distribute, and sell this software and its
5 * documentation for any purpose is hereby granted without fee, provided that
6 * the above copyright notice appear in all copies and that both that
7 * copyright notice and this permission notice appear in supporting
8 * documentation, and that the name of Sascha Hlusiak not be used in
9 * advertising or publicity pertaining to distribution of the software without
10 * specific, written prior permission. Sascha Hlusiak makes no
11 * representations about the suitability of this software for any purpose. It
12 * is provided "as is" without express or implied warranty.
13 *
14 * SASCHA HLUSIAK DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
15 * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
16 * EVENT SHALL SASCHA HLUSIAK BE LIABLE FOR ANY SPECIAL, INDIRECT OR
17 * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
18 * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
19 * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
20 * PERFORMANCE OF THIS SOFTWARE.
21 *
22 */
23
24 /**
25 * This provides the backend for USB-HIDs for NetBSD, OpenBSD and FreeBSD
26 * Needs the uhid module loaded. Device names are /dev/uhid?
27 **/
28
29 #ifdef HAVE_CONFIG_H
30 #include "config.h"
31 #endif
32
33 #include <xorg-server.h>
34 #include <unistd.h>
35 #include <sys/types.h>
36 #include <sys/ioctl.h>
37 #include <fcntl.h>
38 #include <errno.h>
39 #include <stdlib.h>
40
41 #include <xf86.h>
42 #include <xf86_OSproc.h>
43
44 #include <usbhid.h>
45 #ifdef __DragonFly__
46 #include <sys/param.h>
47 # if __DragonFly_version < 300703
48 #include <bus/usb/usb.h>
49 #include <bus/usb/usbhid.h>
50 # else
51 #include <bus/u4b/usb.h>
52 #include <bus/u4b/usbhid.h>
53 #include <bus/u4b/usb_ioctl.h>
54 # endif
55 #else
56 #include <dev/usb/usb.h>
57 #include <dev/usb/usbhid.h>
58 #endif
59 #ifdef HAVE_DEV_USB_USB_IOCTL_H
60 #include <dev/usb/usb_ioctl.h>
61 #endif
62 #ifdef HAVE_BUS_USB_USB_IOCTL_H
63 #include <bus/usb/usb_ioctl.h>
64 #endif
65
66 #include "jstk.h"
67 #include "backend_bsd.h"
68
69
70 struct jstk_bsd_hid_data {
71 int dlen; /* Length of one data chunk */
72 char *data_buf; /* Data buffer with right size */
73 struct hid_item axis_item[MAXAXES]; /* Axis HID items */
74 struct hid_item button_item[MAXBUTTONS]; /* Button HID items */
75 struct hid_item hat_item[MAXAXES]; /* HID items for hats */
76 int hats; /* Number of hats */
77 int hotdata; /* Is unprocessed data available
78 in data_buf? */
79 };
80
81 static void jstkCloseDevice_bsd(JoystickDevPtr joystick);
82 static int jstkReadData_bsd(JoystickDevPtr joystick,
83 JOYSTICKEVENT *event,
84 int *number);
85
86
87
88 /***********************************************************************
89 *
90 * jstkOpenDevice --
91 *
92 * Open and initialize a joystick device
93 * Returns the filedescriptor, or -1 in case of error
94 *
95 ***********************************************************************
96 */
97
98 int
jstkOpenDevice_bsd(JoystickDevPtr joystick,Bool probe)99 jstkOpenDevice_bsd(JoystickDevPtr joystick, Bool probe)
100 {
101 int cur_axis;
102 int is_joystick, report_id = 0;
103 int got_something;
104 struct hid_data *d;
105 struct hid_item h;
106 report_desc_t rd;
107 struct jstk_bsd_hid_data *bsddata;
108
109 if (joystick->fd == -1) {
110 if ((joystick->fd = open(joystick->device, O_RDWR | O_NDELAY, 0)) < 0) {
111 xf86Msg(X_ERROR, "Cannot open joystick '%s' (%s)\n",
112 joystick->device, strerror(errno));
113 return -1;
114 }
115 }
116
117 if ((rd = hid_get_report_desc(joystick->fd)) == 0) {
118 xf86Msg(X_ERROR, "Joystick: hid_get_report_desc failed: %s\n",
119 strerror(errno));
120 jstkCloseDevice_bsd(joystick);
121 return -1;
122 }
123
124 if (ioctl(joystick->fd, USB_GET_REPORT_ID, &report_id) < 0) {
125 xf86Msg(X_ERROR, "Joystick: ioctl USB_GET_REPORT_ID failed: %s\n",
126 strerror(errno));
127 jstkCloseDevice_bsd(joystick);
128 return -1;
129 }
130
131 bsddata = (struct jstk_bsd_hid_data*)
132 malloc(sizeof(struct jstk_bsd_hid_data));
133 joystick->devicedata = (void*) bsddata;
134
135 bsddata->dlen = hid_report_size(rd, hid_input, report_id);
136
137 if ((bsddata->data_buf = malloc(bsddata->dlen)) == NULL) {
138 fprintf(stderr, "error: couldn't malloc %d bytes\n", bsddata->dlen);
139 hid_dispose_report_desc(rd);
140 jstkCloseDevice_bsd(joystick);
141 return -1;
142 }
143
144 is_joystick = 0;
145 got_something = 0;
146 cur_axis = 0;
147 bsddata->hats = 0;
148 joystick->num_axes = 0;
149 joystick->num_buttons = 0;
150
151 for (d = hid_start_parse(rd, 1 << hid_input, report_id);
152 hid_get_item(d, &h); )
153 {
154 int usage, page;
155
156 page = HID_PAGE(h.usage);
157 usage = HID_USAGE(h.usage);
158
159 is_joystick = is_joystick ||
160 (h.kind == hid_collection &&
161 page == HUP_GENERIC_DESKTOP &&
162 (usage == HUG_JOYSTICK || usage == HUG_GAME_PAD));
163
164 if (h.kind != hid_input)
165 continue;
166
167 if (!is_joystick)
168 continue;
169
170 if (page == HUP_GENERIC_DESKTOP) {
171 if (usage == HUG_HAT_SWITCH) {
172 if ((bsddata->hats < MAXAXES) && (joystick->num_axes <= MAXAXES-2)) {
173 got_something = 1;
174 memcpy(&bsddata->hat_item[bsddata->hats], &h, sizeof(h));
175 bsddata->hats++;
176 joystick->num_axes += 2;
177 }
178 } else {
179 if (joystick->num_axes < MAXAXES) {
180 got_something = 1;
181 memcpy(&bsddata->axis_item[cur_axis], &h, sizeof(h));
182 cur_axis++;
183 joystick->num_axes++;
184 }
185 }
186 } else if (page == HUP_BUTTON) {
187 if (joystick->num_buttons < MAXBUTTONS) {
188 got_something = 1;
189 memcpy(&bsddata->button_item[joystick->num_buttons], &h, sizeof(h));
190 joystick->num_buttons++;
191 }
192 }
193 }
194 hid_end_parse(d);
195
196 if (!got_something) {
197 free(bsddata->data_buf);
198 xf86Msg(X_ERROR, "Joystick: Didn't find any usable axes.\n");
199 jstkCloseDevice_bsd(joystick);
200 return -1;
201 }
202
203 bsddata->hotdata = 0;
204 if (probe == TRUE) {
205 xf86Msg(X_INFO, "Joystick: %d buttons, %d axes\n",
206 joystick->num_buttons, joystick->num_axes);
207 }
208
209 joystick->open_proc = jstkOpenDevice_bsd;
210 joystick->read_proc = jstkReadData_bsd;
211 joystick->close_proc = jstkCloseDevice_bsd;
212
213 return joystick->fd;
214 }
215
216
217 /***********************************************************************
218 *
219 * jstkCloseDevice --
220 *
221 * close the handle.
222 *
223 ***********************************************************************
224 */
225
226 static void
jstkCloseDevice_bsd(JoystickDevPtr joystick)227 jstkCloseDevice_bsd(JoystickDevPtr joystick)
228 {
229 jstkCloseDevice(joystick);
230 if (joystick->devicedata != NULL) {
231 if (((struct jstk_bsd_hid_data*)joystick->devicedata)->data_buf)
232 free(((struct jstk_bsd_hid_data*)joystick->devicedata)->data_buf);
233 free(joystick->devicedata);
234 joystick->devicedata = NULL;
235 }
236 }
237
238
239 /***********************************************************************
240 *
241 * jstkReadData --
242 *
243 * Reads data from fd and stores it in the JoystickDevRec struct
244 * fills in the type of event and the number of the button/axis
245 * return 1 if success, 0 otherwise. Success does not neccessarily
246 * mean that there is a new event waiting.
247 *
248 ***********************************************************************
249 */
250
251 static int
jstkReadData_bsd(JoystickDevPtr joystick,JOYSTICKEVENT * event,int * number)252 jstkReadData_bsd(JoystickDevPtr joystick,
253 JOYSTICKEVENT *event,
254 int *number)
255 {
256 int j,d;
257 struct jstk_bsd_hid_data *bsddata =
258 (struct jstk_bsd_hid_data*)(joystick->devicedata);
259
260 if (event != NULL) *event = EVENT_NONE;
261 if (bsddata->hotdata == 0) {
262 j= xf86ReadSerial(joystick->fd,
263 bsddata->data_buf,
264 bsddata->dlen);
265 if (j != bsddata->dlen) {
266 ErrorF("Read: %d byte! Should be %d\n",j,bsddata->dlen);
267 return 0;
268 }
269 bsddata->hotdata = 1;
270 }
271
272 for (j=0; j<joystick->num_axes - (bsddata->hats * 2); j++) {
273 d = hid_get_data(bsddata->data_buf, &bsddata->axis_item[j]);
274 /* Scale the range to our expected range of -32768 to 32767 */
275 d = d - (bsddata->axis_item[j].logical_maximum
276 - bsddata->axis_item[j].logical_minimum) / 2;
277 d = d * 65536 / (bsddata->axis_item[j].logical_maximum
278 - bsddata->axis_item[j].logical_minimum);
279 if (abs(d) < joystick->axis[j].deadzone) d = 0;
280 if (d != joystick->axis[j].value) {
281 joystick->axis[j].value = d;
282 if (event != NULL) *event = EVENT_AXIS;
283 if (number != NULL) *number = j;
284 return 2;
285 }
286 }
287
288 for (j=0; j<bsddata->hats; j++) {
289 int a;
290 int v1_data[9] =
291 { 0, 32767, 32767, 32767, 0, -32768, -32768, -32768, 0 };
292 int v2_data[9] =
293 { -32768, -32768, 0, 32767, 32767, 32767, 0, -32767, 0 };
294
295 a = j*2 + joystick->num_axes - bsddata->hats *2;
296 d = hid_get_data(bsddata->data_buf, &bsddata->hat_item[j])
297 - bsddata->hat_item[j].logical_minimum;
298 if (joystick->axis[a].value != v1_data[d]) {
299 joystick->axis[a].value = v1_data[d];
300 if (event != NULL) *event = EVENT_AXIS;
301 if (number != NULL) *number = a;
302 return 2;
303 }
304 if (joystick->axis[a+1].value != v2_data[d]) {
305 joystick->axis[a+1].value = v2_data[d];
306 if (event != NULL) *event = EVENT_AXIS;
307 if (number != NULL) *number = a+1;
308 return 2;
309 }
310 }
311
312 for (j=0; j<joystick->num_buttons; j++) {
313 int pressed;
314 d = hid_get_data(bsddata->data_buf, &bsddata->button_item[j]);
315 pressed = (d == bsddata->button_item[j].logical_minimum) ? 0 : 1;
316 if (pressed != joystick->button[j].pressed) {
317 joystick->button[j].pressed = pressed;
318 if (event != NULL) *event = EVENT_BUTTON;
319 if (number != NULL) *number = j;
320 return 2;
321 }
322 }
323
324 bsddata->hotdata = 0;
325 return 1;
326 }
327