2 * Copyright 2002-2008, Marcus Overhagen, Stefano Ceccherini, Fredrik Modéen.
4 * Distributed under the terms of the MIT License.
9 #include <JoystickTweaker.h>
13 #include <sys/ioctl.h>
16 #include <Directory.h>
23 static FILE *sLogFile
= NULL
;
26 LOG(const char *fmt
, ...)
31 vsprintf(buf
, fmt
, ap
);
33 fputs(buf
, sLogFile
); fflush(sLogFile
);
36 # define LOG_ERR(text...) LOG(text)
40 # define LOG_ERR(text...) fprintf(stderr, text)
43 #define CALLED() LOG("%s\n", __PRETTY_FUNCTION__)
46 BJoystick::BJoystick()
48 // legacy members for standard mode
57 fDevices(new(std::nothrow
) BList
),
58 fJoystickInfo(new(std::nothrow
) joystick_info
),
59 fJoystickData(new(std::nothrow
) BList
)
62 sLogFile
= fopen("/var/log/joystick.log", "a");
65 if (fJoystickInfo
!= NULL
)
66 memset(fJoystickInfo
, 0, sizeof(joystick_info
));
72 BJoystick::~BJoystick()
77 if (fDevices
!= NULL
) {
78 for (int32 i
= 0; i
< fDevices
->CountItems(); i
++)
79 delete (BString
*)fDevices
->ItemAt(i
);
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
)
93 free(variableJoystick
->data
);
94 delete variableJoystick
;
103 BJoystick::Open(const char *portName
)
106 return Open(portName
, true);
111 BJoystick::Open(const char *portName
, bool enhanced
)
115 if (portName
== NULL
)
118 if (fJoystickInfo
== NULL
|| fJoystickData
== NULL
)
121 fBeBoxMode
= !enhanced
;
124 if (portName
[0] != '/') {
125 snprintf(nameBuffer
, sizeof(nameBuffer
), DEVICE_BASE_PATH
"/%s",
128 snprintf(nameBuffer
, sizeof(nameBuffer
), "%s", portName
);
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
);
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
)
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
);
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
;
197 if (!fJoystickData
->AddItem(variableJoystick
)) {
198 free(variableJoystick
->data
);
199 delete variableJoystick
;
209 BJoystick::Close(void)
223 if (fJoystickInfo
== NULL
|| fJoystickData
== NULL
|| fFD
< 0)
226 for (uint16 i
= 0; i
< fJoystickInfo
->module_info
.num_sticks
; i
++) {
227 variable_joystick
*values
228 = (variable_joystick
*)fJoystickData
->ItemAt(i
);
232 ssize_t result
= read_pos(fFD
, i
, values
->data
,
237 if ((size_t)result
!= values
->data_size
)
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];
251 if (values
->axis_count
>= 2)
252 vertical
= values
->axes
[1];
256 if (values
->button_blocks
> 0) {
257 button1
= (*values
->buttons
& 1) == 0;
258 button2
= (*values
->buttons
& 2) == 0;
270 BJoystick::SetMaxLatency(bigtime_t maxLatency
)
273 if (fJoystickInfo
== NULL
|| fFD
< 0)
276 status_t result
= ioctl(fFD
, B_JOYSTICK_SET_MAX_LATENCY
, &maxLatency
,
279 fJoystickInfo
->max_latency
= maxLatency
;
286 BJoystick::CountDevices()
290 if (fDevices
== NULL
)
293 int32 count
= fDevices
->CountItems();
295 LOG("Count = %d\n", count
);
301 BJoystick::GetDeviceName(int32 index
, char *name
, size_t bufSize
)
304 if (fDevices
== NULL
)
307 if (index
>= fDevices
->CountItems())
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
);
324 BJoystick::RescanDevices()
328 if (fDevices
== NULL
)
337 BJoystick::EnterEnhancedMode(const entry_ref
*ref
)
346 BJoystick::CountSticks()
349 if (fJoystickInfo
== NULL
)
352 return fJoystickInfo
->module_info
.num_sticks
;
357 BJoystick::CountAxes()
360 if (fJoystickInfo
== NULL
)
363 return fJoystickInfo
->module_info
.num_axes
;
368 BJoystick::GetAxisValues(int16
*outValues
, int32 forStick
)
372 if (fJoystickInfo
== NULL
|| fJoystickData
== NULL
)
376 || forStick
>= (int32
)fJoystickInfo
->module_info
.num_sticks
)
379 variable_joystick
*variableJoystick
380 = (variable_joystick
*)fJoystickData
->ItemAt(forStick
);
381 if (variableJoystick
== NULL
)
384 memcpy(outValues
, variableJoystick
->axes
,
385 fJoystickInfo
->module_info
.num_axes
* sizeof(uint16
));
391 BJoystick::GetAxisNameAt(int32 index
, BString
*outName
)
395 if (index
>= CountAxes())
401 // TODO: actually retrieve the name from the driver (via a new ioctl)
409 BJoystick::CountHats()
412 if (fJoystickInfo
== NULL
)
415 return fJoystickInfo
->module_info
.num_hats
;
420 BJoystick::GetHatValues(uint8
*outHats
, int32 forStick
)
424 if (fJoystickInfo
== NULL
|| fJoystickData
== NULL
)
428 || forStick
>= (int32
)fJoystickInfo
->module_info
.num_sticks
)
431 variable_joystick
*variableJoystick
432 = (variable_joystick
*)fJoystickData
->ItemAt(forStick
);
433 if (variableJoystick
== NULL
)
436 memcpy(outHats
, variableJoystick
->hats
,
437 fJoystickInfo
->module_info
.num_hats
);
443 BJoystick::GetHatNameAt(int32 index
, BString
*outName
)
447 if (index
>= CountHats())
453 // TODO: actually retrieve the name from the driver (via a new ioctl)
461 BJoystick::CountButtons()
464 if (fJoystickInfo
== NULL
)
467 return fJoystickInfo
->module_info
.num_buttons
;
472 BJoystick::ButtonValues(int32 forStick
)
476 if (fJoystickInfo
== NULL
|| fJoystickData
== NULL
)
480 || forStick
>= (int32
)fJoystickInfo
->module_info
.num_sticks
)
483 variable_joystick
*variableJoystick
484 = (variable_joystick
*)fJoystickData
->ItemAt(forStick
);
485 if (variableJoystick
== NULL
|| variableJoystick
->button_blocks
== 0)
488 return *variableJoystick
->buttons
;
493 BJoystick::GetButtonValues(bool *outButtons
, int32 forStick
)
497 if (fJoystickInfo
== NULL
|| fJoystickData
== NULL
)
501 || forStick
>= (int32
)fJoystickInfo
->module_info
.num_sticks
)
504 variable_joystick
*variableJoystick
505 = (variable_joystick
*)fJoystickData
->ItemAt(forStick
);
506 if (variableJoystick
== NULL
)
509 int16 buttonCount
= fJoystickInfo
->module_info
.num_buttons
;
510 for (int16 i
= 0; i
< buttonCount
; i
++) {
512 = (variableJoystick
->buttons
[i
/ 32] & (1 << (i
% 32))) != 0;
520 BJoystick::GetButtonNameAt(int32 index
, BString
*outName
)
524 if (index
>= CountButtons())
530 // TODO: actually retrieve the name from the driver (via a new ioctl)
531 *outName
= "Button ";
538 BJoystick::GetControllerModule(BString
*outName
)
541 if (fJoystickInfo
== NULL
|| fFD
< 0)
547 outName
->SetTo(fJoystickInfo
->module_info
.module_name
);
553 BJoystick::GetControllerName(BString
*outName
)
556 if (fJoystickInfo
== NULL
|| fFD
< 0)
562 outName
->SetTo(fJoystickInfo
->module_info
.device_name
);
568 BJoystick::IsCalibrationEnabled()
571 if (fJoystickInfo
== NULL
)
574 return fJoystickInfo
->calibration_enable
;
579 BJoystick::EnableCalibration(bool calibrates
)
582 if (fJoystickInfo
== NULL
|| fFD
< 0)
585 status_t result
= ioctl(fFD
, B_JOYSTICK_SET_RAW_MODE
, &calibrates
,
588 fJoystickInfo
->calibration_enable
= calibrates
;
595 BJoystick::Calibrate(struct _extended_joystick
*reading
)
602 BJoystick::ScanDevices(bool 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
; }