Merge from Chromium at DEPS revision 284076
This commit was generated by merge_to_master.py.
Change-Id: I9a279485b02fe7ceddcd32d992a714ff132e99ae
diff --git a/device/hid/hid.gyp b/device/hid/hid.gyp
index c12845a..2db80fd 100644
--- a/device/hid/hid.gyp
+++ b/device/hid/hid.gyp
@@ -16,6 +16,8 @@
'sources': [
'device_monitor_linux.cc',
'device_monitor_linux.h',
+ 'hid_collection_info.cc',
+ 'hid_collection_info.h',
'hid_connection.cc',
'hid_connection.h',
'hid_connection_linux.cc',
@@ -40,8 +42,6 @@
'hid_service_win.h',
'hid_usage_and_page.cc',
'hid_usage_and_page.h',
- 'hid_utils_mac.cc',
- 'hid_utils_mac.h',
'input_service_linux.cc',
'input_service_linux.h',
],
diff --git a/device/hid/hid_collection_info.cc b/device/hid/hid_collection_info.cc
new file mode 100644
index 0000000..4c55d08
--- /dev/null
+++ b/device/hid/hid_collection_info.cc
@@ -0,0 +1,17 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "device/hid/hid_collection_info.h"
+
+namespace device {
+
+HidCollectionInfo::HidCollectionInfo()
+ : usage(HidUsageAndPage::kGenericDesktopUndefined,
+ HidUsageAndPage::kPageUndefined) {
+}
+
+HidCollectionInfo::~HidCollectionInfo() {
+}
+
+} // namespace device
diff --git a/device/hid/hid_collection_info.h b/device/hid/hid_collection_info.h
new file mode 100644
index 0000000..3b35e5e
--- /dev/null
+++ b/device/hid/hid_collection_info.h
@@ -0,0 +1,29 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef DEVICE_HID_HID_COLLECTION_INFO_H_
+#define DEVICE_HID_HID_COLLECTION_INFO_H_
+
+#include <set>
+
+#include "device/hid/hid_usage_and_page.h"
+
+namespace device {
+
+struct HidCollectionInfo {
+ HidCollectionInfo();
+ ~HidCollectionInfo();
+
+ // Collection's usage ID.
+ HidUsageAndPage usage;
+
+ // HID report IDs which belong
+ // to this collection or to its
+ // embedded collections.
+ std::set<int> report_ids;
+};
+
+} // namespace device"
+
+#endif // DEVICE_HID_HID_COLLECTION_INFO_H_
diff --git a/device/hid/hid_connection.cc b/device/hid/hid_connection.cc
index c134bf2..76809d3 100644
--- a/device/hid/hid_connection.cc
+++ b/device/hid/hid_connection.cc
@@ -4,8 +4,183 @@
#include "device/hid/hid_connection.h"
+#include <algorithm>
+
namespace device {
+namespace {
+
+// Functor used to filter collections by report ID.
+struct CollectionHasReportId {
+ explicit CollectionHasReportId(const uint8_t report_id)
+ : report_id_(report_id) {}
+
+ bool operator()(const HidCollectionInfo& info) const {
+ if (info.report_ids.size() == 0 ||
+ report_id_ == HidConnection::kNullReportId)
+ return false;
+
+ if (report_id_ == HidConnection::kAnyReportId)
+ return true;
+
+ return std::find(info.report_ids.begin(),
+ info.report_ids.end(),
+ report_id_) != info.report_ids.end();
+ }
+
+ private:
+ const uint8_t report_id_;
+};
+
+// Functor returning true if collection has a protected usage.
+struct CollectionIsProtected {
+ bool operator()(const HidCollectionInfo& info) const {
+ return info.usage.IsProtected();
+ }
+};
+
+bool FindCollectionByReportId(const HidDeviceInfo& device_info,
+ const uint8_t report_id,
+ HidCollectionInfo* collection_info) {
+ std::vector<HidCollectionInfo>::const_iterator collection_iter =
+ std::find_if(device_info.collections.begin(),
+ device_info.collections.end(),
+ CollectionHasReportId(report_id));
+ if (collection_iter != device_info.collections.end()) {
+ if (collection_info) {
+ *collection_info = *collection_iter;
+ }
+ return true;
+ }
+
+ return false;
+}
+
+bool HasReportId(const HidDeviceInfo& device_info) {
+ return FindCollectionByReportId(
+ device_info, HidConnection::kAnyReportId, NULL);
+}
+
+bool HasProtectedCollection(const HidDeviceInfo& device_info) {
+ return std::find_if(device_info.collections.begin(),
+ device_info.collections.end(),
+ CollectionIsProtected()) != device_info.collections.end();
+}
+
+} // namespace
+
+HidConnection::HidConnection(const HidDeviceInfo& device_info)
+ : device_info_(device_info) {
+ has_protected_collection_ = HasProtectedCollection(device_info);
+ has_report_id_ = HasReportId(device_info);
+}
+
+HidConnection::~HidConnection() {
+ DCHECK(thread_checker_.CalledOnValidThread());
+}
+
+void HidConnection::Read(scoped_refptr<net::IOBufferWithSize> buffer,
+ const IOCallback& callback) {
+ DCHECK(thread_checker_.CalledOnValidThread());
+ if (device_info_.max_input_report_size == 0) {
+ // The device does not support input reports.
+ callback.Run(false, 0);
+ return;
+ }
+ int expected_buffer_size = device_info_.max_input_report_size;
+ if (!has_report_id()) {
+ expected_buffer_size--;
+ }
+ if (buffer->size() < expected_buffer_size) {
+ // Receive buffer is too small.
+ callback.Run(false, 0);
+ return;
+ }
+
+ PlatformRead(buffer, callback);
+}
+
+void HidConnection::Write(uint8_t report_id,
+ scoped_refptr<net::IOBufferWithSize> buffer,
+ const IOCallback& callback) {
+ DCHECK(thread_checker_.CalledOnValidThread());
+ if (device_info_.max_output_report_size == 0) {
+ // The device does not support output reports.
+ callback.Run(false, 0);
+ return;
+ }
+ if (IsReportIdProtected(report_id)) {
+ callback.Run(false, 0);
+ return;
+ }
+
+ PlatformWrite(report_id, buffer, callback);
+}
+
+void HidConnection::GetFeatureReport(
+ uint8_t report_id,
+ scoped_refptr<net::IOBufferWithSize> buffer,
+ const IOCallback& callback) {
+ DCHECK(thread_checker_.CalledOnValidThread());
+ if (device_info_.max_feature_report_size == 0) {
+ // The device does not support feature reports.
+ callback.Run(false, 0);
+ return;
+ }
+ if (IsReportIdProtected(report_id)) {
+ callback.Run(false, 0);
+ return;
+ }
+ int expected_buffer_size = device_info_.max_feature_report_size;
+ if (!has_report_id()) {
+ expected_buffer_size--;
+ }
+ if (buffer->size() < expected_buffer_size) {
+ // Receive buffer is too small.
+ callback.Run(false, 0);
+ return;
+ }
+
+ PlatformGetFeatureReport(report_id, buffer, callback);
+}
+
+void HidConnection::SendFeatureReport(
+ uint8_t report_id,
+ scoped_refptr<net::IOBufferWithSize> buffer,
+ const IOCallback& callback) {
+ DCHECK(thread_checker_.CalledOnValidThread());
+ if (device_info_.max_feature_report_size == 0) {
+ // The device does not support feature reports.
+ callback.Run(false, 0);
+ return;
+ }
+ if (IsReportIdProtected(report_id)) {
+ callback.Run(false, 0);
+ return;
+ }
+
+ PlatformSendFeatureReport(report_id, buffer, callback);
+}
+
+bool HidConnection::CompleteRead(scoped_refptr<net::IOBufferWithSize> buffer,
+ const IOCallback& callback) {
+ if (buffer->size() == 0 || IsReportIdProtected(buffer->data()[0])) {
+ return false;
+ }
+
+ callback.Run(true, buffer->size());
+ return true;
+}
+
+bool HidConnection::IsReportIdProtected(const uint8_t report_id) {
+ HidCollectionInfo collection_info;
+ if (FindCollectionByReportId(device_info_, report_id, &collection_info)) {
+ return collection_info.usage.IsProtected();
+ }
+
+ return has_protected_collection();
+}
+
PendingHidReport::PendingHidReport() {}
PendingHidReport::~PendingHidReport() {}
@@ -14,9 +189,4 @@
PendingHidRead::~PendingHidRead() {}
-HidConnection::HidConnection(const HidDeviceInfo& device_info)
- : device_info_(device_info) {}
-
-HidConnection::~HidConnection() {}
-
} // namespace device
diff --git a/device/hid/hid_connection.h b/device/hid/hid_connection.h
index 5c08fbc..963b89f 100644
--- a/device/hid/hid_connection.h
+++ b/device/hid/hid_connection.h
@@ -9,6 +9,7 @@
#include "base/callback.h"
#include "base/memory/ref_counted.h"
+#include "base/threading/thread_checker.h"
#include "device/hid/hid_device_info.h"
#include "net/base/io_buffer.h"
@@ -16,31 +17,65 @@
class HidConnection : public base::RefCountedThreadSafe<HidConnection> {
public:
+ enum SpecialReportIds {
+ kNullReportId = 0x00,
+ kAnyReportId = 0xFF,
+ };
+
typedef base::Callback<void(bool success, size_t size)> IOCallback;
- virtual void Read(scoped_refptr<net::IOBufferWithSize> buffer,
- const IOCallback& callback) = 0;
- virtual void Write(uint8_t report_id,
- scoped_refptr<net::IOBufferWithSize> buffer,
- const IOCallback& callback) = 0;
- virtual void GetFeatureReport(uint8_t report_id,
- scoped_refptr<net::IOBufferWithSize> buffer,
- const IOCallback& callback) = 0;
- virtual void SendFeatureReport(uint8_t report_id,
- scoped_refptr<net::IOBufferWithSize> buffer,
- const IOCallback& callback) = 0;
-
const HidDeviceInfo& device_info() const { return device_info_; }
+ bool has_protected_collection() const { return has_protected_collection_; }
+ bool has_report_id() const { return has_report_id_; }
+ const base::ThreadChecker& thread_checker() const { return thread_checker_; }
+
+ void Read(scoped_refptr<net::IOBufferWithSize> buffer,
+ const IOCallback& callback);
+ void Write(uint8_t report_id,
+ scoped_refptr<net::IOBufferWithSize> buffer,
+ const IOCallback& callback);
+ void GetFeatureReport(uint8_t report_id,
+ scoped_refptr<net::IOBufferWithSize> buffer,
+ const IOCallback& callback);
+ void SendFeatureReport(uint8_t report_id,
+ scoped_refptr<net::IOBufferWithSize> buffer,
+ const IOCallback& callback);
protected:
friend class base::RefCountedThreadSafe<HidConnection>;
- friend struct HidDeviceInfo;
explicit HidConnection(const HidDeviceInfo& device_info);
virtual ~HidConnection();
+ virtual void PlatformRead(scoped_refptr<net::IOBufferWithSize> buffer,
+ const IOCallback& callback) = 0;
+ virtual void PlatformWrite(uint8_t report_id,
+ scoped_refptr<net::IOBufferWithSize> buffer,
+ const IOCallback& callback) = 0;
+ virtual void PlatformGetFeatureReport(
+ uint8_t report_id,
+ scoped_refptr<net::IOBufferWithSize> buffer,
+ const IOCallback& callback) = 0;
+ virtual void PlatformSendFeatureReport(
+ uint8_t report_id,
+ scoped_refptr<net::IOBufferWithSize> buffer,
+ const IOCallback& callback) = 0;
+
+ // PlatformRead implementation must call this method on read
+ // success, rather than directly running the callback.
+ // In case incoming buffer is empty or protected, it is filtered
+ // and this method returns false. Otherwise it runs the callback
+ // and returns true.
+ bool CompleteRead(scoped_refptr<net::IOBufferWithSize> buffer,
+ const IOCallback& callback);
+
private:
+ bool IsReportIdProtected(const uint8_t report_id);
+
const HidDeviceInfo device_info_;
+ bool has_report_id_;
+ bool has_protected_collection_;
+ base::ThreadChecker thread_checker_;
DISALLOW_COPY_AND_ASSIGN(HidConnection);
};
diff --git a/device/hid/hid_connection_linux.cc b/device/hid/hid_connection_linux.cc
index 425d88f..0220c2e 100644
--- a/device/hid/hid_connection_linux.cc
+++ b/device/hid/hid_connection_linux.cc
@@ -46,8 +46,6 @@
HidConnectionLinux::HidConnectionLinux(HidDeviceInfo device_info,
std::string dev_node)
: HidConnection(device_info) {
- DCHECK(thread_checker_.CalledOnValidThread());
-
int flags = base::File::FLAG_OPEN |
base::File::FLAG_READ |
base::File::FLAG_WRITE;
@@ -72,7 +70,7 @@
if (fcntl(device_file.GetPlatformFile(), F_SETFL,
fcntl(device_file.GetPlatformFile(), F_GETFL) | O_NONBLOCK)) {
- PLOG(ERROR) << "Failed to set non-blocking flag to device file.";
+ PLOG(ERROR) << "Failed to set non-blocking flag to device file";
return;
}
device_file_ = device_file.Pass();
@@ -88,48 +86,13 @@
}
HidConnectionLinux::~HidConnectionLinux() {
- DCHECK(thread_checker_.CalledOnValidThread());
Disconnect();
+ Flush();
}
-void HidConnectionLinux::OnFileCanReadWithoutBlocking(int fd) {
- DCHECK(thread_checker_.CalledOnValidThread());
- DCHECK_EQ(fd, device_file_.GetPlatformFile());
-
- uint8 buffer[1024] = {0};
- int bytes_read =
- HANDLE_EINTR(read(device_file_.GetPlatformFile(), buffer, 1024));
- if (bytes_read < 0) {
- if (errno == EAGAIN) {
- return;
- }
- Disconnect();
- return;
- }
-
- PendingHidReport report;
- report.buffer = new net::IOBufferWithSize(bytes_read);
- memcpy(report.buffer->data(), buffer, bytes_read);
- pending_reports_.push(report);
- ProcessReadQueue();
-}
-
-void HidConnectionLinux::OnFileCanWriteWithoutBlocking(int fd) {}
-
-void HidConnectionLinux::Disconnect() {
- DCHECK(thread_checker_.CalledOnValidThread());
- device_file_watcher_.StopWatchingFileDescriptor();
- device_file_.Close();
- while (!pending_reads_.empty()) {
- PendingHidRead pending_read = pending_reads_.front();
- pending_reads_.pop();
- pending_read.callback.Run(false, 0);
- }
-}
-
-void HidConnectionLinux::Read(scoped_refptr<net::IOBufferWithSize> buffer,
- const IOCallback& callback) {
- DCHECK(thread_checker_.CalledOnValidThread());
+void HidConnectionLinux::PlatformRead(
+ scoped_refptr<net::IOBufferWithSize> buffer,
+ const IOCallback& callback) {
PendingHidRead pending_read;
pending_read.buffer = buffer;
pending_read.callback = callback;
@@ -137,16 +100,17 @@
ProcessReadQueue();
}
-void HidConnectionLinux::Write(uint8_t report_id,
- scoped_refptr<net::IOBufferWithSize> buffer,
- const IOCallback& callback) {
- DCHECK(thread_checker_.CalledOnValidThread());
+void HidConnectionLinux::PlatformWrite(
+ uint8_t report_id,
+ scoped_refptr<net::IOBufferWithSize> buffer,
+ const IOCallback& callback) {
// If report ID is non-zero, insert it into a new copy of the buffer.
if (report_id != 0)
buffer = CopyBufferWithReportId(buffer, report_id);
int bytes_written = HANDLE_EINTR(
write(device_file_.GetPlatformFile(), buffer->data(), buffer->size()));
if (bytes_written < 0) {
+ VPLOG(1) << "Write failed";
Disconnect();
callback.Run(false, 0);
} else {
@@ -154,12 +118,10 @@
}
}
-void HidConnectionLinux::GetFeatureReport(
+void HidConnectionLinux::PlatformGetFeatureReport(
uint8_t report_id,
scoped_refptr<net::IOBufferWithSize> buffer,
const IOCallback& callback) {
- DCHECK(thread_checker_.CalledOnValidThread());
-
if (buffer->size() == 0) {
callback.Run(false, 0);
return;
@@ -170,39 +132,97 @@
int result = ioctl(device_file_.GetPlatformFile(),
HIDIOCGFEATURE(buffer->size()),
buffer->data());
- if (result < 0)
+ if (result < 0) {
+ VPLOG(1) << "Failed to get feature report";
callback.Run(false, 0);
- else
+ } else {
callback.Run(true, result);
+ }
}
-void HidConnectionLinux::SendFeatureReport(
+void HidConnectionLinux::PlatformSendFeatureReport(
uint8_t report_id,
scoped_refptr<net::IOBufferWithSize> buffer,
const IOCallback& callback) {
- DCHECK(thread_checker_.CalledOnValidThread());
if (report_id != 0)
buffer = CopyBufferWithReportId(buffer, report_id);
int result = ioctl(device_file_.GetPlatformFile(),
HIDIOCSFEATURE(buffer->size()),
buffer->data());
- if (result < 0)
+ if (result < 0) {
+ VPLOG(1) << "Failed to send feature report";
callback.Run(false, 0);
- else
+ } else {
callback.Run(true, result);
+ }
+}
+
+void HidConnectionLinux::OnFileCanReadWithoutBlocking(int fd) {
+ DCHECK(thread_checker().CalledOnValidThread());
+ DCHECK_EQ(fd, device_file_.GetPlatformFile());
+
+ uint8 raw_buffer[1024] = {0};
+ int bytes_read =
+ HANDLE_EINTR(read(device_file_.GetPlatformFile(), raw_buffer, 1024));
+ if (bytes_read < 0) {
+ if (errno == EAGAIN) {
+ return;
+ }
+ VPLOG(1) << "Read failed";
+ Disconnect();
+ return;
+ }
+
+ scoped_refptr<net::IOBufferWithSize> buffer =
+ new net::IOBufferWithSize(bytes_read);
+ memcpy(buffer->data(), raw_buffer, bytes_read);
+
+ ProcessInputReport(buffer);
+}
+
+void HidConnectionLinux::OnFileCanWriteWithoutBlocking(int fd) {
+}
+
+void HidConnectionLinux::Disconnect() {
+ DCHECK(thread_checker().CalledOnValidThread());
+ device_file_watcher_.StopWatchingFileDescriptor();
+ device_file_.Close();
+
+ Flush();
+}
+
+void HidConnectionLinux::Flush() {
+ while (!pending_reads_.empty()) {
+ pending_reads_.front().callback.Run(false, 0);
+ pending_reads_.pop();
+ }
+}
+
+void HidConnectionLinux::ProcessInputReport(
+ scoped_refptr<net::IOBufferWithSize> buffer) {
+ DCHECK(thread_checker().CalledOnValidThread());
+ PendingHidReport report;
+ report.buffer = buffer;
+ pending_reports_.push(report);
+ ProcessReadQueue();
}
void HidConnectionLinux::ProcessReadQueue() {
+ DCHECK(thread_checker().CalledOnValidThread());
while (pending_reads_.size() && pending_reports_.size()) {
PendingHidRead read = pending_reads_.front();
- pending_reads_.pop();
PendingHidReport report = pending_reports_.front();
- if (report.buffer->size() > read.buffer->size()) {
- read.callback.Run(false, report.buffer->size());
+
+ if (read.buffer->size() < report.buffer->size()) {
+ read.callback.Run(false, 0);
+ pending_reads_.pop();
} else {
memcpy(read.buffer->data(), report.buffer->data(), report.buffer->size());
pending_reports_.pop();
- read.callback.Run(true, report.buffer->size());
+
+ if (CompleteRead(report.buffer, read.callback)) {
+ pending_reads_.pop();
+ }
}
}
}
diff --git a/device/hid/hid_connection_linux.h b/device/hid/hid_connection_linux.h
index 108ad88..1f5a7a8 100644
--- a/device/hid/hid_connection_linux.h
+++ b/device/hid/hid_connection_linux.h
@@ -8,10 +8,8 @@
#include <queue>
#include "base/files/file.h"
-#include "base/memory/ref_counted.h"
#include "base/message_loop/message_pump_libevent.h"
#include "device/hid/hid_connection.h"
-#include "device/hid/hid_device_info.h"
namespace device {
@@ -20,19 +18,22 @@
public:
HidConnectionLinux(HidDeviceInfo device_info, std::string dev_node);
- virtual void Read(scoped_refptr<net::IOBufferWithSize> buffer,
- const IOCallback& callback) OVERRIDE;
- virtual void Write(uint8_t report_id,
- scoped_refptr<net::IOBufferWithSize> buffer,
- const IOCallback& callback) OVERRIDE;
- virtual void GetFeatureReport(uint8_t report_id,
- scoped_refptr<net::IOBufferWithSize> buffer,
- const IOCallback& callback) OVERRIDE;
- virtual void SendFeatureReport(uint8_t report_id,
- scoped_refptr<net::IOBufferWithSize> buffer,
- const IOCallback& callback) OVERRIDE;
+ // HidConnection implementation.
+ virtual void PlatformRead(scoped_refptr<net::IOBufferWithSize> buffer,
+ const IOCallback& callback) OVERRIDE;
+ virtual void PlatformWrite(uint8_t report_id,
+ scoped_refptr<net::IOBufferWithSize> buffer,
+ const IOCallback& callback) OVERRIDE;
+ virtual void PlatformGetFeatureReport(
+ uint8_t report_id,
+ scoped_refptr<net::IOBufferWithSize> buffer,
+ const IOCallback& callback) OVERRIDE;
+ virtual void PlatformSendFeatureReport(
+ uint8_t report_id,
+ scoped_refptr<net::IOBufferWithSize> buffer,
+ const IOCallback& callback) OVERRIDE;
- // Implements base::MessagePumpLibevent::Watcher
+ // base::MessagePumpLibevent::Watcher implementation.
virtual void OnFileCanReadWithoutBlocking(int fd) OVERRIDE;
virtual void OnFileCanWriteWithoutBlocking(int fd) OVERRIDE;
@@ -40,17 +41,18 @@
friend class base::RefCountedThreadSafe<HidConnectionLinux>;
virtual ~HidConnectionLinux();
- void ProcessReadQueue();
void Disconnect();
+ void Flush();
+ void ProcessInputReport(scoped_refptr<net::IOBufferWithSize> buffer);
+ void ProcessReadQueue();
+
base::File device_file_;
base::MessagePumpLibevent::FileDescriptorWatcher device_file_watcher_;
std::queue<PendingHidReport> pending_reports_;
std::queue<PendingHidRead> pending_reads_;
- base::ThreadChecker thread_checker_;
-
DISALLOW_COPY_AND_ASSIGN(HidConnectionLinux);
};
diff --git a/device/hid/hid_connection_mac.cc b/device/hid/hid_connection_mac.cc
index ce17df4..521f287 100644
--- a/device/hid/hid_connection_mac.cc
+++ b/device/hid/hid_connection_mac.cc
@@ -7,7 +7,6 @@
#include "base/bind.h"
#include "base/mac/foundation_util.h"
#include "base/message_loop/message_loop.h"
-#include "base/threading/thread_restrictions.h"
#include "device/hid/hid_connection_mac.h"
namespace device {
@@ -15,85 +14,70 @@
HidConnectionMac::HidConnectionMac(HidDeviceInfo device_info)
: HidConnection(device_info),
device_(device_info.device_id, base::scoped_policy::RETAIN) {
- DCHECK(thread_checker_.CalledOnValidThread());
-
message_loop_ = base::MessageLoopProxy::current();
DCHECK(device_.get());
- inbound_buffer_.reset((uint8_t*)malloc(device_info.input_report_size));
+ inbound_buffer_.reset((uint8_t*)malloc(device_info.max_input_report_size));
IOHIDDeviceRegisterInputReportCallback(device_.get(),
inbound_buffer_.get(),
- device_info.input_report_size,
+ device_info.max_input_report_size,
&HidConnectionMac::InputReportCallback,
this);
IOHIDDeviceOpen(device_, kIOHIDOptionsTypeNone);
}
HidConnectionMac::~HidConnectionMac() {
- DCHECK(thread_checker_.CalledOnValidThread());
-
- while (!pending_reads_.empty()) {
- pending_reads_.front().callback.Run(false, 0);
- pending_reads_.pop();
- }
-
IOHIDDeviceClose(device_, kIOHIDOptionsTypeNone);
+ Flush();
}
-void HidConnectionMac::Read(scoped_refptr<net::IOBufferWithSize> buffer,
- const IOCallback& callback) {
- DCHECK(thread_checker_.CalledOnValidThread());
+void HidConnectionMac::PlatformRead(scoped_refptr<net::IOBufferWithSize> buffer,
+ const IOCallback& callback) {
if (!device_) {
callback.Run(false, 0);
return;
}
- PendingHidRead read;
- read.buffer = buffer;
- read.callback = callback;
- pending_reads_.push(read);
+
+ PendingHidRead pending_read;
+ pending_read.buffer = buffer;
+ pending_read.callback = callback;
+ pending_reads_.push(pending_read);
ProcessReadQueue();
}
-void HidConnectionMac::Write(uint8_t report_id,
- scoped_refptr<net::IOBufferWithSize> buffer,
- const IOCallback& callback) {
- DCHECK(thread_checker_.CalledOnValidThread());
- WriteReport(kIOHIDReportTypeOutput, report_id, buffer, callback);
-}
-
-void HidConnectionMac::GetFeatureReport(
+void HidConnectionMac::PlatformWrite(
uint8_t report_id,
scoped_refptr<net::IOBufferWithSize> buffer,
const IOCallback& callback) {
- DCHECK(thread_checker_.CalledOnValidThread());
- if (device_info().feature_report_size == 0) {
- callback.Run(false, 0);
- return;
- }
+ WriteReport(kIOHIDReportTypeOutput, report_id, buffer, callback);
+}
- if (buffer->size() < device_info().feature_report_size) {
+void HidConnectionMac::PlatformGetFeatureReport(
+ uint8_t report_id,
+ scoped_refptr<net::IOBufferWithSize> buffer,
+ const IOCallback& callback) {
+ if (!device_) {
callback.Run(false, 0);
return;
}
uint8_t* feature_report_buffer = reinterpret_cast<uint8_t*>(buffer->data());
- CFIndex feature_report_size = device_info().feature_report_size;
+ CFIndex max_feature_report_size = device_info().max_feature_report_size;
IOReturn result = IOHIDDeviceGetReport(device_,
kIOHIDReportTypeFeature,
report_id,
feature_report_buffer,
- &feature_report_size);
+ &max_feature_report_size);
if (result == kIOReturnSuccess)
- callback.Run(true, feature_report_size);
+ callback.Run(true, max_feature_report_size);
else
callback.Run(false, 0);
}
-void HidConnectionMac::SendFeatureReport(
+void HidConnectionMac::PlatformSendFeatureReport(
uint8_t report_id,
scoped_refptr<net::IOBufferWithSize> buffer,
const IOCallback& callback) {
- DCHECK(thread_checker_.CalledOnValidThread());
WriteReport(kIOHIDReportTypeFeature, report_id, buffer, callback);
}
@@ -112,45 +96,18 @@
connection->message_loop_->PostTask(
FROM_HERE,
- base::Bind(
- &HidConnectionMac::ProcessInputReport, connection, type, buffer));
-}
-
-void HidConnectionMac::ProcessReadQueue() {
- DCHECK(thread_checker_.CalledOnValidThread());
- while (pending_reads_.size() && pending_reports_.size()) {
- PendingHidRead read = pending_reads_.front();
- pending_reads_.pop();
- PendingHidReport report = pending_reports_.front();
- if (read.buffer->size() < report.buffer->size()) {
- read.callback.Run(false, report.buffer->size());
- } else {
- memcpy(read.buffer->data(), report.buffer->data(), report.buffer->size());
- pending_reports_.pop();
- read.callback.Run(true, report.buffer->size());
- }
- }
-}
-
-void HidConnectionMac::ProcessInputReport(
- IOHIDReportType type,
- scoped_refptr<net::IOBufferWithSize> buffer) {
- DCHECK(thread_checker_.CalledOnValidThread());
- PendingHidReport report;
- report.buffer = buffer;
- pending_reports_.push(report);
- ProcessReadQueue();
+ base::Bind(&HidConnectionMac::ProcessInputReport, connection, buffer));
}
void HidConnectionMac::WriteReport(IOHIDReportType type,
uint8_t report_id,
scoped_refptr<net::IOBufferWithSize> buffer,
const IOCallback& callback) {
- DCHECK(thread_checker_.CalledOnValidThread());
if (!device_) {
callback.Run(false, 0);
return;
}
+
scoped_refptr<net::IOBufferWithSize> output_buffer;
if (report_id != 0) {
output_buffer = new net::IOBufferWithSize(buffer->size() + 1);
@@ -173,4 +130,40 @@
}
}
+void HidConnectionMac::Flush() {
+ while (!pending_reads_.empty()) {
+ pending_reads_.front().callback.Run(false, 0);
+ pending_reads_.pop();
+ }
+}
+
+void HidConnectionMac::ProcessInputReport(
+ scoped_refptr<net::IOBufferWithSize> buffer) {
+ DCHECK(thread_checker().CalledOnValidThread());
+ PendingHidReport report;
+ report.buffer = buffer;
+ pending_reports_.push(report);
+ ProcessReadQueue();
+}
+
+void HidConnectionMac::ProcessReadQueue() {
+ DCHECK(thread_checker().CalledOnValidThread());
+ while (pending_reads_.size() && pending_reports_.size()) {
+ PendingHidRead read = pending_reads_.front();
+ PendingHidReport report = pending_reports_.front();
+
+ if (read.buffer->size() < report.buffer->size()) {
+ read.callback.Run(false, 0);
+ pending_reads_.pop();
+ } else {
+ memcpy(read.buffer->data(), report.buffer->data(), report.buffer->size());
+ pending_reports_.pop();
+
+ if (CompleteRead(report.buffer, read.callback)) {
+ pending_reads_.pop();
+ }
+ }
+ }
+}
+
} // namespace device
diff --git a/device/hid/hid_connection_mac.h b/device/hid/hid_connection_mac.h
index c307fb6..02dde04 100644
--- a/device/hid/hid_connection_mac.h
+++ b/device/hid/hid_connection_mac.h
@@ -11,11 +11,8 @@
#include <queue>
#include "base/mac/foundation_util.h"
-#include "base/memory/ref_counted.h"
#include "base/memory/scoped_ptr.h"
-#include "base/threading/thread_checker.h"
#include "device/hid/hid_connection.h"
-#include "device/hid/hid_device_info.h"
namespace base {
class MessageLoopProxy;
@@ -31,17 +28,20 @@
public:
explicit HidConnectionMac(HidDeviceInfo device_info);
- virtual void Read(scoped_refptr<net::IOBufferWithSize> buffer,
- const IOCallback& callback) OVERRIDE;
- virtual void Write(uint8_t report_id,
- scoped_refptr<net::IOBufferWithSize> buffer,
- const IOCallback& callback) OVERRIDE;
- virtual void GetFeatureReport(uint8_t report_id,
- scoped_refptr<net::IOBufferWithSize> buffer,
- const IOCallback& callback) OVERRIDE;
- virtual void SendFeatureReport(uint8_t report_id,
- scoped_refptr<net::IOBufferWithSize> buffer,
- const IOCallback& callback) OVERRIDE;
+ // HidConnection implementation.
+ virtual void PlatformRead(scoped_refptr<net::IOBufferWithSize> buffer,
+ const IOCallback& callback) OVERRIDE;
+ virtual void PlatformWrite(uint8_t report_id,
+ scoped_refptr<net::IOBufferWithSize> buffer,
+ const IOCallback& callback) OVERRIDE;
+ virtual void PlatformGetFeatureReport(
+ uint8_t report_id,
+ scoped_refptr<net::IOBufferWithSize> buffer,
+ const IOCallback& callback) OVERRIDE;
+ virtual void PlatformSendFeatureReport(
+ uint8_t report_id,
+ scoped_refptr<net::IOBufferWithSize> buffer,
+ const IOCallback& callback) OVERRIDE;
private:
virtual ~HidConnectionMac();
@@ -53,29 +53,26 @@
uint32_t report_id,
uint8_t* report_bytes,
CFIndex report_length);
- void ProcessReadQueue();
- void ProcessInputReport(IOHIDReportType type,
- scoped_refptr<net::IOBufferWithSize> buffer);
void WriteReport(IOHIDReportType type,
uint8_t report_id,
scoped_refptr<net::IOBufferWithSize> buffer,
const IOCallback& callback);
- scoped_refptr<base::MessageLoopProxy> message_loop_;
+ void Flush();
+ void ProcessInputReport(scoped_refptr<net::IOBufferWithSize> buffer);
+ void ProcessReadQueue();
base::ScopedCFTypeRef<IOHIDDeviceRef> device_;
+ scoped_refptr<base::MessageLoopProxy> message_loop_;
scoped_ptr<uint8_t, base::FreeDeleter> inbound_buffer_;
std::queue<PendingHidReport> pending_reports_;
std::queue<PendingHidRead> pending_reads_;
- base::ThreadChecker thread_checker_;
-
DISALLOW_COPY_AND_ASSIGN(HidConnectionMac);
};
-
} // namespace device
#endif // DEVICE_HID_HID_CONNECTION_MAC_H_
diff --git a/device/hid/hid_connection_win.cc b/device/hid/hid_connection_win.cc
index 17448f0..767feac 100644
--- a/device/hid/hid_connection_win.cc
+++ b/device/hid/hid_connection_win.cc
@@ -8,12 +8,7 @@
#include "base/files/file.h"
#include "base/message_loop/message_loop.h"
-#include "base/stl_util.h"
-#include "base/threading/thread_restrictions.h"
#include "base/win/object_watcher.h"
-#include "base/win/scoped_handle.h"
-#include "device/hid/hid_service.h"
-#include "device/hid/hid_service_win.h"
#define INITGUID
@@ -103,7 +98,6 @@
HidConnectionWin::HidConnectionWin(const HidDeviceInfo& device_info)
: HidConnection(device_info) {
- DCHECK(thread_checker_.CalledOnValidThread());
file_.Set(CreateFileA(device_info.device_id.c_str(),
GENERIC_WRITE | GENERIC_READ,
FILE_SHARE_READ | FILE_SHARE_WRITE,
@@ -124,40 +118,15 @@
}
}
-bool HidConnectionWin::available() const {
- return file_.IsValid();
-}
-
HidConnectionWin::~HidConnectionWin() {
- DCHECK(thread_checker_.CalledOnValidThread());
CancelIo(file_.Get());
}
-void HidConnectionWin::Read(scoped_refptr<net::IOBufferWithSize> buffer,
- const HidConnection::IOCallback& callback) {
- DCHECK(thread_checker_.CalledOnValidThread());
- if (device_info().input_report_size == 0) {
- // The device does not support input reports.
- callback.Run(false, 0);
- return;
- }
+void HidConnectionWin::PlatformRead(scoped_refptr<net::IOBufferWithSize> buffer,
+ const HidConnection::IOCallback& callback) {
+ scoped_refptr<net::IOBufferWithSize> receive_buffer =
+ new net::IOBufferWithSize(device_info().max_input_report_size);
- // This fairly awkward logic is correct: If Windows does not expect a device
- // to supply a report ID in its input reports, it requires the buffer to be
- // 1 byte larger than what the device actually sends.
- int receive_buffer_size = device_info().input_report_size;
- int expected_buffer_size = receive_buffer_size;
- if (!device_info().has_report_id)
- expected_buffer_size -= 1;
-
- if (buffer->size() < expected_buffer_size) {
- callback.Run(false, 0);
- return;
- }
-
- scoped_refptr<net::IOBufferWithSize> receive_buffer(buffer);
- if (receive_buffer_size != expected_buffer_size)
- receive_buffer = new net::IOBufferWithSize(receive_buffer_size);
scoped_refptr<PendingHidTransfer> transfer(
new PendingHidTransfer(this, buffer, receive_buffer, callback));
transfers_.insert(transfer);
@@ -169,16 +138,10 @@
transfer->GetOverlapped()));
}
-void HidConnectionWin::Write(uint8_t report_id,
- scoped_refptr<net::IOBufferWithSize> buffer,
- const HidConnection::IOCallback& callback) {
- DCHECK(thread_checker_.CalledOnValidThread());
- if (device_info().output_report_size == 0) {
- // The device does not support output reports.
- callback.Run(false, 0);
- return;
- }
-
+void HidConnectionWin::PlatformWrite(
+ uint8_t report_id,
+ scoped_refptr<net::IOBufferWithSize> buffer,
+ const HidConnection::IOCallback& callback) {
// The Windows API always wants either a report ID (if supported) or
// zero at the front of every output report.
scoped_refptr<net::IOBufferWithSize> output_buffer(buffer);
@@ -197,32 +160,15 @@
transfer->GetOverlapped()));
}
-void HidConnectionWin::GetFeatureReport(
+void HidConnectionWin::PlatformGetFeatureReport(
uint8_t report_id,
scoped_refptr<net::IOBufferWithSize> buffer,
const IOCallback& callback) {
- DCHECK(thread_checker_.CalledOnValidThread());
- if (device_info().feature_report_size == 0) {
- // The device does not support feature reports.
- callback.Run(false, 0);
- return;
- }
-
- int receive_buffer_size = device_info().feature_report_size;
- int expected_buffer_size = receive_buffer_size;
- if (!device_info().has_report_id)
- expected_buffer_size -= 1;
- if (buffer->size() < expected_buffer_size) {
- callback.Run(false, 0);
- return;
- }
-
- scoped_refptr<net::IOBufferWithSize> receive_buffer(buffer);
- if (receive_buffer_size != expected_buffer_size)
- receive_buffer = new net::IOBufferWithSize(receive_buffer_size);
-
+ scoped_refptr<net::IOBufferWithSize> receive_buffer =
+ new net::IOBufferWithSize(device_info().max_feature_report_size);
// The first byte of the destination buffer is the report ID being requested.
receive_buffer->data()[0] = report_id;
+
scoped_refptr<PendingHidTransfer> transfer(
new PendingHidTransfer(this, buffer, receive_buffer, callback));
transfers_.insert(transfer);
@@ -237,17 +183,10 @@
transfer->GetOverlapped()));
}
-void HidConnectionWin::SendFeatureReport(
+void HidConnectionWin::PlatformSendFeatureReport(
uint8_t report_id,
scoped_refptr<net::IOBufferWithSize> buffer,
const IOCallback& callback) {
- DCHECK(thread_checker_.CalledOnValidThread());
- if (device_info().feature_report_size == 0) {
- // The device does not support feature reports.
- callback.Run(false, 0);
- return;
- }
-
// The Windows API always wants either a report ID (if supported) or
// zero at the front of every output report.
scoped_refptr<net::IOBufferWithSize> output_buffer(buffer);
@@ -270,25 +209,42 @@
void HidConnectionWin::OnTransferFinished(
scoped_refptr<PendingHidTransfer> transfer) {
- DWORD bytes_transferred;
transfers_.erase(transfer);
+
+ DWORD bytes_transferred;
if (GetOverlappedResult(
file_, transfer->GetOverlapped(), &bytes_transferred, FALSE)) {
- if (bytes_transferred == 0)
+ if (bytes_transferred == 0) {
transfer->callback_.Run(true, 0);
- // If this is an input transfer and the receive buffer is not the same as
- // the target buffer, we need to copy the receive buffer into the target
- // buffer, discarding the first byte. This is because the target buffer's
- // owner is not expecting a report ID but Windows will always provide one.
- if (transfer->receive_buffer_ &&
- transfer->receive_buffer_ != transfer->target_buffer_) {
- // Move one byte forward.
- --bytes_transferred;
- memcpy(transfer->target_buffer_->data(),
- transfer->receive_buffer_->data() + 1,
- bytes_transferred);
+ return;
}
- transfer->callback_.Run(true, bytes_transferred);
+
+ if (transfer->receive_buffer_) {
+ // If owner HID top-level collection does not have report ID, we need to
+ // copy the receive buffer into the target buffer, discarding the first
+ // byte. This is because the target buffer's owner is not expecting a
+ // report ID but Windows will always provide one.
+ if (!has_report_id()) {
+ uint8_t report_id = transfer->receive_buffer_->data()[0];
+ // Assert first byte is 0x00
+ if (report_id != HidConnection::kNullReportId) {
+ VLOG(1) << "Unexpected report ID in HID report:" << report_id;
+ transfer->callback_.Run(false, 0);
+ } else {
+ // Move one byte forward.
+ --bytes_transferred;
+ memcpy(transfer->target_buffer_->data(),
+ transfer->receive_buffer_->data() + 1,
+ bytes_transferred);
+ }
+ } else {
+ memcpy(transfer->target_buffer_->data(),
+ transfer->receive_buffer_->data(),
+ bytes_transferred);
+ }
+ }
+
+ CompleteRead(transfer->target_buffer_, transfer->callback_);
} else {
transfer->callback_.Run(false, 0);
}
diff --git a/device/hid/hid_connection_win.h b/device/hid/hid_connection_win.h
index 263897a..6706044 100644
--- a/device/hid/hid_connection_win.h
+++ b/device/hid/hid_connection_win.h
@@ -9,12 +9,8 @@
#include <set>
-#include "base/callback.h"
-#include "base/memory/ref_counted.h"
-#include "base/message_loop/message_loop.h"
-#include "base/threading/thread_checker.h"
+#include "base/win/scoped_handle.h"
#include "device/hid/hid_connection.h"
-#include "device/hid/hid_device_info.h"
namespace device {
@@ -24,30 +20,35 @@
public:
explicit HidConnectionWin(const HidDeviceInfo& device_info);
- bool available() const;
+ // HidConnection implementation.
+ virtual void PlatformRead(scoped_refptr<net::IOBufferWithSize> buffer,
+ const IOCallback& callback) OVERRIDE;
+ virtual void PlatformWrite(uint8_t report_id,
+ scoped_refptr<net::IOBufferWithSize> buffer,
+ const IOCallback& callback) OVERRIDE;
+ virtual void PlatformGetFeatureReport(
+ uint8_t report_id,
+ scoped_refptr<net::IOBufferWithSize> buffer,
+ const IOCallback& callback) OVERRIDE;
+ virtual void PlatformSendFeatureReport(
+ uint8_t report_id,
+ scoped_refptr<net::IOBufferWithSize> buffer,
+ const IOCallback& callback) OVERRIDE;
- virtual void Read(scoped_refptr<net::IOBufferWithSize> buffer,
- const IOCallback& callback) OVERRIDE;
- virtual void Write(uint8_t report_id,
- scoped_refptr<net::IOBufferWithSize> buffer,
- const IOCallback& callback) OVERRIDE;
- virtual void GetFeatureReport(uint8_t report_id,
- scoped_refptr<net::IOBufferWithSize> buffer,
- const IOCallback& callback) OVERRIDE;
- virtual void SendFeatureReport(uint8_t report_id,
- scoped_refptr<net::IOBufferWithSize> buffer,
- const IOCallback& callback) OVERRIDE;
+ private:
+ friend class HidServiceWin;
+ friend struct PendingHidTransfer;
+
+ ~HidConnectionWin();
+
+ bool available() const { return file_.IsValid(); }
void OnTransferFinished(scoped_refptr<PendingHidTransfer> transfer);
void OnTransferCanceled(scoped_refptr<PendingHidTransfer> transfer);
- private:
- ~HidConnectionWin();
-
base::win::ScopedHandle file_;
- std::set<scoped_refptr<PendingHidTransfer> > transfers_;
- base::ThreadChecker thread_checker_;
+ std::set<scoped_refptr<PendingHidTransfer> > transfers_;
DISALLOW_COPY_AND_ASSIGN(HidConnectionWin);
};
diff --git a/device/hid/hid_device_info.cc b/device/hid/hid_device_info.cc
index 89be442..26891f8 100644
--- a/device/hid/hid_device_info.cc
+++ b/device/hid/hid_device_info.cc
@@ -12,13 +12,13 @@
HidDeviceInfo::HidDeviceInfo()
: device_id(kInvalidHidDeviceId),
- bus_type(kHIDBusTypeUSB),
vendor_id(0),
product_id(0),
- input_report_size(0),
- output_report_size(0),
- feature_report_size(0),
- has_report_id(false) {}
+ bus_type(kHIDBusTypeUSB),
+ max_input_report_size(0),
+ max_output_report_size(0),
+ max_feature_report_size(0) {
+}
HidDeviceInfo::~HidDeviceInfo() {}
diff --git a/device/hid/hid_device_info.h b/device/hid/hid_device_info.h
index 1b143c2..2ed51ac 100644
--- a/device/hid/hid_device_info.h
+++ b/device/hid/hid_device_info.h
@@ -9,7 +9,7 @@
#include <vector>
#include "build/build_config.h"
-#include "device/hid/hid_usage_and_page.h"
+#include "device/hid/hid_collection_info.h"
#if defined(OS_MACOSX)
#include <IOKit/hid/IOHIDDevice.h>
@@ -34,20 +34,19 @@
HidDeviceInfo();
~HidDeviceInfo();
+ // Device identification.
HidDeviceId device_id;
-
- HidBusType bus_type;
uint16_t vendor_id;
uint16_t product_id;
-
- int input_report_size;
- int output_report_size;
- int feature_report_size;
- std::vector<HidUsageAndPage> usages;
- bool has_report_id;
-
std::string product_name;
std::string serial_number;
+ HidBusType bus_type;
+
+ // Top-Level Collections information.
+ std::vector<HidCollectionInfo> collections;
+ int max_input_report_size;
+ int max_output_report_size;
+ int max_feature_report_size;
};
} // namespace device
diff --git a/device/hid/hid_report_descriptor.cc b/device/hid/hid_report_descriptor.cc
index f2cb0f4..a06d284 100644
--- a/device/hid/hid_report_descriptor.cc
+++ b/device/hid/hid_report_descriptor.cc
@@ -8,6 +8,12 @@
namespace device {
+namespace {
+
+const int kBitsPerByte = 8;
+
+} // namespace
+
HidReportDescriptor::HidReportDescriptor(const uint8_t* bytes, size_t size) {
size_t header_index = 0;
HidReportDescriptorItem* item = NULL;
@@ -20,42 +26,148 @@
HidReportDescriptor::~HidReportDescriptor() {}
-void HidReportDescriptor::GetTopLevelCollections(
- std::vector<HidUsageAndPage>* topLevelCollections) {
- DCHECK(topLevelCollections);
- STLClearObject(topLevelCollections);
+void HidReportDescriptor::GetDetails(
+ std::vector<HidCollectionInfo>* top_level_collections,
+ int* max_input_report_size,
+ int* max_output_report_size,
+ int* max_feature_report_size) {
+ DCHECK(top_level_collections);
+ DCHECK(max_input_report_size);
+ DCHECK(max_output_report_size);
+ DCHECK(max_feature_report_size);
+ STLClearObject(top_level_collections);
+
+ *max_input_report_size = 0;
+ *max_output_report_size = 0;
+ *max_feature_report_size = 0;
+
+ // Global tags data:
+ HidUsageAndPage::Page current_usage_page = HidUsageAndPage::kPageUndefined;
+ int current_report_count = 0;
+ int cached_report_count = 0;
+ int current_report_size = 0;
+ int cached_report_size = 0;
+ int current_input_report_size = 0;
+ int current_output_report_size = 0;
+ int current_feature_report_size = 0;
+
+ // Local tags data:
+ uint16_t current_usage = 0;
for (std::vector<linked_ptr<HidReportDescriptorItem> >::const_iterator
items_iter = items().begin();
items_iter != items().end();
++items_iter) {
- linked_ptr<HidReportDescriptorItem> item = *items_iter;
+ linked_ptr<HidReportDescriptorItem> current_item = *items_iter;
- bool isTopLevelCollection =
- item->tag() == HidReportDescriptorItem::kTagCollection &&
- item->parent() == NULL;
+ switch (current_item->tag()) {
+ // Main tags:
+ case HidReportDescriptorItem::kTagCollection:
+ if (!current_item->parent()) {
+ // This is a top-level collection.
+ HidCollectionInfo collection;
+ collection.usage = HidUsageAndPage(current_usage, current_usage_page);
+ top_level_collections->push_back(collection);
+ }
+ break;
+ case HidReportDescriptorItem::kTagInput:
+ current_input_report_size += current_report_count * current_report_size;
+ break;
+ case HidReportDescriptorItem::kTagOutput:
+ current_output_report_size +=
+ current_report_count * current_report_size;
+ break;
+ case HidReportDescriptorItem::kTagFeature:
+ current_feature_report_size +=
+ current_report_count * current_report_size;
+ break;
- if (isTopLevelCollection) {
- uint16_t collection_usage = 0;
- HidUsageAndPage::Page collection_usage_page =
- HidUsageAndPage::kPageUndefined;
+ // Global tags:
+ case HidReportDescriptorItem::kTagUsagePage:
+ current_usage_page =
+ (HidUsageAndPage::Page)current_item->GetShortData();
+ break;
+ case HidReportDescriptorItem::kTagReportId:
+ if (top_level_collections->size() > 0) {
+ // Store report ID.
+ top_level_collections->back().report_ids.insert(
+ current_item->GetShortData());
- HidReportDescriptorItem* usage = item->previous();
- if (usage && usage->tag() == HidReportDescriptorItem::kTagUsage) {
- collection_usage = usage->GetShortData();
- }
+ // We need to increase report sizes by report ID field length.
+ if (current_input_report_size > 0)
+ current_input_report_size += kBitsPerByte;
+ if (current_output_report_size > 0)
+ current_output_report_size += kBitsPerByte;
+ if (current_feature_report_size > 0)
+ current_feature_report_size += kBitsPerByte;
- HidReportDescriptorItem* usage_page = usage->previous();
- if (usage_page &&
- usage_page->tag() == HidReportDescriptorItem::kTagUsagePage) {
- collection_usage_page =
- (HidUsageAndPage::Page)usage_page->GetShortData();
- }
+ // Update max report sizes.
+ *max_input_report_size =
+ std::max(*max_input_report_size, current_input_report_size);
+ *max_output_report_size =
+ std::max(*max_output_report_size, current_output_report_size);
+ *max_feature_report_size =
+ std::max(*max_feature_report_size, current_feature_report_size);
- topLevelCollections->push_back(
- HidUsageAndPage(collection_usage, collection_usage_page));
+ // Set report sizes to be 1-byte long (report ID field).
+ current_input_report_size = 0;
+ current_output_report_size = 0;
+ current_feature_report_size = 0;
+ }
+ break;
+ case HidReportDescriptorItem::kTagReportCount:
+ current_report_count = current_item->GetShortData();
+ break;
+ case HidReportDescriptorItem::kTagReportSize:
+ current_report_size = current_item->GetShortData();
+ break;
+ case HidReportDescriptorItem::kTagPush:
+ // Cache report count and size.
+ cached_report_count = current_report_count;
+ cached_report_size = current_report_size;
+ break;
+ case HidReportDescriptorItem::kTagPop:
+ // Restore cache.
+ current_report_count = cached_report_count;
+ current_report_size = cached_report_size;
+ // Reset cache.
+ cached_report_count = 0;
+ cached_report_size = 0;
+ break;
+
+ // Local tags:
+ case HidReportDescriptorItem::kTagUsage:
+ current_usage = current_item->GetShortData();
+ break;
+
+ default:
+ break;
}
}
+
+ if (top_level_collections->size() > 0 &&
+ top_level_collections->back().report_ids.size() > 0) {
+ // We need to increase report sizes by report ID field length.
+ if (current_input_report_size > 0)
+ current_input_report_size += kBitsPerByte;
+ if (current_output_report_size > 0)
+ current_output_report_size += kBitsPerByte;
+ if (current_feature_report_size > 0)
+ current_feature_report_size += kBitsPerByte;
+ }
+
+ // Update max report sizes
+ *max_input_report_size =
+ std::max(*max_input_report_size, current_input_report_size);
+ *max_output_report_size =
+ std::max(*max_output_report_size, current_output_report_size);
+ *max_feature_report_size =
+ std::max(*max_feature_report_size, current_feature_report_size);
+
+ // Convert bits into bytes
+ *max_input_report_size /= kBitsPerByte;
+ *max_output_report_size /= kBitsPerByte;
+ *max_feature_report_size /= kBitsPerByte;
}
} // namespace device
diff --git a/device/hid/hid_report_descriptor.h b/device/hid/hid_report_descriptor.h
index fa67fa4..94d90ad 100644
--- a/device/hid/hid_report_descriptor.h
+++ b/device/hid/hid_report_descriptor.h
@@ -8,8 +8,8 @@
#include <vector>
#include "base/memory/linked_ptr.h"
+#include "device/hid/hid_collection_info.h"
#include "device/hid/hid_report_descriptor_item.h"
-#include "device/hid/hid_usage_and_page.h"
namespace device {
@@ -25,9 +25,12 @@
return items_;
}
- // Returns HID usages of top-level collections present in the descriptor.
- void GetTopLevelCollections(
- std::vector<HidUsageAndPage>* topLevelCollections);
+ // Returns top-level collections present in the descriptor,
+ // together with max report sizes
+ void GetDetails(std::vector<HidCollectionInfo>* top_level_collections,
+ int* max_input_report_size,
+ int* max_output_report_size,
+ int* max_feature_report_size);
private:
std::vector<linked_ptr<HidReportDescriptorItem> > items_;
diff --git a/device/hid/hid_report_descriptor_item.cc b/device/hid/hid_report_descriptor_item.cc
index bdd03ce..60ba764 100644
--- a/device/hid/hid_report_descriptor_item.cc
+++ b/device/hid/hid_report_descriptor_item.cc
@@ -90,17 +90,17 @@
case 0x00:
return kCollectionTypePhysical;
case 0x01:
- return kCollectionTypePhysical;
+ return kCollectionTypeApplication;
case 0x02:
- return kCollectionTypePhysical;
+ return kCollectionTypeLogical;
case 0x03:
- return kCollectionTypePhysical;
+ return kCollectionTypeReport;
case 0x04:
- return kCollectionTypePhysical;
+ return kCollectionTypeNamedArray;
case 0x05:
- return kCollectionTypePhysical;
+ return kCollectionTypeUsageSwitch;
case 0x06:
- return kCollectionTypePhysical;
+ return kCollectionTypeUsageModifier;
default:
break;
}
diff --git a/device/hid/hid_report_descriptor_unittest.cc b/device/hid/hid_report_descriptor_unittest.cc
index 0d25889..619e682 100644
--- a/device/hid/hid_report_descriptor_unittest.cc
+++ b/device/hid/hid_report_descriptor_unittest.cc
@@ -14,392 +14,272 @@
namespace {
-std::ostream& operator<<(std::ostream& os,
- const HidUsageAndPage::Page& usage_page) {
- switch (usage_page) {
- case HidUsageAndPage::kPageUndefined:
- os << "Undefined";
- break;
- case HidUsageAndPage::kPageGenericDesktop:
- os << "Generic Desktop";
- break;
- case HidUsageAndPage::kPageSimulation:
- os << "Simulation";
- break;
- case HidUsageAndPage::kPageVirtualReality:
- os << "Virtual Reality";
- break;
- case HidUsageAndPage::kPageSport:
- os << "Sport";
- break;
- case HidUsageAndPage::kPageGame:
- os << "Game";
- break;
- case HidUsageAndPage::kPageKeyboard:
- os << "Keyboard";
- break;
- case HidUsageAndPage::kPageLed:
- os << "Led";
- break;
- case HidUsageAndPage::kPageButton:
- os << "Button";
- break;
- case HidUsageAndPage::kPageOrdinal:
- os << "Ordinal";
- break;
- case HidUsageAndPage::kPageTelephony:
- os << "Telephony";
- break;
- case HidUsageAndPage::kPageConsumer:
- os << "Consumer";
- break;
- case HidUsageAndPage::kPageDigitizer:
- os << "Digitizer";
- break;
- case HidUsageAndPage::kPagePidPage:
- os << "Pid Page";
- break;
- case HidUsageAndPage::kPageUnicode:
- os << "Unicode";
- break;
- case HidUsageAndPage::kPageAlphanumericDisplay:
- os << "Alphanumeric Display";
- break;
- case HidUsageAndPage::kPageMedicalInstruments:
- os << "Medical Instruments";
- break;
- case HidUsageAndPage::kPageMonitor0:
- os << "Monitor 0";
- break;
- case HidUsageAndPage::kPageMonitor1:
- os << "Monitor 1";
- break;
- case HidUsageAndPage::kPageMonitor2:
- os << "Monitor 2";
- break;
- case HidUsageAndPage::kPageMonitor3:
- os << "Monitor 3";
- break;
- case HidUsageAndPage::kPagePower0:
- os << "Power 0";
- break;
- case HidUsageAndPage::kPagePower1:
- os << "Power 1";
- break;
- case HidUsageAndPage::kPagePower2:
- os << "Power 2";
- break;
- case HidUsageAndPage::kPagePower3:
- os << "Power 3";
- break;
- case HidUsageAndPage::kPageBarCodeScanner:
- os << "Bar Code Scanner";
- break;
- case HidUsageAndPage::kPageScale:
- os << "Scale";
- break;
- case HidUsageAndPage::kPageMagneticStripeReader:
- os << "Magnetic Stripe Reader";
- break;
- case HidUsageAndPage::kPageReservedPointOfSale:
- os << "Reserved Point Of Sale";
- break;
- case HidUsageAndPage::kPageCameraControl:
- os << "Camera Control";
- break;
- case HidUsageAndPage::kPageArcade:
- os << "Arcade";
- break;
- case HidUsageAndPage::kPageVendor:
- os << "Vendor";
- break;
- case HidUsageAndPage::kPageMediaCenter:
- os << "Media Center";
- break;
- default:
- NOTREACHED();
- break;
- }
- return os;
-}
+// Digitizer descriptor from HID descriptor tool
+// http://www.usb.org/developers/hidpage/dt2_4.zip
+const uint8_t kDigitizer[] = {
+ 0x05, 0x0d, // Usage Page (Digitizer)
+ 0x09, 0x01, // Usage (0x1)
+ 0xa1, 0x01, // Collection (Application)
+ 0x85, 0x01, // Report ID (0x1)
+ 0x09, 0x21, // Usage (0x21)
+ 0xa1, 0x00, // Collection (Physical)
+ 0x05, 0x01, // Usage Page (Generic Desktop)
+ 0x09, 0x30, // Usage (0x30)
+ 0x09, 0x31, // Usage (0x31)
+ 0x75, 0x10, // Report Size (16)
+ 0x95, 0x02, // Report Count (2)
+ 0x15, 0x00, // Logical Minimum (0)
+ 0x26, 0xe0, 0x2e, // Logical Maximum (12000)
+ 0x35, 0x00, // Physical Minimum (0)
+ 0x45, 0x0c, // Physical Maximum (12)
+ 0x65, 0x13, // Unit (19)
+ 0x55, 0x00, // Unit Exponent (0)
+ 0xa4, // Push
+ 0x81, 0x02, // Input (Dat|Arr|Rel|NoWrp|Lin|Prf|NoNull|BitF)
+ 0x05, 0x0d, // Usage Page (Digitizer)
+ 0x09, 0x32, // Usage (0x32)
+ 0x09, 0x44, // Usage (0x44)
+ 0x09, 0x42, // Usage (0x42)
+ 0x15, 0x00, // Logical Minimum (0)
+ 0x25, 0x01, // Logical Maximum (1)
+ 0x35, 0x00, // Physical Minimum (0)
+ 0x45, 0x01, // Physical Maximum (1)
+ 0x75, 0x01, // Report Size (1)
+ 0x95, 0x03, // Report Count (3)
+ 0x65, 0x00, // Unit (0)
+ 0x81, 0x02, // Input (Dat|Arr|Rel|NoWrp|Lin|Prf|NoNull|BitF)
+ 0x95, 0x01, // Report Count (1)
+ 0x75, 0x05, // Report Size (5)
+ 0x81, 0x03, // Input (Con|Arr|Rel|NoWrp|Lin|Prf|NoNull|BitF)
+ 0xc0, // End Collection
+ 0x85, 0x02, // Report ID (0x2)
+ 0x09, 0x20, // Usage (0x20)
+ 0xa1, 0x00, // Collection (Physical)
+ 0xb4, // Pop
+ 0xa4, // Push
+ 0x09, 0x30, // Usage (0x30)
+ 0x09, 0x31, // Usage (0x31)
+ 0x81, 0x02, // Input (Dat|Arr|Rel|NoWrp|Lin|Prf|NoNull|BitF)
+ 0x05, 0x0d, // Usage Page (Digitizer)
+ 0x09, 0x32, // Usage (0x32)
+ 0x15, 0x00, // Logical Minimum (0)
+ 0x25, 0x01, // Logical Maximum (1)
+ 0x35, 0x00, // Physical Minimum (0)
+ 0x45, 0x01, // Physical Maximum (1)
+ 0x65, 0x00, // Unit (0)
+ 0x75, 0x01, // Report Size (1)
+ 0x81, 0x02, // Input (Dat|Arr|Rel|NoWrp|Lin|Prf|NoNull|BitF)
+ 0x05, 0x09, // Usage Page (Button)
+ 0x19, 0x00, // Usage Minimum (0)
+ 0x29, 0x10, // Usage Maximum (16)
+ 0x25, 0x10, // Logical Maximum (16)
+ 0x75, 0x05, // Report Size (5)
+ 0x81, 0x40, // Input (Dat|Var|Rel|NoWrp|Lin|Prf|Null|BitF)
+ 0x75, 0x02, // Report Size (2)
+ 0x81, 0x01, // Input (Con|Var|Rel|NoWrp|Lin|Prf|NoNull|BitF)
+ 0xc0, // End Collection
+ 0x85, 0x03, // Report ID (0x3)
+ 0x05, 0x0d, // Usage Page (Digitizer)
+ 0x09, 0x20, // Usage (0x20)
+ 0xa1, 0x00, // Collection (Physical)
+ 0xb4, // Pop
+ 0x09, 0x30, // Usage (0x30)
+ 0x09, 0x31, // Usage (0x31)
+ 0x81, 0x02, // Input (Dat|Arr|Rel|NoWrp|Lin|Prf|NoNull|BitF)
+ 0x05, 0x0d, // Usage Page (Digitizer)
+ 0x09, 0x32, // Usage (0x32)
+ 0x09, 0x44, // Usage (0x44)
+ 0x75, 0x01, // Report Size (1)
+ 0x15, 0x00, // Logical Minimum (0)
+ 0x25, 0x01, // Logical Maximum (1)
+ 0x35, 0x00, // Physical Minimum (0)
+ 0x45, 0x01, // Physical Maximum (1)
+ 0x65, 0x00, // Unit (0)
+ 0x81, 0x02, // Input (Dat|Arr|Rel|NoWrp|Lin|Prf|NoNull|BitF)
+ 0x95, 0x06, // Report Count (6)
+ 0x81, 0x03, // Input (Con|Arr|Rel|NoWrp|Lin|Prf|NoNull|BitF)
+ 0x09, 0x30, // Usage (0x30)
+ 0x15, 0x00, // Logical Minimum (0)
+ 0x25, 0x7f, // Logical Maximum (127)
+ 0x35, 0x00, // Physical Minimum (0)
+ 0x45, 0x2d, // Physical Maximum (45)
+ 0x67, 0x11, 0xe1, // Unit (57617)
+ 0x00, 0x00, // Default
+ 0x55, 0x04, // Unit Exponent (4)
+ 0x75, 0x08, // Report Size (8)
+ 0x95, 0x01, // Report Count (1)
+ 0x81, 0x12, // Input (Dat|Arr|Rel|NoWrp|NoLin|Prf|NoNull|BitF)
+ 0xc0, // End Collection
+ 0xc0 // End Collection
+};
-std::ostream& operator<<(std::ostream& os,
- const HidUsageAndPage& usage_and_page) {
- os << "Usage Page: " << usage_and_page.usage_page << ", Usage: "
- << "0x" << std::hex << std::uppercase << usage_and_page.usage;
- return os;
-}
-
-std::ostream& operator<<(std::ostream& os,
- const HidReportDescriptorItem::Tag& tag) {
- switch (tag) {
- case HidReportDescriptorItem::kTagDefault:
- os << "Default";
- break;
- case HidReportDescriptorItem::kTagInput:
- os << "Input";
- break;
- case HidReportDescriptorItem::kTagOutput:
- os << "Output";
- break;
- case HidReportDescriptorItem::kTagFeature:
- os << "Feature";
- break;
- case HidReportDescriptorItem::kTagCollection:
- os << "Collection";
- break;
- case HidReportDescriptorItem::kTagEndCollection:
- os << "End Collection";
- break;
- case HidReportDescriptorItem::kTagUsagePage:
- os << "Usage Page";
- break;
- case HidReportDescriptorItem::kTagLogicalMinimum:
- os << "Logical Minimum";
- break;
- case HidReportDescriptorItem::kTagLogicalMaximum:
- os << "Logical Maximum";
- break;
- case HidReportDescriptorItem::kTagPhysicalMinimum:
- os << "Physical Minimum";
- break;
- case HidReportDescriptorItem::kTagPhysicalMaximum:
- os << "Physical Maximum";
- break;
- case HidReportDescriptorItem::kTagUnitExponent:
- os << "Unit Exponent";
- break;
- case HidReportDescriptorItem::kTagUnit:
- os << "Unit";
- break;
- case HidReportDescriptorItem::kTagReportSize:
- os << "Report Size";
- break;
- case HidReportDescriptorItem::kTagReportId:
- os << "Report ID";
- break;
- case HidReportDescriptorItem::kTagReportCount:
- os << "Report Count";
- break;
- case HidReportDescriptorItem::kTagPush:
- os << "Push";
- break;
- case HidReportDescriptorItem::kTagPop:
- os << "Pop";
- break;
- case HidReportDescriptorItem::kTagUsage:
- os << "Usage";
- break;
- case HidReportDescriptorItem::kTagUsageMinimum:
- os << "Usage Minimum";
- break;
- case HidReportDescriptorItem::kTagUsageMaximum:
- os << "Usage Maximum";
- break;
- case HidReportDescriptorItem::kTagDesignatorIndex:
- os << "Designator Index";
- break;
- case HidReportDescriptorItem::kTagDesignatorMinimum:
- os << "Designator Minimum";
- break;
- case HidReportDescriptorItem::kTagDesignatorMaximum:
- os << "Designator Maximum";
- break;
- case HidReportDescriptorItem::kTagStringIndex:
- os << "String Index";
- break;
- case HidReportDescriptorItem::kTagStringMinimum:
- os << "String Minimum";
- break;
- case HidReportDescriptorItem::kTagStringMaximum:
- os << "String Maximum";
- break;
- case HidReportDescriptorItem::kTagDelimiter:
- os << "Delimeter";
- break;
- case HidReportDescriptorItem::kTagLong:
- os << "Long";
- break;
- default:
- NOTREACHED();
- break;
- }
-
- return os;
-}
-
-std::ostream& operator<<(std::ostream& os,
- const HidReportDescriptorItem::ReportInfo& data) {
- if (data.data_or_constant)
- os << "Con";
- else
- os << "Dat";
- if (data.array_or_variable)
- os << "|Arr";
- else
- os << "|Var";
- if (data.absolute_or_relative)
- os << "|Abs";
- else
- os << "|Rel";
- if (data.wrap)
- os << "|Wrp";
- else
- os << "|NoWrp";
- if (data.linear)
- os << "|NoLin";
- else
- os << "|Lin";
- if (data.preferred)
- os << "|NoPrf";
- else
- os << "|Prf";
- if (data.null)
- os << "|Null";
- else
- os << "|NoNull";
- if (data.bit_field_or_buffer)
- os << "|Buff";
- else
- os << "|BitF";
- return os;
-}
-
-std::ostream& operator<<(std::ostream& os,
- const HidReportDescriptorItem::CollectionType& type) {
- switch (type) {
- case HidReportDescriptorItem::kCollectionTypePhysical:
- os << "Physical";
- break;
- case HidReportDescriptorItem::kCollectionTypeApplication:
- os << "Application";
- break;
- case HidReportDescriptorItem::kCollectionTypeLogical:
- os << "Logical";
- break;
- case HidReportDescriptorItem::kCollectionTypeReport:
- os << "Report";
- break;
- case HidReportDescriptorItem::kCollectionTypeNamedArray:
- os << "Named Array";
- break;
- case HidReportDescriptorItem::kCollectionTypeUsageSwitch:
- os << "Usage Switch";
- break;
- case HidReportDescriptorItem::kCollectionTypeUsageModifier:
- os << "Usage Modifier";
- break;
- case HidReportDescriptorItem::kCollectionTypeReserved:
- os << "Reserved";
- break;
- case HidReportDescriptorItem::kCollectionTypeVendor:
- os << "Vendor";
- break;
- default:
- NOTREACHED();
- break;
- }
- return os;
-}
-
-std::ostream& operator<<(std::ostream& os,
- const HidReportDescriptorItem& item) {
- HidReportDescriptorItem::Tag item_tag = item.tag();
- uint32_t data = item.GetShortData();
-
- std::ostringstream sstr;
- sstr << item_tag;
- sstr << " (";
-
- long pos = sstr.tellp();
- switch (item_tag) {
- case HidReportDescriptorItem::kTagDefault:
- case HidReportDescriptorItem::kTagEndCollection:
- case HidReportDescriptorItem::kTagPush:
- case HidReportDescriptorItem::kTagPop:
- case HidReportDescriptorItem::kTagLong:
- break;
-
- case HidReportDescriptorItem::kTagCollection:
- sstr << HidReportDescriptorItem::GetCollectionTypeFromValue(data);
- break;
-
- case HidReportDescriptorItem::kTagInput:
- case HidReportDescriptorItem::kTagOutput:
- case HidReportDescriptorItem::kTagFeature:
- sstr << (HidReportDescriptorItem::ReportInfo&)data;
- break;
-
- case HidReportDescriptorItem::kTagUsagePage:
- sstr << (HidUsageAndPage::Page)data;
- break;
-
- case HidReportDescriptorItem::kTagUsage:
- case HidReportDescriptorItem::kTagReportId:
- sstr << "0x" << std::hex << std::uppercase << data;
- break;
-
- default:
- sstr << data;
- break;
- }
- if (pos == sstr.tellp()) {
- std::string str = sstr.str();
- str.erase(str.end() - 2, str.end());
- os << str;
- } else {
- os << sstr.str() << ")";
- }
-
- return os;
-}
-
-const char kIndentStep[] = " ";
-
-std::ostream& operator<<(std::ostream& os,
- const HidReportDescriptor& descriptor) {
- for (std::vector<linked_ptr<HidReportDescriptorItem> >::const_iterator
- items_iter = descriptor.items().begin();
- items_iter != descriptor.items().end();
- ++items_iter) {
- linked_ptr<HidReportDescriptorItem> item = *items_iter;
- size_t indentLevel = item->GetDepth();
- for (size_t i = 0; i < indentLevel; i++)
- os << kIndentStep;
- os << *item.get() << std::endl;
- }
- return os;
-}
-
-// See 'E.6 Report Descriptor (Keyboard)'
-// in HID specifications (v1.11)
+// Keyboard descriptor from HID descriptor tool
+// http://www.usb.org/developers/hidpage/dt2_4.zip
const uint8_t kKeyboard[] = {
- 0x05, 0x01, 0x09, 0x06, 0xA1, 0x01, 0x05, 0x07, 0x19, 0xE0, 0x29,
- 0xE7, 0x15, 0x00, 0x25, 0x01, 0x75, 0x01, 0x95, 0x08, 0x81, 0x02,
- 0x95, 0x01, 0x75, 0x08, 0x81, 0x01, 0x95, 0x05, 0x75, 0x01, 0x05,
- 0x08, 0x19, 0x01, 0x29, 0x05, 0x91, 0x02, 0x95, 0x01, 0x75, 0x03,
- 0x91, 0x01, 0x95, 0x06, 0x75, 0x08, 0x15, 0x00, 0x25, 0x65, 0x05,
- 0x07, 0x19, 0x00, 0x29, 0x65, 0x81, 0x00, 0xC0};
+ 0x05, 0x01, // Usage Page (Generic Desktop)
+ 0x09, 0x06, // Usage (0x6)
+ 0xa1, 0x01, // Collection (Application)
+ 0x05, 0x07, // Usage Page (Keyboard)
+ 0x19, 0xe0, // Usage Minimum (224)
+ 0x29, 0xe7, // Usage Maximum (231)
+ 0x15, 0x00, // Logical Minimum (0)
+ 0x25, 0x01, // Logical Maximum (1)
+ 0x75, 0x01, // Report Size (1)
+ 0x95, 0x08, // Report Count (8)
+ 0x81, 0x02, // Input (Dat|Arr|Rel|NoWrp|Lin|Prf|NoNull|BitF)
+ 0x95, 0x01, // Report Count (1)
+ 0x75, 0x08, // Report Size (8)
+ 0x81, 0x03, // Input (Con|Arr|Rel|NoWrp|Lin|Prf|NoNull|BitF)
+ 0x95, 0x05, // Report Count (5)
+ 0x75, 0x01, // Report Size (1)
+ 0x05, 0x08, // Usage Page (Led)
+ 0x19, 0x01, // Usage Minimum (1)
+ 0x29, 0x05, // Usage Maximum (5)
+ 0x91, 0x02, // Output (Dat|Arr|Rel|NoWrp|Lin|Prf|NoNull|BitF)
+ 0x95, 0x01, // Report Count (1)
+ 0x75, 0x03, // Report Size (3)
+ 0x91, 0x03, // Output (Con|Arr|Rel|NoWrp|Lin|Prf|NoNull|BitF)
+ 0x95, 0x06, // Report Count (6)
+ 0x75, 0x08, // Report Size (8)
+ 0x15, 0x00, // Logical Minimum (0)
+ 0x25, 0x65, // Logical Maximum (101)
+ 0x05, 0x07, // Usage Page (Keyboard)
+ 0x19, 0x00, // Usage Minimum (0)
+ 0x29, 0x65, // Usage Maximum (101)
+ 0x81, 0x00, // Input (Dat|Var|Rel|NoWrp|Lin|Prf|NoNull|BitF)
+ 0xc0 // End Collection
+};
-// See 'E.10 Report Descriptor (Mouse)'
-// in HID specifications (v1.11)
-const uint8_t kMouse[] = {0x05, 0x01, 0x09, 0x02, 0xA1, 0x01, 0x09, 0x01, 0xA1,
- 0x00, 0x05, 0x09, 0x19, 0x01, 0x29, 0x03, 0x15, 0x00,
- 0x25, 0x01, 0x95, 0x03, 0x75, 0x01, 0x81, 0x02, 0x95,
- 0x01, 0x75, 0x05, 0x81, 0x01, 0x05, 0x01, 0x09, 0x30,
- 0x09, 0x31, 0x15, 0x81, 0x25, 0x7F, 0x75, 0x08, 0x95,
- 0x02, 0x81, 0x06, 0xC0, 0xC0};
+// Monitor descriptor from HID descriptor tool
+// http://www.usb.org/developers/hidpage/dt2_4.zip
+const uint8_t kMonitor[] = {
+ 0x05, 0x80, // Usage Page (Monitor 0)
+ 0x09, 0x01, // Usage (0x1)
+ 0xa1, 0x01, // Collection (Application)
+ 0x85, 0x01, // Report ID (0x1)
+ 0x15, 0x00, // Logical Minimum (0)
+ 0x26, 0xff, 0x00, // Logical Maximum (255)
+ 0x75, 0x08, // Report Size (8)
+ 0x95, 0x80, // Report Count (128)
+ 0x09, 0x02, // Usage (0x2)
+ 0xb2, 0x02, 0x01, // Feature (Dat|Arr|Rel|NoWrp|Lin|Prf|NoNull|Buff)
+ 0x85, 0x02, // Report ID (0x2)
+ 0x95, 0xf3, // Report Count (243)
+ 0x09, 0x03, // Usage (0x3)
+ 0xb2, 0x02, 0x01, // Feature (Dat|Arr|Rel|NoWrp|Lin|Prf|NoNull|Buff)
+ 0x85, 0x03, // Report ID (0x3)
+ 0x05, 0x82, // Usage Page (Monitor 2)
+ 0x95, 0x01, // Report Count (1)
+ 0x75, 0x10, // Report Size (16)
+ 0x26, 0xc8, 0x00, // Logical Maximum (200)
+ 0x09, 0x10, // Usage (0x10)
+ 0xb1, 0x02, // Feature (Dat|Arr|Rel|NoWrp|Lin|Prf|NoNull|BitF)
+ 0x85, 0x04, // Report ID (0x4)
+ 0x25, 0x64, // Logical Maximum (100)
+ 0x09, 0x12, // Usage (0x12)
+ 0xb1, 0x02, // Feature (Dat|Arr|Rel|NoWrp|Lin|Prf|NoNull|BitF)
+ 0x95, 0x06, // Report Count (6)
+ 0x26, 0xff, 0x00, // Logical Maximum (255)
+ 0x09, 0x16, // Usage (0x16)
+ 0x09, 0x18, // Usage (0x18)
+ 0x09, 0x1a, // Usage (0x1A)
+ 0x09, 0x6c, // Usage (0x6C)
+ 0x09, 0x6e, // Usage (0x6E)
+ 0x09, 0x70, // Usage (0x70)
+ 0xb1, 0x02, // Feature (Dat|Arr|Rel|NoWrp|Lin|Prf|NoNull|BitF)
+ 0x85, 0x05, // Report ID (0x5)
+ 0x25, 0x7f, // Logical Maximum (127)
+ 0x09, 0x20, // Usage (0x20)
+ 0x09, 0x22, // Usage (0x22)
+ 0x09, 0x30, // Usage (0x30)
+ 0x09, 0x32, // Usage (0x32)
+ 0x09, 0x42, // Usage (0x42)
+ 0x09, 0x44, // Usage (0x44)
+ 0xb1, 0x02, // Feature (Dat|Arr|Rel|NoWrp|Lin|Prf|NoNull|BitF)
+ 0xc0 // End Collection
+};
+// Mouse descriptor from HID descriptor tool
+// http://www.usb.org/developers/hidpage/dt2_4.zip
+const uint8_t kMouse[] = {
+ 0x05, 0x01, // Usage Page (Generic Desktop)
+ 0x09, 0x02, // Usage (0x2)
+ 0xa1, 0x01, // Collection (Application)
+ 0x09, 0x01, // Usage (0x1)
+ 0xa1, 0x00, // Collection (Physical)
+ 0x05, 0x09, // Usage Page (Button)
+ 0x19, 0x01, // Usage Minimum (1)
+ 0x29, 0x03, // Usage Maximum (3)
+ 0x15, 0x00, // Logical Minimum (0)
+ 0x25, 0x01, // Logical Maximum (1)
+ 0x95, 0x03, // Report Count (3)
+ 0x75, 0x01, // Report Size (1)
+ 0x81, 0x02, // Input (Dat|Arr|Rel|NoWrp|Lin|Prf|NoNull|BitF)
+ 0x95, 0x01, // Report Count (1)
+ 0x75, 0x05, // Report Size (5)
+ 0x81, 0x03, // Input (Con|Arr|Rel|NoWrp|Lin|Prf|NoNull|BitF)
+ 0x05, 0x01, // Usage Page (Generic Desktop)
+ 0x09, 0x30, // Usage (0x30)
+ 0x09, 0x31, // Usage (0x31)
+ 0x15, 0x81, // Logical Minimum (129)
+ 0x25, 0x7f, // Logical Maximum (127)
+ 0x75, 0x08, // Report Size (8)
+ 0x95, 0x02, // Report Count (2)
+ 0x81, 0x06, // Input (Dat|Arr|Abs|NoWrp|Lin|Prf|NoNull|BitF)
+ 0xc0, // End Collection
+ 0xc0 // End Collection
+};
+
+// Logitech Unifying receiver descriptor
const uint8_t kLogitechUnifyingReceiver[] = {
- 0x06, 0x00, 0xFF, 0x09, 0x01, 0xA1, 0x01, 0x85, 0x10, 0x75, 0x08,
- 0x95, 0x06, 0x15, 0x00, 0x26, 0xFF, 0x00, 0x09, 0x01, 0x81, 0x00,
- 0x09, 0x01, 0x91, 0x00, 0xC0, 0x06, 0x00, 0xFF, 0x09, 0x02, 0xA1,
- 0x01, 0x85, 0x11, 0x75, 0x08, 0x95, 0x13, 0x15, 0x00, 0x26, 0xFF,
- 0x00, 0x09, 0x02, 0x81, 0x00, 0x09, 0x02, 0x91, 0x00, 0xC0, 0x06,
- 0x00, 0xFF, 0x09, 0x04, 0xA1, 0x01, 0x85, 0x20, 0x75, 0x08, 0x95,
- 0x0E, 0x15, 0x00, 0x26, 0xFF, 0x00, 0x09, 0x41, 0x81, 0x00, 0x09,
- 0x41, 0x91, 0x00, 0x85, 0x21, 0x95, 0x1F, 0x15, 0x00, 0x26, 0xFF,
- 0x00, 0x09, 0x42, 0x81, 0x00, 0x09, 0x42, 0x91, 0x00, 0xC0};
+ 0x06, 0x00, 0xFF, // Usage Page (Vendor)
+ 0x09, 0x01, // Usage (0x1)
+ 0xA1, 0x01, // Collection (Application)
+ 0x85, 0x10, // Report ID (0x10)
+ 0x75, 0x08, // Report Size (8)
+ 0x95, 0x06, // Report Count (6)
+ 0x15, 0x00, // Logical Minimum (0)
+ 0x26, 0xFF, 0x00, // Logical Maximum (255)
+ 0x09, 0x01, // Usage (0x1)
+ 0x81, 0x00, // Input (Dat|Var|Rel|NoWrp|Lin|Prf|NoNull|BitF)
+ 0x09, 0x01, // Usage (0x1)
+ 0x91, 0x00, // Output (Dat|Var|Rel|NoWrp|Lin|Prf|NoNull|BitF)
+ 0xC0, // End Collection
+ 0x06, 0x00, 0xFF, // Usage Page (Vendor)
+ 0x09, 0x02, // Usage (0x2)
+ 0xA1, 0x01, // Collection (Application)
+ 0x85, 0x11, // Report ID (0x11)
+ 0x75, 0x08, // Report Size (8)
+ 0x95, 0x13, // Report Count (19)
+ 0x15, 0x00, // Logical Minimum (0)
+ 0x26, 0xFF, 0x00, // Logical Maximum (255)
+ 0x09, 0x02, // Usage (0x2)
+ 0x81, 0x00, // Input (Dat|Var|Rel|NoWrp|Lin|Prf|NoNull|BitF)
+ 0x09, 0x02, // Usage (0x2)
+ 0x91, 0x00, // Output (Dat|Var|Rel|NoWrp|Lin|Prf|NoNull|BitF)
+ 0xC0, // End Collection
+ 0x06, 0x00, 0xFF, // Usage Page (Vendor)
+ 0x09, 0x04, // Usage (0x4)
+ 0xA1, 0x01, // Collection (Application)
+ 0x85, 0x20, // Report ID (0x20)
+ 0x75, 0x08, // Report Size (8)
+ 0x95, 0x0E, // Report Count (14)
+ 0x15, 0x00, // Logical Minimum (0)
+ 0x26, 0xFF, 0x00, // Logical Maximum (255)
+ 0x09, 0x41, // Usage (0x41)
+ 0x81, 0x00, // Input (Dat|Var|Rel|NoWrp|Lin|Prf|NoNull|BitF)
+ 0x09, 0x41, // Usage (0x41)
+ 0x91, 0x00, // Output (Dat|Var|Rel|NoWrp|Lin|Prf|NoNull|BitF)
+ 0x85, 0x21, // Report ID (0x21)
+ 0x95, 0x1F, // Report Count (31)
+ 0x15, 0x00, // Logical Minimum (0)
+ 0x26, 0xFF, 0x00, // Logical Maximum (255)
+ 0x09, 0x42, // Usage (0x42)
+ 0x81, 0x00, // Input (Dat|Var|Rel|NoWrp|Lin|Prf|NoNull|BitF)
+ 0x09, 0x42, // Usage (0x42)
+ 0x91, 0x00, // Output (Dat|Var|Rel|NoWrp|Lin|Prf|NoNull|BitF)
+ 0xC0 // End Collection
+};
} // namespace
@@ -415,199 +295,135 @@
}
public:
- void ParseDescriptor(const std::string& expected,
- const uint8_t* bytes,
- size_t size) {
+ void ValidateDetails(
+ const std::vector<HidCollectionInfo>& expected_collections,
+ const int expected_max_input_report_size,
+ const int expected_max_output_report_size,
+ const int expected_max_feature_report_size,
+ const uint8_t* bytes,
+ size_t size) {
descriptor_ = new HidReportDescriptor(bytes, size);
- std::stringstream actual;
- actual << *descriptor_;
+ std::vector<HidCollectionInfo> actual_collections;
+ int actual_max_input_report_size;
+ int actual_max_output_report_size;
+ int actual_max_feature_report_size;
+ descriptor_->GetDetails(&actual_collections,
+ &actual_max_input_report_size,
+ &actual_max_output_report_size,
+ &actual_max_feature_report_size);
- std::cout << "HID report descriptor:" << std::endl;
- std::cout << actual.str();
+ ASSERT_EQ(expected_collections.size(), actual_collections.size());
- // TODO(jracle@logitech.com): refactor string comparison in favor of
- // testing individual fields.
- ASSERT_EQ(expected, actual.str());
- }
+ std::vector<HidCollectionInfo>::const_iterator actual_collections_iter =
+ actual_collections.begin();
+ std::vector<HidCollectionInfo>::const_iterator expected_collections_iter =
+ expected_collections.begin();
- void GetTopLevelCollections(const std::vector<HidUsageAndPage>& expected,
- const uint8_t* bytes,
- size_t size) {
- descriptor_ = new HidReportDescriptor(bytes, size);
+ while (expected_collections_iter != expected_collections.end() &&
+ actual_collections_iter != actual_collections.end()) {
+ HidCollectionInfo expected_collection = *expected_collections_iter;
+ HidCollectionInfo actual_collection = *actual_collections_iter;
- std::vector<HidUsageAndPage> actual;
- descriptor_->GetTopLevelCollections(&actual);
+ ASSERT_EQ(expected_collection.usage.usage_page,
+ actual_collection.usage.usage_page);
+ ASSERT_EQ(expected_collection.usage.usage, actual_collection.usage.usage);
+ ASSERT_THAT(actual_collection.report_ids,
+ ContainerEq(expected_collection.report_ids));
- std::cout << "HID top-level collections:" << std::endl;
- for (std::vector<HidUsageAndPage>::const_iterator iter = actual.begin();
- iter != actual.end();
- ++iter) {
- std::cout << *iter << std::endl;
+ expected_collections_iter++;
+ actual_collections_iter++;
}
- ASSERT_THAT(actual, ContainerEq(expected));
+ ASSERT_EQ(expected_max_input_report_size, actual_max_input_report_size);
+ ASSERT_EQ(expected_max_output_report_size, actual_max_output_report_size);
+ ASSERT_EQ(expected_max_feature_report_size, actual_max_feature_report_size);
}
private:
HidReportDescriptor* descriptor_;
};
-TEST_F(HidReportDescriptorTest, ParseDescriptor_Keyboard) {
- const char expected[] = {
- "Usage Page (Generic Desktop)\n"
- "Usage (0x6)\n"
- "Collection (Physical)\n"
- " Usage Page (Keyboard)\n"
- " Usage Minimum (224)\n"
- " Usage Maximum (231)\n"
- " Logical Minimum (0)\n"
- " Logical Maximum (1)\n"
- " Report Size (1)\n"
- " Report Count (8)\n"
- " Input (Dat|Arr|Rel|NoWrp|Lin|Prf|NoNull|BitF)\n"
- " Report Count (1)\n"
- " Report Size (8)\n"
- " Input (Con|Var|Rel|NoWrp|Lin|Prf|NoNull|BitF)\n"
- " Report Count (5)\n"
- " Report Size (1)\n"
- " Usage Page (Led)\n"
- " Usage Minimum (1)\n"
- " Usage Maximum (5)\n"
- " Output (Dat|Arr|Rel|NoWrp|Lin|Prf|NoNull|BitF)\n"
- " Report Count (1)\n"
- " Report Size (3)\n"
- " Output (Con|Var|Rel|NoWrp|Lin|Prf|NoNull|BitF)\n"
- " Report Count (6)\n"
- " Report Size (8)\n"
- " Logical Minimum (0)\n"
- " Logical Maximum (101)\n"
- " Usage Page (Keyboard)\n"
- " Usage Minimum (0)\n"
- " Usage Maximum (101)\n"
- " Input (Dat|Var|Rel|NoWrp|Lin|Prf|NoNull|BitF)\n"
- "End Collection\n"};
-
- ParseDescriptor(std::string(expected), kKeyboard, sizeof(kKeyboard));
+TEST_F(HidReportDescriptorTest, ValidateDetails_Digitizer) {
+ HidCollectionInfo digitizer;
+ digitizer.usage = HidUsageAndPage(0x01, HidUsageAndPage::kPageDigitizer);
+ digitizer.report_ids.insert(1);
+ digitizer.report_ids.insert(2);
+ digitizer.report_ids.insert(3);
+ HidCollectionInfo expected[] = {digitizer};
+ ValidateDetails(std::vector<HidCollectionInfo>(
+ expected, expected + ARRAYSIZE_UNSAFE(expected)),
+ 7,
+ 0,
+ 0,
+ kDigitizer,
+ sizeof(kDigitizer));
}
-TEST_F(HidReportDescriptorTest, TopLevelCollections_Keyboard) {
- HidUsageAndPage expected[] = {
- HidUsageAndPage(0x06, HidUsageAndPage::kPageGenericDesktop)};
-
- GetTopLevelCollections(std::vector<HidUsageAndPage>(
- expected, expected + ARRAYSIZE_UNSAFE(expected)),
- kKeyboard,
- sizeof(kKeyboard));
+TEST_F(HidReportDescriptorTest, ValidateDetails_Keyboard) {
+ HidCollectionInfo keyboard;
+ keyboard.usage = HidUsageAndPage(0x06, HidUsageAndPage::kPageGenericDesktop);
+ HidCollectionInfo expected[] = {keyboard};
+ ValidateDetails(std::vector<HidCollectionInfo>(
+ expected, expected + ARRAYSIZE_UNSAFE(expected)),
+ 8,
+ 1,
+ 0,
+ kKeyboard,
+ sizeof(kKeyboard));
}
-TEST_F(HidReportDescriptorTest, ParseDescriptor_Mouse) {
- const char expected[] = {
- "Usage Page (Generic Desktop)\n"
- "Usage (0x2)\n"
- "Collection (Physical)\n"
- " Usage (0x1)\n"
- " Collection (Physical)\n"
- " Usage Page (Button)\n"
- " Usage Minimum (1)\n"
- " Usage Maximum (3)\n"
- " Logical Minimum (0)\n"
- " Logical Maximum (1)\n"
- " Report Count (3)\n"
- " Report Size (1)\n"
- " Input (Dat|Arr|Rel|NoWrp|Lin|Prf|NoNull|BitF)\n"
- " Report Count (1)\n"
- " Report Size (5)\n"
- " Input (Con|Var|Rel|NoWrp|Lin|Prf|NoNull|BitF)\n"
- " Usage Page (Generic Desktop)\n"
- " Usage (0x30)\n"
- " Usage (0x31)\n"
- " Logical Minimum (129)\n"
- " Logical Maximum (127)\n"
- " Report Size (8)\n"
- " Report Count (2)\n"
- " Input (Dat|Arr|Abs|NoWrp|Lin|Prf|NoNull|BitF)\n"
- " End Collection\n"
- "End Collection\n"};
-
- ParseDescriptor(std::string(expected), kMouse, sizeof(kMouse));
+TEST_F(HidReportDescriptorTest, ValidateDetails_Monitor) {
+ HidCollectionInfo monitor;
+ monitor.usage = HidUsageAndPage(0x01, HidUsageAndPage::kPageMonitor0);
+ monitor.report_ids.insert(1);
+ monitor.report_ids.insert(2);
+ monitor.report_ids.insert(3);
+ monitor.report_ids.insert(4);
+ monitor.report_ids.insert(5);
+ HidCollectionInfo expected[] = {monitor};
+ ValidateDetails(std::vector<HidCollectionInfo>(
+ expected, expected + ARRAYSIZE_UNSAFE(expected)),
+ 0,
+ 0,
+ 244,
+ kMonitor,
+ sizeof(kMonitor));
}
-TEST_F(HidReportDescriptorTest, TopLevelCollections_Mouse) {
- HidUsageAndPage expected[] = {
- HidUsageAndPage(0x02, HidUsageAndPage::kPageGenericDesktop)};
-
- GetTopLevelCollections(std::vector<HidUsageAndPage>(
- expected, expected + ARRAYSIZE_UNSAFE(expected)),
- kMouse,
- sizeof(kMouse));
+TEST_F(HidReportDescriptorTest, ValidateDetails_Mouse) {
+ HidCollectionInfo mouse;
+ mouse.usage = HidUsageAndPage(0x02, HidUsageAndPage::kPageGenericDesktop);
+ HidCollectionInfo expected[] = {mouse};
+ ValidateDetails(std::vector<HidCollectionInfo>(
+ expected, expected + ARRAYSIZE_UNSAFE(expected)),
+ 3,
+ 0,
+ 0,
+ kMouse,
+ sizeof(kMouse));
}
-TEST_F(HidReportDescriptorTest, ParseDescriptor_LogitechUnifyingReceiver) {
- const char expected[] = {
- "Usage Page (Vendor)\n"
- "Usage (0x1)\n"
- "Collection (Physical)\n"
- " Report ID (0x10)\n"
- " Report Size (8)\n"
- " Report Count (6)\n"
- " Logical Minimum (0)\n"
- " Logical Maximum (255)\n"
- " Usage (0x1)\n"
- " Input (Dat|Var|Rel|NoWrp|Lin|Prf|NoNull|BitF)\n"
- " Usage (0x1)\n"
- " Output (Dat|Var|Rel|NoWrp|Lin|Prf|NoNull|BitF)\n"
- "End Collection\n"
- "Usage Page (Vendor)\n"
- "Usage (0x2)\n"
- "Collection (Physical)\n"
- " Report ID (0x11)\n"
- " Report Size (8)\n"
- " Report Count (19)\n"
- " Logical Minimum (0)\n"
- " Logical Maximum (255)\n"
- " Usage (0x2)\n"
- " Input (Dat|Var|Rel|NoWrp|Lin|Prf|NoNull|BitF)\n"
- " Usage (0x2)\n"
- " Output (Dat|Var|Rel|NoWrp|Lin|Prf|NoNull|BitF)\n"
- "End Collection\n"
- "Usage Page (Vendor)\n"
- "Usage (0x4)\n"
- "Collection (Physical)\n"
- " Report ID (0x20)\n"
- " Report Size (8)\n"
- " Report Count (14)\n"
- " Logical Minimum (0)\n"
- " Logical Maximum (255)\n"
- " Usage (0x41)\n"
- " Input (Dat|Var|Rel|NoWrp|Lin|Prf|NoNull|BitF)\n"
- " Usage (0x41)\n"
- " Output (Dat|Var|Rel|NoWrp|Lin|Prf|NoNull|BitF)\n"
- " Report ID (0x21)\n"
- " Report Count (31)\n"
- " Logical Minimum (0)\n"
- " Logical Maximum (255)\n"
- " Usage (0x42)\n"
- " Input (Dat|Var|Rel|NoWrp|Lin|Prf|NoNull|BitF)\n"
- " Usage (0x42)\n"
- " Output (Dat|Var|Rel|NoWrp|Lin|Prf|NoNull|BitF)\n"
- "End Collection\n"};
+TEST_F(HidReportDescriptorTest, ValidateDetails_LogitechUnifyingReceiver) {
+ HidCollectionInfo hidpp_short;
+ hidpp_short.usage = HidUsageAndPage(0x01, HidUsageAndPage::kPageVendor);
+ hidpp_short.report_ids.insert(0x10);
+ HidCollectionInfo hidpp_long;
+ hidpp_long.usage = HidUsageAndPage(0x02, HidUsageAndPage::kPageVendor);
+ hidpp_long.report_ids.insert(0x11);
+ HidCollectionInfo hidpp_dj;
+ hidpp_dj.usage = HidUsageAndPage(0x04, HidUsageAndPage::kPageVendor);
+ hidpp_dj.report_ids.insert(0x20);
+ hidpp_dj.report_ids.insert(0x21);
- ParseDescriptor(std::string(expected),
+ HidCollectionInfo expected[] = {hidpp_short, hidpp_long, hidpp_dj};
+ ValidateDetails(std::vector<HidCollectionInfo>(
+ expected, expected + ARRAYSIZE_UNSAFE(expected)),
+ 32,
+ 32,
+ 0,
kLogitechUnifyingReceiver,
sizeof(kLogitechUnifyingReceiver));
}
-TEST_F(HidReportDescriptorTest, TopLevelCollections_LogitechUnifyingReceiver) {
- HidUsageAndPage expected[] = {
- HidUsageAndPage(0x01, HidUsageAndPage::kPageVendor),
- HidUsageAndPage(0x02, HidUsageAndPage::kPageVendor),
- HidUsageAndPage(0x04, HidUsageAndPage::kPageVendor), };
-
- GetTopLevelCollections(std::vector<HidUsageAndPage>(
- expected, expected + ARRAYSIZE_UNSAFE(expected)),
- kLogitechUnifyingReceiver,
- sizeof(kLogitechUnifyingReceiver));
-}
-
} // namespace device
diff --git a/device/hid/hid_service_linux.cc b/device/hid/hid_service_linux.cc
index 5257dcd..4f1d8c7 100644
--- a/device/hid/hid_service_linux.cc
+++ b/device/hid/hid_service_linux.cc
@@ -2,17 +2,18 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
+#include "device/hid/hid_service_linux.h"
+
#include <linux/hidraw.h>
#include <sys/ioctl.h>
-
#include <stdint.h>
#include <string>
#include "base/bind.h"
+#include "base/files/file.h"
#include "base/files/file_path.h"
#include "base/logging.h"
-#include "base/platform_file.h"
#include "base/stl_util.h"
#include "base/strings/string_number_conversions.h"
#include "base/strings/string_piece.h"
@@ -20,14 +21,12 @@
#include "device/hid/hid_connection_linux.h"
#include "device/hid/hid_device_info.h"
#include "device/hid/hid_report_descriptor.h"
-#include "device/hid/hid_service_linux.h"
#include "device/udev_linux/udev.h"
namespace device {
namespace {
-const char kHIDSubSystem[] = "hid";
const char kHidrawSubsystem[] = "hidraw";
const char kHIDID[] = "HID_ID";
const char kHIDName[] = "HID_NAME";
@@ -53,11 +52,7 @@
device_info.device_id);
if (device) {
- std::string dev_node;
- if (!FindHidrawDevNode(device.get(), &dev_node)) {
- LOG(ERROR) << "Cannot open HID device as hidraw device.";
- return NULL;
- }
+ std::string dev_node = udev_device_get_devnode(device.get());
return new HidConnectionLinux(device_info, dev_node);
}
@@ -77,7 +72,7 @@
if (!device_path)
return;
const char* subsystem = udev_device_get_subsystem(device);
- if (!subsystem || strcmp(subsystem, kHIDSubSystem) != 0)
+ if (!subsystem || strcmp(subsystem, kHidrawSubsystem) != 0)
return;
HidDeviceInfo device_info;
@@ -86,7 +81,12 @@
uint32_t int_property = 0;
const char* str_property = NULL;
- const char* hid_id = udev_device_get_property_value(device, kHIDID);
+ udev_device *parent = udev_device_get_parent(device);
+ if (!parent) {
+ return;
+ }
+
+ const char* hid_id = udev_device_get_property_value(parent, kHIDID);
if (!hid_id)
return;
@@ -104,21 +104,16 @@
device_info.product_id = int_property;
}
- str_property = udev_device_get_property_value(device, kHIDUnique);
+ str_property = udev_device_get_property_value(parent, kHIDUnique);
if (str_property != NULL)
device_info.serial_number = str_property;
- str_property = udev_device_get_property_value(device, kHIDName);
+ str_property = udev_device_get_property_value(parent, kHIDName);
if (str_property != NULL)
device_info.product_name = str_property;
- std::string dev_node;
- if (!FindHidrawDevNode(device, &dev_node)) {
- LOG(ERROR) << "Cannot find device node for HID device.";
- return;
- }
-
- int flags = base::File::FLAG_OPEN | base::File::FLAG_READ;
+ const std::string dev_node = udev_device_get_devnode(device);
+ const int flags = base::File::FLAG_OPEN | base::File::FLAG_READ;
base::File device_file(base::FilePath(dev_node), flags);
if (!device_file.IsValid()) {
@@ -130,7 +125,7 @@
int desc_size = 0;
int res = ioctl(device_file.GetPlatformFile(), HIDIOCGRDESCSIZE, &desc_size);
if (res < 0) {
- LOG(ERROR) << "HIDIOCGRDESCSIZE failed.";
+ PLOG(ERROR) << "Failed to get report descriptor size";
device_file.Close();
return;
}
@@ -140,7 +135,7 @@
res = ioctl(device_file.GetPlatformFile(), HIDIOCGRDESC, &rpt_desc);
if (res < 0) {
- LOG(ERROR) << "HIDIOCGRDESC failed.";
+ PLOG(ERROR) << "Failed to get report descriptor";
device_file.Close();
return;
}
@@ -148,7 +143,10 @@
device_file.Close();
HidReportDescriptor report_descriptor(rpt_desc.value, rpt_desc.size);
- report_descriptor.GetTopLevelCollections(&device_info.usages);
+ report_descriptor.GetDetails(&device_info.collections,
+ &device_info.max_input_report_size,
+ &device_info.max_output_report_size,
+ &device_info.max_feature_report_size);
AddDevice(device_info);
}
@@ -159,44 +157,4 @@
RemoveDevice(device_path);
}
-bool HidServiceLinux::FindHidrawDevNode(udev_device* parent,
- std::string* result) {
- udev* udev = udev_device_get_udev(parent);
- if (!udev) {
- return false;
- }
- ScopedUdevEnumeratePtr enumerate(udev_enumerate_new(udev));
- if (!enumerate) {
- return false;
- }
- if (udev_enumerate_add_match_subsystem(enumerate.get(), kHidrawSubsystem)) {
- return false;
- }
- if (udev_enumerate_scan_devices(enumerate.get())) {
- return false;
- }
- std::string parent_path(udev_device_get_devpath(parent));
- if (parent_path.length() == 0 || *parent_path.rbegin() != '/')
- parent_path += '/';
- udev_list_entry* devices = udev_enumerate_get_list_entry(enumerate.get());
- for (udev_list_entry* i = devices; i != NULL;
- i = udev_list_entry_get_next(i)) {
- ScopedUdevDevicePtr hid_dev(
- udev_device_new_from_syspath(udev, udev_list_entry_get_name(i)));
- const char* raw_path = udev_device_get_devnode(hid_dev.get());
- std::string device_path = udev_device_get_devpath(hid_dev.get());
- if (raw_path &&
- !device_path.compare(0, parent_path.length(), parent_path)) {
- std::string sub_path = device_path.substr(parent_path.length());
- if (sub_path.substr(0, sizeof(kHidrawSubsystem) - 1) ==
- kHidrawSubsystem) {
- *result = raw_path;
- return true;
- }
- }
- }
-
- return false;
-}
-
} // namespace device
diff --git a/device/hid/hid_service_linux.h b/device/hid/hid_service_linux.h
index 8d5b115..c69096d 100644
--- a/device/hid/hid_service_linux.h
+++ b/device/hid/hid_service_linux.h
@@ -32,8 +32,6 @@
private:
virtual ~HidServiceLinux();
- static bool FindHidrawDevNode(udev_device* parent, std::string* result);
-
DISALLOW_COPY_AND_ASSIGN(HidServiceLinux);
};
diff --git a/device/hid/hid_service_mac.cc b/device/hid/hid_service_mac.cc
index ed85ec2..98bfd92 100644
--- a/device/hid/hid_service_mac.cc
+++ b/device/hid/hid_service_mac.cc
@@ -7,17 +7,19 @@
#include <CoreFoundation/CoreFoundation.h>
#include <IOKit/hid/IOHIDManager.h>
+#include <set>
#include <string>
#include <vector>
#include "base/bind.h"
#include "base/logging.h"
+#include "base/mac/foundation_util.h"
#include "base/message_loop/message_loop_proxy.h"
#include "base/stl_util.h"
#include "base/strings/string_number_conversions.h"
+#include "base/strings/sys_string_conversions.h"
#include "base/threading/thread_restrictions.h"
#include "device/hid/hid_connection_mac.h"
-#include "device/hid/hid_utils_mac.h"
namespace device {
@@ -48,6 +50,89 @@
CFSetApplyFunction(devices, HidEnumerationBackInserter, device_list);
}
+bool TryGetHidIntProperty(IOHIDDeviceRef device,
+ CFStringRef key,
+ int32_t* result) {
+ CFNumberRef ref =
+ base::mac::CFCast<CFNumberRef>(IOHIDDeviceGetProperty(device, key));
+ return ref && CFNumberGetValue(ref, kCFNumberSInt32Type, result);
+}
+
+int32_t GetHidIntProperty(IOHIDDeviceRef device, CFStringRef key) {
+ int32_t value;
+ if (TryGetHidIntProperty(device, key, &value))
+ return value;
+ return 0;
+}
+
+bool TryGetHidStringProperty(IOHIDDeviceRef device,
+ CFStringRef key,
+ std::string* result) {
+ CFStringRef ref =
+ base::mac::CFCast<CFStringRef>(IOHIDDeviceGetProperty(device, key));
+ if (!ref) {
+ return false;
+ }
+ *result = base::SysCFStringRefToUTF8(ref);
+ return true;
+}
+
+std::string GetHidStringProperty(IOHIDDeviceRef device, CFStringRef key) {
+ std::string value;
+ TryGetHidStringProperty(device, key, &value);
+ return value;
+}
+
+void GetReportIds(IOHIDElementRef element, std::set<int>& reportIDs) {
+ CFArrayRef children = IOHIDElementGetChildren(element);
+ if (!children)
+ return;
+ CFIndex childrenCount = CFArrayGetCount(children);
+ for (CFIndex j = 0; j < childrenCount; ++j) {
+ const IOHIDElementRef child = static_cast<IOHIDElementRef>(
+ const_cast<void*>(CFArrayGetValueAtIndex(children, j)));
+ uint32_t reportID = IOHIDElementGetReportID(child);
+ if (reportID) {
+ reportIDs.insert(reportID);
+ }
+ GetReportIds(child, reportIDs);
+ }
+}
+
+void GetCollectionInfos(IOHIDDeviceRef device,
+ std::vector<HidCollectionInfo>* top_level_collections) {
+ STLClearObject(top_level_collections);
+ CFMutableDictionaryRef collections_filter =
+ CFDictionaryCreateMutable(kCFAllocatorDefault,
+ 0,
+ &kCFTypeDictionaryKeyCallBacks,
+ &kCFTypeDictionaryValueCallBacks);
+ const int kCollectionTypeValue = kIOHIDElementTypeCollection;
+ CFNumberRef collection_type_id = CFNumberCreate(
+ kCFAllocatorDefault, kCFNumberIntType, &kCollectionTypeValue);
+ CFDictionarySetValue(
+ collections_filter, CFSTR(kIOHIDElementTypeKey), collection_type_id);
+ CFRelease(collection_type_id);
+ CFArrayRef collections = IOHIDDeviceCopyMatchingElements(
+ device, collections_filter, kIOHIDOptionsTypeNone);
+ CFIndex collectionsCount = CFArrayGetCount(collections);
+ for (CFIndex i = 0; i < collectionsCount; i++) {
+ const IOHIDElementRef collection = static_cast<IOHIDElementRef>(
+ const_cast<void*>(CFArrayGetValueAtIndex(collections, i)));
+ // Top-Level Collection has no parent
+ if (IOHIDElementGetParent(collection) == 0) {
+ HidCollectionInfo collection_info;
+ HidUsageAndPage::Page page = static_cast<HidUsageAndPage::Page>(
+ IOHIDElementGetUsagePage(collection));
+ uint16_t usage = IOHIDElementGetUsage(collection);
+ collection_info.usage = HidUsageAndPage(usage, page);
+ // Explore children recursively and retrieve their report IDs
+ GetReportIds(collection, collection_info.report_ids);
+ top_level_collections->push_back(collection_info);
+ }
+ }
+}
+
} // namespace
HidServiceMac::HidServiceMac() {
@@ -136,41 +221,23 @@
// Note that our ownership of hid_device is implied if calling this method.
// It is balanced in PlatformRemoveDevice.
DCHECK(thread_checker_.CalledOnValidThread());
-
HidDeviceInfo device_info;
device_info.device_id = hid_device;
device_info.vendor_id =
GetHidIntProperty(hid_device, CFSTR(kIOHIDVendorIDKey));
device_info.product_id =
GetHidIntProperty(hid_device, CFSTR(kIOHIDProductIDKey));
- device_info.input_report_size =
- GetHidIntProperty(hid_device, CFSTR(kIOHIDMaxInputReportSizeKey));
- device_info.output_report_size =
- GetHidIntProperty(hid_device, CFSTR(kIOHIDMaxOutputReportSizeKey));
- device_info.feature_report_size =
- GetHidIntProperty(hid_device, CFSTR(kIOHIDMaxFeatureReportSizeKey));
- CFTypeRef deviceUsagePairsRaw =
- IOHIDDeviceGetProperty(hid_device, CFSTR(kIOHIDDeviceUsagePairsKey));
- CFArrayRef deviceUsagePairs =
- base::mac::CFCast<CFArrayRef>(deviceUsagePairsRaw);
- CFIndex deviceUsagePairsCount = CFArrayGetCount(deviceUsagePairs);
- for (CFIndex i = 0; i < deviceUsagePairsCount; i++) {
- CFDictionaryRef deviceUsagePair = base::mac::CFCast<CFDictionaryRef>(
- CFArrayGetValueAtIndex(deviceUsagePairs, i));
- CFNumberRef usage_raw = base::mac::CFCast<CFNumberRef>(
- CFDictionaryGetValue(deviceUsagePair, CFSTR(kIOHIDDeviceUsageKey)));
- uint16_t usage;
- CFNumberGetValue(usage_raw, kCFNumberSInt32Type, &usage);
- CFNumberRef page_raw = base::mac::CFCast<CFNumberRef>(
- CFDictionaryGetValue(deviceUsagePair, CFSTR(kIOHIDDeviceUsagePageKey)));
- HidUsageAndPage::Page page;
- CFNumberGetValue(page_raw, kCFNumberSInt32Type, &page);
- device_info.usages.push_back(HidUsageAndPage(usage, page));
- }
device_info.product_name =
GetHidStringProperty(hid_device, CFSTR(kIOHIDProductKey));
device_info.serial_number =
GetHidStringProperty(hid_device, CFSTR(kIOHIDSerialNumberKey));
+ GetCollectionInfos(hid_device, &device_info.collections);
+ device_info.max_input_report_size =
+ GetHidIntProperty(hid_device, CFSTR(kIOHIDMaxInputReportSizeKey));
+ device_info.max_output_report_size =
+ GetHidIntProperty(hid_device, CFSTR(kIOHIDMaxOutputReportSizeKey));
+ device_info.max_feature_report_size =
+ GetHidIntProperty(hid_device, CFSTR(kIOHIDMaxFeatureReportSizeKey));
AddDevice(device_info);
}
diff --git a/device/hid/hid_service_win.cc b/device/hid/hid_service_win.cc
index 82477a5..9f27cff 100644
--- a/device/hid/hid_service_win.cc
+++ b/device/hid/hid_service_win.cc
@@ -187,38 +187,50 @@
PHIDP_PREPARSED_DATA preparsed_data;
if (HidD_GetPreparsedData(device_handle.Get(), &preparsed_data) &&
preparsed_data) {
- HIDP_CAPS capabilities;
+ HIDP_CAPS capabilities = {0};
if (HidP_GetCaps(preparsed_data, &capabilities) == HIDP_STATUS_SUCCESS) {
- device_info.input_report_size = capabilities.InputReportByteLength;
- device_info.output_report_size = capabilities.OutputReportByteLength;
- device_info.feature_report_size = capabilities.FeatureReportByteLength;
- device_info.usages.push_back(HidUsageAndPage(
- capabilities.Usage,
- static_cast<HidUsageAndPage::Page>(capabilities.UsagePage)));
- }
- // Detect if the device supports report ids.
- if (capabilities.NumberInputValueCaps > 0) {
- scoped_ptr<HIDP_VALUE_CAPS[]> value_caps(
- new HIDP_VALUE_CAPS[capabilities.NumberInputValueCaps]);
- USHORT value_caps_length = capabilities.NumberInputValueCaps;
- if (HidP_GetValueCaps(HidP_Input, &value_caps[0], &value_caps_length,
- preparsed_data) == HIDP_STATUS_SUCCESS) {
- device_info.has_report_id = (value_caps[0].ReportID != 0);
- }
- }
- if (!device_info.has_report_id && capabilities.NumberInputButtonCaps > 0)
- {
- scoped_ptr<HIDP_BUTTON_CAPS[]> button_caps(
- new HIDP_BUTTON_CAPS[capabilities.NumberInputButtonCaps]);
+ device_info.max_input_report_size = capabilities.InputReportByteLength;
+ device_info.max_output_report_size = capabilities.OutputReportByteLength;
+ device_info.max_feature_report_size =
+ capabilities.FeatureReportByteLength;
+ HidCollectionInfo collection_info;
+ collection_info.usage = HidUsageAndPage(
+ capabilities.Usage,
+ static_cast<HidUsageAndPage::Page>(capabilities.UsagePage));
USHORT button_caps_length = capabilities.NumberInputButtonCaps;
- if (HidP_GetButtonCaps(HidP_Input,
- &button_caps[0],
- &button_caps_length,
- preparsed_data) == HIDP_STATUS_SUCCESS) {
- device_info.has_report_id = (button_caps[0].ReportID != 0);
+ if (button_caps_length > 0) {
+ scoped_ptr<HIDP_BUTTON_CAPS[]> button_caps(
+ new HIDP_BUTTON_CAPS[button_caps_length]);
+ if (HidP_GetButtonCaps(HidP_Input,
+ &button_caps[0],
+ &button_caps_length,
+ preparsed_data) == HIDP_STATUS_SUCCESS) {
+ for (int i = 0; i < button_caps_length; i++) {
+ int report_id = button_caps[i].ReportID;
+ if (report_id != 0) {
+ collection_info.report_ids.insert(report_id);
+ }
+ }
+ }
}
+ USHORT value_caps_length = capabilities.NumberInputValueCaps;
+ if (value_caps_length > 0) {
+ scoped_ptr<HIDP_VALUE_CAPS[]> value_caps(
+ new HIDP_VALUE_CAPS[value_caps_length]);
+ if (HidP_GetValueCaps(HidP_Input,
+ &value_caps[0],
+ &value_caps_length,
+ preparsed_data) == HIDP_STATUS_SUCCESS) {
+ for (int i = 0; i < value_caps_length; i++) {
+ int report_id = value_caps[i].ReportID;
+ if (report_id != 0) {
+ collection_info.report_ids.insert(report_id);
+ }
+ }
+ }
+ }
+ device_info.collections.push_back(collection_info);
}
-
HidD_FreePreparsedData(preparsed_data);
}
diff --git a/device/hid/hid_usage_and_page.cc b/device/hid/hid_usage_and_page.cc
index 773346b..079ec66 100644
--- a/device/hid/hid_usage_and_page.cc
+++ b/device/hid/hid_usage_and_page.cc
@@ -6,8 +6,31 @@
namespace device {
-bool HidUsageAndPage::operator==(const HidUsageAndPage& other) const {
- return usage == other.usage && usage_page == other.usage_page;
+bool HidUsageAndPage::IsProtected() const {
+ if (usage_page == HidUsageAndPage::kPageKeyboard)
+ return true;
+
+ if (usage_page != HidUsageAndPage::kPageGenericDesktop)
+ return false;
+
+ if (usage == HidUsageAndPage::kGenericDesktopPointer ||
+ usage == HidUsageAndPage::kGenericDesktopMouse ||
+ usage == HidUsageAndPage::kGenericDesktopKeyboard ||
+ usage == HidUsageAndPage::kGenericDesktopKeypad) {
+ return true;
+ }
+
+ if (usage >= HidUsageAndPage::kGenericDesktopSystemControl &&
+ usage <= HidUsageAndPage::kGenericDesktopSystemWarmRestart) {
+ return true;
+ }
+
+ if (usage >= HidUsageAndPage::kGenericDesktopSystemDock &&
+ usage <= HidUsageAndPage::kGenericDesktopSystemDisplaySwap) {
+ return true;
+ }
+
+ return false;
}
} // namespace device
diff --git a/device/hid/hid_usage_and_page.h b/device/hid/hid_usage_and_page.h
index 98ac80d..635e9b3 100644
--- a/device/hid/hid_usage_and_page.h
+++ b/device/hid/hid_usage_and_page.h
@@ -126,7 +126,8 @@
uint16_t usage;
Page usage_page;
- bool operator==(const HidUsageAndPage& other) const;
+ // Indicates whether this usage is protected by Chrome.
+ bool IsProtected() const;
};
} // namespace device
diff --git a/device/hid/hid_utils_mac.cc b/device/hid/hid_utils_mac.cc
deleted file mode 100644
index 46605d8..0000000
--- a/device/hid/hid_utils_mac.cc
+++ /dev/null
@@ -1,45 +0,0 @@
-// Copyright 2014 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "device/hid/hid_utils_mac.h"
-
-#include "base/mac/foundation_util.h"
-#include "base/strings/sys_string_conversions.h"
-
-namespace device {
-
-int32_t GetHidIntProperty(IOHIDDeviceRef device, CFStringRef key) {
- int32_t value;
- if (TryGetHidIntProperty(device, key, &value))
- return value;
- return 0;
-}
-
-std::string GetHidStringProperty(IOHIDDeviceRef device, CFStringRef key) {
- std::string value;
- TryGetHidStringProperty(device, key, &value);
- return value;
-}
-
-bool TryGetHidIntProperty(IOHIDDeviceRef device,
- CFStringRef key,
- int32_t* result) {
- CFNumberRef ref = base::mac::CFCast<CFNumberRef>(
- IOHIDDeviceGetProperty(device, key));
- return ref && CFNumberGetValue(ref, kCFNumberSInt32Type, result);
-}
-
-bool TryGetHidStringProperty(IOHIDDeviceRef device,
- CFStringRef key,
- std::string* result) {
- CFStringRef ref = base::mac::CFCast<CFStringRef>(
- IOHIDDeviceGetProperty(device, key));
- if (!ref) {
- return false;
- }
- *result = base::SysCFStringRefToUTF8(ref);
- return true;
-}
-
-} // namespace device
diff --git a/device/hid/hid_utils_mac.h b/device/hid/hid_utils_mac.h
deleted file mode 100644
index e9b2524..0000000
--- a/device/hid/hid_utils_mac.h
+++ /dev/null
@@ -1,30 +0,0 @@
-// Copyright 2014 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef DEVICE_HID_HID_UTILS_MAC_H_
-#define DEVICE_HID_HID_UTILS_MAC_H_
-
-#include <CoreFoundation/CoreFoundation.h>
-#include <IOKit/hid/IOHIDManager.h>
-#include <stdint.h>
-
-#include <string>
-
-namespace device {
-
-int32_t GetHidIntProperty(IOHIDDeviceRef device, CFStringRef key);
-
-std::string GetHidStringProperty(IOHIDDeviceRef device, CFStringRef key);
-
-bool TryGetHidIntProperty(IOHIDDeviceRef device,
- CFStringRef key,
- int32_t* result);
-
-bool TryGetHidStringProperty(IOHIDDeviceRef device,
- CFStringRef key,
- std::string* result);
-
-} // namespace device
-
-#endif // DEVICE_HID_HID_UTILS_MAC_H_