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 #include "device/gamepad/gamepad_device_linux.h"
6 
7 #include <fcntl.h>
8 #include <limits.h>
9 #include <linux/hidraw.h>
10 #include <linux/input.h>
11 #include <linux/joystick.h>
12 #include <sys/ioctl.h>
13 
14 #include "base/callback_helpers.h"
15 #include "base/posix/eintr_wrapper.h"
16 #include "base/stl_util.h"
17 #include "base/strings/string_number_conversions.h"
18 #include "base/strings/string_piece.h"
19 #include "base/strings/string_util.h"
20 #include "base/strings/stringprintf.h"
21 #include "build/chromeos_buildflags.h"
22 #include "device/gamepad/dualshock4_controller.h"
23 #include "device/gamepad/gamepad_data_fetcher.h"
24 #include "device/gamepad/hid_haptic_gamepad.h"
25 #include "device/gamepad/hid_writer_linux.h"
26 #include "device/gamepad/xbox_hid_controller.h"
27 #include "device/udev_linux/udev.h"
28 
29 #if BUILDFLAG(IS_ASH)
30 #include "chromeos/dbus/permission_broker/permission_broker_client.h"
31 #endif  // BUILDFLAG(IS_ASH)
32 
33 namespace device {
34 
35 namespace {
36 
37 const char kInputSubsystem[] = "input";
38 const char kUsbSubsystem[] = "usb";
39 const char kUsbDeviceType[] = "usb_device";
40 const float kMaxLinuxAxisValue = 32767.0;
41 const int kInvalidEffectId = -1;
42 const uint16_t kRumbleMagnitudeMax = 0xffff;
43 
44 const size_t kSpecialKeys[] = {
45     // Xbox One S pre-FW update reports Xbox button as SystemMainMenu over BT.
46     KEY_MENU,
47     // Power is used for the Guide button on the Nvidia Shield 2015 gamepad.
48     KEY_POWER,
49     // Search is used for the Guide button on the Nvidia Shield 2015 gamepad.
50     KEY_SEARCH,
51     // Start, Back, and Guide buttons are often reported as Consumer Home or
52     // Back.
53     KEY_HOMEPAGE, KEY_BACK,
54 };
55 const size_t kSpecialKeysLen = base::size(kSpecialKeys);
56 
57 #define LONG_BITS (CHAR_BIT * sizeof(long))
58 #define BITS_TO_LONGS(x) (((x) + LONG_BITS - 1) / LONG_BITS)
59 
test_bit(int bit,const unsigned long * data)60 static inline bool test_bit(int bit, const unsigned long* data) {
61   return data[bit / LONG_BITS] & (1UL << (bit % LONG_BITS));
62 }
63 
GetEvdevBusType(const base::ScopedFD & fd)64 GamepadBusType GetEvdevBusType(const base::ScopedFD& fd) {
65   struct input_id input_info;
66   if (HANDLE_EINTR(ioctl(fd.get(), EVIOCGID, &input_info)) >= 0) {
67     if (input_info.bustype == BUS_USB)
68       return GAMEPAD_BUS_USB;
69     if (input_info.bustype == BUS_BLUETOOTH)
70       return GAMEPAD_BUS_BLUETOOTH;
71   }
72   return GAMEPAD_BUS_UNKNOWN;
73 }
74 
HasRumbleCapability(const base::ScopedFD & fd)75 bool HasRumbleCapability(const base::ScopedFD& fd) {
76   unsigned long evbit[BITS_TO_LONGS(EV_MAX)];
77   unsigned long ffbit[BITS_TO_LONGS(FF_MAX)];
78 
79   if (HANDLE_EINTR(ioctl(fd.get(), EVIOCGBIT(0, EV_MAX), evbit)) < 0 ||
80       HANDLE_EINTR(ioctl(fd.get(), EVIOCGBIT(EV_FF, FF_MAX), ffbit)) < 0) {
81     return false;
82   }
83 
84   if (!test_bit(EV_FF, evbit)) {
85     return false;
86   }
87 
88   return test_bit(FF_RUMBLE, ffbit);
89 }
90 
91 // Check an evdev device for key codes which sometimes appear on gamepads but
92 // aren't reported by joydev. If a special key is found, the corresponding entry
93 // of the |has_special_key| vector is set to true. Returns the number of
94 // special keys found.
CheckSpecialKeys(const base::ScopedFD & fd,std::vector<bool> * has_special_key)95 size_t CheckSpecialKeys(const base::ScopedFD& fd,
96                         std::vector<bool>* has_special_key) {
97   DCHECK(has_special_key);
98   unsigned long evbit[BITS_TO_LONGS(EV_MAX)];
99   unsigned long keybit[BITS_TO_LONGS(KEY_MAX)];
100   size_t found_special_keys = 0;
101 
102   has_special_key->clear();
103   if (HANDLE_EINTR(ioctl(fd.get(), EVIOCGBIT(0, EV_MAX), evbit)) < 0 ||
104       HANDLE_EINTR(ioctl(fd.get(), EVIOCGBIT(EV_KEY, KEY_MAX), keybit)) < 0) {
105     return 0;
106   }
107 
108   if (!test_bit(EV_KEY, evbit)) {
109     return 0;
110   }
111 
112   has_special_key->resize(kSpecialKeysLen, false);
113   for (size_t special_index = 0; special_index < kSpecialKeysLen;
114        ++special_index) {
115     if (test_bit(kSpecialKeys[special_index], keybit)) {
116       (*has_special_key)[special_index] = true;
117       ++found_special_keys;
118     }
119   }
120 
121   return found_special_keys;
122 }
123 
GetHidrawDevinfo(const base::ScopedFD & fd,GamepadBusType * bus_type,std::string * product_name,uint16_t * vendor_id,uint16_t * product_id)124 bool GetHidrawDevinfo(const base::ScopedFD& fd,
125                       GamepadBusType* bus_type,
126                       std::string* product_name,
127                       uint16_t* vendor_id,
128                       uint16_t* product_id) {
129   struct hidraw_devinfo info;
130   if (HANDLE_EINTR(ioctl(fd.get(), HIDIOCGRAWINFO, &info)) < 0)
131     return false;
132   if (bus_type) {
133     if (info.bustype == BUS_USB)
134       *bus_type = GAMEPAD_BUS_USB;
135     else if (info.bustype == BUS_BLUETOOTH)
136       *bus_type = GAMEPAD_BUS_BLUETOOTH;
137     else
138       *bus_type = GAMEPAD_BUS_UNKNOWN;
139   }
140   if (vendor_id)
141     *vendor_id = static_cast<uint16_t>(info.vendor);
142   if (product_id)
143     *product_id = static_cast<uint16_t>(info.product);
144 
145   constexpr size_t kStringDescriptorMax = 256;
146   if (product_name &&
147       HANDLE_EINTR(ioctl(fd.get(), HIDIOCGRAWNAME(kStringDescriptorMax),
148                          base::WriteInto(product_name, kStringDescriptorMax))) <
149           0) {
150     product_name->clear();
151   }
152 
153   return true;
154 }
155 
StoreRumbleEffect(const base::ScopedFD & fd,int effect_id,uint16_t duration,uint16_t start_delay,uint16_t strong_magnitude,uint16_t weak_magnitude)156 int StoreRumbleEffect(const base::ScopedFD& fd,
157                       int effect_id,
158                       uint16_t duration,
159                       uint16_t start_delay,
160                       uint16_t strong_magnitude,
161                       uint16_t weak_magnitude) {
162   struct ff_effect effect;
163   memset(&effect, 0, sizeof(effect));
164   effect.type = FF_RUMBLE;
165   effect.id = effect_id;
166   effect.replay.length = duration;
167   effect.replay.delay = start_delay;
168   effect.u.rumble.strong_magnitude = strong_magnitude;
169   effect.u.rumble.weak_magnitude = weak_magnitude;
170 
171   if (HANDLE_EINTR(ioctl(fd.get(), EVIOCSFF, (const void*)&effect)) < 0)
172     return kInvalidEffectId;
173   return effect.id;
174 }
175 
DestroyEffect(const base::ScopedFD & fd,int effect_id)176 void DestroyEffect(const base::ScopedFD& fd, int effect_id) {
177   HANDLE_EINTR(ioctl(fd.get(), EVIOCRMFF, effect_id));
178 }
179 
StartOrStopEffect(const base::ScopedFD & fd,int effect_id,bool do_start)180 bool StartOrStopEffect(const base::ScopedFD& fd, int effect_id, bool do_start) {
181   struct input_event start_stop;
182   memset(&start_stop, 0, sizeof(start_stop));
183   start_stop.type = EV_FF;
184   start_stop.code = effect_id;
185   start_stop.value = do_start ? 1 : 0;
186   ssize_t nbytes = HANDLE_EINTR(
187       write(fd.get(), (const void*)&start_stop, sizeof(start_stop)));
188   return nbytes == sizeof(start_stop);
189 }
190 
HexStringToUInt16WithDefault(base::StringPiece input,uint16_t default_value)191 uint16_t HexStringToUInt16WithDefault(base::StringPiece input,
192                                       uint16_t default_value) {
193   uint32_t out = 0;
194   if (!base::HexStringToUInt(input, &out) ||
195       out > std::numeric_limits<uint16_t>::max()) {
196     return default_value;
197   }
198   return static_cast<uint16_t>(out);
199 }
200 
201 #if BUILDFLAG(IS_ASH)
OnOpenPathSuccess(chromeos::PermissionBrokerClient::OpenPathCallback callback,scoped_refptr<base::SequencedTaskRunner> polling_runner,base::ScopedFD fd)202 void OnOpenPathSuccess(
203     chromeos::PermissionBrokerClient::OpenPathCallback callback,
204     scoped_refptr<base::SequencedTaskRunner> polling_runner,
205     base::ScopedFD fd) {
206   polling_runner->PostTask(FROM_HERE,
207                            base::BindOnce(std::move(callback), std::move(fd)));
208 }
209 
OnOpenPathError(chromeos::PermissionBrokerClient::OpenPathCallback callback,scoped_refptr<base::SequencedTaskRunner> polling_runner,const std::string & error_name,const std::string & error_message)210 void OnOpenPathError(
211     chromeos::PermissionBrokerClient::OpenPathCallback callback,
212     scoped_refptr<base::SequencedTaskRunner> polling_runner,
213     const std::string& error_name,
214     const std::string& error_message) {
215   polling_runner->PostTask(
216       FROM_HERE, base::BindOnce(std::move(callback), base::ScopedFD()));
217 }
218 
OpenPathWithPermissionBroker(const std::string & path,chromeos::PermissionBrokerClient::OpenPathCallback callback,scoped_refptr<base::SequencedTaskRunner> polling_runner)219 void OpenPathWithPermissionBroker(
220     const std::string& path,
221     chromeos::PermissionBrokerClient::OpenPathCallback callback,
222     scoped_refptr<base::SequencedTaskRunner> polling_runner) {
223   auto* client = chromeos::PermissionBrokerClient::Get();
224   DCHECK(client) << "Could not get permission broker client.";
225   auto copyable_callback = base::AdaptCallbackForRepeating(std::move(callback));
226   auto success_callback =
227       base::BindOnce(&OnOpenPathSuccess, copyable_callback, polling_runner);
228   auto error_callback =
229       base::BindOnce(&OnOpenPathError, copyable_callback, polling_runner);
230   client->OpenPath(path, std::move(success_callback),
231                    std::move(error_callback));
232 }
233 #endif  // BUILDFLAG(IS_ASH)
234 
235 }  // namespace
236 
GamepadDeviceLinux(const std::string & syspath_prefix,scoped_refptr<base::SequencedTaskRunner> dbus_runner)237 GamepadDeviceLinux::GamepadDeviceLinux(
238     const std::string& syspath_prefix,
239     scoped_refptr<base::SequencedTaskRunner> dbus_runner)
240     : syspath_prefix_(syspath_prefix),
241       button_indices_used_(Gamepad::kButtonsLengthCap, false),
242       dbus_runner_(dbus_runner),
243       polling_runner_(base::SequencedTaskRunnerHandle::Get()) {}
244 
245 GamepadDeviceLinux::~GamepadDeviceLinux() = default;
246 
DoShutdown()247 void GamepadDeviceLinux::DoShutdown() {
248   CloseJoydevNode();
249   CloseEvdevNode();
250   CloseHidrawNode();
251 }
252 
IsEmpty() const253 bool GamepadDeviceLinux::IsEmpty() const {
254   return !joydev_fd_.is_valid() && !evdev_fd_.is_valid() &&
255          !hidraw_fd_.is_valid();
256 }
257 
SupportsVibration() const258 bool GamepadDeviceLinux::SupportsVibration() const {
259   if (dualshock4_ || xbox_hid_ || hid_haptics_)
260     return true;
261 
262   // The Xbox Adaptive Controller reports force feedback capability, but the
263   // device itself does not have any vibration actuators.
264   if (gamepad_id_ == GamepadId::kMicrosoftProduct0b0a)
265     return false;
266 
267   return supports_force_feedback_ && evdev_fd_.is_valid();
268 }
269 
ReadPadState(Gamepad * pad)270 void GamepadDeviceLinux::ReadPadState(Gamepad* pad) {
271   DCHECK(joydev_fd_.is_valid());
272 
273   // Read button and axis events from the joydev device.
274   bool pad_updated = ReadJoydevState(pad);
275 
276   // Evdev special buttons must be initialized after we have read from joydev
277   // at least once to ensure we do not assign a button index already in use by
278   // joydev.
279   if (!evdev_special_keys_initialized_)
280     InitializeEvdevSpecialKeys();
281 
282   // Read button events from the evdev device.
283   if (!special_button_map_.empty()) {
284     if (ReadEvdevSpecialKeys(pad))
285       pad_updated = true;
286   }
287 
288   // Mark used buttons.
289   for (size_t button_index = 0; button_index < Gamepad::kButtonsLengthCap;
290        ++button_index) {
291     pad->buttons[button_index].used = button_indices_used_[button_index];
292   }
293 
294   if (pad_updated)
295     pad->timestamp = GamepadDataFetcher::CurrentTimeInMicroseconds();
296 }
297 
ReadJoydevState(Gamepad * pad)298 bool GamepadDeviceLinux::ReadJoydevState(Gamepad* pad) {
299   DCHECK(polling_runner_->RunsTasksInCurrentSequence());
300   DCHECK(pad);
301 
302   if (!joydev_fd_.is_valid())
303     return false;
304 
305   // Read button and axis events from the joydev device.
306   bool pad_updated = false;
307   js_event event;
308   while (HANDLE_EINTR(read(joydev_fd_.get(), &event, sizeof(struct js_event))) >
309          0) {
310     size_t item = event.number;
311     if (event.type & JS_EVENT_AXIS) {
312       if (item >= Gamepad::kAxesLengthCap)
313         continue;
314 
315       pad->axes[item] = event.value / kMaxLinuxAxisValue;
316       pad->axes_used |= 1 << item;
317 
318       if (item >= pad->axes_length)
319         pad->axes_length = item + 1;
320       pad_updated = true;
321     } else if (event.type & JS_EVENT_BUTTON) {
322       if (item >= Gamepad::kButtonsLengthCap)
323         continue;
324 
325       pad->buttons[item].used = true;
326       pad->buttons[item].pressed = event.value;
327       pad->buttons[item].value = event.value ? 1.0 : 0.0;
328 
329       // When a joydev device is opened, synthetic events are generated for
330       // each joystick button and axis with the JS_EVENT_INIT flag set on the
331       // event type. Use this signal to mark these button indices as used.
332       if (event.type & JS_EVENT_INIT)
333         button_indices_used_[item] = true;
334 
335       if (item >= pad->buttons_length)
336         pad->buttons_length = item + 1;
337       pad_updated = true;
338     }
339   }
340   return pad_updated;
341 }
342 
InitializeEvdevSpecialKeys()343 void GamepadDeviceLinux::InitializeEvdevSpecialKeys() {
344   DCHECK(polling_runner_->RunsTasksInCurrentSequence());
345   if (!evdev_fd_.is_valid())
346     return;
347 
348   // Do some one-time initialization to decide indices for the evdev special
349   // buttons.
350   evdev_special_keys_initialized_ = true;
351   std::vector<bool> special_key_present;
352   size_t unmapped_button_count =
353       CheckSpecialKeys(evdev_fd_, &special_key_present);
354 
355   special_button_map_.clear();
356   if (unmapped_button_count > 0) {
357     // Insert special buttons at unused button indices.
358     special_button_map_.resize(kSpecialKeysLen, -1);
359     size_t button_index = 0;
360     for (size_t special_index = 0; special_index < kSpecialKeysLen;
361          ++special_index) {
362       if (!special_key_present[special_index])
363         continue;
364 
365       // Advance to the next unused button index.
366       while (button_indices_used_[button_index] &&
367              button_index < Gamepad::kButtonsLengthCap) {
368         ++button_index;
369       }
370       if (button_index >= Gamepad::kButtonsLengthCap)
371         break;
372 
373       special_button_map_[special_index] = button_index;
374       button_indices_used_[button_index] = true;
375       ++button_index;
376 
377       if (--unmapped_button_count == 0)
378         break;
379     }
380   }
381 }
382 
ReadEvdevSpecialKeys(Gamepad * pad)383 bool GamepadDeviceLinux::ReadEvdevSpecialKeys(Gamepad* pad) {
384   DCHECK(polling_runner_->RunsTasksInCurrentSequence());
385   DCHECK(pad);
386 
387   if (!evdev_fd_.is_valid())
388     return false;
389 
390   // Read special button events through evdev.
391   bool pad_updated = false;
392   input_event ev;
393   ssize_t bytes_read;
394   while ((bytes_read = HANDLE_EINTR(
395               read(evdev_fd_.get(), &ev, sizeof(input_event)))) > 0) {
396     if (size_t{bytes_read} < sizeof(input_event))
397       break;
398     if (ev.type != EV_KEY)
399       continue;
400 
401     for (size_t special_index = 0; special_index < kSpecialKeysLen;
402          ++special_index) {
403       int button_index = special_button_map_[special_index];
404       if (button_index < 0)
405         continue;
406       if (ev.code == kSpecialKeys[special_index]) {
407         pad->buttons[button_index].pressed = ev.value;
408         pad->buttons[button_index].value = ev.value ? 1.0 : 0.0;
409         pad_updated = true;
410       }
411     }
412   }
413 
414   return pad_updated;
415 }
416 
GetMappingFunction() const417 GamepadStandardMappingFunction GamepadDeviceLinux::GetMappingFunction() const {
418   return GetGamepadStandardMappingFunction(name_, vendor_id_, product_id_,
419                                            hid_specification_version_,
420                                            version_number_, bus_type_);
421 }
422 
IsSameDevice(const UdevGamepadLinux & pad_info)423 bool GamepadDeviceLinux::IsSameDevice(const UdevGamepadLinux& pad_info) {
424   return pad_info.syspath_prefix == syspath_prefix_;
425 }
426 
OpenJoydevNode(const UdevGamepadLinux & pad_info,udev_device * device)427 bool GamepadDeviceLinux::OpenJoydevNode(const UdevGamepadLinux& pad_info,
428                                         udev_device* device) {
429   DCHECK(polling_runner_->RunsTasksInCurrentSequence());
430   DCHECK(pad_info.type == UdevGamepadLinux::Type::JOYDEV);
431   DCHECK(pad_info.syspath_prefix == syspath_prefix_);
432 
433   CloseJoydevNode();
434   joydev_fd_ =
435       base::ScopedFD(open(pad_info.path.c_str(), O_RDONLY | O_NONBLOCK));
436   if (!joydev_fd_.is_valid())
437     return false;
438 
439   udev_device* parent_device =
440       device::udev_device_get_parent_with_subsystem_devtype(
441           device, kInputSubsystem, nullptr);
442 
443   const base::StringPiece vendor_id =
444       udev_device_get_sysattr_value(parent_device, "id/vendor");
445   const base::StringPiece product_id =
446       udev_device_get_sysattr_value(parent_device, "id/product");
447   const base::StringPiece hid_version =
448       udev_device_get_sysattr_value(parent_device, "id/version");
449   const base::StringPiece name =
450       udev_device_get_sysattr_value(parent_device, "name");
451 
452   uint16_t vendor_id_int = HexStringToUInt16WithDefault(vendor_id, 0);
453   uint16_t product_id_int = HexStringToUInt16WithDefault(product_id, 0);
454   uint16_t hid_version_int = HexStringToUInt16WithDefault(hid_version, 0);
455   uint16_t version_number_int = 0;
456 
457   // In many cases the information the input subsystem contains isn't
458   // as good as the information that the device bus has, walk up further
459   // to the subsystem/device type "usb"/"usb_device" and if this device
460   // has the same vendor/product id, prefer the description from that.
461   struct udev_device* usb_device =
462       udev_device_get_parent_with_subsystem_devtype(
463           parent_device, kUsbSubsystem, kUsbDeviceType);
464   std::string name_string(name);
465   if (usb_device) {
466     const base::StringPiece usb_vendor_id =
467         udev_device_get_sysattr_value(usb_device, "idVendor");
468     const base::StringPiece usb_product_id =
469         udev_device_get_sysattr_value(usb_device, "idProduct");
470 
471     if (vendor_id == usb_vendor_id && product_id == usb_product_id) {
472       const char* manufacturer =
473           udev_device_get_sysattr_value(usb_device, "manufacturer");
474       const char* product =
475           udev_device_get_sysattr_value(usb_device, "product");
476 
477       if (manufacturer && product) {
478         // Replace the previous name string with one containing the better
479         // information.
480         name_string = base::StringPrintf("%s %s", manufacturer, product);
481       }
482     }
483 
484     const base::StringPiece version_number =
485         udev_device_get_sysattr_value(usb_device, "bcdDevice");
486     version_number_int = HexStringToUInt16WithDefault(version_number, 0);
487   }
488 
489   joydev_index_ = pad_info.index;
490   vendor_id_ = vendor_id_int;
491   product_id_ = product_id_int;
492   hid_specification_version_ = hid_version_int;
493   version_number_ = version_number_int;
494   name_ = name_string;
495   gamepad_id_ =
496       GamepadIdList::Get().GetGamepadId(name_, vendor_id_, product_id_);
497 
498   return true;
499 }
500 
CloseJoydevNode()501 void GamepadDeviceLinux::CloseJoydevNode() {
502   DCHECK(polling_runner_->RunsTasksInCurrentSequence());
503   joydev_fd_.reset();
504   joydev_index_ = -1;
505   vendor_id_ = 0;
506   product_id_ = 0;
507   version_number_ = 0;
508   name_.clear();
509   gamepad_id_ = GamepadId::kUnknownGamepad;
510 
511   // Button indices must be recomputed once the joydev node is closed.
512   button_indices_used_.clear();
513   special_button_map_.clear();
514   evdev_special_keys_initialized_ = false;
515 }
516 
OpenEvdevNode(const UdevGamepadLinux & pad_info)517 bool GamepadDeviceLinux::OpenEvdevNode(const UdevGamepadLinux& pad_info) {
518   DCHECK(polling_runner_->RunsTasksInCurrentSequence());
519   DCHECK(pad_info.type == UdevGamepadLinux::Type::EVDEV);
520   DCHECK(pad_info.syspath_prefix == syspath_prefix_);
521 
522   CloseEvdevNode();
523   evdev_fd_ = base::ScopedFD(open(pad_info.path.c_str(), O_RDWR | O_NONBLOCK));
524   if (!evdev_fd_.is_valid())
525     return false;
526 
527   supports_force_feedback_ = HasRumbleCapability(evdev_fd_);
528   bus_type_ = GetEvdevBusType(evdev_fd_);
529 
530   return true;
531 }
532 
CloseEvdevNode()533 void GamepadDeviceLinux::CloseEvdevNode() {
534   DCHECK(polling_runner_->RunsTasksInCurrentSequence());
535   if (evdev_fd_.is_valid()) {
536     if (effect_id_ != kInvalidEffectId) {
537       DestroyEffect(evdev_fd_, effect_id_);
538       effect_id_ = kInvalidEffectId;
539     }
540   }
541   evdev_fd_.reset();
542   supports_force_feedback_ = false;
543 
544   // Clear any entries in |button_indices_used_| that were taken by evdev.
545   if (!special_button_map_.empty()) {
546     for (int button_index : special_button_map_) {
547       if (button_index >= 0)
548         button_indices_used_[button_index] = false;
549     }
550   }
551   special_button_map_.clear();
552   evdev_special_keys_initialized_ = false;
553 }
554 
OpenHidrawNode(const UdevGamepadLinux & pad_info,OpenDeviceNodeCallback callback)555 void GamepadDeviceLinux::OpenHidrawNode(const UdevGamepadLinux& pad_info,
556                                         OpenDeviceNodeCallback callback) {
557   DCHECK(polling_runner_->RunsTasksInCurrentSequence());
558   DCHECK(pad_info.type == UdevGamepadLinux::Type::HIDRAW);
559   DCHECK(pad_info.syspath_prefix == syspath_prefix_);
560 
561   CloseHidrawNode();
562 
563   auto fd = base::ScopedFD(open(pad_info.path.c_str(), O_RDWR | O_NONBLOCK));
564 
565 #if BUILDFLAG(IS_ASH)
566   // If we failed to open the device it may be due to insufficient permissions.
567   // Try again using the PermissionBrokerClient.
568   if (!fd.is_valid()) {
569     DCHECK(dbus_runner_);
570     DCHECK(polling_runner_);
571     auto open_path_callback =
572         base::BindOnce(&GamepadDeviceLinux::OnOpenHidrawNodeComplete,
573                        weak_factory_.GetWeakPtr(), std::move(callback));
574     dbus_runner_->PostTask(
575         FROM_HERE,
576         base::BindOnce(&OpenPathWithPermissionBroker, pad_info.path,
577                        std::move(open_path_callback), polling_runner_));
578     return;
579   }
580 #endif  // BUILDFLAG(IS_ASH)
581 
582   OnOpenHidrawNodeComplete(std::move(callback), std::move(fd));
583 }
584 
OnOpenHidrawNodeComplete(OpenDeviceNodeCallback callback,base::ScopedFD fd)585 void GamepadDeviceLinux::OnOpenHidrawNodeComplete(
586     OpenDeviceNodeCallback callback,
587     base::ScopedFD fd) {
588   DCHECK(polling_runner_->RunsTasksInCurrentSequence());
589   if (fd.is_valid())
590     InitializeHidraw(std::move(fd));
591   std::move(callback).Run(this);
592 }
593 
InitializeHidraw(base::ScopedFD fd)594 void GamepadDeviceLinux::InitializeHidraw(base::ScopedFD fd) {
595   DCHECK(polling_runner_->RunsTasksInCurrentSequence());
596   DCHECK(fd.is_valid());
597   hidraw_fd_ = std::move(fd);
598 
599   std::string product_name;
600   uint16_t vendor_id;
601   uint16_t product_id;
602   GamepadId gamepad_id;
603   bool is_dualshock4 = false;
604   bool is_xbox_hid = false;
605   bool is_hid_haptic = false;
606   if (GetHidrawDevinfo(hidraw_fd_, &bus_type_, &product_name, &vendor_id,
607                        &product_id)) {
608     gamepad_id =
609         GamepadIdList::Get().GetGamepadId(product_name, vendor_id, product_id);
610     is_dualshock4 = Dualshock4Controller::IsDualshock4(gamepad_id);
611     is_xbox_hid = XboxHidController::IsXboxHid(gamepad_id);
612     is_hid_haptic = HidHapticGamepad::IsHidHaptic(vendor_id, product_id);
613     DCHECK_LE(is_dualshock4 + is_xbox_hid + is_hid_haptic, 1);
614   }
615 
616   if (is_dualshock4 && !dualshock4_) {
617     dualshock4_ = std::make_unique<Dualshock4Controller>(
618         gamepad_id, bus_type_, std::make_unique<HidWriterLinux>(hidraw_fd_));
619   }
620 
621   if (is_xbox_hid && !xbox_hid_) {
622     xbox_hid_ = std::make_unique<XboxHidController>(
623         std::make_unique<HidWriterLinux>(hidraw_fd_));
624   }
625 
626   if (is_hid_haptic && !hid_haptics_) {
627     hid_haptics_ = HidHapticGamepad::Create(
628         vendor_id, product_id, std::make_unique<HidWriterLinux>(hidraw_fd_));
629   }
630 }
631 
CloseHidrawNode()632 void GamepadDeviceLinux::CloseHidrawNode() {
633   DCHECK(polling_runner_->RunsTasksInCurrentSequence());
634   if (dualshock4_)
635     dualshock4_->Shutdown();
636   dualshock4_.reset();
637   if (xbox_hid_)
638     xbox_hid_->Shutdown();
639   xbox_hid_.reset();
640   if (hid_haptics_)
641     hid_haptics_->Shutdown();
642   hid_haptics_.reset();
643   hidraw_fd_.reset();
644 }
645 
SetVibration(double strong_magnitude,double weak_magnitude)646 void GamepadDeviceLinux::SetVibration(double strong_magnitude,
647                                       double weak_magnitude) {
648   DCHECK(polling_runner_->RunsTasksInCurrentSequence());
649   if (dualshock4_) {
650     dualshock4_->SetVibration(strong_magnitude, weak_magnitude);
651     return;
652   }
653 
654   if (xbox_hid_) {
655     xbox_hid_->SetVibration(strong_magnitude, weak_magnitude);
656     return;
657   }
658 
659   if (hid_haptics_) {
660     hid_haptics_->SetVibration(strong_magnitude, weak_magnitude);
661     return;
662   }
663 
664   uint16_t strong_magnitude_scaled =
665       static_cast<uint16_t>(strong_magnitude * kRumbleMagnitudeMax);
666   uint16_t weak_magnitude_scaled =
667       static_cast<uint16_t>(weak_magnitude * kRumbleMagnitudeMax);
668 
669   // AbstractHapticGamepad will call SetZeroVibration when the effect is
670   // complete, so we don't need to set the duration here except to make sure it
671   // is at least as long as the maximum duration.
672   uint16_t duration_millis =
673       static_cast<uint16_t>(GamepadHapticActuator::kMaxEffectDurationMillis);
674 
675   // Upload the effect and get the new effect ID. If we already created an
676   // effect on this device, reuse its ID.
677   effect_id_ =
678       StoreRumbleEffect(evdev_fd_, effect_id_, duration_millis, 0,
679                         strong_magnitude_scaled, weak_magnitude_scaled);
680 
681   if (effect_id_ != kInvalidEffectId)
682     StartOrStopEffect(evdev_fd_, effect_id_, true);
683 }
684 
SetZeroVibration()685 void GamepadDeviceLinux::SetZeroVibration() {
686   DCHECK(polling_runner_->RunsTasksInCurrentSequence());
687   if (dualshock4_) {
688     dualshock4_->SetZeroVibration();
689     return;
690   }
691 
692   if (xbox_hid_) {
693     xbox_hid_->SetZeroVibration();
694     return;
695   }
696 
697   if (hid_haptics_) {
698     hid_haptics_->SetZeroVibration();
699     return;
700   }
701 
702   if (effect_id_ != kInvalidEffectId)
703     StartOrStopEffect(evdev_fd_, effect_id_, false);
704 }
705 
GetWeakPtr()706 base::WeakPtr<AbstractHapticGamepad> GamepadDeviceLinux::GetWeakPtr() {
707   DCHECK(polling_runner_->RunsTasksInCurrentSequence());
708   return weak_factory_.GetWeakPtr();
709 }
710 
711 }  // namespace device
712