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 // signal that we support variable reads 145 fJoystickInfo->module_info.flags |= js_flag_variable_size_reads; 146 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); 153 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; 168 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(); 182 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; 190 } 191 192 if (result != B_OK) { 193 delete variableJoystick; 194 return result; 195 } 196 197 if (!fJoystickData->AddItem(variableJoystick)) { 198 free(variableJoystick->data); 199 delete variableJoystick; 200 return B_NO_MEMORY; 201 } 202 } 203 204 return fFD; 205 } 206 207 208 void 209 BJoystick::Close(void) 210 { 211 CALLED(); 212 if (fFD >= 0) { 213 close(fFD); 214 fFD = -1; 215 } 216 } 217 218 219 status_t 220 BJoystick::Update() 221 { 222 CALLED(); 223 if (fJoystickInfo == NULL || fJoystickData == NULL || fFD < 0) 224 return B_NO_INIT; 225 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; 231 232 ssize_t result = read_pos(fFD, i, values->data, 233 values->data_size); 234 if (result < 0) 235 return result; 236 237 if ((size_t)result != values->data_size) 238 return B_ERROR; 239 240 if (i > 0) 241 continue; 242 243 // fill in the legacy values for the first stick 244 timestamp = *values->timestamp; 245 246 if (values->axis_count >= 1) 247 horizontal = values->axes[0]; 248 else 249 horizontal = 0; 250 251 if (values->axis_count >= 2) 252 vertical = values->axes[1]; 253 else 254 vertical = 0; 255 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; 262 } 263 } 264 265 return B_OK; 266 } 267 268 269 status_t 270 BJoystick::SetMaxLatency(bigtime_t maxLatency) 271 { 272 CALLED(); 273 if (fJoystickInfo == NULL || fFD < 0) 274 return B_NO_INIT; 275 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; 280 281 return result; 282 } 283 284 285 int32 286 BJoystick::CountDevices() 287 { 288 CALLED(); 289 290 if (fDevices == NULL) 291 return 0; 292 293 int32 count = fDevices->CountItems(); 294 295 LOG("Count = %d\n", count); 296 return count; 297 } 298 299 300 status_t 301 BJoystick::GetDeviceName(int32 index, char *name, size_t bufSize) 302 { 303 CALLED(); 304 if (fDevices == NULL) 305 return B_NO_INIT; 306 307 if (index >= fDevices->CountItems()) 308 return B_BAD_INDEX; 309 310 if (name == NULL) 311 return B_BAD_VALUE; 312 313 BString *deviceName = (BString *)fDevices->ItemAt(index); 314 if (deviceName->Length() > (int32)bufSize) 315 return B_NAME_TOO_LONG; 316 317 strlcpy(name, deviceName->String(), bufSize); 318 LOG("Device Name = %s\n", name); 319 return B_OK; 320 } 321 322 323 status_t 324 BJoystick::RescanDevices() 325 { 326 CALLED(); 327 328 if (fDevices == NULL) 329 return B_NO_INIT; 330 331 ScanDevices(true); 332 return B_OK; 333 } 334 335 336 bool 337 BJoystick::EnterEnhancedMode(const entry_ref *ref) 338 { 339 CALLED(); 340 fBeBoxMode = false; 341 return !fBeBoxMode; 342 } 343 344 345 int32 346 BJoystick::CountSticks() 347 { 348 CALLED(); 349 if (fJoystickInfo == NULL) 350 return 0; 351 352 return fJoystickInfo->module_info.num_sticks; 353 } 354 355 356 int32 357 BJoystick::CountAxes() 358 { 359 CALLED(); 360 if (fJoystickInfo == NULL) 361 return 0; 362 363 return fJoystickInfo->module_info.num_axes; 364 } 365 366 367 status_t 368 BJoystick::GetAxisValues(int16 *outValues, int32 forStick) 369 { 370 CALLED(); 371 372 if (fJoystickInfo == NULL || fJoystickData == NULL) 373 return B_NO_INIT; 374 375 if (forStick < 0 376 || forStick >= (int32)fJoystickInfo->module_info.num_sticks) 377 return B_BAD_INDEX; 378 379 variable_joystick *variableJoystick 380 = (variable_joystick *)fJoystickData->ItemAt(forStick); 381 if (variableJoystick == NULL) 382 return B_NO_INIT; 383 384 memcpy(outValues, variableJoystick->axes, 385 fJoystickInfo->module_info.num_axes * sizeof(uint16)); 386 return B_OK; 387 } 388 389 390 status_t 391 BJoystick::GetAxisNameAt(int32 index, BString *outName) 392 { 393 CALLED(); 394 395 if (index >= CountAxes()) 396 return B_BAD_INDEX; 397 398 if (outName == NULL) 399 return B_BAD_VALUE; 400 401 // TODO: actually retrieve the name from the driver (via a new ioctl) 402 *outName = "Axis "; 403 *outName << index; 404 return B_OK; 405 } 406 407 408 int32 409 BJoystick::CountHats() 410 { 411 CALLED(); 412 if (fJoystickInfo == NULL) 413 return 0; 414 415 return fJoystickInfo->module_info.num_hats; 416 } 417 418 419 status_t 420 BJoystick::GetHatValues(uint8 *outHats, int32 forStick) 421 { 422 CALLED(); 423 424 if (fJoystickInfo == NULL || fJoystickData == NULL) 425 return B_NO_INIT; 426 427 if (forStick < 0 428 || forStick >= (int32)fJoystickInfo->module_info.num_sticks) 429 return B_BAD_INDEX; 430 431 variable_joystick *variableJoystick 432 = (variable_joystick *)fJoystickData->ItemAt(forStick); 433 if (variableJoystick == NULL) 434 return B_NO_INIT; 435 436 memcpy(outHats, variableJoystick->hats, 437 fJoystickInfo->module_info.num_hats); 438 return B_OK; 439 } 440 441 442 status_t 443 BJoystick::GetHatNameAt(int32 index, BString *outName) 444 { 445 CALLED(); 446 447 if (index >= CountHats()) 448 return B_BAD_INDEX; 449 450 if (outName == NULL) 451 return B_BAD_VALUE; 452 453 // TODO: actually retrieve the name from the driver (via a new ioctl) 454 *outName = "Hat "; 455 *outName << index; 456 return B_OK; 457 } 458 459 460 int32 461 BJoystick::CountButtons() 462 { 463 CALLED(); 464 if (fJoystickInfo == NULL) 465 return 0; 466 467 return fJoystickInfo->module_info.num_buttons; 468 } 469 470 471 uint32 472 BJoystick::ButtonValues(int32 forStick) 473 { 474 CALLED(); 475 476 if (fJoystickInfo == NULL || fJoystickData == NULL) 477 return 0; 478 479 if (forStick < 0 480 || forStick >= (int32)fJoystickInfo->module_info.num_sticks) 481 return 0; 482 483 variable_joystick *variableJoystick 484 = (variable_joystick *)fJoystickData->ItemAt(forStick); 485 if (variableJoystick == NULL || variableJoystick->button_blocks == 0) 486 return 0; 487 488 return *variableJoystick->buttons; 489 } 490 491 492 status_t 493 BJoystick::GetButtonValues(bool *outButtons, int32 forStick) 494 { 495 CALLED(); 496 497 if (fJoystickInfo == NULL || fJoystickData == NULL) 498 return B_NO_INIT; 499 500 if (forStick < 0 501 || forStick >= (int32)fJoystickInfo->module_info.num_sticks) 502 return B_BAD_INDEX; 503 504 variable_joystick *variableJoystick 505 = (variable_joystick *)fJoystickData->ItemAt(forStick); 506 if (variableJoystick == NULL) 507 return B_NO_INIT; 508 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; 513 } 514 515 return B_OK; 516 } 517 518 519 status_t 520 BJoystick::GetButtonNameAt(int32 index, BString *outName) 521 { 522 CALLED(); 523 524 if (index >= CountButtons()) 525 return B_BAD_INDEX; 526 527 if (outName == NULL) 528 return B_BAD_VALUE; 529 530 // TODO: actually retrieve the name from the driver (via a new ioctl) 531 *outName = "Button "; 532 *outName << index; 533 return B_OK; 534 } 535 536 537 status_t 538 BJoystick::GetControllerModule(BString *outName) 539 { 540 CALLED(); 541 if (fJoystickInfo == NULL || fFD < 0) 542 return B_NO_INIT; 543 544 if (outName == NULL) 545 return B_BAD_VALUE; 546 547 outName->SetTo(fJoystickInfo->module_info.module_name); 548 return B_OK; 549 } 550 551 552 status_t 553 BJoystick::GetControllerName(BString *outName) 554 { 555 CALLED(); 556 if (fJoystickInfo == NULL || fFD < 0) 557 return B_NO_INIT; 558 559 if (outName == NULL) 560 return B_BAD_VALUE; 561 562 outName->SetTo(fJoystickInfo->module_info.device_name); 563 return B_OK; 564 } 565 566 567 bool 568 BJoystick::IsCalibrationEnabled() 569 { 570 CALLED(); 571 if (fJoystickInfo == NULL) 572 return false; 573 574 return fJoystickInfo->calibration_enable; 575 } 576 577 578 status_t 579 BJoystick::EnableCalibration(bool calibrates) 580 { 581 CALLED(); 582 if (fJoystickInfo == NULL || fFD < 0) 583 return B_NO_INIT; 584 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; 589 590 return result; 591 } 592 593 594 void 595 BJoystick::Calibrate(struct _extended_joystick *reading) 596 { 597 CALLED(); 598 } 599 600 601 void 602 BJoystick::ScanDevices(bool useDisabled) 603 { 604 CALLED(); 605 if (useDisabled) { 606 _BJoystickTweaker joystickTweaker(*this); 607 joystickTweaker.scan_including_disabled(); 608 } 609 } 610 611 612 // #pragma mark - FBC protection 613 614 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; } 621