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 23static FILE *sLogFile = NULL; 24 25inline void 26LOG(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 46BJoystick::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 75BJoystick::~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 105status_t 106BJoystick::Open(const char *portName) 107{ 108 CALLED(); 109 return Open(portName, true); 110} 111 112 113status_t 114BJoystick::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 211void 212BJoystick::Close(void) 213{ 214 CALLED(); 215 if (fFD >= 0) { 216 close(fFD); 217 fFD = -1; 218 } 219} 220 221 222status_t 223BJoystick::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 272status_t 273BJoystick::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 288int32 289BJoystick::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 303status_t 304BJoystick::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 326status_t 327BJoystick::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 339bool 340BJoystick::EnterEnhancedMode(const entry_ref *ref) 341{ 342 CALLED(); 343 fBeBoxMode = false; 344 return !fBeBoxMode; 345} 346 347 348int32 349BJoystick::CountSticks() 350{ 351 CALLED(); 352 if (fJoystickInfo == NULL) 353 return 0; 354 355 return fJoystickInfo->module_info.num_sticks; 356} 357 358 359int32 360BJoystick::CountAxes() 361{ 362 CALLED(); 363 if (fJoystickInfo == NULL) 364 return 0; 365 366 return fJoystickInfo->module_info.num_axes; 367} 368 369 370status_t 371BJoystick::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 393status_t 394BJoystick::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 411int32 412BJoystick::CountHats() 413{ 414 CALLED(); 415 if (fJoystickInfo == NULL) 416 return 0; 417 418 return fJoystickInfo->module_info.num_hats; 419} 420 421 422status_t 423BJoystick::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 445status_t 446BJoystick::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 463int32 464BJoystick::CountButtons() 465{ 466 CALLED(); 467 if (fJoystickInfo == NULL) 468 return 0; 469 470 return fJoystickInfo->module_info.num_buttons; 471} 472 473 474uint32 475BJoystick::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 495status_t 496BJoystick::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 522status_t 523BJoystick::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 540status_t 541BJoystick::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 555status_t 556BJoystick::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 570bool 571BJoystick::IsCalibrationEnabled() 572{ 573 CALLED(); 574 if (fJoystickInfo == NULL) 575 return false; 576 577 return fJoystickInfo->calibration_enable; 578} 579 580 581status_t 582BJoystick::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 597void 598BJoystick::Calibrate(struct _extended_joystick *reading) 599{ 600 CALLED(); 601} 602 603 604void 605BJoystick::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 618void BJoystick::_ReservedJoystick1() {} 619void BJoystick::_ReservedJoystick2() {} 620void BJoystick::_ReservedJoystick3() {} 621status_t BJoystick::_Reserved_Joystick_4(void*, ...) { return B_ERROR; } 622status_t BJoystick::_Reserved_Joystick_5(void*, ...) { return B_ERROR; } 623status_t BJoystick::_Reserved_Joystick_6(void*, ...) { return B_ERROR; } 624