1 /** \file joy-unix-usb.c
2 * \brief NetBSD/FreeBSD USB joystick support
3 *
4 * \author Dieter Baron <dillo@nih.at>
5 * \author Marco van den Heuvel <blackystardust68@yahoo.com>
6 */
7
8 /*
9 * This file is part of VICE, the Versatile Commodore Emulator.
10 * See README for copyright notice.
11 *
12 * This program is free software; you can redistribute it and/or modify
13 * it under the terms of the GNU General Public License as published by
14 * the Free Software Foundation; either version 2 of the License, or
15 * (at your option) any later version.
16 *
17 * This program is distributed in the hope that it will be useful,
18 * but WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 * GNU General Public License for more details.
21 *
22 * You should have received a copy of the GNU General Public License
23 * along with this program; if not, write to the Free Software
24 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
25 * 02111-1307 USA.
26 *
27 */
28
29 #include "vice.h"
30
31 #if defined(UNIX_COMPILE) && !defined(MACOSX_SUPPORT)
32
33 #include <fcntl.h>
34 #include <stdio.h>
35 #include <unistd.h>
36
37 #include "cmdline.h"
38 #include "joy.h"
39 #include "joystick.h"
40 #include "keyboard.h"
41 #include "log.h"
42 #include "resources.h"
43 #include "types.h"
44
45 #if defined(HAS_JOYSTICK) && defined(HAS_USB_JOYSTICK)
46
47 #define ITEM_AXIS 0
48 #define ITEM_BUTTON 1
49 #define ITEM_HAT 2
50
51 int hat_or[] = { 1, 9, 8, 10, 2, 6, 4, 5, };
52
53 extern log_t joystick_log;
54
55 #ifdef HAVE_USB_H
56 #include <usb.h>
57 #endif
58
59 #ifdef __DragonFly__
60 /* sys/param.h contains the __DragonFly_version macro */
61 # include <sys/param.h>
62 # if __DragonFly_version >= 300200
63 /* DragonFly >= 3.2 (USB4BSD stack) */
64 # include <bus/u4b/usb.h>
65 # include <bus/u4b/usbhid.h>
66 # else
67 /* DragonFly < 3.2: old USB stack */
68 # include <bus/usb/usb.h>
69 # include <bus/usb/usbhid.h>
70 # endif
71 #else
72 # ifdef __FreeBSD__
73 # include <sys/ioccom.h>
74 # endif
75 # include <dev/usb/usb.h>
76 # include <dev/usb/usbhid.h>
77 #endif
78
79 #include <errno.h>
80 #include <stdlib.h>
81 #include <string.h>
82
83 #if defined(HAVE_USBHID_H)
84 #include <usbhid.h>
85 #elif defined(HAVE_LIBUSB_H)
86 #include <libusb.h>
87 #elif defined(HAVE_LIBUSBHID_H)
88 #include <libusbhid.h>
89 #endif
90
91 #define MAX_DEV 4 /* number of uhid devices to try */
92
93 struct usb_joy_item {
94 struct hid_item item;
95 struct usb_joy_item *next;
96
97 int type;
98 int min_or;
99 int min_val;
100 int max_or;
101 int max_val;
102 };
103
104 static struct usb_joy_item *usb_joy_item[2];
105
106 static int usb_joy_fd[2] = { -1, -1 };
107 static int usb_joy_size[2];
108 static char *usb_joy_buf[2];
109
usb_joy_add_item(struct usb_joy_item ** item,struct hid_item * hi,int orval,int type)110 static int usb_joy_add_item(struct usb_joy_item **item, struct hid_item *hi, int orval, int type)
111 {
112 struct usb_joy_item *it;
113 int w;
114
115 if ((it=malloc(sizeof(*it))) == NULL) {
116 /* XXX */
117 return -1;
118 }
119
120 it->next = *item;
121 *item = it;
122
123 memcpy(&it->item, hi, sizeof(*hi));
124 it->type = type;
125 switch (type) {
126 case ITEM_AXIS:
127 w = (hi->logical_maximum - hi->logical_minimum) / 3;
128 it->min_or = orval;
129 it->min_val = hi->logical_minimum + w;
130 it->max_or = orval * 2;
131 it->max_val = hi->logical_maximum - w;
132 break;
133 case ITEM_BUTTON:
134 it->min_or = 0;
135 it->min_val = hi->logical_minimum;
136 it->max_or = orval;
137 it->max_val = hi->logical_maximum - 1;
138 break;
139 case ITEM_HAT:
140 it->min_val = hi->logical_minimum;
141 break;
142 }
143
144 return 0;
145 }
146
usb_free_item(struct usb_joy_item ** item)147 static void usb_free_item(struct usb_joy_item **item)
148 {
149 struct usb_joy_item *it, *it2;
150
151 it=*item;
152 while (it) {
153 it2 = it;
154 it = it->next;
155 free(it2);
156 }
157 *item = NULL;
158 }
159
usb_joystick_init(void)160 int usb_joystick_init(void)
161 {
162 int i, j, id = 0, fd;
163 report_desc_t report;
164 struct hid_item h;
165 struct hid_data *d;
166 int is_joy, found;
167 char dev[32];
168
169 for (j=i=0; i<2 && j<MAX_DEV; j++) {
170 sprintf(dev, "/dev/uhid%d", j);
171 fd = open(dev, O_RDONLY | O_NONBLOCK);
172 if (fd < 0) {
173 continue;
174 }
175
176 #if defined(USB_GET_REPORT_ID) && !defined(__DragonFly__)
177 if (ioctl(fd, USB_GET_REPORT_ID, &id) < 0) {
178 log_warning(joystick_log, "Cannot get report id for joystick device `%s'.", dev);
179 close(fd);
180 }
181 #endif
182
183 if ((report=hid_get_report_desc(fd)) == NULL) {
184 log_warning(joystick_log, "Cannot report description for joystick device `%s'.", dev);
185 close(fd);
186 continue;
187 }
188 usb_joy_size[i] = hid_report_size(report, hid_input, id);
189
190 usb_joy_item[i] = NULL;
191
192 found = 0;
193 is_joy = 0;
194 #if !defined(HAVE_USBHID_H) && !defined(HAVE_LIBUSB_H) && defined(HAVE_LIBUSBHID)
195 for (d = hid_start_parse(report, id);
196 #else
197 for (d = hid_start_parse(report, 1 << hid_input, id);
198 #endif
199 hid_get_item(d, &h);) {
200 if (h.kind == hid_collection && HID_PAGE(h.usage) == HUP_GENERIC_DESKTOP && (HID_USAGE(h.usage) == HUG_JOYSTICK || HID_USAGE(h.usage) == HUG_GAME_PAD)) {
201 is_joy = 1;
202 continue;
203 }
204 if (!is_joy) {
205 continue;
206 }
207
208 switch (HID_PAGE(h.usage)) {
209 case HUP_GENERIC_DESKTOP:
210 switch (HID_USAGE(h.usage)) {
211 case HUG_X:
212 case HUG_RX:
213 if (usb_joy_add_item(usb_joy_item + i, &h, 4, ITEM_AXIS) == 0) {
214 found |= 4;
215 }
216 break;
217 case HUG_Y:
218 case HUG_RY:
219 if (usb_joy_add_item(usb_joy_item + i, &h, 1, ITEM_AXIS) == 0) {
220 found |= 1;
221 }
222 break;
223 case HUG_HAT_SWITCH:
224 if (usb_joy_add_item(usb_joy_item + i, &h, 0, ITEM_HAT) == 0) {
225 found |= 5;
226 }
227 break;
228 }
229 break;
230 case HUP_BUTTON:
231 if (usb_joy_add_item(usb_joy_item + i, &h, 16, ITEM_BUTTON) == 0) {
232 found |= 16;
233 }
234 break;
235 }
236 }
237 hid_end_parse(d);
238
239 if (found != 21) {
240 close(fd);
241 usb_free_item(usb_joy_item + i);
242 log_message(joystick_log, "Not all axes found in joystick device `%s'.", dev);
243 continue;
244 }
245
246 if ((usb_joy_buf[i] = malloc(usb_joy_size[i])) == NULL) {
247 log_warning(joystick_log, "Cannot allocate buffer for joystick device `%s'.", dev);
248 close(fd);
249 usb_free_item(usb_joy_item + i);
250 continue;
251 }
252
253 log_message(joystick_log, "USB joystick found: `%s'.", dev);
254 usb_joy_fd[i] = fd;
255 i++;
256 }
257 return 0;
258 }
259
usb_joystick_close(void)260 void usb_joystick_close(void)
261 {
262 int i;
263
264 for (i = 0; i < 2; i++) {
265 if (usb_joy_fd[i] < 0) {
266 continue;
267 }
268
269 close(usb_joy_fd[i]);
270 usb_joy_fd[i] = -1;
271 usb_free_item(usb_joy_item+i);
272 }
273 }
274
usb_joystick(void)275 void usb_joystick(void)
276 {
277 int i, jp, val, ret;
278 struct usb_joy_item *it;
279
280 for (i = 0; i < 4; i++) {
281 jp = joystick_port_map[i];
282 if (jp != JOYDEV_USB_0 && jp != JOYDEV_USB_1) {
283 continue;
284 }
285
286 jp -= JOYDEV_USB_0;
287
288 if (usb_joy_fd[jp] < 0) {
289 continue;
290 }
291
292 val = 0;
293 while ((ret = read(usb_joy_fd[jp], usb_joy_buf[jp], usb_joy_size[jp])) == usb_joy_size[jp]) {
294 val = 1;
295 }
296 if (ret != -1 && errno != EAGAIN) {
297 /* XXX */
298 printf("strange read return: %d/%d\n", ret, errno);
299 continue;
300 }
301 if (!val) {
302 continue;
303 }
304
305 joystick_set_value_absolute(i + 1, 0);
306
307 for (it = usb_joy_item[jp]; it; it = it->next) {
308 val = hid_get_data(usb_joy_buf[jp], &it->item);
309 if (it->type == ITEM_HAT) {
310 val -= it->min_val;
311 if (val >= 0 && val <= 7) {
312 joystick_set_value_or(i + 1, hat_or[val]);
313 }
314 } else {
315 if (val <= it->min_val) {
316 joystick_set_value_or(i + 1, it->min_or);
317 } else if (val > it->max_val) {
318 joystick_set_value_or(i + 1, it->max_or);
319 }
320 }
321 }
322 }
323 }
324
325 #endif /* HAS_JOYSTICK && HAS_USB_JOYSTICK */
326 #endif
327
328