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