xref: /haiku/src/kits/device/Joystick.cpp (revision ef13dbda922b4cf26edc3d0bd5ca665e801c6b9d)
1 /*
2  * Copyright 2002-2008, Marcus Overhagen, Stefano Ceccherini, Fredrik Modéen.
3  * All rights reserved.
4  * Distributed under the terms of the MIT License.
5  */
6 
7 
8 #include <Joystick.h>
9 #include <JoystickTweaker.h>
10 
11 #include <new>
12 
13 #include <errno.h>
14 #include <fcntl.h>
15 #include <stdio.h>
16 
17 #include <sys/ioctl.h>
18 
19 #include <Debug.h>
20 #include <Directory.h>
21 #include <List.h>
22 #include <Path.h>
23 #include <String.h>
24 
25 
26 #if DEBUG
27 static FILE *sLogFile = NULL;
28 
29 inline void
30 LOG(const char *fmt, ...)
31 {
32 	char buf[1024];
33 	va_list ap;
34 	va_start(ap, fmt);
35 	vsprintf(buf, fmt, ap);
36 	va_end(ap);
37 	fputs(buf, sLogFile); fflush(sLogFile);
38 }
39 
40 #	define LOG_ERR(text...) LOG(text)
41 
42 #else
43 #	define LOG(text...)
44 #	define LOG_ERR(text...) fprintf(stderr, text)
45 #endif
46 
47 #define CALLED() LOG("%s\n", __PRETTY_FUNCTION__)
48 
49 
50 BJoystick::BJoystick()
51 	:
52 	// legacy members for standard mode
53 	timestamp(0),
54 	horizontal(0),
55 	vertical(0),
56 	button1(0),
57 	button2(0),
58 
59 	fBeBoxMode(false),
60 	fFD(-1),
61 	fDevices(new(std::nothrow) BList),
62 	fJoystickInfo(new(std::nothrow) joystick_info),
63 	fExtendedJoystick(new(std::nothrow) BList)
64 {
65 #if DEBUG
66 	sLogFile = fopen("/var/log/joystick.log", "a");
67 #endif
68 
69 	if (fJoystickInfo != NULL)
70 		memset(fJoystickInfo, 0, sizeof(joystick_info));
71 }
72 
73 
74 BJoystick::~BJoystick()
75 {
76 	if (fFD >= 0)
77 		close(fFD);
78 
79 	if (fDevices != NULL) {
80 		for (int32 i = 0; i < fDevices->CountItems(); i++)
81 			delete (BString *)fDevices->ItemAt(i);
82 
83 		delete fDevices;
84 	}
85 
86 	delete fJoystickInfo;
87 
88 	if (fExtendedJoystick != NULL) {
89 		for (int32 i = 0; i < fExtendedJoystick->CountItems(); i++)
90 			delete (extended_joystick *)fExtendedJoystick->ItemAt(i);
91 
92 		delete fExtendedJoystick;
93 	}
94 }
95 
96 
97 status_t
98 BJoystick::Open(const char *portName)
99 {
100 	CALLED();
101 	return Open(portName, true);
102 }
103 
104 
105 status_t
106 BJoystick::Open(const char *portName, bool enhanced)
107 {
108 	CALLED();
109 
110 	if (portName == NULL)
111 		return B_BAD_VALUE;
112 
113 	if (fJoystickInfo == NULL || fExtendedJoystick == NULL)
114 		return B_NO_INIT;
115 
116 	fBeBoxMode = !enhanced;
117 
118 	char nameBuffer[64];
119 	if (portName[0] != '/')
120 		snprintf(nameBuffer, sizeof(nameBuffer), DEVICEPATH"/%s", portName);
121 	else
122 		snprintf(nameBuffer, sizeof(nameBuffer), "%s", portName);
123 
124 	if (fFD >= 0)
125 		close(fFD);
126 
127 	// TODO: BeOS don't use O_EXCL, and this seems to lead to some issues. I
128 	// added this flag having read some comments by Marco Nelissen on the
129 	// annotated BeBook. I think BeOS uses O_RDWR|O_NONBLOCK here.
130 	fFD = open(nameBuffer, O_RDWR | O_NONBLOCK | O_EXCL);
131 
132 	if (fFD >= 0) {
133 		// we used open() with O_NONBLOCK flag to let it return immediately,
134 		// but we want read/write operations to block if needed, so we clear
135 		// that bit here.
136 		int flags = fcntl(fFD, F_GETFL);
137 		fcntl(fFD, F_SETFL, flags & ~O_NONBLOCK);
138 
139 		// read the Joystick Description file for this port/joystick
140 		_BJoystickTweaker joystickTweaker(*this);
141 		joystickTweaker.GetInfo(fJoystickInfo, portName);
142 
143 		LOG("ioctl - %d\n", fJoystickInfo->module_info.num_buttons);
144 		ioctl(fFD, B_JOYSTICK_SET_DEVICE_MODULE, &fJoystickInfo->module_info,
145 			sizeof(joystick_module_info));
146 		ioctl(fFD, B_JOYSTICK_GET_DEVICE_MODULE, &fJoystickInfo->module_info,
147 			sizeof(joystick_module_info));
148 		LOG("ioctl - %d\n", fJoystickInfo->module_info.num_buttons);
149 
150 		// Allocate the extended_joystick structures to hold the info for each
151 		// "stick". Note that the whole num_sticks thing seems a bit bogus, as
152 		// all sticks would be required to have exactly the same attributes,
153 		// i.e. axis, hat and button counts, since there is only one global
154 		// joystick_info for the whole device. What's implemented here is a
155 		// "best guess", using the read position in Update() to select the
156 		// stick for which an extended_joystick structure shall be returned.
157 		for (uint16 i = 0; i < fJoystickInfo->module_info.num_sticks; i++) {
158 			extended_joystick *extendedJoystick
159 				= new(std::nothrow) extended_joystick;
160 			if (extendedJoystick == NULL)
161 				return B_NO_MEMORY;
162 
163 			if (!fExtendedJoystick->AddItem(extendedJoystick)) {
164 				delete extendedJoystick;
165 				return B_NO_MEMORY;
166 			}
167 		}
168 
169 		return fFD;
170 	} else
171 		return errno;
172 }
173 
174 
175 void
176 BJoystick::Close(void)
177 {
178 	CALLED();
179 	if (fFD >= 0) {
180 		close(fFD);
181 		fFD = -1;
182 	}
183 }
184 
185 
186 void
187 BJoystick::ScanDevices(bool useDisabled)
188 {
189 	CALLED();
190 	if (useDisabled) {
191 		_BJoystickTweaker joystickTweaker(*this);
192 		joystickTweaker.scan_including_disabled();
193 	}
194 }
195 
196 
197 int32
198 BJoystick::CountDevices()
199 {
200 	CALLED();
201 
202 	// Refresh devices list
203 	ScanDevices(true);
204 
205 	int32 count = 0;
206 	if (fDevices != NULL)
207 		count = fDevices->CountItems();
208 
209 	LOG("Count = %d\n", count);
210 	return count;
211 }
212 
213 
214 status_t
215 BJoystick::GetDeviceName(int32 index, char *name, size_t bufSize)
216 {
217 	CALLED();
218 	if (fDevices == NULL)
219 		return B_NO_INIT;
220 
221 	if (index >= fDevices->CountItems())
222 		return B_BAD_INDEX;
223 
224 	if (name == NULL)
225 		return B_BAD_VALUE;
226 
227 	BString *deviceName = (BString *)fDevices->ItemAt(index);
228 	if (deviceName->Length() > (int32)bufSize)
229 		return B_NAME_TOO_LONG;
230 
231 	strlcpy(name, deviceName->String(), bufSize);
232 	LOG("Device Name = %s\n", name);
233 	return B_OK;
234 }
235 
236 
237 bool
238 BJoystick::EnterEnhancedMode(const entry_ref *ref)
239 {
240 	CALLED();
241 	fBeBoxMode = false;
242 	return !fBeBoxMode;
243 }
244 
245 
246 int32
247 BJoystick::CountSticks()
248 {
249 	CALLED();
250 	if (fJoystickInfo == NULL)
251 		return 0;
252 
253 	return fJoystickInfo->module_info.num_sticks;
254 }
255 
256 
257 int32
258 BJoystick::CountAxes()
259 {
260 	CALLED();
261 	if (fJoystickInfo == NULL)
262 		return 0;
263 
264 	return fJoystickInfo->module_info.num_axes;
265 }
266 
267 
268 int32
269 BJoystick::CountHats()
270 {
271 	CALLED();
272 	if (fJoystickInfo == NULL)
273 		return 0;
274 
275 	return fJoystickInfo->module_info.num_hats;
276 }
277 
278 
279 int32
280 BJoystick::CountButtons()
281 {
282 	CALLED();
283 	if (fJoystickInfo == NULL)
284 		return 0;
285 
286 	return fJoystickInfo->module_info.num_buttons;
287 }
288 
289 
290 status_t
291 BJoystick::GetControllerModule(BString *outName)
292 {
293 	CALLED();
294 	if (fJoystickInfo == NULL || fFD < 0)
295 		return B_NO_INIT;
296 
297 	if (outName == NULL)
298 		return B_BAD_VALUE;
299 
300 	outName->SetTo(fJoystickInfo->module_info.module_name);
301 	return B_OK;
302 }
303 
304 
305 status_t
306 BJoystick::GetControllerName(BString *outName)
307 {
308 	CALLED();
309 	if (fJoystickInfo == NULL || fFD < 0)
310 		return B_NO_INIT;
311 
312 	if (outName == NULL)
313 		return B_BAD_VALUE;
314 
315 	outName->SetTo(fJoystickInfo->module_info.device_name);
316 	return B_OK;
317 }
318 
319 
320 bool
321 BJoystick::IsCalibrationEnabled()
322 {
323 	CALLED();
324 	if (fJoystickInfo == NULL)
325 		return false;
326 
327 	return fJoystickInfo->calibration_enable;
328 }
329 
330 
331 status_t
332 BJoystick::EnableCalibration(bool calibrates)
333 {
334 	CALLED();
335 	if (fJoystickInfo == NULL || fFD < 0)
336 		return B_NO_INIT;
337 
338 	status_t result = ioctl(fFD, B_JOYSTICK_SET_RAW_MODE, &calibrates,
339 		sizeof(calibrates));
340 	if (result == B_OK)
341 		fJoystickInfo->calibration_enable = calibrates;
342 
343 	return result;
344 }
345 
346 
347 status_t
348 BJoystick::SetMaxLatency(bigtime_t maxLatency)
349 {
350 	CALLED();
351 	if (fJoystickInfo == NULL || fFD < 0)
352 		return B_NO_INIT;
353 
354 	status_t result = ioctl(fFD, B_JOYSTICK_SET_MAX_LATENCY, &maxLatency,
355 		sizeof(maxLatency));
356 	if (result == B_OK)
357 		fJoystickInfo->max_latency = maxLatency;
358 
359 	return result;
360 }
361 
362 
363 status_t
364 BJoystick::GetAxisNameAt(int32 index, BString *outName)
365 {
366 	CALLED();
367 
368 	if (index >= CountAxes())
369 		return B_BAD_INDEX;
370 
371 	if (outName == NULL)
372 		return B_BAD_VALUE;
373 
374 	// TODO: actually retrieve the name from the driver (via a new ioctl)
375 	*outName = "Axis ";
376 	*outName << index;
377 	return B_OK;
378 }
379 
380 
381 status_t
382 BJoystick::GetHatNameAt(int32 index, BString *outName)
383 {
384 	CALLED();
385 
386 	if (index >= CountHats())
387 		return B_BAD_INDEX;
388 
389 	if (outName == NULL)
390 		return B_BAD_VALUE;
391 
392 	// TODO: actually retrieve the name from the driver (via a new ioctl)
393 	*outName = "Hat ";
394 	*outName << index;
395 	return B_OK;
396 }
397 
398 
399 status_t
400 BJoystick::GetButtonNameAt(int32 index, BString *outName)
401 {
402 	CALLED();
403 
404 	if (index >= CountButtons())
405 		return B_BAD_INDEX;
406 
407 	if (outName == NULL)
408 		return B_BAD_VALUE;
409 
410 	// TODO: actually retrieve the name from the driver (via a new ioctl)
411 	*outName = "Button ";
412 	*outName << index;
413 	return B_OK;
414 }
415 
416 
417 status_t
418 BJoystick::GetAxisValues(int16 *outValues, int32 forStick)
419 {
420 	CALLED();
421 
422 	if (fJoystickInfo == NULL || fExtendedJoystick == NULL)
423 		return B_NO_INIT;
424 
425 	if (forStick < 0
426 		|| forStick >= (int32)fJoystickInfo->module_info.num_sticks)
427 		return B_BAD_INDEX;
428 
429 	extended_joystick *extendedJoystick
430 		= (extended_joystick *)fExtendedJoystick->ItemAt(forStick);
431 	if (extendedJoystick == NULL)
432 		return B_NO_INIT;
433 
434 	memcpy(outValues, extendedJoystick->axes,
435 		fJoystickInfo->module_info.num_axes * sizeof(uint16));
436 	return B_OK;
437 }
438 
439 
440 status_t
441 BJoystick::GetHatValues(uint8 *outHats, int32 forStick)
442 {
443 	CALLED();
444 
445 	if (fJoystickInfo == NULL || fExtendedJoystick == NULL)
446 		return B_NO_INIT;
447 
448 	if (forStick < 0
449 		|| forStick >= (int32)fJoystickInfo->module_info.num_sticks)
450 		return B_BAD_INDEX;
451 
452 	extended_joystick *extendedJoystick
453 		= (extended_joystick *)fExtendedJoystick->ItemAt(forStick);
454 	if (extendedJoystick == NULL)
455 		return B_NO_INIT;
456 
457 	memcpy(outHats, extendedJoystick->hats,
458 		fJoystickInfo->module_info.num_hats);
459 	return B_OK;
460 }
461 
462 
463 uint32
464 BJoystick::ButtonValues(int32 forStick)
465 {
466 	CALLED();
467 
468 	if (fJoystickInfo == NULL || fExtendedJoystick == NULL)
469 		return 0;
470 
471 	if (forStick < 0
472 		|| forStick >= (int32)fJoystickInfo->module_info.num_sticks)
473 		return 0;
474 
475 	extended_joystick *extendedJoystick
476 		= (extended_joystick *)fExtendedJoystick->ItemAt(forStick);
477 	if (extendedJoystick == NULL)
478 		return 0;
479 
480 	return extendedJoystick->buttons;
481 }
482 
483 
484 status_t
485 BJoystick::Update()
486 {
487 	CALLED();
488 	if (fJoystickInfo == NULL || fExtendedJoystick == NULL || fFD < 0)
489 		return B_NO_INIT;
490 
491 	for (uint16 i = 0; i < fJoystickInfo->module_info.num_sticks; i++) {
492 		extended_joystick *extendedJoystick
493 			= (extended_joystick *)fExtendedJoystick->ItemAt(i);
494 		if (extendedJoystick == NULL)
495 			return B_NO_INIT;
496 
497 		ssize_t result = read_pos(fFD, i, extendedJoystick,
498 			sizeof(extended_joystick));
499 		if (result < 0)
500 			return result;
501 
502 		if (result != sizeof(extended_joystick))
503 			return B_ERROR;
504 
505 		if (i > 0)
506 			continue;
507 
508 		// fill in the legacy values for the first stick
509 		timestamp = extendedJoystick->timestamp;
510 		horizontal = (uint32)((int32)extendedJoystick->axes[0] + 32768);
511 		vertical = (uint32)((int32)extendedJoystick->axes[1] + 32768);
512 			// TODO: if we really want to go that far: scale the value correctly
513 		button1 = (extendedJoystick->buttons & 1) == 0;
514 		button2 = (extendedJoystick->buttons & 2) == 0;
515 	}
516 
517 	return B_OK;
518 }
519 
520 
521 void
522 BJoystick::Calibrate(struct _extended_joystick *reading)
523 {
524 	CALLED();
525 }
526 
527 
528 status_t
529 BJoystick::GatherEnhanced_info(const entry_ref *ref)
530 {
531 	CALLED();
532 	return B_ERROR;
533 }
534 
535 
536 status_t
537 BJoystick::SaveConfig(const entry_ref *ref)
538 {
539 	CALLED();
540 	return B_ERROR;
541 }
542 
543 
544 //	#pragma mark - FBC protection
545 
546 
547 void BJoystick::_ReservedJoystick1() {}
548 void BJoystick::_ReservedJoystick2() {}
549 void BJoystick::_ReservedJoystick3() {}
550 status_t BJoystick::_Reserved_Joystick_4(void*, ...) { return B_ERROR; }
551 status_t BJoystick::_Reserved_Joystick_5(void*, ...) { return B_ERROR; }
552 status_t BJoystick::_Reserved_Joystick_6(void*, ...) { return B_ERROR; }
553