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->module_info, 0, sizeof(joystick_module_info)); 67 fJoystickInfo->calibration_enable = false; 68 fJoystickInfo->max_latency = 0; 69 } 70 71 RescanDevices(); 72 } 73 74 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 106 BJoystick::Open(const char *portName) 107 { 108 CALLED(); 109 return Open(portName, true); 110 } 111 112 113 status_t 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 212 BJoystick::Close(void) 213 { 214 CALLED(); 215 if (fFD >= 0) { 216 close(fFD); 217 fFD = -1; 218 } 219 } 220 221 222 status_t 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 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 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 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 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 340 BJoystick::EnterEnhancedMode(const entry_ref *ref) 341 { 342 CALLED(); 343 fBeBoxMode = false; 344 return !fBeBoxMode; 345 } 346 347 348 int32 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 598 BJoystick::Calibrate(struct _extended_joystick *reading) 599 { 600 CALLED(); 601 } 602 603 604 void 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 618 void BJoystick::_ReservedJoystick1() {} 619 void BJoystick::_ReservedJoystick2() {} 620 void BJoystick::_ReservedJoystick3() {} 621 status_t BJoystick::_Reserved_Joystick_4(void*, ...) { return B_ERROR; } 622 status_t BJoystick::_Reserved_Joystick_5(void*, ...) { return B_ERROR; } 623 status_t BJoystick::_Reserved_Joystick_6(void*, ...) { return B_ERROR; } 624