1 // Copyright 2018 The Chromium Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style license that can be 3 // found in the LICENSE file. 4 5 #ifndef DEVICE_GAMEPAD_GAMEPAD_DEVICE_LINUX_ 6 #define DEVICE_GAMEPAD_GAMEPAD_DEVICE_LINUX_ 7 8 #include <memory> 9 #include <string> 10 #include <vector> 11 12 #include "base/files/scoped_file.h" 13 #include "base/memory/weak_ptr.h" 14 #include "device/gamepad/abstract_haptic_gamepad.h" 15 #include "device/gamepad/gamepad_id_list.h" 16 #include "device/gamepad/gamepad_standard_mappings.h" 17 #include "device/gamepad/udev_gamepad_linux.h" 18 19 extern "C" { 20 struct udev_device; 21 } 22 23 namespace device { 24 25 class Dualshock4Controller; 26 class HidHapticGamepad; 27 class XboxHidController; 28 29 // GamepadDeviceLinux represents a single gamepad device which may be accessed 30 // through multiple host interfaces. Gamepad button and axis state are queried 31 // through the joydev interface, while haptics commands are routed through the 32 // evdev interface. A gamepad must be enumerated through joydev to be usable, 33 // but the evdev interface is only required for haptic effects. 34 // 35 // For some devices, haptics are not supported through evdev and are instead 36 // sent through the raw HID (hidraw) interface. 37 class GamepadDeviceLinux final : public AbstractHapticGamepad { 38 public: 39 using OpenDeviceNodeCallback = base::OnceCallback<void(GamepadDeviceLinux*)>; 40 41 GamepadDeviceLinux(const std::string& syspath_prefix, 42 scoped_refptr<base::SequencedTaskRunner> dbus_runner); 43 ~GamepadDeviceLinux() override; 44 45 // Returns true if no device nodes are associated with this device. 46 bool IsEmpty() const; 47 GetJoydevIndex()48 int GetJoydevIndex() const { return joydev_index_; } GetVendorId()49 uint16_t GetVendorId() const { return vendor_id_; } GetProductId()50 uint16_t GetProductId() const { return product_id_; } GetVersionNumber()51 uint16_t GetVersionNumber() const { return version_number_; } GetName()52 std::string GetName() const { return name_; } GetSyspathPrefix()53 std::string GetSyspathPrefix() const { return syspath_prefix_; } GetBusType()54 GamepadBusType GetBusType() const { return bus_type_; } 55 GamepadStandardMappingFunction GetMappingFunction() const; 56 57 bool SupportsVibration() const; 58 59 // Reads the current gamepad state into |pad|. 60 void ReadPadState(Gamepad* pad); 61 62 // Reads the state of gamepad buttons and axes using joydev. Returns true if 63 // |pad| was updated. 64 bool ReadJoydevState(Gamepad* pad); 65 66 // Discovers and assigns button indices for key codes that are outside the 67 // normal gamepad button range. 68 void InitializeEvdevSpecialKeys(); 69 70 // Reads the state of keys outside the normal button range using evdev. 71 // Returns true if |pad| was updated. 72 bool ReadEvdevSpecialKeys(Gamepad* pad); 73 74 // Returns true if |pad_info| describes this device. 75 bool IsSameDevice(const UdevGamepadLinux& pad_info); 76 77 // Opens the joydev device node and queries device info. 78 bool OpenJoydevNode(const UdevGamepadLinux& pad_info, udev_device* device); 79 80 // Closes the joydev device node and clears device info. 81 void CloseJoydevNode(); 82 83 // Opens the evdev device node and initializes haptics. 84 bool OpenEvdevNode(const UdevGamepadLinux& pad_info); 85 86 // Closes the evdev device node and shuts down haptics. 87 void CloseEvdevNode(); 88 89 // Opens the hidraw device node and initializes haptics. 90 void OpenHidrawNode(const UdevGamepadLinux& pad_info, 91 OpenDeviceNodeCallback callback); 92 93 // Closes the hidraw device node and shuts down haptics. 94 void CloseHidrawNode(); 95 96 // AbstractHapticGamepad public implementation. 97 void SetVibration(double strong_magnitude, double weak_magnitude) override; 98 void SetZeroVibration() override; 99 base::WeakPtr<AbstractHapticGamepad> GetWeakPtr() override; 100 101 private: 102 using OpenPathCallback = base::OnceCallback<void(base::ScopedFD)>; 103 104 // AbstractHapticGamepad private implementation. 105 void DoShutdown() override; 106 107 void OnOpenHidrawNodeComplete(OpenDeviceNodeCallback callback, 108 base::ScopedFD fd); 109 void InitializeHidraw(base::ScopedFD fd); 110 111 #if defined(OS_CHROMEOS) 112 void OpenPathWithPermissionBroker(const std::string& path, 113 OpenPathCallback callback); 114 void OnOpenPathSuccess(OpenPathCallback callback, base::ScopedFD fd); 115 void OnOpenPathError(OpenPathCallback callback, 116 const std::string& error_name, 117 const std::string& error_message); 118 #endif 119 120 // The syspath prefix is used to identify device nodes that refer to the same 121 // underlying gamepad through different interfaces. 122 // 123 // Joydev and evdev nodes that refer to the same device will share a parent 124 // node that represents the physical device. We can compare the syspaths of 125 // the parent nodes to determine when two nodes refer to the same device. 126 // 127 // The syspath for a hidraw node will match the parent syspath of a joydev or 128 // evdev node up to the subsystem. To simplify this comparison, we only store 129 // the syspath prefix up to the subsystem. 130 std::string syspath_prefix_; 131 132 // The file descriptor for the device's joydev node. 133 base::ScopedFD joydev_fd_; 134 135 // The index of the device's joydev node, or -1 if unknown. 136 // The joydev index is the integer at the end of the joydev node path and is 137 // used to assign the gamepad to a slot. For example, a device with path 138 // /dev/input/js2 has index 2 and will be assigned to the 3rd gamepad slot. 139 int joydev_index_ = -1; 140 141 // Maps from indices in the Gamepad buttons array to a boolean value 142 // indicating whether the button index is already mapped. 143 std::vector<bool> button_indices_used_; 144 145 // An identifier for the gamepad device model. 146 GamepadId gamepad_id_ = GamepadId::kUnknownGamepad; 147 148 // The vendor ID of the device. 149 uint16_t vendor_id_; 150 151 // The product ID of the device. 152 uint16_t product_id_; 153 154 // The version of the HID specification that this device is compliant with. 155 // The hid-sony driver patches this value to indicate that a newer mapping has 156 // been applied. 157 uint16_t hid_specification_version_; 158 159 // The version number of the device. 160 uint16_t version_number_; 161 162 // A string identifying the manufacturer and model of the device. 163 std::string name_; 164 165 // The file descriptor for the device's evdev node. 166 base::ScopedFD evdev_fd_; 167 168 // The ID of the haptic effect stored on the device, or -1 if none is stored. 169 int effect_id_ = -1; 170 171 // True if the device supports rumble effects through the evdev device node. 172 bool supports_force_feedback_ = false; 173 174 // Set to true once the evdev button capabilities have been checked. 175 bool evdev_special_keys_initialized_ = false; 176 177 // Mapping from "special" index (an index within the kSpecialKeys table) to 178 // button index (an index within the Gamepad buttons array), or -1 if the 179 // button is not mapped. Empty if no special buttons are mapped. 180 std::vector<int> special_button_map_; 181 182 // The file descriptor for the device's hidraw node. 183 base::ScopedFD hidraw_fd_; 184 185 // The type of the bus through which the device is connected, or 186 // GAMEPAD_BUS_UNKNOWN if the bus type could not be determined. 187 GamepadBusType bus_type_ = GAMEPAD_BUS_UNKNOWN; 188 189 // Dualshock4 functionality, if available. 190 std::unique_ptr<Dualshock4Controller> dualshock4_; 191 192 // Xbox Wireless Controller behaves like a HID gamepad when connected over 193 // Bluetooth. In this mode, haptics functionality is provided by |xbox_hid_|. 194 // When connected over USB, Xbox Wireless Controller is supported through the 195 // platform driver (xpad). 196 std::unique_ptr<XboxHidController> xbox_hid_; 197 198 // A controller that uses a HID output report for vibration effects. 199 std::unique_ptr<HidHapticGamepad> hid_haptics_; 200 201 // Task runner to use for D-Bus tasks. D-Bus client classes (including 202 // PermissionBrokerClient) are not thread-safe and should be used only on the 203 // UI thread. 204 scoped_refptr<base::SequencedTaskRunner> dbus_runner_; 205 206 // Task runner to use for gamepad polling. 207 scoped_refptr<base::SequencedTaskRunner> polling_runner_; 208 209 base::WeakPtrFactory<GamepadDeviceLinux> weak_factory_{this}; 210 }; 211 212 } // namespace device 213 214 #endif // DEVICE_GAMEPAD_GAMEPAD_DEVICE_LINUX_ 215