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