xref: /haiku/src/kits/device/Joystick.cpp (revision bb2420a47472560ac4035c77035ce1b9e373d009)
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 status_t
178 BJoystick::Update()
179 {
180 	CALLED();
181 	if (fJoystickInfo == NULL || fExtendedJoystick == NULL || fFD < 0)
182 		return B_NO_INIT;
183 
184 	for (uint16 i = 0; i < fJoystickInfo->module_info.num_sticks; i++) {
185 		extended_joystick *extendedJoystick
186 			= (extended_joystick *)fExtendedJoystick->ItemAt(i);
187 		if (extendedJoystick == NULL)
188 			return B_NO_INIT;
189 
190 		ssize_t result = read_pos(fFD, i, extendedJoystick,
191 			sizeof(extended_joystick));
192 		if (result < 0)
193 			return result;
194 
195 		if (result != sizeof(extended_joystick))
196 			return B_ERROR;
197 
198 		if (i > 0)
199 			continue;
200 
201 		// fill in the legacy values for the first stick
202 		timestamp = extendedJoystick->timestamp;
203 		horizontal = extendedJoystick->axes[0];
204 		vertical = extendedJoystick->axes[1];
205 		button1 = (extendedJoystick->buttons & 1) == 0;
206 		button2 = (extendedJoystick->buttons & 2) == 0;
207 	}
208 
209 	return B_OK;
210 }
211 
212 
213 status_t
214 BJoystick::SetMaxLatency(bigtime_t maxLatency)
215 {
216 	CALLED();
217 	if (fJoystickInfo == NULL || fFD < 0)
218 		return B_NO_INIT;
219 
220 	status_t result = ioctl(fFD, B_JOYSTICK_SET_MAX_LATENCY, &maxLatency,
221 		sizeof(maxLatency));
222 	if (result == B_OK)
223 		fJoystickInfo->max_latency = maxLatency;
224 
225 	return result;
226 }
227 
228 
229 int32
230 BJoystick::CountDevices()
231 {
232 	CALLED();
233 
234 	if (fDevices == NULL)
235 		return 0;
236 
237 	int32 count = fDevices->CountItems();
238 
239 	LOG("Count = %d\n", count);
240 	return count;
241 }
242 
243 
244 status_t
245 BJoystick::GetDeviceName(int32 index, char *name, size_t bufSize)
246 {
247 	CALLED();
248 	if (fDevices == NULL)
249 		return B_NO_INIT;
250 
251 	if (index >= fDevices->CountItems())
252 		return B_BAD_INDEX;
253 
254 	if (name == NULL)
255 		return B_BAD_VALUE;
256 
257 	BString *deviceName = (BString *)fDevices->ItemAt(index);
258 	if (deviceName->Length() > (int32)bufSize)
259 		return B_NAME_TOO_LONG;
260 
261 	strlcpy(name, deviceName->String(), bufSize);
262 	LOG("Device Name = %s\n", name);
263 	return B_OK;
264 }
265 
266 
267 status_t
268 BJoystick::RescanDevices()
269 {
270 	CALLED();
271 
272 	if (fDevices == NULL)
273 		return B_NO_INIT;
274 
275 	ScanDevices(true);
276 	return B_OK;
277 }
278 
279 
280 bool
281 BJoystick::EnterEnhancedMode(const entry_ref *ref)
282 {
283 	CALLED();
284 	fBeBoxMode = false;
285 	return !fBeBoxMode;
286 }
287 
288 
289 int32
290 BJoystick::CountSticks()
291 {
292 	CALLED();
293 	if (fJoystickInfo == NULL)
294 		return 0;
295 
296 	return fJoystickInfo->module_info.num_sticks;
297 }
298 
299 
300 int32
301 BJoystick::CountAxes()
302 {
303 	CALLED();
304 	if (fJoystickInfo == NULL)
305 		return 0;
306 
307 	return fJoystickInfo->module_info.num_axes;
308 }
309 
310 
311 status_t
312 BJoystick::GetAxisValues(int16 *outValues, int32 forStick)
313 {
314 	CALLED();
315 
316 	if (fJoystickInfo == NULL || fExtendedJoystick == NULL)
317 		return B_NO_INIT;
318 
319 	if (forStick < 0
320 		|| forStick >= (int32)fJoystickInfo->module_info.num_sticks)
321 		return B_BAD_INDEX;
322 
323 	extended_joystick *extendedJoystick
324 		= (extended_joystick *)fExtendedJoystick->ItemAt(forStick);
325 	if (extendedJoystick == NULL)
326 		return B_NO_INIT;
327 
328 	memcpy(outValues, extendedJoystick->axes,
329 		fJoystickInfo->module_info.num_axes * sizeof(uint16));
330 	return B_OK;
331 }
332 
333 
334 status_t
335 BJoystick::GetAxisNameAt(int32 index, BString *outName)
336 {
337 	CALLED();
338 
339 	if (index >= CountAxes())
340 		return B_BAD_INDEX;
341 
342 	if (outName == NULL)
343 		return B_BAD_VALUE;
344 
345 	// TODO: actually retrieve the name from the driver (via a new ioctl)
346 	*outName = "Axis ";
347 	*outName << index;
348 	return B_OK;
349 }
350 
351 
352 int32
353 BJoystick::CountHats()
354 {
355 	CALLED();
356 	if (fJoystickInfo == NULL)
357 		return 0;
358 
359 	return fJoystickInfo->module_info.num_hats;
360 }
361 
362 
363 status_t
364 BJoystick::GetHatValues(uint8 *outHats, int32 forStick)
365 {
366 	CALLED();
367 
368 	if (fJoystickInfo == NULL || fExtendedJoystick == NULL)
369 		return B_NO_INIT;
370 
371 	if (forStick < 0
372 		|| forStick >= (int32)fJoystickInfo->module_info.num_sticks)
373 		return B_BAD_INDEX;
374 
375 	extended_joystick *extendedJoystick
376 		= (extended_joystick *)fExtendedJoystick->ItemAt(forStick);
377 	if (extendedJoystick == NULL)
378 		return B_NO_INIT;
379 
380 	memcpy(outHats, extendedJoystick->hats,
381 		fJoystickInfo->module_info.num_hats);
382 	return B_OK;
383 }
384 
385 
386 status_t
387 BJoystick::GetHatNameAt(int32 index, BString *outName)
388 {
389 	CALLED();
390 
391 	if (index >= CountHats())
392 		return B_BAD_INDEX;
393 
394 	if (outName == NULL)
395 		return B_BAD_VALUE;
396 
397 	// TODO: actually retrieve the name from the driver (via a new ioctl)
398 	*outName = "Hat ";
399 	*outName << index;
400 	return B_OK;
401 }
402 
403 
404 int32
405 BJoystick::CountButtons()
406 {
407 	CALLED();
408 	if (fJoystickInfo == NULL)
409 		return 0;
410 
411 	return fJoystickInfo->module_info.num_buttons;
412 }
413 
414 
415 uint32
416 BJoystick::ButtonValues(int32 forStick)
417 {
418 	CALLED();
419 
420 	if (fJoystickInfo == NULL || fExtendedJoystick == NULL)
421 		return 0;
422 
423 	if (forStick < 0
424 		|| forStick >= (int32)fJoystickInfo->module_info.num_sticks)
425 		return 0;
426 
427 	extended_joystick *extendedJoystick
428 		= (extended_joystick *)fExtendedJoystick->ItemAt(forStick);
429 	if (extendedJoystick == NULL)
430 		return 0;
431 
432 	return extendedJoystick->buttons;
433 }
434 
435 
436 status_t
437 BJoystick::GetButtonNameAt(int32 index, BString *outName)
438 {
439 	CALLED();
440 
441 	if (index >= CountButtons())
442 		return B_BAD_INDEX;
443 
444 	if (outName == NULL)
445 		return B_BAD_VALUE;
446 
447 	// TODO: actually retrieve the name from the driver (via a new ioctl)
448 	*outName = "Button ";
449 	*outName << index;
450 	return B_OK;
451 }
452 
453 
454 status_t
455 BJoystick::GetControllerModule(BString *outName)
456 {
457 	CALLED();
458 	if (fJoystickInfo == NULL || fFD < 0)
459 		return B_NO_INIT;
460 
461 	if (outName == NULL)
462 		return B_BAD_VALUE;
463 
464 	outName->SetTo(fJoystickInfo->module_info.module_name);
465 	return B_OK;
466 }
467 
468 
469 status_t
470 BJoystick::GetControllerName(BString *outName)
471 {
472 	CALLED();
473 	if (fJoystickInfo == NULL || fFD < 0)
474 		return B_NO_INIT;
475 
476 	if (outName == NULL)
477 		return B_BAD_VALUE;
478 
479 	outName->SetTo(fJoystickInfo->module_info.device_name);
480 	return B_OK;
481 }
482 
483 
484 bool
485 BJoystick::IsCalibrationEnabled()
486 {
487 	CALLED();
488 	if (fJoystickInfo == NULL)
489 		return false;
490 
491 	return fJoystickInfo->calibration_enable;
492 }
493 
494 
495 status_t
496 BJoystick::EnableCalibration(bool calibrates)
497 {
498 	CALLED();
499 	if (fJoystickInfo == NULL || fFD < 0)
500 		return B_NO_INIT;
501 
502 	status_t result = ioctl(fFD, B_JOYSTICK_SET_RAW_MODE, &calibrates,
503 		sizeof(calibrates));
504 	if (result == B_OK)
505 		fJoystickInfo->calibration_enable = calibrates;
506 
507 	return result;
508 }
509 
510 
511 void
512 BJoystick::Calibrate(struct _extended_joystick *reading)
513 {
514 	CALLED();
515 }
516 
517 
518 void
519 BJoystick::ScanDevices(bool useDisabled)
520 {
521 	CALLED();
522 	if (useDisabled) {
523 		_BJoystickTweaker joystickTweaker(*this);
524 		joystickTweaker.scan_including_disabled();
525 	}
526 }
527 
528 
529 //	#pragma mark - FBC protection
530 
531 
532 void BJoystick::_ReservedJoystick1() {}
533 void BJoystick::_ReservedJoystick2() {}
534 void BJoystick::_ReservedJoystick3() {}
535 status_t BJoystick::_Reserved_Joystick_4(void*, ...) { return B_ERROR; }
536 status_t BJoystick::_Reserved_Joystick_5(void*, ...) { return B_ERROR; }
537 status_t BJoystick::_Reserved_Joystick_6(void*, ...) { return B_ERROR; }
538