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 status_t 178 BJoystick::Update() 179 { 180 CALLED(); 181 if (fJoystickInfo == NULL || fExtendedJoystick == NULL || fFD < 0) 182 return B_NO_INIT; 183 184 for (uint16 i = 0; i < fJoystickInfo->module_info.num_sticks; i++) { 185 extended_joystick *extendedJoystick 186 = (extended_joystick *)fExtendedJoystick->ItemAt(i); 187 if (extendedJoystick == NULL) 188 return B_NO_INIT; 189 190 ssize_t result = read_pos(fFD, i, extendedJoystick, 191 sizeof(extended_joystick)); 192 if (result < 0) 193 return result; 194 195 if (result != sizeof(extended_joystick)) 196 return B_ERROR; 197 198 if (i > 0) 199 continue; 200 201 // fill in the legacy values for the first stick 202 timestamp = extendedJoystick->timestamp; 203 horizontal = extendedJoystick->axes[0]; 204 vertical = extendedJoystick->axes[1]; 205 button1 = (extendedJoystick->buttons & 1) == 0; 206 button2 = (extendedJoystick->buttons & 2) == 0; 207 } 208 209 return B_OK; 210 } 211 212 213 status_t 214 BJoystick::SetMaxLatency(bigtime_t maxLatency) 215 { 216 CALLED(); 217 if (fJoystickInfo == NULL || fFD < 0) 218 return B_NO_INIT; 219 220 status_t result = ioctl(fFD, B_JOYSTICK_SET_MAX_LATENCY, &maxLatency, 221 sizeof(maxLatency)); 222 if (result == B_OK) 223 fJoystickInfo->max_latency = maxLatency; 224 225 return result; 226 } 227 228 229 int32 230 BJoystick::CountDevices() 231 { 232 CALLED(); 233 234 if (fDevices == NULL) 235 return 0; 236 237 int32 count = fDevices->CountItems(); 238 239 LOG("Count = %d\n", count); 240 return count; 241 } 242 243 244 status_t 245 BJoystick::GetDeviceName(int32 index, char *name, size_t bufSize) 246 { 247 CALLED(); 248 if (fDevices == NULL) 249 return B_NO_INIT; 250 251 if (index >= fDevices->CountItems()) 252 return B_BAD_INDEX; 253 254 if (name == NULL) 255 return B_BAD_VALUE; 256 257 BString *deviceName = (BString *)fDevices->ItemAt(index); 258 if (deviceName->Length() > (int32)bufSize) 259 return B_NAME_TOO_LONG; 260 261 strlcpy(name, deviceName->String(), bufSize); 262 LOG("Device Name = %s\n", name); 263 return B_OK; 264 } 265 266 267 status_t 268 BJoystick::RescanDevices() 269 { 270 CALLED(); 271 272 if (fDevices == NULL) 273 return B_NO_INIT; 274 275 ScanDevices(true); 276 return B_OK; 277 } 278 279 280 bool 281 BJoystick::EnterEnhancedMode(const entry_ref *ref) 282 { 283 CALLED(); 284 fBeBoxMode = false; 285 return !fBeBoxMode; 286 } 287 288 289 int32 290 BJoystick::CountSticks() 291 { 292 CALLED(); 293 if (fJoystickInfo == NULL) 294 return 0; 295 296 return fJoystickInfo->module_info.num_sticks; 297 } 298 299 300 int32 301 BJoystick::CountAxes() 302 { 303 CALLED(); 304 if (fJoystickInfo == NULL) 305 return 0; 306 307 return fJoystickInfo->module_info.num_axes; 308 } 309 310 311 status_t 312 BJoystick::GetAxisValues(int16 *outValues, int32 forStick) 313 { 314 CALLED(); 315 316 if (fJoystickInfo == NULL || fExtendedJoystick == NULL) 317 return B_NO_INIT; 318 319 if (forStick < 0 320 || forStick >= (int32)fJoystickInfo->module_info.num_sticks) 321 return B_BAD_INDEX; 322 323 extended_joystick *extendedJoystick 324 = (extended_joystick *)fExtendedJoystick->ItemAt(forStick); 325 if (extendedJoystick == NULL) 326 return B_NO_INIT; 327 328 memcpy(outValues, extendedJoystick->axes, 329 fJoystickInfo->module_info.num_axes * sizeof(uint16)); 330 return B_OK; 331 } 332 333 334 status_t 335 BJoystick::GetAxisNameAt(int32 index, BString *outName) 336 { 337 CALLED(); 338 339 if (index >= CountAxes()) 340 return B_BAD_INDEX; 341 342 if (outName == NULL) 343 return B_BAD_VALUE; 344 345 // TODO: actually retrieve the name from the driver (via a new ioctl) 346 *outName = "Axis "; 347 *outName << index; 348 return B_OK; 349 } 350 351 352 int32 353 BJoystick::CountHats() 354 { 355 CALLED(); 356 if (fJoystickInfo == NULL) 357 return 0; 358 359 return fJoystickInfo->module_info.num_hats; 360 } 361 362 363 status_t 364 BJoystick::GetHatValues(uint8 *outHats, int32 forStick) 365 { 366 CALLED(); 367 368 if (fJoystickInfo == NULL || fExtendedJoystick == NULL) 369 return B_NO_INIT; 370 371 if (forStick < 0 372 || forStick >= (int32)fJoystickInfo->module_info.num_sticks) 373 return B_BAD_INDEX; 374 375 extended_joystick *extendedJoystick 376 = (extended_joystick *)fExtendedJoystick->ItemAt(forStick); 377 if (extendedJoystick == NULL) 378 return B_NO_INIT; 379 380 memcpy(outHats, extendedJoystick->hats, 381 fJoystickInfo->module_info.num_hats); 382 return B_OK; 383 } 384 385 386 status_t 387 BJoystick::GetHatNameAt(int32 index, BString *outName) 388 { 389 CALLED(); 390 391 if (index >= CountHats()) 392 return B_BAD_INDEX; 393 394 if (outName == NULL) 395 return B_BAD_VALUE; 396 397 // TODO: actually retrieve the name from the driver (via a new ioctl) 398 *outName = "Hat "; 399 *outName << index; 400 return B_OK; 401 } 402 403 404 int32 405 BJoystick::CountButtons() 406 { 407 CALLED(); 408 if (fJoystickInfo == NULL) 409 return 0; 410 411 return fJoystickInfo->module_info.num_buttons; 412 } 413 414 415 uint32 416 BJoystick::ButtonValues(int32 forStick) 417 { 418 CALLED(); 419 420 if (fJoystickInfo == NULL || fExtendedJoystick == NULL) 421 return 0; 422 423 if (forStick < 0 424 || forStick >= (int32)fJoystickInfo->module_info.num_sticks) 425 return 0; 426 427 extended_joystick *extendedJoystick 428 = (extended_joystick *)fExtendedJoystick->ItemAt(forStick); 429 if (extendedJoystick == NULL) 430 return 0; 431 432 return extendedJoystick->buttons; 433 } 434 435 436 status_t 437 BJoystick::GetButtonNameAt(int32 index, BString *outName) 438 { 439 CALLED(); 440 441 if (index >= CountButtons()) 442 return B_BAD_INDEX; 443 444 if (outName == NULL) 445 return B_BAD_VALUE; 446 447 // TODO: actually retrieve the name from the driver (via a new ioctl) 448 *outName = "Button "; 449 *outName << index; 450 return B_OK; 451 } 452 453 454 status_t 455 BJoystick::GetControllerModule(BString *outName) 456 { 457 CALLED(); 458 if (fJoystickInfo == NULL || fFD < 0) 459 return B_NO_INIT; 460 461 if (outName == NULL) 462 return B_BAD_VALUE; 463 464 outName->SetTo(fJoystickInfo->module_info.module_name); 465 return B_OK; 466 } 467 468 469 status_t 470 BJoystick::GetControllerName(BString *outName) 471 { 472 CALLED(); 473 if (fJoystickInfo == NULL || fFD < 0) 474 return B_NO_INIT; 475 476 if (outName == NULL) 477 return B_BAD_VALUE; 478 479 outName->SetTo(fJoystickInfo->module_info.device_name); 480 return B_OK; 481 } 482 483 484 bool 485 BJoystick::IsCalibrationEnabled() 486 { 487 CALLED(); 488 if (fJoystickInfo == NULL) 489 return false; 490 491 return fJoystickInfo->calibration_enable; 492 } 493 494 495 status_t 496 BJoystick::EnableCalibration(bool calibrates) 497 { 498 CALLED(); 499 if (fJoystickInfo == NULL || fFD < 0) 500 return B_NO_INIT; 501 502 status_t result = ioctl(fFD, B_JOYSTICK_SET_RAW_MODE, &calibrates, 503 sizeof(calibrates)); 504 if (result == B_OK) 505 fJoystickInfo->calibration_enable = calibrates; 506 507 return result; 508 } 509 510 511 void 512 BJoystick::Calibrate(struct _extended_joystick *reading) 513 { 514 CALLED(); 515 } 516 517 518 void 519 BJoystick::ScanDevices(bool useDisabled) 520 { 521 CALLED(); 522 if (useDisabled) { 523 _BJoystickTweaker joystickTweaker(*this); 524 joystickTweaker.scan_including_disabled(); 525 } 526 } 527 528 529 // #pragma mark - FBC protection 530 531 532 void BJoystick::_ReservedJoystick1() {} 533 void BJoystick::_ReservedJoystick2() {} 534 void BJoystick::_ReservedJoystick3() {} 535 status_t BJoystick::_Reserved_Joystick_4(void*, ...) { return B_ERROR; } 536 status_t BJoystick::_Reserved_Joystick_5(void*, ...) { return B_ERROR; } 537 status_t BJoystick::_Reserved_Joystick_6(void*, ...) { return B_ERROR; } 538