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