Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(148)

Side by Side Diff: device/hid/hid_connection_linux.cc

Issue 143883005: HID backend (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@hid-impl-base
Patch Set: Created 6 years, 11 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
(Empty)
1 // Copyright (c) 2014 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/hid/hid_connection_linux.h"
6
7 #include <errno.h>
8 #include <fcntl.h>
9 #include <libudev.h>
10 #include <linux/hidraw.h>
11 #include <string>
12
13 #include "base/threading/thread_restrictions.h"
14 #include "device/hid/hid_service.h"
15 #include "device/hid/hid_service_linux.h"
16
17
18 namespace device {
19
20 namespace {
21
22 const char* kHidrawSubsystem = "hidraw";
23
24 } // namespace
25
26 HidConnectionLinux::HidConnectionLinux(HidDeviceInfo device_info,
27 ScopedUdevDevicePtr udev_raw_device)
28 : HidConnection(device_info),
29 initialized_(false) {
30 udev_device* dev = udev_raw_device.get();
31 std::string dev_node;
32 if (!FindHidrawDevNode(dev, &dev_node)) {
33 LOG(ERROR) << "Cannot open HID device as hidraw device.";
34 return;
35 }
36
37 base::PlatformFileError error;
38
39 int flags = base::PLATFORM_FILE_OPEN |
40 base::PLATFORM_FILE_READ |
41 base::PLATFORM_FILE_WRITE |
42 base::PLATFORM_FILE_EXCLUSIVE_READ |
43 base::PLATFORM_FILE_EXCLUSIVE_WRITE;
44
45 base::PlatformFile device_file = base::CreatePlatformFile(
46 base::FilePath(dev_node),
47 flags,
48 NULL,
49 &error);
50 if (error || device_file <= 0) {
51 LOG(ERROR) << error;
52 if (device_file)
53 base::ClosePlatformFile(device_file);
54 return;
55 }
56 if (fcntl(device_file, F_SETFL, fcntl(device_file, F_GETFL) | O_NONBLOCK)) {
57 PLOG(ERROR) << "Failed to set non-blocking flag to device file.";
58 return;
59 }
60 device_file_ = device_file;
61
62 if (!base::MessageLoopForIO::current()->WatchFileDescriptor(
63 device_file_,
64 true,
65 base::MessageLoopForIO::WATCH_READ_WRITE,
66 &device_file_watcher_,
67 this)) {
68 LOG(ERROR) << "Cannot start watching file descriptor.";
69 return;
70 }
71
72 initialized_ = true;
73 }
74
75 HidConnectionLinux::~HidConnectionLinux() {
76 Disconnect();
77 }
78
79 void HidConnectionLinux::OnFileCanReadWithoutBlocking(int fd) {
80 DCHECK_EQ(fd, device_file_);
81 DCHECK(initialized_);
82
83 uint8 buffer[1024] = {0};
84 int bytes = read(device_file_, buffer, 1024);
85 if (bytes < 0) {
86 if (errno == EAGAIN) {
87 return;
88 }
89 Disconnect();
90 return;
91 }
92 scoped_refptr<net::IOBuffer> io_buffer(new net::IOBuffer(bytes));
93 memcpy(io_buffer->data(), buffer, bytes);
94 input_reports_.push(std::make_pair(io_buffer, bytes));
95
96 ProcessReadQueue();
97 }
98
99 void HidConnectionLinux::OnFileCanWriteWithoutBlocking(int fd) {
100 DCHECK_EQ(fd, device_file_);
101 DCHECK(initialized_);
102
103 if (!write_queue_.empty()) {
104 Tuple3<scoped_refptr<net::IOBuffer>, size_t, HidIOCallback> head
105 = write_queue_.front();
106 write_queue_.pop();
107 int bytes = write(device_file_, head.a->data(), head.b);
108 if (bytes < 0) {
109 if (errno == EAGAIN) {
110 return;
111 }
112 Disconnect();
113 return;
114 }
115 head.c.Run(true, NULL, bytes);
116 }
117 }
118
119 void HidConnectionLinux::Disconnect() {
120 if (!initialized_)
121 return;
122 initialized_ = false;
123 device_file_watcher_.StopWatchingFileDescriptor();
124 close(device_file_);
125 while (!read_queue_.empty()) {
126 HidIOCallback callback = read_queue_.front();
127 read_queue_.pop();
128 callback.Run(false, NULL, 0);
129 }
130 while (!write_queue_.empty()) {
131 Tuple3<scoped_refptr<net::IOBuffer>, size_t, HidIOCallback> head
132 = write_queue_.front();
133 write_queue_.pop();
134 head.c.Run(false, NULL, 0);
135 }
136 }
137
138 void HidConnectionLinux::Read(const HidIOCallback& callback) {
139 if (!initialized_) {
140 DCHECK(read_queue_.empty());
141 // There might be unread reports.
142 if (!input_reports_.empty()){
143 std::pair<scoped_refptr<net::IOBuffer>, size_t> head =
144 input_reports_.front();
145 input_reports_.pop();
146 callback.Run(true, head.first, head.second);
147 return;
148 }
149 callback.Run(false, NULL, 0);
150 return;
151 } else {
152 read_queue_.push(callback);
153 ProcessReadQueue();
154 }
155 }
156
157 void HidConnectionLinux::Write(scoped_refptr<net::IOBuffer> buffer,
158 size_t size,
159 const HidIOCallback& callback) {
160 if (!initialized_) {
161 callback.Run(false, NULL, 0);
162 return;
163 } else {
164 write_queue_.push(MakeTuple(buffer, size, callback));
165 }
166 }
167
168 void HidConnectionLinux::GetFeatureReport(const HidIOCallback& callback) {
169 if (!initialized_) {
170 callback.Run(false, NULL, 0);
171 return;
172 }
173 NOTIMPLEMENTED();
174 }
175
176 void HidConnectionLinux::SendFeatureReport(scoped_refptr<net::IOBuffer> buffer,
177 size_t size,
178 const HidIOCallback& callback) {
179 if (!initialized_) {
180 callback.Run(false, NULL, 0);
181 return;
182 }
183 NOTIMPLEMENTED();
184 }
185
186 void HidConnectionLinux::ProcessReadQueue() {
187 while(read_queue_.size() && input_reports_.size()) {
188 HidIOCallback callback = read_queue_.front();
189 read_queue_.pop();
190 std::pair<scoped_refptr<net::IOBuffer>, size_t> report =
191 input_reports_.front();
192 input_reports_.pop();
193 callback.Run(true, report.first, report.second);
194 }
195 }
196
197 bool HidConnectionLinux::FindHidrawDevNode(udev_device* parent,
198 std::string* result) {
199 udev* udev = udev_device_get_udev(parent);
200 if (!udev)
201 return false;
202
203 ScopedUdevEnumeratePtr enumerate(udev_enumerate_new(udev));
204 if (!enumerate)
205 return false;
206
207 if (udev_enumerate_add_match_parent(enumerate.get(), parent)) {
208 return false;
209 }
210
211 if (udev_enumerate_add_match_subsystem(enumerate.get(), kHidrawSubsystem)) {
212 return false;
213 }
214 if (udev_enumerate_scan_devices(enumerate.get())) {
215 return false;
216 }
217
218 udev_list_entry* devices = udev_enumerate_get_list_entry(enumerate.get());
219 for (udev_list_entry* i = devices; i != NULL;
220 i = udev_list_entry_get_next(i)) {
221 ScopedUdevDevicePtr hid_dev(
222 udev_device_new_from_syspath(udev, udev_list_entry_get_name(i)));
223 const char* raw_path = udev_device_get_devnode(hid_dev.get());
224 if (raw_path) {
225 *result = raw_path;
226 return true;
227 }
228 }
229
230 return false;
231 }
232
233 } // namespace device
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698