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