hid_connection_linux.cc revision 5d1f7b1de12d16ceb2c938c56701a3e8bfa558f7
15d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)// Copyright (c) 2014 The Chromium Authors. All rights reserved. 25d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be 35d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)// found in the LICENSE file. 45d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 55d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include "device/hid/hid_connection_linux.h" 65d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 75d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include <errno.h> 85d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include <fcntl.h> 95d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include <libudev.h> 105d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include <linux/hidraw.h> 115d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include <string> 125d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 135d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include "base/threading/thread_restrictions.h" 145d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include "base/tuple.h" 155d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include "device/hid/hid_service.h" 165d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include "device/hid/hid_service_linux.h" 175d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 185d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 195d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)namespace device { 205d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 215d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)namespace { 225d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 235d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)const char kHidrawSubsystem[] = "hidraw"; 245d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 255d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)} // namespace 265d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 275d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)HidConnectionLinux::HidConnectionLinux(HidDeviceInfo device_info, 285d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) ScopedUdevDevicePtr udev_raw_device) 295d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) : HidConnection(device_info), 305d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) initialized_(false) { 315d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) DCHECK(thread_checker_.CalledOnValidThread()); 325d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 335d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) udev_device* dev = udev_raw_device.get(); 345d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) std::string dev_node; 355d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) if (!FindHidrawDevNode(dev, &dev_node)) { 365d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) LOG(ERROR) << "Cannot open HID device as hidraw device."; 375d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) return; 385d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) } 395d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 405d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) base::PlatformFileError error; 415d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 425d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) int flags = base::PLATFORM_FILE_OPEN | 435d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) base::PLATFORM_FILE_READ | 445d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) base::PLATFORM_FILE_WRITE | 455d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) base::PLATFORM_FILE_EXCLUSIVE_READ | 465d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) base::PLATFORM_FILE_EXCLUSIVE_WRITE; 475d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 485d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) base::PlatformFile device_file = base::CreatePlatformFile( 495d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) base::FilePath(dev_node), 505d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) flags, 515d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) NULL, 525d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) &error); 535d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) if (error || device_file <= 0) { 545d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) LOG(ERROR) << error; 555d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) if (device_file) 565d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) base::ClosePlatformFile(device_file); 575d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) return; 585d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) } 595d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) if (fcntl(device_file, F_SETFL, fcntl(device_file, F_GETFL) | O_NONBLOCK)) { 605d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) PLOG(ERROR) << "Failed to set non-blocking flag to device file."; 615d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) return; 625d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) } 635d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) device_file_ = device_file; 645d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 655d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) if (!base::MessageLoopForIO::current()->WatchFileDescriptor( 665d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) device_file_, 675d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) true, 685d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) base::MessageLoopForIO::WATCH_READ_WRITE, 695d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) &device_file_watcher_, 705d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) this)) { 715d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) LOG(ERROR) << "Cannot start watching file descriptor."; 725d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) return; 735d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) } 745d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 755d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) initialized_ = true; 765d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)} 775d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 785d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)HidConnectionLinux::~HidConnectionLinux() { 795d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) DCHECK(thread_checker_.CalledOnValidThread()); 805d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) Disconnect(); 815d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)} 825d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 835d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)void HidConnectionLinux::OnFileCanReadWithoutBlocking(int fd) { 845d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) DCHECK(thread_checker_.CalledOnValidThread()); 855d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) DCHECK_EQ(fd, device_file_); 865d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) DCHECK(initialized_); 875d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 885d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) uint8 buffer[1024] = {0}; 895d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) int bytes = read(device_file_, buffer, 1024); 905d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) if (bytes < 0) { 915d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) if (errno == EAGAIN) { 925d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) return; 935d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) } 945d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) Disconnect(); 955d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) return; 965d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) } 975d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) scoped_refptr<net::IOBuffer> io_buffer(new net::IOBuffer(bytes)); 985d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) memcpy(io_buffer->data(), buffer, bytes); 995d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) input_reports_.push(std::make_pair(io_buffer, bytes)); 1005d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 1015d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) ProcessReadQueue(); 1025d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)} 1035d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 1045d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)void HidConnectionLinux::OnFileCanWriteWithoutBlocking(int fd) {} 1055d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 1065d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)void HidConnectionLinux::Disconnect() { 1075d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) DCHECK(thread_checker_.CalledOnValidThread()); 1085d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) if (!initialized_) 1095d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) return; 1105d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 1115d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) initialized_ = false; 1125d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) device_file_watcher_.StopWatchingFileDescriptor(); 1135d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) close(device_file_); 1145d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) while (!read_queue_.empty()) { 1155d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) PendingRequest callback = read_queue_.front(); 1165d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) read_queue_.pop(); 1175d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) callback.c.Run(false, 0); 1185d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) } 1195d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)} 1205d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 1215d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)void HidConnectionLinux::Read(scoped_refptr<net::IOBuffer> buffer, 1225d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) size_t size, 1235d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) const IOCallback& callback) { 1245d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) DCHECK(thread_checker_.CalledOnValidThread()); 1255d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) if (!initialized_) { 1265d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) DCHECK(read_queue_.empty()); 1275d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) // There might be unread reports. 1285d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) if (!input_reports_.empty()){ 1295d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) read_queue_.push(MakeTuple(buffer, size, callback)); 1305d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) ProcessReadQueue(); 1315d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) } 1325d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) callback.Run(false, 0); 1335d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) return; 1345d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) } else { 1355d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) read_queue_.push(MakeTuple(buffer, size, callback)); 1365d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) ProcessReadQueue(); 1375d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) } 1385d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)} 1395d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 1405d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)void HidConnectionLinux::Write(scoped_refptr<net::IOBuffer> buffer, 1415d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) size_t size, 1425d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) const IOCallback& callback) { 1435d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) DCHECK(thread_checker_.CalledOnValidThread()); 1445d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) if (!initialized_) { 1455d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) callback.Run(false, 0); 1465d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) return; 1475d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) } else { 1485d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) int bytes = write(device_file_, buffer->data(), size); 1495d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) if (bytes < 0) { 1505d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) Disconnect(); 1515d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) callback.Run(false, 0); 1525d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) } else { 1535d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) callback.Run(true, bytes); 1545d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) } 1555d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) } 1565d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)} 1575d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 1585d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)void HidConnectionLinux::GetFeatureReport(scoped_refptr<net::IOBuffer> buffer, 1595d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) size_t size, 1605d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) const IOCallback& callback) { 1615d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) DCHECK(thread_checker_.CalledOnValidThread()); 1625d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) if (!initialized_) { 1635d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) callback.Run(false, 0); 1645d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) return; 1655d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) } 1665d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) NOTIMPLEMENTED(); 1675d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)} 1685d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 1695d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)void HidConnectionLinux::SendFeatureReport(scoped_refptr<net::IOBuffer> buffer, 1705d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) size_t size, 1715d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) const IOCallback& callback) { 1725d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) DCHECK(thread_checker_.CalledOnValidThread()); 1735d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) if (!initialized_) { 1745d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) callback.Run(false, 0); 1755d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) return; 1765d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) } 1775d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) NOTIMPLEMENTED(); 1785d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)} 1795d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 1805d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)void HidConnectionLinux::ProcessReadQueue() { 1815d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) while(read_queue_.size() && input_reports_.size()) { 1825d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) PendingRequest request = read_queue_.front(); 1835d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) read_queue_.pop(); 1845d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) PendingReport report = input_reports_.front(); 1855d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) if (report.second > request.b) { 1865d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) request.c.Run(false, report.second); 1875d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) } else { 1885d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) memcpy(request.a->data(), report.first->data(), report.second); 1895d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) input_reports_.pop(); 1905d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) request.c.Run(true, report.second); 1915d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) } 1925d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) } 1935d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)} 1945d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 1955d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)bool HidConnectionLinux::FindHidrawDevNode(udev_device* parent, 1965d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) std::string* result) { 1975d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) udev* udev = udev_device_get_udev(parent); 1985d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) if (!udev) 1995d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) return false; 2005d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 2015d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) ScopedUdevEnumeratePtr enumerate(udev_enumerate_new(udev)); 2025d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) if (!enumerate) 2035d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) return false; 2045d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 2055d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) if (udev_enumerate_add_match_subsystem(enumerate.get(), kHidrawSubsystem)) { 2065d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) return false; 2075d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) } 2085d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) if (udev_enumerate_scan_devices(enumerate.get())) { 2095d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) return false; 2105d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) } 2115d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 2125d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) const char* parent_path = udev_device_get_devpath(parent); 2135d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) udev_list_entry* devices = udev_enumerate_get_list_entry(enumerate.get()); 2145d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) for (udev_list_entry* i = devices; i != NULL; 2155d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) i = udev_list_entry_get_next(i)) { 2165d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) ScopedUdevDevicePtr hid_dev( 2175d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) udev_device_new_from_syspath(udev, udev_list_entry_get_name(i))); 2185d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) const char* raw_path = udev_device_get_devnode(hid_dev.get()); 2195d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) if (strncmp(parent_path, 2205d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) udev_device_get_devpath(hid_dev.get()), 2215d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) strlen(parent_path)) == 0 && 2225d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) raw_path) { 2235d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) *result = raw_path; 2245d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) return true; 2255d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) } 2265d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) } 2275d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 2285d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) return false; 2295d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)} 2305d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 2315d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)} // namespace device 232