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