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