00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034
00035 #include "linux-input.h"
00036
00037 #include <linux/input.h>
00038 #include <sstream>
00039
00040 #include "perf/perf.h"
00041 #include "util/file.h"
00042
00043
00044 namespace gamepad {
00045
00046
00047
00048 static const char * s_devicePath = "/dev/input/";
00049 static const char * s_prefix = "LinuxInput";
00050
00051 static SetString s_devicePaths;
00052
00053 enum eFFState {
00054 eFF_NotLoaded = 1,
00055 eFF_Loaded = 2,
00056 eFF_Playing = 3,
00057
00058
00059 eFF_Invalid = 0
00060 };
00061
00062
00063
00064 struct rumble_t {
00065
00066 rumble_t(void) throw() { this->clear(); }
00067 void clear(void) throw() {
00068 state = eFF_Invalid;
00069 id = -1;
00070 }
00071
00072
00073 eFFState state;
00074 int id;
00075 };
00076
00077
00078
00079
00080
00081
00082
00083
00084 static bool
00085 test_bit
00086 (
00087 IN int bit,
00088 IN const byte_t * array
00089 )
00090 {
00091 ASSERT(bit >= 0, "Bad bit: %d", bit);
00092 ASSERT(array, "null");
00093
00094 int offset = bit / 8;
00095 byte_t b = array[offset];
00096 byte_t mask = 1 << (bit % 8);
00097 return b & mask;
00098 }
00099
00100
00101
00102 #define DUMP_EVBIT(name, desc) { \
00103 if (test_bit(EV_ ##name , pb)) { DPRINTF(" %s", desc); } \
00104 }
00105
00106 static void
00107 dumpCapabilities
00108 (
00109 IN const byte_t * pb
00110 )
00111 throw()
00112 {
00113 ASSERT(pb, "null");
00114
00115 DPRINTF("Device capabilities:");
00116 DUMP_EVBIT(SYN, "Synchronizes");
00117 DUMP_EVBIT(KEY, "Buttons/keys");
00118 DUMP_EVBIT(REL, "Relative input");
00119 DUMP_EVBIT(ABS, "Absolute input");
00120 DUMP_EVBIT(MSC, "Miscellaneous");
00121 DUMP_EVBIT(SW, "Switch");
00122 DUMP_EVBIT(LED, "LEDs");
00123 DUMP_EVBIT(SND, "Sound");
00124 DUMP_EVBIT(REP, "Repeat events");
00125 DUMP_EVBIT(FF, "Force Feedback");
00126 DUMP_EVBIT(PWR, "Power management");
00127 DUMP_EVBIT(FF_STATUS, "Force feedback status");
00128 }
00129
00130
00131
00132 static int
00133 getIndex
00134 (
00135 IN int value,
00136 IN const int * map,
00137 IN int size
00138 )
00139 {
00140 THROW(value >= 0, "Bad input index value: " << value);
00141 ASSERT(map, "null");
00142 ASSERT(size > 0, "Bad map size: %d", size);
00143
00144 for (int i = 0; i < size; ++i) {
00145 if (value == map[i])
00146 return i;
00147 }
00148
00149
00150
00151 DPRINTF("WARNING: input index not found in map? %d", value);
00152
00153 return -1;
00154 }
00155
00156
00157
00158 static bool
00159 isInputEntry
00160 (
00161 IN smart_fd& fd
00162 )
00163 {
00164 ASSERT(fd, "invalid");
00165
00166
00167 byte_t eventTypes[(EV_MAX + 7) / 8];
00168 if (ioctl(fd, EVIOCGBIT(0, sizeof(eventTypes)), eventTypes) < 0) {
00169 return false;
00170 }
00171
00172
00173
00174 if (!test_bit(EV_KEY, eventTypes) ||
00175 !test_bit(EV_ABS, eventTypes)) {
00176 return false;
00177 }
00178
00179
00180
00181 byte_t potTypes[(ABS_MAX + 7) / 8];
00182 byte_t keyTypes[(KEY_MAX + 7) / 8];
00183 if (ioctl(fd, EVIOCGBIT(EV_ABS, sizeof(potTypes)), potTypes) < 0 ||
00184 ioctl(fd, EVIOCGBIT(EV_KEY, sizeof(keyTypes)), keyTypes) < 0) {
00185 return false;
00186 }
00187
00188 if (!test_bit(ABS_X, potTypes) || !test_bit(ABS_Y, potTypes)) {
00189 return false;
00190 }
00191 if (test_bit(BTN_TRIGGER, keyTypes) ||
00192 test_bit(BTN_A, keyTypes) ||
00193 test_bit(BTN_1, keyTypes)) {
00194 return true;
00195 }
00196
00197
00198 return false;
00199 }
00200
00201
00202
00203 const char *
00204 getInputIndex
00205 (
00206 IN const char * path
00207 )
00208 {
00209 ASSERT(path, "null");
00210
00211 const char * key = "/dev/input/event";
00212
00213 const char * p = strstr(path, key);
00214 THROW(p, "Bad joystick device path: " << path);
00215
00216 p += strlen(key);
00217
00218 DPRINTF("path: '%s' --> index '%s'", path, p);
00219 return p;
00220 }
00221
00222
00223
00224
00225
00226
00227
00228
00229
00230
00231 class LIDevice : public SourceDevice {
00232 public:
00233
00234 LIDevice(void) throw();
00235 ~LIDevice(void) throw();
00236
00237
00238 void initialize(IN const char * path,
00239 IN bool wantForceFeedback);
00240
00241
00242 const char * getPublicName(void) throw() { return m_name.c_str(); }
00243 const char * getUniqueId(void) throw() { return m_uid.c_str(); }
00244 eDeviceState getState(void) throw();
00245 int getNumPots(void) throw() { return m_nPots; }
00246 int getNumButtons(void) throw() { return m_nButtons; }
00247 void poll(void) throw();
00248 const pot_value_t& getPotValue(IN int potIndex);
00249 eButton getButtonValue(IN int buttonIndex);
00250
00251
00252
00253
00254
00255
00256
00257
00258
00259 private:
00260
00261
00262 std::string m_path;
00263 std::string m_name;
00264 std::string m_uid;
00265 smart_fd m_fd;
00266 byte_t m_eventTypes[(EV_MAX + 7) / 8];
00267 int m_nPots;
00268 int m_nButtons;
00269 std::vector<int> m_buttonMap;
00270 std::vector<int> m_potMap;
00271 std::vector<byte_t> m_button;
00272 std::vector<pot_value_t> m_pot;
00273 std::vector<rumble_t> m_rumble;
00274 };
00275
00276
00277 LIDevice::LIDevice(void)
00278 throw()
00279 {
00280 m_nPots = 0;
00281 m_nButtons = 0;
00282 }
00283
00284
00285 LIDevice::~LIDevice(void)
00286 throw()
00287 {
00288 }
00289
00290
00291
00292
00293
00294
00295
00296
00297
00298 void
00299 LIDevice::initialize
00300 (
00301 IN const char * path,
00302 IN bool wantForceFeedback
00303 )
00304 {
00305 perf::Timer timer("LinuxInputDevice::initialize()");
00306 ASSERT(path, "null");
00307
00308 DPRINTF("Opening linux joystick source device: '%s'", path);
00309
00310
00311 if (wantForceFeedback) {
00312 DPRINTF("Enabling force feedback.");
00313 DPRINTF("Watch out for kernel crashes when you unplug the gamepad!");
00314 }
00315
00316
00317 m_path = path;
00318
00319
00320 THROW(m_fd.open(path, O_RDWR),
00321 "Failed to open linux joystick device: " << path);
00322
00323
00324 char buffer[256];
00325 THROW(ioctl(m_fd, EVIOCGNAME(sizeof(buffer)), buffer) >= 0,
00326 "Failed to acquire linux joystick device name");
00327 m_name = buffer;
00328 DPRINTF(" public name: '%s'", m_name.c_str());
00329
00330
00331 struct input_id iid;
00332 THROW(ioctl(m_fd, EVIOCGID, &iid) >= 0,
00333 "Failed to acquire event input ID data");
00334
00335
00336 std::ostringstream out;
00337 out << s_prefix << ",";
00338 out << buffer << ",";
00339 out << "vendor:" << iid.vendor << ",";
00340 out << "product:" << iid.product << ",";
00341 out << "version:" << iid.version << ",";
00342 out << "idx:" << getInputIndex(path);
00343
00344 m_uid = out.str();
00345 DPRINTF(" unique ID: '%s'", m_uid.c_str());
00346
00347
00348 THROW(ioctl(m_fd, EVIOCGBIT(0, sizeof(m_eventTypes)), m_eventTypes) >= 0,
00349 "Failed to acquire device capabilities");
00350 dumpCapabilities(m_eventTypes);
00351
00352
00353 THROW(test_bit(EV_KEY, m_eventTypes),
00354 "Device reported no buttons/keys");
00355 m_buttonMap.clear();
00356 byte_t keyStats[(KEY_MAX + 7) / 8];
00357 THROW(ioctl(m_fd, EVIOCGBIT(EV_KEY, sizeof(keyStats)), keyStats) >= 0,
00358 "Failed to retrieve key/button bitfield");
00359 for (int i = 0; i < KEY_MAX; ++i) {
00360 if (test_bit(i, keyStats)) {
00361 m_buttonMap.push_back(i);
00362 m_button.push_back(eButtonUp);
00363 }
00364 }
00365 m_nButtons = m_buttonMap.size();
00366 DPRINTF("Found %d buttons on device", m_nButtons);
00367
00368
00369 THROW(test_bit(EV_ABS, m_eventTypes),
00370 "Device reported no potentiometers");
00371 m_potMap.clear();
00372 byte_t potStats[(ABS_MAX + 7) / 8];
00373 THROW(ioctl(m_fd, EVIOCGBIT(EV_ABS, sizeof(potStats)), potStats) >= 0,
00374 "Failed to retrieve absolute potentiometer bitfield");
00375 for (int i = 0; i < ABS_MAX; ++i) {
00376 if (test_bit(i, potStats)) {
00377 m_potMap.push_back(i);
00378 pot_value_t pv;
00379 m_pot.push_back(pv);
00380 }
00381 }
00382 m_nPots = m_potMap.size();
00383 DPRINTF("Found %d potentiometers on device", m_nPots);
00384
00385
00386
00387
00388
00389
00390
00391
00392
00393
00394
00395
00396
00397
00398
00399
00400
00401
00402
00403
00404
00405
00406
00407
00408
00409
00410
00411
00412
00413
00414
00415
00416
00417
00418
00419
00420 THROW(!fcntl(m_fd, F_SETFL, O_NONBLOCK),
00421 "Failed to set linux joystick device to nonblocking i/o");
00422 }
00423
00424
00425
00426
00427
00428
00429
00430
00431
00432 eDeviceState
00433 LIDevice::getState
00434 (
00435 void
00436 )
00437 throw()
00438 {
00439 if (s_devicePaths.end() == s_devicePaths.find(m_path.c_str())) {
00440
00441 return eDevice_Detached;
00442 }
00443
00444
00445 return eDevice_Attached;
00446 }
00447
00448
00449
00450 void
00451 LIDevice::poll
00452 (
00453 void
00454 )
00455 throw()
00456 {
00457 ASSERT(m_fd, "need to open device first");
00458
00459
00460 for (int i = 0; i < m_nButtons; ++i) {
00461 m_button[i] &= ~eButtonWasPushed;
00462 m_button[i] &= ~eButtonWasReleased;
00463 }
00464
00465
00466 struct input_event event[32];
00467 while (true) {
00468 int len = read(m_fd, event, sizeof(event));
00469 if (len <= 0) {
00470 break;
00471 }
00472
00473 int nEvents = len / sizeof(event[0]);
00474 for (int i = 0; i < nEvents; ++i) {
00475 int idx = -1;
00476 switch (event[i].type) {
00477 case EV_ABS:
00478 idx = getIndex(event[i].code, m_potMap.data(), m_nPots);
00479 if (idx >= 0 && idx < m_nPots) {
00480 pot_value_t& pv = m_pot[idx];
00481 pv.value = event[i].value;
00482 if (pv.value < pv.minSeen) {
00483 pv.minSeen = pv.value;
00484 }
00485 if (pv.value > pv.maxSeen) {
00486 pv.maxSeen = pv.value;
00487 }
00488 }
00489 break;
00490
00491 case EV_KEY:
00492 idx = getIndex(event[i].code, m_buttonMap.data(), m_nButtons);
00493 if (idx < 0 || idx >= m_nButtons)
00494 break;
00495 if (event[i].value) {
00496
00497 m_button[idx] |= eButtonWasPushed;
00498 m_button[idx] |= eButtonDown;
00499 } else {
00500
00501 m_button[idx] &= ~eButtonDown;
00502
00503
00504 m_button[idx] |= eButtonWasReleased;
00505 }
00506 break;
00507 }
00508 }
00509 }
00510 }
00511
00512
00513
00514 const pot_value_t&
00515 LIDevice::getPotValue
00516 (
00517 IN int potIndex
00518 )
00519 {
00520 THROW(potIndex >= 0 && potIndex < m_nPots,
00521 "Bad pot index: " << potIndex);
00522 return m_pot[potIndex];
00523 }
00524
00525
00526
00527 eButton
00528 LIDevice::getButtonValue
00529 (
00530 IN int buttonIndex
00531 )
00532 {
00533 THROW(buttonIndex >= 0 && buttonIndex < m_nButtons,
00534 "Bad button index: " << buttonIndex);
00535 return (eButton) m_button[buttonIndex];
00536 }
00537
00538
00539
00540
00541
00542
00543
00544
00545
00546
00547
00548
00549
00550
00551
00552
00553
00554
00555
00556
00557
00558
00559
00560
00561
00562
00563
00564
00565
00566
00567
00568
00569
00570
00571
00572
00573
00574
00575
00576
00577
00578
00579
00580
00581
00582
00583
00584
00585
00586
00587
00588
00589
00590
00591
00592
00593
00594
00595
00596
00597
00598
00599
00600
00601
00602
00603
00604
00605
00606
00607
00608
00609
00610
00611
00612
00613
00614
00615
00616
00617
00618
00619 static void
00620 refreshLinuxInputDevicePaths
00621 (
00622 void
00623 )
00624 {
00625 perf::Timer timer("refreshLinuxInputDevicePaths");
00626
00627
00628 smart_dir dir;
00629 dir.open(s_devicePath);
00630 ASSERT(dir, "should have a valid open directory now");
00631
00632
00633 SetString newSet;
00634 struct dirent entry;
00635 while (dir.getNextEntry(entry)) {
00636
00637 if (strncmp("event", entry.d_name, 5)) {
00638 continue;
00639 }
00640
00641 std::string path;
00642 appendPath(s_devicePath, entry.d_name, path);
00643
00644
00645 if (s_devicePaths.end() != s_devicePaths.find(path.c_str())) {
00646
00647 newSet.insert(path);
00648 continue;
00649 }
00650
00651
00652 smart_fd fd;
00653 if (fd.open(path.c_str(), O_RDONLY) && isInputEntry(fd)) {
00654 newSet.insert(path);
00655 }
00656 }
00657
00658
00659 s_devicePaths = newSet;
00660 }
00661
00662
00663
00664 smart_ptr<SourceDevice>
00665 getLinuxInputSourceDevice
00666 (
00667 IN const char * path,
00668 IN bool wantForceFeedback
00669 )
00670 {
00671 ASSERT(path, "null");
00672
00673
00674 smart_ptr<LIDevice> local = new LIDevice;
00675 ASSERT(local, "out of memory");
00676 local->initialize(path, wantForceFeedback);
00677
00678
00679 return local;
00680 }
00681
00682
00683
00684
00685
00686
00687
00688
00689
00690
00691 class Factory : public SourceDeviceFactory {
00692 public:
00693
00694 ~Factory(void) throw() { }
00695
00696
00697 void initialize(IN bool wantForceFeedback) {
00698 m_wantForceFeedback = wantForceFeedback;
00699 }
00700
00701
00702 const char * getName(void) const throw()
00703 { return "Linux Input Factory"; }
00704 int getCount(void);
00705 smart_ptr<SourceDevice> getSourceDevice(IN int index);
00706
00707 private:
00708
00709 typedef std::map<std::string, smart_ptr<SourceDevice> > device_map_t;
00710
00711
00712 bool m_wantForceFeedback;
00713 device_map_t m_devices;
00714 };
00715
00716
00717
00718 int
00719 Factory::getCount
00720 (
00721 void
00722 )
00723 {
00724
00725 refreshLinuxInputDevicePaths();
00726
00727
00728 VecString badPaths;
00729 for (device_map_t::iterator i = m_devices.begin(); i != m_devices.end();
00730 ++i) {
00731 const char * path = i->first.c_str();
00732 if (s_devicePaths.end() == s_devicePaths.find(path)) {
00733
00734 badPaths.push_back(path);
00735 }
00736 }
00737 for (VecString::iterator i = badPaths.begin(); i != badPaths.end();
00738 ++i) {
00739 device_map_t::iterator iBad = m_devices.find(*i);
00740 ASSERT(m_devices.end() != iBad, "Just saw this in map!");
00741 m_devices.erase(iBad);
00742 }
00743 ASSERT(m_devices.size() <= s_devicePaths.size(),
00744 "Should have devices for a subset of paths!");
00745
00746
00747 return s_devicePaths.size();
00748 }
00749
00750
00751
00752 smart_ptr<SourceDevice>
00753 Factory::getSourceDevice
00754 (
00755 IN int index
00756 )
00757 {
00758
00759 const char * path = NULL;
00760 for (SetString::const_iterator i = s_devicePaths.begin();
00761 i != s_devicePaths.end(); ++i, --index) {
00762 if (!index) {
00763 path = i->c_str();
00764 break;
00765 }
00766 }
00767 if (!path) {
00768 DPRINTF("Invalid source device index: %d", index);
00769 return NULL;
00770 }
00771
00772
00773 device_map_t::iterator i = m_devices.find(path);
00774 if (m_devices.end() != i) {
00775 return i->second;
00776 }
00777
00778
00779 smart_ptr<SourceDevice> device =
00780 getLinuxInputSourceDevice(path, m_wantForceFeedback);
00781 ASSERT(device, "failed to create linux input source device");
00782 m_devices[path] = device;
00783 return device;
00784 }
00785
00786
00787
00788
00789
00790
00791
00792
00793
00794 smart_ptr<SourceDeviceFactory>
00795 getLinuxInputSourceDeviceFactory
00796 (
00797 IN bool wantForceFeedback
00798 )
00799 {
00800 smart_ptr<Factory> local = new Factory;
00801 ASSERT(local, "out of memory");
00802
00803 local->initialize(wantForceFeedback);
00804
00805 return local;
00806 }
00807
00808
00809
00810 };
00811