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