HaikuDepot: notify work status from main window
[haiku.git] / src / kits / device / Joystick.cpp
blob6ec405de78d3a4c8aea64e4b93ae1236f0e35c49
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 */
8 #include <Joystick.h>
9 #include <JoystickTweaker.h>
11 #include <new>
12 #include <stdio.h>
13 #include <sys/ioctl.h>
15 #include <Debug.h>
16 #include <Directory.h>
17 #include <List.h>
18 #include <Path.h>
19 #include <String.h>
22 #if DEBUG
23 static FILE *sLogFile = NULL;
25 inline void
26 LOG(const char *fmt, ...)
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);
36 # define LOG_ERR(text...) LOG(text)
38 #else
39 # define LOG(text...)
40 # define LOG_ERR(text...) fprintf(stderr, text)
41 #endif
43 #define CALLED() LOG("%s\n", __PRETTY_FUNCTION__)
46 BJoystick::BJoystick()
48 // legacy members for standard mode
49 timestamp(0),
50 horizontal(0),
51 vertical(0),
52 button1(true),
53 button2(true),
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)
61 #if DEBUG
62 sLogFile = fopen("/var/log/joystick.log", "a");
63 #endif
65 if (fJoystickInfo != NULL)
66 memset(fJoystickInfo, 0, sizeof(joystick_info));
68 RescanDevices();
72 BJoystick::~BJoystick()
74 if (fFD >= 0)
75 close(fFD);
77 if (fDevices != NULL) {
78 for (int32 i = 0; i < fDevices->CountItems(); i++)
79 delete (BString *)fDevices->ItemAt(i);
81 delete fDevices;
84 delete fJoystickInfo;
86 if (fJoystickData != NULL) {
87 for (int32 i = 0; i < fJoystickData->CountItems(); i++) {
88 variable_joystick *variableJoystick
89 = (variable_joystick *)fJoystickData->ItemAt(i);
90 if (variableJoystick == NULL)
91 continue;
93 free(variableJoystick->data);
94 delete variableJoystick;
97 delete fJoystickData;
102 status_t
103 BJoystick::Open(const char *portName)
105 CALLED();
106 return Open(portName, true);
110 status_t
111 BJoystick::Open(const char *portName, bool enhanced)
113 CALLED();
115 if (portName == NULL)
116 return B_BAD_VALUE;
118 if (fJoystickInfo == NULL || fJoystickData == NULL)
119 return B_NO_INIT;
121 fBeBoxMode = !enhanced;
123 char nameBuffer[64];
124 if (portName[0] != '/') {
125 snprintf(nameBuffer, sizeof(nameBuffer), DEVICE_BASE_PATH"/%s",
126 portName);
127 } else
128 snprintf(nameBuffer, sizeof(nameBuffer), "%s", portName);
130 if (fFD >= 0)
131 close(fFD);
133 // TODO: BeOS don't use O_EXCL, and this seems to lead to some issues. I
134 // added this flag having read some comments by Marco Nelissen on the
135 // annotated BeBook. I think BeOS uses O_RDWR | O_NONBLOCK here.
136 fFD = open(nameBuffer, O_RDWR | O_NONBLOCK | O_EXCL);
137 if (fFD < 0)
138 return B_ERROR;
140 // read the Joystick Description file for this port/joystick
141 _BJoystickTweaker joystickTweaker(*this);
142 joystickTweaker.GetInfo(fJoystickInfo, portName);
144 // signal that we support variable reads
145 fJoystickInfo->module_info.flags |= js_flag_variable_size_reads;
147 LOG("ioctl - %d\n", fJoystickInfo->module_info.num_buttons);
148 ioctl(fFD, B_JOYSTICK_SET_DEVICE_MODULE, &fJoystickInfo->module_info,
149 sizeof(joystick_module_info));
150 ioctl(fFD, B_JOYSTICK_GET_DEVICE_MODULE, &fJoystickInfo->module_info,
151 sizeof(joystick_module_info));
152 LOG("ioctl - %d\n", fJoystickInfo->module_info.num_buttons);
154 // Allocate the variable_joystick structures to hold the info for each
155 // "stick". Note that the whole num_sticks thing seems a bit bogus, as
156 // all sticks would be required to have exactly the same attributes,
157 // i.e. axis, hat and button counts, since there is only one global
158 // joystick_info for the whole device. What's implemented here is a
159 // "best guess", using the read position in Update() to select the
160 // stick for which data shall be returned.
161 bool supportsVariable
162 = (fJoystickInfo->module_info.flags & js_flag_variable_size_reads) != 0;
163 for (uint16 i = 0; i < fJoystickInfo->module_info.num_sticks; i++) {
164 variable_joystick *variableJoystick
165 = new(std::nothrow) variable_joystick;
166 if (variableJoystick == NULL)
167 return B_NO_MEMORY;
169 status_t result;
170 if (supportsVariable) {
171 // The driver supports arbitrary controls.
172 result = variableJoystick->initialize(
173 fJoystickInfo->module_info.num_axes,
174 fJoystickInfo->module_info.num_hats,
175 fJoystickInfo->module_info.num_buttons);
176 } else {
177 // The driver doesn't support our variable requests so we construct
178 // a data structure that is compatible with extended_joystick and
179 // just use that in reads. This allows us to use a single data
180 // format internally but be compatible with both inputs.
181 result = variableJoystick->initialize_to_extended_joystick();
183 // Also ensure that we don't read over those boundaries.
184 if (fJoystickInfo->module_info.num_axes > MAX_AXES)
185 fJoystickInfo->module_info.num_axes = MAX_AXES;
186 if (fJoystickInfo->module_info.num_hats > MAX_HATS)
187 fJoystickInfo->module_info.num_hats = MAX_HATS;
188 if (fJoystickInfo->module_info.num_buttons > MAX_BUTTONS)
189 fJoystickInfo->module_info.num_buttons = MAX_BUTTONS;
192 if (result != B_OK) {
193 delete variableJoystick;
194 return result;
197 if (!fJoystickData->AddItem(variableJoystick)) {
198 free(variableJoystick->data);
199 delete variableJoystick;
200 return B_NO_MEMORY;
204 return fFD;
208 void
209 BJoystick::Close(void)
211 CALLED();
212 if (fFD >= 0) {
213 close(fFD);
214 fFD = -1;
219 status_t
220 BJoystick::Update()
222 CALLED();
223 if (fJoystickInfo == NULL || fJoystickData == NULL || fFD < 0)
224 return B_NO_INIT;
226 for (uint16 i = 0; i < fJoystickInfo->module_info.num_sticks; i++) {
227 variable_joystick *values
228 = (variable_joystick *)fJoystickData->ItemAt(i);
229 if (values == NULL)
230 return B_NO_INIT;
232 ssize_t result = read_pos(fFD, i, values->data,
233 values->data_size);
234 if (result < 0)
235 return result;
237 if ((size_t)result != values->data_size)
238 return B_ERROR;
240 if (i > 0)
241 continue;
243 // fill in the legacy values for the first stick
244 timestamp = *values->timestamp;
246 if (values->axis_count >= 1)
247 horizontal = values->axes[0];
248 else
249 horizontal = 0;
251 if (values->axis_count >= 2)
252 vertical = values->axes[1];
253 else
254 vertical = 0;
256 if (values->button_blocks > 0) {
257 button1 = (*values->buttons & 1) == 0;
258 button2 = (*values->buttons & 2) == 0;
259 } else {
260 button1 = true;
261 button2 = true;
265 return B_OK;
269 status_t
270 BJoystick::SetMaxLatency(bigtime_t maxLatency)
272 CALLED();
273 if (fJoystickInfo == NULL || fFD < 0)
274 return B_NO_INIT;
276 status_t result = ioctl(fFD, B_JOYSTICK_SET_MAX_LATENCY, &maxLatency,
277 sizeof(maxLatency));
278 if (result == B_OK)
279 fJoystickInfo->max_latency = maxLatency;
281 return result;
285 int32
286 BJoystick::CountDevices()
288 CALLED();
290 if (fDevices == NULL)
291 return 0;
293 int32 count = fDevices->CountItems();
295 LOG("Count = %d\n", count);
296 return count;
300 status_t
301 BJoystick::GetDeviceName(int32 index, char *name, size_t bufSize)
303 CALLED();
304 if (fDevices == NULL)
305 return B_NO_INIT;
307 if (index >= fDevices->CountItems())
308 return B_BAD_INDEX;
310 if (name == NULL)
311 return B_BAD_VALUE;
313 BString *deviceName = (BString *)fDevices->ItemAt(index);
314 if (deviceName->Length() > (int32)bufSize)
315 return B_NAME_TOO_LONG;
317 strlcpy(name, deviceName->String(), bufSize);
318 LOG("Device Name = %s\n", name);
319 return B_OK;
323 status_t
324 BJoystick::RescanDevices()
326 CALLED();
328 if (fDevices == NULL)
329 return B_NO_INIT;
331 ScanDevices(true);
332 return B_OK;
336 bool
337 BJoystick::EnterEnhancedMode(const entry_ref *ref)
339 CALLED();
340 fBeBoxMode = false;
341 return !fBeBoxMode;
345 int32
346 BJoystick::CountSticks()
348 CALLED();
349 if (fJoystickInfo == NULL)
350 return 0;
352 return fJoystickInfo->module_info.num_sticks;
356 int32
357 BJoystick::CountAxes()
359 CALLED();
360 if (fJoystickInfo == NULL)
361 return 0;
363 return fJoystickInfo->module_info.num_axes;
367 status_t
368 BJoystick::GetAxisValues(int16 *outValues, int32 forStick)
370 CALLED();
372 if (fJoystickInfo == NULL || fJoystickData == NULL)
373 return B_NO_INIT;
375 if (forStick < 0
376 || forStick >= (int32)fJoystickInfo->module_info.num_sticks)
377 return B_BAD_INDEX;
379 variable_joystick *variableJoystick
380 = (variable_joystick *)fJoystickData->ItemAt(forStick);
381 if (variableJoystick == NULL)
382 return B_NO_INIT;
384 memcpy(outValues, variableJoystick->axes,
385 fJoystickInfo->module_info.num_axes * sizeof(uint16));
386 return B_OK;
390 status_t
391 BJoystick::GetAxisNameAt(int32 index, BString *outName)
393 CALLED();
395 if (index >= CountAxes())
396 return B_BAD_INDEX;
398 if (outName == NULL)
399 return B_BAD_VALUE;
401 // TODO: actually retrieve the name from the driver (via a new ioctl)
402 *outName = "Axis ";
403 *outName << index;
404 return B_OK;
408 int32
409 BJoystick::CountHats()
411 CALLED();
412 if (fJoystickInfo == NULL)
413 return 0;
415 return fJoystickInfo->module_info.num_hats;
419 status_t
420 BJoystick::GetHatValues(uint8 *outHats, int32 forStick)
422 CALLED();
424 if (fJoystickInfo == NULL || fJoystickData == NULL)
425 return B_NO_INIT;
427 if (forStick < 0
428 || forStick >= (int32)fJoystickInfo->module_info.num_sticks)
429 return B_BAD_INDEX;
431 variable_joystick *variableJoystick
432 = (variable_joystick *)fJoystickData->ItemAt(forStick);
433 if (variableJoystick == NULL)
434 return B_NO_INIT;
436 memcpy(outHats, variableJoystick->hats,
437 fJoystickInfo->module_info.num_hats);
438 return B_OK;
442 status_t
443 BJoystick::GetHatNameAt(int32 index, BString *outName)
445 CALLED();
447 if (index >= CountHats())
448 return B_BAD_INDEX;
450 if (outName == NULL)
451 return B_BAD_VALUE;
453 // TODO: actually retrieve the name from the driver (via a new ioctl)
454 *outName = "Hat ";
455 *outName << index;
456 return B_OK;
460 int32
461 BJoystick::CountButtons()
463 CALLED();
464 if (fJoystickInfo == NULL)
465 return 0;
467 return fJoystickInfo->module_info.num_buttons;
471 uint32
472 BJoystick::ButtonValues(int32 forStick)
474 CALLED();
476 if (fJoystickInfo == NULL || fJoystickData == NULL)
477 return 0;
479 if (forStick < 0
480 || forStick >= (int32)fJoystickInfo->module_info.num_sticks)
481 return 0;
483 variable_joystick *variableJoystick
484 = (variable_joystick *)fJoystickData->ItemAt(forStick);
485 if (variableJoystick == NULL || variableJoystick->button_blocks == 0)
486 return 0;
488 return *variableJoystick->buttons;
492 status_t
493 BJoystick::GetButtonValues(bool *outButtons, int32 forStick)
495 CALLED();
497 if (fJoystickInfo == NULL || fJoystickData == NULL)
498 return B_NO_INIT;
500 if (forStick < 0
501 || forStick >= (int32)fJoystickInfo->module_info.num_sticks)
502 return B_BAD_INDEX;
504 variable_joystick *variableJoystick
505 = (variable_joystick *)fJoystickData->ItemAt(forStick);
506 if (variableJoystick == NULL)
507 return B_NO_INIT;
509 int16 buttonCount = fJoystickInfo->module_info.num_buttons;
510 for (int16 i = 0; i < buttonCount; i++) {
511 outButtons[i]
512 = (variableJoystick->buttons[i / 32] & (1 << (i % 32))) != 0;
515 return B_OK;
519 status_t
520 BJoystick::GetButtonNameAt(int32 index, BString *outName)
522 CALLED();
524 if (index >= CountButtons())
525 return B_BAD_INDEX;
527 if (outName == NULL)
528 return B_BAD_VALUE;
530 // TODO: actually retrieve the name from the driver (via a new ioctl)
531 *outName = "Button ";
532 *outName << index;
533 return B_OK;
537 status_t
538 BJoystick::GetControllerModule(BString *outName)
540 CALLED();
541 if (fJoystickInfo == NULL || fFD < 0)
542 return B_NO_INIT;
544 if (outName == NULL)
545 return B_BAD_VALUE;
547 outName->SetTo(fJoystickInfo->module_info.module_name);
548 return B_OK;
552 status_t
553 BJoystick::GetControllerName(BString *outName)
555 CALLED();
556 if (fJoystickInfo == NULL || fFD < 0)
557 return B_NO_INIT;
559 if (outName == NULL)
560 return B_BAD_VALUE;
562 outName->SetTo(fJoystickInfo->module_info.device_name);
563 return B_OK;
567 bool
568 BJoystick::IsCalibrationEnabled()
570 CALLED();
571 if (fJoystickInfo == NULL)
572 return false;
574 return fJoystickInfo->calibration_enable;
578 status_t
579 BJoystick::EnableCalibration(bool calibrates)
581 CALLED();
582 if (fJoystickInfo == NULL || fFD < 0)
583 return B_NO_INIT;
585 status_t result = ioctl(fFD, B_JOYSTICK_SET_RAW_MODE, &calibrates,
586 sizeof(calibrates));
587 if (result == B_OK)
588 fJoystickInfo->calibration_enable = calibrates;
590 return result;
594 void
595 BJoystick::Calibrate(struct _extended_joystick *reading)
597 CALLED();
601 void
602 BJoystick::ScanDevices(bool useDisabled)
604 CALLED();
605 if (useDisabled) {
606 _BJoystickTweaker joystickTweaker(*this);
607 joystickTweaker.scan_including_disabled();
612 // #pragma mark - FBC protection
615 void BJoystick::_ReservedJoystick1() {}
616 void BJoystick::_ReservedJoystick2() {}
617 void BJoystick::_ReservedJoystick3() {}
618 status_t BJoystick::_Reserved_Joystick_4(void*, ...) { return B_ERROR; }
619 status_t BJoystick::_Reserved_Joystick_5(void*, ...) { return B_ERROR; }
620 status_t BJoystick::_Reserved_Joystick_6(void*, ...) { return B_ERROR; }