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