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