gamepad_platform_data_fetcher_linux.cc 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380
  1. // Copyright (c) 2012 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. #include "device/gamepad/gamepad_platform_data_fetcher_linux.h"
  5. #include <stddef.h>
  6. #include <string.h>
  7. #include <sys/stat.h>
  8. #include <sys/types.h>
  9. #include <unistd.h>
  10. #include "base/bind.h"
  11. #include "base/callback_helpers.h"
  12. #include "base/strings/string_number_conversions.h"
  13. #include "base/strings/utf_string_conversions.h"
  14. #include "base/trace_event/trace_event.h"
  15. #include "device/gamepad/gamepad_blocklist.h"
  16. #include "device/gamepad/gamepad_id_list.h"
  17. #include "device/gamepad/gamepad_uma.h"
  18. #include "device/gamepad/nintendo_controller.h"
  19. #include "device/udev_linux/scoped_udev.h"
  20. namespace device {
  21. GamepadPlatformDataFetcherLinux::Factory::Factory(
  22. scoped_refptr<base::SequencedTaskRunner> dbus_runner)
  23. : dbus_runner_(std::move(dbus_runner)) {}
  24. GamepadPlatformDataFetcherLinux::Factory::~Factory() = default;
  25. std::unique_ptr<GamepadDataFetcher>
  26. GamepadPlatformDataFetcherLinux::Factory::CreateDataFetcher() {
  27. return std::make_unique<GamepadPlatformDataFetcherLinux>(dbus_runner_);
  28. }
  29. GamepadSource GamepadPlatformDataFetcherLinux::Factory::source() {
  30. return GAMEPAD_SOURCE_LINUX_UDEV;
  31. }
  32. GamepadSource GamepadPlatformDataFetcherLinux::Factory::static_source() {
  33. return GAMEPAD_SOURCE_LINUX_UDEV;
  34. }
  35. GamepadPlatformDataFetcherLinux::GamepadPlatformDataFetcherLinux(
  36. scoped_refptr<base::SequencedTaskRunner> dbus_runner)
  37. : dbus_runner_(dbus_runner) {}
  38. GamepadPlatformDataFetcherLinux::~GamepadPlatformDataFetcherLinux() {
  39. for (auto it = devices_.begin(); it != devices_.end(); ++it) {
  40. GamepadDeviceLinux* device = it->get();
  41. device->Shutdown();
  42. }
  43. }
  44. GamepadSource GamepadPlatformDataFetcherLinux::source() {
  45. return Factory::static_source();
  46. }
  47. void GamepadPlatformDataFetcherLinux::OnAddedToProvider() {
  48. std::vector<UdevWatcher::Filter> filters;
  49. filters.emplace_back(UdevGamepadLinux::kInputSubsystem, "");
  50. filters.emplace_back(UdevGamepadLinux::kHidrawSubsystem, "");
  51. udev_watcher_ = UdevWatcher::StartWatching(this, filters);
  52. for (auto it = devices_.begin(); it != devices_.end(); ++it)
  53. it->get()->Shutdown();
  54. devices_.clear();
  55. udev_watcher_->EnumerateExistingDevices();
  56. }
  57. void GamepadPlatformDataFetcherLinux::OnDeviceAdded(
  58. ScopedUdevDevicePtr device) {
  59. RefreshDevice(device.get());
  60. }
  61. void GamepadPlatformDataFetcherLinux::OnDeviceRemoved(
  62. ScopedUdevDevicePtr device) {
  63. RefreshDevice(device.get());
  64. }
  65. void GamepadPlatformDataFetcherLinux::OnDeviceChanged(
  66. ScopedUdevDevicePtr device) {
  67. RefreshDevice(device.get());
  68. }
  69. void GamepadPlatformDataFetcherLinux::GetGamepadData(bool) {
  70. TRACE_EVENT0("GAMEPAD", "GetGamepadData");
  71. // Update our internal state.
  72. for (const auto& device : devices_) {
  73. if (device->GetJoydevIndex() >= 0)
  74. ReadDeviceData(device->GetJoydevIndex());
  75. }
  76. }
  77. // Used during enumeration, and monitor notifications.
  78. void GamepadPlatformDataFetcherLinux::RefreshDevice(udev_device* dev) {
  79. std::unique_ptr<UdevGamepadLinux> udev_gamepad =
  80. UdevGamepadLinux::Create(dev);
  81. if (udev_gamepad) {
  82. const UdevGamepadLinux& pad_info = *udev_gamepad.get();
  83. if (pad_info.type == UdevGamepadLinux::Type::JOYDEV) {
  84. // If |syspath_prefix| is empty, the device was already disconnected.
  85. if (pad_info.syspath_prefix.empty())
  86. DisconnectUnrecognizedGamepad(pad_info.index);
  87. else
  88. RefreshJoydevDevice(dev, pad_info);
  89. } else if (pad_info.type == UdevGamepadLinux::Type::EVDEV) {
  90. RefreshEvdevDevice(dev, pad_info);
  91. } else if (pad_info.type == UdevGamepadLinux::Type::HIDRAW) {
  92. RefreshHidrawDevice(dev, pad_info);
  93. }
  94. }
  95. }
  96. GamepadDeviceLinux* GamepadPlatformDataFetcherLinux::GetDeviceWithJoydevIndex(
  97. int joydev_index) {
  98. for (auto it = devices_.begin(); it != devices_.end(); ++it) {
  99. GamepadDeviceLinux* device = it->get();
  100. if (device->GetJoydevIndex() == joydev_index)
  101. return device;
  102. }
  103. return nullptr;
  104. }
  105. void GamepadPlatformDataFetcherLinux::RemoveDevice(GamepadDeviceLinux* device) {
  106. for (auto it = devices_.begin(); it != devices_.end(); ++it) {
  107. if (it->get() == device) {
  108. device->Shutdown();
  109. devices_.erase(it);
  110. return;
  111. }
  112. }
  113. }
  114. bool GamepadPlatformDataFetcherLinux::DisconnectUnrecognizedGamepad(int index) {
  115. for (auto it = devices_.begin(); it != devices_.end(); ++it) {
  116. const auto& device = *it;
  117. if (device->GetJoydevIndex() == index) {
  118. device->Shutdown();
  119. devices_.erase(it);
  120. return true;
  121. }
  122. }
  123. return false;
  124. }
  125. GamepadDeviceLinux* GamepadPlatformDataFetcherLinux::GetOrCreateMatchingDevice(
  126. const UdevGamepadLinux& pad_info) {
  127. for (auto it = devices_.begin(); it != devices_.end(); ++it) {
  128. GamepadDeviceLinux* device = it->get();
  129. if (device->IsSameDevice(pad_info))
  130. return device;
  131. }
  132. auto emplace_result = devices_.emplace(std::make_unique<GamepadDeviceLinux>(
  133. pad_info.syspath_prefix, dbus_runner_));
  134. return emplace_result.first->get();
  135. }
  136. void GamepadPlatformDataFetcherLinux::RefreshJoydevDevice(
  137. udev_device* dev,
  138. const UdevGamepadLinux& pad_info) {
  139. const int joydev_index = pad_info.index;
  140. GamepadDeviceLinux* device = GetOrCreateMatchingDevice(pad_info);
  141. if (device == nullptr)
  142. return;
  143. // If the device cannot be opened, the joystick has been disconnected.
  144. if (!device->OpenJoydevNode(pad_info, dev)) {
  145. if (device->IsEmpty())
  146. RemoveDevice(device);
  147. return;
  148. }
  149. std::string name = device->GetName();
  150. uint16_t vendor_id = device->GetVendorId();
  151. uint16_t product_id = device->GetProductId();
  152. // Filter out devices that have gamepad-like HID usages but aren't gamepads.
  153. if (GamepadIsExcluded(vendor_id, product_id)) {
  154. device->CloseJoydevNode();
  155. RemoveDevice(device);
  156. return;
  157. }
  158. const GamepadId gamepad_id =
  159. GamepadIdList::Get().GetGamepadId(name, vendor_id, product_id);
  160. if (NintendoController::IsNintendoController(gamepad_id)) {
  161. // Nintendo devices are handled by the Nintendo data fetcher.
  162. device->CloseJoydevNode();
  163. RemoveDevice(device);
  164. return;
  165. }
  166. bool is_recognized = gamepad_id != GamepadId::kUnknownGamepad;
  167. PadState* state = GetPadState(joydev_index, is_recognized);
  168. if (!state) {
  169. // No slot available for device, don't use.
  170. device->CloseJoydevNode();
  171. RemoveDevice(device);
  172. return;
  173. }
  174. // The device pointed to by dev contains information about the logical
  175. // joystick device. In order to get the information about the physical
  176. // hardware, get the parent device that is also in the "input" subsystem.
  177. // This function should just walk up the tree one level.
  178. udev_device* parent_dev =
  179. device::udev_device_get_parent_with_subsystem_devtype(
  180. dev, UdevGamepadLinux::kInputSubsystem, nullptr);
  181. if (!parent_dev) {
  182. device->CloseJoydevNode();
  183. if (device->IsEmpty())
  184. RemoveDevice(device);
  185. return;
  186. }
  187. // If the device is on our list, record it by ID. If the device is unknown,
  188. // record that an unknown gamepad was enumerated.
  189. if (is_recognized)
  190. RecordUnknownGamepad(source());
  191. else
  192. RecordConnectedGamepad(gamepad_id);
  193. state->mapper = device->GetMappingFunction();
  194. Gamepad& pad = state->data;
  195. UpdateGamepadStrings(name, vendor_id, product_id, state->mapper != nullptr,
  196. pad);
  197. pad.vibration_actuator.type = GamepadHapticActuatorType::kDualRumble;
  198. pad.vibration_actuator.not_null = device->SupportsVibration();
  199. pad.connected = true;
  200. }
  201. void GamepadPlatformDataFetcherLinux::RefreshEvdevDevice(
  202. udev_device* dev,
  203. const UdevGamepadLinux& pad_info) {
  204. GamepadDeviceLinux* device = GetOrCreateMatchingDevice(pad_info);
  205. if (device == nullptr)
  206. return;
  207. if (!device->OpenEvdevNode(pad_info)) {
  208. if (device->IsEmpty())
  209. RemoveDevice(device);
  210. return;
  211. }
  212. int joydev_index = device->GetJoydevIndex();
  213. if (joydev_index >= 0) {
  214. PadState* state = GetPadState(joydev_index);
  215. DCHECK(state);
  216. if (state) {
  217. Gamepad& pad = state->data;
  218. // To select the correct mapper for an arbitrary gamepad we may need info
  219. // from both the joydev and evdev nodes. For instance, a gamepad that
  220. // connects over USB and Bluetooth may need to select a mapper based on
  221. // the connection type, but this information is only available through
  222. // evdev. To ensure that gamepads are usable when evdev is unavailable, a
  223. // preliminary mapping is assigned when the joydev node is enumerated.
  224. //
  225. // Here we check if associating the evdev node changed the mapping
  226. // function that should be used for this gamepad. If so, assign the new
  227. // mapper and rebuild the gamepad strings.
  228. GamepadStandardMappingFunction mapper = device->GetMappingFunction();
  229. if (mapper != state->mapper) {
  230. state->mapper = mapper;
  231. UpdateGamepadStrings(device->GetName(), device->GetVendorId(),
  232. device->GetProductId(), mapper != nullptr, pad);
  233. }
  234. pad.vibration_actuator.not_null = device->SupportsVibration();
  235. }
  236. }
  237. }
  238. void GamepadPlatformDataFetcherLinux::RefreshHidrawDevice(
  239. udev_device* dev,
  240. const UdevGamepadLinux& pad_info) {
  241. GamepadDeviceLinux* device = GetOrCreateMatchingDevice(pad_info);
  242. if (device == nullptr)
  243. return;
  244. device->OpenHidrawNode(
  245. pad_info,
  246. base::BindOnce(&GamepadPlatformDataFetcherLinux::OnHidrawDeviceOpened,
  247. weak_factory_.GetWeakPtr()));
  248. }
  249. void GamepadPlatformDataFetcherLinux::OnHidrawDeviceOpened(
  250. GamepadDeviceLinux* device) {
  251. DCHECK(device);
  252. if (device->IsEmpty()) {
  253. RemoveDevice(device);
  254. return;
  255. }
  256. int joydev_index = device->GetJoydevIndex();
  257. if (joydev_index < 0)
  258. return;
  259. PadState* state = GetPadState(joydev_index);
  260. if (!state)
  261. return;
  262. Gamepad& pad = state->data;
  263. pad.vibration_actuator.type = GamepadHapticActuatorType::kDualRumble;
  264. pad.vibration_actuator.not_null = device->SupportsVibration();
  265. }
  266. void GamepadPlatformDataFetcherLinux::ReadDeviceData(size_t index) {
  267. GamepadDeviceLinux* device = GetDeviceWithJoydevIndex(index);
  268. if (!device)
  269. return;
  270. PadState* state = GetPadState(index);
  271. if (!state)
  272. return;
  273. device->ReadPadState(&state->data);
  274. }
  275. void GamepadPlatformDataFetcherLinux::PlayEffect(
  276. int pad_id,
  277. mojom::GamepadHapticEffectType type,
  278. mojom::GamepadEffectParametersPtr params,
  279. mojom::GamepadHapticsManager::PlayVibrationEffectOnceCallback callback,
  280. scoped_refptr<base::SequencedTaskRunner> callback_runner) {
  281. if (pad_id < 0 || pad_id >= static_cast<int>(Gamepads::kItemsLengthCap)) {
  282. RunVibrationCallback(
  283. std::move(callback), std::move(callback_runner),
  284. mojom::GamepadHapticsResult::GamepadHapticsResultError);
  285. return;
  286. }
  287. GamepadDeviceLinux* device = GetDeviceWithJoydevIndex(pad_id);
  288. if (!device) {
  289. RunVibrationCallback(
  290. std::move(callback), std::move(callback_runner),
  291. mojom::GamepadHapticsResult::GamepadHapticsResultError);
  292. return;
  293. }
  294. device->PlayEffect(type, std::move(params), std::move(callback),
  295. std::move(callback_runner));
  296. }
  297. void GamepadPlatformDataFetcherLinux::ResetVibration(
  298. int pad_id,
  299. mojom::GamepadHapticsManager::ResetVibrationActuatorCallback callback,
  300. scoped_refptr<base::SequencedTaskRunner> callback_runner) {
  301. if (pad_id < 0 || pad_id >= static_cast<int>(Gamepads::kItemsLengthCap)) {
  302. RunVibrationCallback(
  303. std::move(callback), std::move(callback_runner),
  304. mojom::GamepadHapticsResult::GamepadHapticsResultError);
  305. return;
  306. }
  307. GamepadDeviceLinux* device = GetDeviceWithJoydevIndex(pad_id);
  308. if (!device) {
  309. RunVibrationCallback(
  310. std::move(callback), std::move(callback_runner),
  311. mojom::GamepadHapticsResult::GamepadHapticsResultError);
  312. return;
  313. }
  314. device->ResetVibration(std::move(callback), std::move(callback_runner));
  315. }
  316. } // namespace device