15821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Copyright (c) 2012 The Chromium Authors. All rights reserved.
25821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be
35821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// found in the LICENSE file.
45821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
55821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "content/browser/gamepad/gamepad_platform_data_fetcher_linux.h"
65821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
75821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <fcntl.h>
85821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <libudev.h>
95821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <linux/joystick.h>
105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <string.h>
115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <sys/stat.h>
125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <sys/types.h>
135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <unistd.h>
145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/debug/trace_event.h"
169ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch#include "base/message_loop/message_loop.h"
172a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "base/posix/eintr_wrapper.h"
18868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)#include "base/strings/string_number_conversions.h"
19868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)#include "base/strings/string_util.h"
20868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)#include "base/strings/stringprintf.h"
21868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)#include "base/strings/utf_string_conversions.h"
225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "content/browser/udev_linux.h"
235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace {
255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const char kInputSubsystem[] = "input";
275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const char kUsbSubsystem[] = "usb";
285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const char kUsbDeviceType[] = "usb_device";
295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const float kMaxLinuxAxisValue = 32767.0;
305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void CloseFileDescriptorIfValid(int fd) {
325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (fd >= 0)
335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    close(fd);
345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool IsGamepad(udev_device* dev, int* index, std::string* path) {
375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!udev_device_get_property_value(dev, "ID_INPUT_JOYSTICK"))
385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  const char* node_path = udev_device_get_devnode(dev);
415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!node_path)
425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  static const char kJoystickRoot[] = "/dev/input/js";
455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  bool is_gamepad = StartsWithASCII(node_path, kJoystickRoot, true);
465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!is_gamepad)
475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int tmp_idx = -1;
505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  const int base_len = sizeof(kJoystickRoot) - 1;
515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  base::StringPiece str(&node_path[base_len], strlen(node_path) - base_len);
525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!base::StringToInt(str, &tmp_idx))
535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (tmp_idx < 0 ||
55f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)      tmp_idx >= static_cast<int>(blink::WebGamepads::itemsLengthCap)) {
565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  *index = tmp_idx;
595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  *path = node_path;
605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return true;
615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}  // namespace
645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace content {
665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
67f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)using blink::WebGamepad;
68f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)using blink::WebGamepads;
695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)GamepadPlatformDataFetcherLinux::GamepadPlatformDataFetcherLinux() {
715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for (size_t i = 0; i < arraysize(device_fds_); ++i)
725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    device_fds_[i] = -1;
735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  memset(mappers_, 0, sizeof(mappers_));
745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  std::vector<UdevLinux::UdevMonitorFilter> filters;
765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  filters.push_back(UdevLinux::UdevMonitorFilter(kInputSubsystem, NULL));
775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  udev_.reset(
785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      new UdevLinux(filters,
795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                    base::Bind(&GamepadPlatformDataFetcherLinux::RefreshDevice,
805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                               base::Unretained(this))));
815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  EnumerateDevices();
835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)GamepadPlatformDataFetcherLinux::~GamepadPlatformDataFetcherLinux() {
865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for (size_t i = 0; i < WebGamepads::itemsLengthCap; ++i)
875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    CloseFileDescriptorIfValid(device_fds_[i]);
885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void GamepadPlatformDataFetcherLinux::GetGamepadData(WebGamepads* pads, bool) {
915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  TRACE_EVENT0("GAMEPAD", "GetGamepadData");
925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  data_.length = WebGamepads::itemsLengthCap;
945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Update our internal state.
965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for (size_t i = 0; i < WebGamepads::itemsLengthCap; ++i) {
975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (device_fds_[i] >= 0) {
985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      ReadDeviceData(i);
995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
1005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Copy to the current state to the output buffer, using the mapping
1035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // function, if there is one available.
1045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  pads->length = data_.length;
1055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for (size_t i = 0; i < WebGamepads::itemsLengthCap; ++i) {
1065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (mappers_[i])
1075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      mappers_[i](data_.items[i], &pads->items[i]);
1085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    else
1095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      pads->items[i] = data_.items[i];
1105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Used during enumeration, and monitor notifications.
1145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void GamepadPlatformDataFetcherLinux::RefreshDevice(udev_device* dev) {
1155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int index;
1165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  std::string node_path;
1175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (IsGamepad(dev, &index, &node_path)) {
1185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    int& device_fd = device_fds_[index];
1195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    WebGamepad& pad = data_.items[index];
1205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    GamepadStandardMappingFunction& mapper = mappers_[index];
1215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    CloseFileDescriptorIfValid(device_fd);
1235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // The device pointed to by dev contains information about the logical
1255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // joystick device. In order to get the information about the physical
1265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // hardware, get the parent device that is also in the "input" subsystem.
1275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // This function should just walk up the tree one level.
1285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    dev = udev_device_get_parent_with_subsystem_devtype(
1295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        dev,
1305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        kInputSubsystem,
1315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        NULL);
1325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (!dev) {
1335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // Unable to get device information, don't use this device.
1345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      device_fd = -1;
1355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      pad.connected = false;
1365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return;
1375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
1385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    device_fd = HANDLE_EINTR(open(node_path.c_str(), O_RDONLY | O_NONBLOCK));
1405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (device_fd < 0) {
1415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // Unable to open device, don't use.
1425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      pad.connected = false;
1435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return;
1445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
1455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const char* vendor_id = udev_device_get_sysattr_value(dev, "id/vendor");
1475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const char* product_id = udev_device_get_sysattr_value(dev, "id/product");
1485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    mapper = GetGamepadStandardMappingFunction(vendor_id, product_id);
1495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Driver returns utf-8 strings here, so combine in utf-8 first and
1515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // convert to WebUChar later once we've picked an id string.
1525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const char* name = udev_device_get_sysattr_value(dev, "name");
1535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    std::string name_string = base::StringPrintf("%s", name);
1545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // In many cases the information the input subsystem contains isn't
1565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // as good as the information that the device bus has, walk up further
1575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // to the subsystem/device type "usb"/"usb_device" and if this device
1585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // has the same vendor/product id, prefer the description from that.
1595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    struct udev_device *usb_dev = udev_device_get_parent_with_subsystem_devtype(
1605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        dev,
1615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        kUsbSubsystem,
1625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        kUsbDeviceType);
1635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (usb_dev) {
1645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      const char* usb_vendor_id =
1655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          udev_device_get_sysattr_value(usb_dev, "idVendor");
1665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      const char* usb_product_id =
1675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          udev_device_get_sysattr_value(usb_dev, "idProduct");
1685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if (strcmp(vendor_id, usb_vendor_id) == 0 &&
1705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          strcmp(product_id, usb_product_id) == 0) {
1715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        const char* manufacturer =
1725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            udev_device_get_sysattr_value(usb_dev, "manufacturer");
1735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        const char* product = udev_device_get_sysattr_value(usb_dev, "product");
1745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        // Replace the previous name string with one containing the better
1765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        // information, again driver returns utf-8 strings here so combine
1775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        // in utf-8 for conversion to WebUChar below.
1785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        name_string = base::StringPrintf("%s %s", manufacturer, product);
1795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      }
1805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
1815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Append the vendor and product information then convert the utf-8
1835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // id string to WebUChar.
1845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    std::string id = name_string + base::StringPrintf(
1855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        " (%sVendor: %s Product: %s)",
1865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        mapper ? "STANDARD GAMEPAD " : "",
1875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        vendor_id,
1885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        product_id);
189a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)    base::TruncateUTF8ToByteSize(id, WebGamepad::idLengthCap - 1, &id);
1905d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    base::string16 tmp16 = base::UTF8ToUTF16(id);
1915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    memset(pad.id, 0, sizeof(pad.id));
1925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    tmp16.copy(pad.id, arraysize(pad.id) - 1);
1935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
194a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    if (mapper) {
195a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      std::string mapping = "standard";
196a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      base::TruncateUTF8ToByteSize(mapping, WebGamepad::mappingLengthCap - 1,
197a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)          &mapping);
198a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      tmp16 = base::UTF8ToUTF16(mapping);
199a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      memset(pad.mapping, 0, sizeof(pad.mapping));
200a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      tmp16.copy(pad.mapping, arraysize(pad.mapping) - 1);
201a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    } else {
202a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      pad.mapping[0] = 0;
203a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    }
204a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
2055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    pad.connected = true;
2065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
2075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void GamepadPlatformDataFetcherLinux::EnumerateDevices() {
2105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  udev_enumerate* enumerate = udev_enumerate_new(udev_->udev_handle());
2115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!enumerate)
2125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
2135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int ret = udev_enumerate_add_match_subsystem(enumerate, kInputSubsystem);
2145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (ret != 0)
2155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
2165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ret = udev_enumerate_scan_devices(enumerate);
2175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (ret != 0)
2185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
2195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  udev_list_entry* devices = udev_enumerate_get_list_entry(enumerate);
2215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for (udev_list_entry* dev_list_entry = devices;
2225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)       dev_list_entry != NULL;
2235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)       dev_list_entry = udev_list_entry_get_next(dev_list_entry)) {
2245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Get the filename of the /sys entry for the device and create a
2255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // udev_device object (dev) representing it
2265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const char* path = udev_list_entry_get_name(dev_list_entry);
2275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    udev_device* dev = udev_device_new_from_syspath(udev_->udev_handle(), path);
2285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (!dev)
2295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      continue;
2305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    RefreshDevice(dev);
2315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    udev_device_unref(dev);
2325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
2335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Free the enumerator object
2345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  udev_enumerate_unref(enumerate);
2355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void GamepadPlatformDataFetcherLinux::ReadDeviceData(size_t index) {
2385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Linker does not like CHECK_LT(index, WebGamepads::itemsLengthCap). =/
2395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (index >= WebGamepads::itemsLengthCap) {
2405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    CHECK(false);
2415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
2425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
2435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  const int& fd = device_fds_[index];
2455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  WebGamepad& pad = data_.items[index];
2465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK_GE(fd, 0);
2475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  js_event event;
2492a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  while (HANDLE_EINTR(read(fd, &event, sizeof(struct js_event))) > 0) {
2505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    size_t item = event.number;
2515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (event.type & JS_EVENT_AXIS) {
2525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if (item >= WebGamepad::axesLengthCap)
2535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        continue;
2545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      pad.axes[item] = event.value / kMaxLinuxAxisValue;
2555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if (item >= pad.axesLength)
2565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        pad.axesLength = item + 1;
2575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    } else if (event.type & JS_EVENT_BUTTON) {
2585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if (item >= WebGamepad::buttonsLengthCap)
2595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        continue;
260a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      pad.buttons[item].pressed = event.value;
261a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      pad.buttons[item].value = event.value ? 1.0 : 0.0;
2625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if (item >= pad.buttonsLength)
2635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        pad.buttonsLength = item + 1;
2645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
2655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    pad.timestamp = event.time;
2665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
2675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}  // namespace content
270