summaryrefslogtreecommitdiffstats
path: root/device/hid
diff options
context:
space:
mode:
authorcsharp@chromium.org <csharp@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2014-07-03 17:14:13 +0000
committercsharp@chromium.org <csharp@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2014-07-03 17:14:13 +0000
commit0eac598eeed59ebebdeb0d44e93677fbb9cb9d5a (patch)
tree6c5033490339860687bd80a6f6a663784eddd654 /device/hid
parentc9ab4198a25ff667f69acc6c9c8dad10c81bbe64 (diff)
downloadchromium_src-0eac598eeed59ebebdeb0d44e93677fbb9cb9d5a.zip
chromium_src-0eac598eeed59ebebdeb0d44e93677fbb9cb9d5a.tar.gz
chromium_src-0eac598eeed59ebebdeb0d44e93677fbb9cb9d5a.tar.bz2
Revert 281133 "chrome.hid: enrich model with report IDs"
Speculative revert to try and fix Win browser tests. > chrome.hid: enrich model with report IDs > > - add report IDs and max report size > - don't expose sensitive usages > > BUG=364423 > R=rockot@chromium.org > TESTS=run device_unittests (HidReportDescriptorTest) > > Review URL: https://codereview.chromium.org/317783010 TBR=jracle@logitech.com Review URL: https://codereview.chromium.org/369923002 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@281282 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'device/hid')
-rw-r--r--device/hid/hid.gyp4
-rw-r--r--device/hid/hid_collection_info.cc17
-rw-r--r--device/hid/hid_collection_info.h29
-rw-r--r--device/hid/hid_connection.cc180
-rw-r--r--device/hid/hid_connection.h61
-rw-r--r--device/hid/hid_connection_linux.cc124
-rw-r--r--device/hid/hid_connection_linux.h38
-rw-r--r--device/hid/hid_connection_mac.cc123
-rw-r--r--device/hid/hid_connection_mac.h39
-rw-r--r--device/hid/hid_connection_win.cc132
-rw-r--r--device/hid/hid_connection_win.h45
-rw-r--r--device/hid/hid_device_info.cc10
-rw-r--r--device/hid/hid_device_info.h19
-rw-r--r--device/hid/hid_report_descriptor.cc170
-rw-r--r--device/hid/hid_report_descriptor.h11
-rw-r--r--device/hid/hid_report_descriptor_item.cc12
-rw-r--r--device/hid/hid_report_descriptor_unittest.cc924
-rw-r--r--device/hid/hid_service_linux.cc5
-rw-r--r--device/hid/hid_service_mac.cc119
-rw-r--r--device/hid/hid_service_win.cc68
-rw-r--r--device/hid/hid_usage_and_page.cc27
-rw-r--r--device/hid/hid_usage_and_page.h3
-rw-r--r--device/hid/hid_utils_mac.cc45
-rw-r--r--device/hid/hid_utils_mac.h30
24 files changed, 1030 insertions, 1205 deletions
diff --git a/device/hid/hid.gyp b/device/hid/hid.gyp
index 2db80fd..c12845a 100644
--- a/device/hid/hid.gyp
+++ b/device/hid/hid.gyp
@@ -16,8 +16,6 @@
'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',
@@ -42,6 +40,8 @@
'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
deleted file mode 100644
index 4c55d08..0000000
--- a/device/hid/hid_collection_info.cc
+++ /dev/null
@@ -1,17 +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_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
deleted file mode 100644
index 3b35e5e..0000000
--- a/device/hid/hid_collection_info.h
+++ /dev/null
@@ -1,29 +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_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 76809d3..c134bf2 100644
--- a/device/hid/hid_connection.cc
+++ b/device/hid/hid_connection.cc
@@ -4,183 +4,8 @@
#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() {}
@@ -189,4 +14,9 @@ PendingHidRead::PendingHidRead() {}
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 963b89f..5c08fbc 100644
--- a/device/hid/hid_connection.h
+++ b/device/hid/hid_connection.h
@@ -9,7 +9,6 @@
#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"
@@ -17,65 +16,31 @@ namespace device {
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 0220c2e..331e3f3 100644
--- a/device/hid/hid_connection_linux.cc
+++ b/device/hid/hid_connection_linux.cc
@@ -46,6 +46,8 @@ scoped_refptr<net::IOBufferWithSize> CopyBufferWithReportId(
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;
@@ -86,13 +88,49 @@ HidConnectionLinux::HidConnectionLinux(HidDeviceInfo device_info,
}
HidConnectionLinux::~HidConnectionLinux() {
+ DCHECK(thread_checker_.CalledOnValidThread());
Disconnect();
- Flush();
}
-void HidConnectionLinux::PlatformRead(
- scoped_refptr<net::IOBufferWithSize> buffer,
- const IOCallback& callback) {
+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;
+ }
+ VPLOG(1) << "Read failed";
+ 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());
PendingHidRead pending_read;
pending_read.buffer = buffer;
pending_read.callback = callback;
@@ -100,10 +138,10 @@ void HidConnectionLinux::PlatformRead(
ProcessReadQueue();
}
-void HidConnectionLinux::PlatformWrite(
- uint8_t report_id,
- scoped_refptr<net::IOBufferWithSize> buffer,
- const IOCallback& callback) {
+void HidConnectionLinux::Write(uint8_t report_id,
+ scoped_refptr<net::IOBufferWithSize> buffer,
+ const IOCallback& callback) {
+ DCHECK(thread_checker_.CalledOnValidThread());
// If report ID is non-zero, insert it into a new copy of the buffer.
if (report_id != 0)
buffer = CopyBufferWithReportId(buffer, report_id);
@@ -118,10 +156,12 @@ void HidConnectionLinux::PlatformWrite(
}
}
-void HidConnectionLinux::PlatformGetFeatureReport(
+void HidConnectionLinux::GetFeatureReport(
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;
@@ -140,10 +180,11 @@ void HidConnectionLinux::PlatformGetFeatureReport(
}
}
-void HidConnectionLinux::PlatformSendFeatureReport(
+void HidConnectionLinux::SendFeatureReport(
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(),
@@ -157,72 +198,17 @@ void HidConnectionLinux::PlatformSendFeatureReport(
}
}
-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 (read.buffer->size() < report.buffer->size()) {
- read.callback.Run(false, 0);
- pending_reads_.pop();
+ if (report.buffer->size() > read.buffer->size()) {
+ read.callback.Run(false, report.buffer->size());
} else {
memcpy(read.buffer->data(), report.buffer->data(), report.buffer->size());
pending_reports_.pop();
-
- if (CompleteRead(report.buffer, read.callback)) {
- pending_reads_.pop();
- }
+ read.callback.Run(true, report.buffer->size());
}
}
}
diff --git a/device/hid/hid_connection_linux.h b/device/hid/hid_connection_linux.h
index 1f5a7a8..108ad88 100644
--- a/device/hid/hid_connection_linux.h
+++ b/device/hid/hid_connection_linux.h
@@ -8,8 +8,10 @@
#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 {
@@ -18,22 +20,19 @@ class HidConnectionLinux : public HidConnection,
public:
HidConnectionLinux(HidDeviceInfo device_info, std::string dev_node);
- // 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;
-
- // base::MessagePumpLibevent::Watcher implementation.
+ 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;
+
+ // Implements base::MessagePumpLibevent::Watcher
virtual void OnFileCanReadWithoutBlocking(int fd) OVERRIDE;
virtual void OnFileCanWriteWithoutBlocking(int fd) OVERRIDE;
@@ -41,11 +40,8 @@ class HidConnectionLinux : public HidConnection,
friend class base::RefCountedThreadSafe<HidConnectionLinux>;
virtual ~HidConnectionLinux();
- void Disconnect();
-
- void Flush();
- void ProcessInputReport(scoped_refptr<net::IOBufferWithSize> buffer);
void ProcessReadQueue();
+ void Disconnect();
base::File device_file_;
base::MessagePumpLibevent::FileDescriptorWatcher device_file_watcher_;
@@ -53,6 +49,8 @@ class HidConnectionLinux : public HidConnection,
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 521f287..ce17df4 100644
--- a/device/hid/hid_connection_mac.cc
+++ b/device/hid/hid_connection_mac.cc
@@ -7,6 +7,7 @@
#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 {
@@ -14,70 +15,85 @@ namespace device {
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.max_input_report_size));
+ inbound_buffer_.reset((uint8_t*)malloc(device_info.input_report_size));
IOHIDDeviceRegisterInputReportCallback(device_.get(),
inbound_buffer_.get(),
- device_info.max_input_report_size,
+ device_info.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::PlatformRead(scoped_refptr<net::IOBufferWithSize> buffer,
- const IOCallback& callback) {
+void HidConnectionMac::Read(scoped_refptr<net::IOBufferWithSize> buffer,
+ const IOCallback& callback) {
+ DCHECK(thread_checker_.CalledOnValidThread());
if (!device_) {
callback.Run(false, 0);
return;
}
-
- PendingHidRead pending_read;
- pending_read.buffer = buffer;
- pending_read.callback = callback;
- pending_reads_.push(pending_read);
+ PendingHidRead read;
+ read.buffer = buffer;
+ read.callback = callback;
+ pending_reads_.push(read);
ProcessReadQueue();
}
-void HidConnectionMac::PlatformWrite(
- uint8_t report_id,
- scoped_refptr<net::IOBufferWithSize> buffer,
- const IOCallback& callback) {
+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::PlatformGetFeatureReport(
+void HidConnectionMac::GetFeatureReport(
uint8_t report_id,
scoped_refptr<net::IOBufferWithSize> buffer,
const IOCallback& callback) {
- if (!device_) {
+ DCHECK(thread_checker_.CalledOnValidThread());
+ if (device_info().feature_report_size == 0) {
+ callback.Run(false, 0);
+ return;
+ }
+
+ if (buffer->size() < device_info().feature_report_size) {
callback.Run(false, 0);
return;
}
uint8_t* feature_report_buffer = reinterpret_cast<uint8_t*>(buffer->data());
- CFIndex max_feature_report_size = device_info().max_feature_report_size;
+ CFIndex feature_report_size = device_info().feature_report_size;
IOReturn result = IOHIDDeviceGetReport(device_,
kIOHIDReportTypeFeature,
report_id,
feature_report_buffer,
- &max_feature_report_size);
+ &feature_report_size);
if (result == kIOReturnSuccess)
- callback.Run(true, max_feature_report_size);
+ callback.Run(true, feature_report_size);
else
callback.Run(false, 0);
}
-void HidConnectionMac::PlatformSendFeatureReport(
+void HidConnectionMac::SendFeatureReport(
uint8_t report_id,
scoped_refptr<net::IOBufferWithSize> buffer,
const IOCallback& callback) {
+ DCHECK(thread_checker_.CalledOnValidThread());
WriteReport(kIOHIDReportTypeFeature, report_id, buffer, callback);
}
@@ -96,18 +112,45 @@ void HidConnectionMac::InputReportCallback(void* context,
connection->message_loop_->PostTask(
FROM_HERE,
- base::Bind(&HidConnectionMac::ProcessInputReport, connection, buffer));
+ 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();
}
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);
@@ -130,40 +173,4 @@ void HidConnectionMac::WriteReport(IOHIDReportType type,
}
}
-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 02dde04..c307fb6 100644
--- a/device/hid/hid_connection_mac.h
+++ b/device/hid/hid_connection_mac.h
@@ -11,8 +11,11 @@
#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;
@@ -28,20 +31,17 @@ class HidConnectionMac : public HidConnection {
public:
explicit HidConnectionMac(HidDeviceInfo device_info);
- // 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:
virtual ~HidConnectionMac();
@@ -53,26 +53,29 @@ class HidConnectionMac : public HidConnection {
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);
- void Flush();
- void ProcessInputReport(scoped_refptr<net::IOBufferWithSize> buffer);
- void ProcessReadQueue();
+ scoped_refptr<base::MessageLoopProxy> message_loop_;
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 767feac..17448f0 100644
--- a/device/hid/hid_connection_win.cc
+++ b/device/hid/hid_connection_win.cc
@@ -8,7 +8,12 @@
#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
@@ -98,6 +103,7 @@ void PendingHidTransfer::WillDestroyCurrentMessageLoop() {
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,
@@ -118,15 +124,40 @@ HidConnectionWin::HidConnectionWin(const HidDeviceInfo& device_info)
}
}
+bool HidConnectionWin::available() const {
+ return file_.IsValid();
+}
+
HidConnectionWin::~HidConnectionWin() {
+ DCHECK(thread_checker_.CalledOnValidThread());
CancelIo(file_.Get());
}
-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);
+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;
+ }
+
+ // 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);
@@ -138,10 +169,16 @@ void HidConnectionWin::PlatformRead(scoped_refptr<net::IOBufferWithSize> buffer,
transfer->GetOverlapped()));
}
-void HidConnectionWin::PlatformWrite(
- uint8_t report_id,
- scoped_refptr<net::IOBufferWithSize> buffer,
- const HidConnection::IOCallback& callback) {
+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;
+ }
+
// 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);
@@ -160,15 +197,32 @@ void HidConnectionWin::PlatformWrite(
transfer->GetOverlapped()));
}
-void HidConnectionWin::PlatformGetFeatureReport(
+void HidConnectionWin::GetFeatureReport(
uint8_t report_id,
scoped_refptr<net::IOBufferWithSize> buffer,
const IOCallback& callback) {
- scoped_refptr<net::IOBufferWithSize> receive_buffer =
- new net::IOBufferWithSize(device_info().max_feature_report_size);
+ 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);
+
// 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);
@@ -183,10 +237,17 @@ void HidConnectionWin::PlatformGetFeatureReport(
transfer->GetOverlapped()));
}
-void HidConnectionWin::PlatformSendFeatureReport(
+void HidConnectionWin::SendFeatureReport(
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);
@@ -209,42 +270,25 @@ void HidConnectionWin::PlatformSendFeatureReport(
void HidConnectionWin::OnTransferFinished(
scoped_refptr<PendingHidTransfer> transfer) {
- transfers_.erase(transfer);
-
DWORD bytes_transferred;
+ transfers_.erase(transfer);
if (GetOverlappedResult(
file_, transfer->GetOverlapped(), &bytes_transferred, FALSE)) {
- if (bytes_transferred == 0) {
+ if (bytes_transferred == 0)
transfer->callback_.Run(true, 0);
- return;
+ // 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);
}
-
- 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_);
+ transfer->callback_.Run(true, bytes_transferred);
} else {
transfer->callback_.Run(false, 0);
}
diff --git a/device/hid/hid_connection_win.h b/device/hid/hid_connection_win.h
index 6706044..263897a 100644
--- a/device/hid/hid_connection_win.h
+++ b/device/hid/hid_connection_win.h
@@ -9,8 +9,12 @@
#include <set>
-#include "base/win/scoped_handle.h"
+#include "base/callback.h"
+#include "base/memory/ref_counted.h"
+#include "base/message_loop/message_loop.h"
+#include "base/threading/thread_checker.h"
#include "device/hid/hid_connection.h"
+#include "device/hid/hid_device_info.h"
namespace device {
@@ -20,36 +24,31 @@ class HidConnectionWin : public HidConnection {
public:
explicit HidConnectionWin(const HidDeviceInfo& device_info);
- // 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;
+ bool available() const;
- private:
- friend class HidServiceWin;
- friend struct PendingHidTransfer;
-
- ~HidConnectionWin();
-
- bool available() const { return file_.IsValid(); }
+ 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;
void OnTransferFinished(scoped_refptr<PendingHidTransfer> transfer);
void OnTransferCanceled(scoped_refptr<PendingHidTransfer> transfer);
- base::win::ScopedHandle file_;
+ private:
+ ~HidConnectionWin();
+ base::win::ScopedHandle file_;
std::set<scoped_refptr<PendingHidTransfer> > transfers_;
+ base::ThreadChecker thread_checker_;
+
DISALLOW_COPY_AND_ASSIGN(HidConnectionWin);
};
diff --git a/device/hid/hid_device_info.cc b/device/hid/hid_device_info.cc
index 26891f8..89be442 100644
--- a/device/hid/hid_device_info.cc
+++ b/device/hid/hid_device_info.cc
@@ -12,13 +12,13 @@ const char kInvalidHidDeviceId[] = "";
HidDeviceInfo::HidDeviceInfo()
: device_id(kInvalidHidDeviceId),
+ bus_type(kHIDBusTypeUSB),
vendor_id(0),
product_id(0),
- bus_type(kHIDBusTypeUSB),
- max_input_report_size(0),
- max_output_report_size(0),
- max_feature_report_size(0) {
-}
+ input_report_size(0),
+ output_report_size(0),
+ feature_report_size(0),
+ has_report_id(false) {}
HidDeviceInfo::~HidDeviceInfo() {}
diff --git a/device/hid/hid_device_info.h b/device/hid/hid_device_info.h
index 2ed51ac..1b143c2 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_collection_info.h"
+#include "device/hid/hid_usage_and_page.h"
#if defined(OS_MACOSX)
#include <IOKit/hid/IOHIDDevice.h>
@@ -34,19 +34,20 @@ struct HidDeviceInfo {
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 a06d284..f2cb0f4 100644
--- a/device/hid/hid_report_descriptor.cc
+++ b/device/hid/hid_report_descriptor.cc
@@ -8,12 +8,6 @@
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;
@@ -26,148 +20,42 @@ HidReportDescriptor::HidReportDescriptor(const uint8_t* bytes, size_t size) {
HidReportDescriptor::~HidReportDescriptor() {}
-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;
+void HidReportDescriptor::GetTopLevelCollections(
+ std::vector<HidUsageAndPage>* topLevelCollections) {
+ DCHECK(topLevelCollections);
+ STLClearObject(topLevelCollections);
for (std::vector<linked_ptr<HidReportDescriptorItem> >::const_iterator
items_iter = items().begin();
items_iter != items().end();
++items_iter) {
- linked_ptr<HidReportDescriptorItem> current_item = *items_iter;
-
- 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;
-
- // 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());
-
- // 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);
-
- // 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;
+ linked_ptr<HidReportDescriptorItem> item = *items_iter;
+
+ bool isTopLevelCollection =
+ item->tag() == HidReportDescriptorItem::kTagCollection &&
+ item->parent() == NULL;
+
+ if (isTopLevelCollection) {
+ uint16_t collection_usage = 0;
+ HidUsageAndPage::Page collection_usage_page =
+ HidUsageAndPage::kPageUndefined;
+
+ HidReportDescriptorItem* usage = item->previous();
+ if (usage && usage->tag() == HidReportDescriptorItem::kTagUsage) {
+ collection_usage = usage->GetShortData();
+ }
+
+ HidReportDescriptorItem* usage_page = usage->previous();
+ if (usage_page &&
+ usage_page->tag() == HidReportDescriptorItem::kTagUsagePage) {
+ collection_usage_page =
+ (HidUsageAndPage::Page)usage_page->GetShortData();
+ }
+
+ topLevelCollections->push_back(
+ HidUsageAndPage(collection_usage, collection_usage_page));
}
}
-
- 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 94d90ad..fa67fa4 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,12 +25,9 @@ class HidReportDescriptor {
return items_;
}
- // 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);
+ // Returns HID usages of top-level collections present in the descriptor.
+ void GetTopLevelCollections(
+ std::vector<HidUsageAndPage>* topLevelCollections);
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 60ba764..bdd03ce 100644
--- a/device/hid/hid_report_descriptor_item.cc
+++ b/device/hid/hid_report_descriptor_item.cc
@@ -90,17 +90,17 @@ HidReportDescriptorItem::GetCollectionTypeFromValue(uint32_t value) {
case 0x00:
return kCollectionTypePhysical;
case 0x01:
- return kCollectionTypeApplication;
+ return kCollectionTypePhysical;
case 0x02:
- return kCollectionTypeLogical;
+ return kCollectionTypePhysical;
case 0x03:
- return kCollectionTypeReport;
+ return kCollectionTypePhysical;
case 0x04:
- return kCollectionTypeNamedArray;
+ return kCollectionTypePhysical;
case 0x05:
- return kCollectionTypeUsageSwitch;
+ return kCollectionTypePhysical;
case 0x06:
- return kCollectionTypeUsageModifier;
+ return kCollectionTypePhysical;
default:
break;
}
diff --git a/device/hid/hid_report_descriptor_unittest.cc b/device/hid/hid_report_descriptor_unittest.cc
index 619e682..0d25889 100644
--- a/device/hid/hid_report_descriptor_unittest.cc
+++ b/device/hid/hid_report_descriptor_unittest.cc
@@ -14,272 +14,392 @@ namespace device {
namespace {
-// 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::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;
+}
-// Keyboard descriptor from HID descriptor tool
-// http://www.usb.org/developers/hidpage/dt2_4.zip
-const uint8_t kKeyboard[] = {
- 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
-};
+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;
+}
-// 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
-};
+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;
+ }
-// 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
-};
+ 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)
+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};
+
+// 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};
-// Logitech Unifying receiver descriptor
const uint8_t kLogitechUnifyingReceiver[] = {
- 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
-};
+ 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};
} // namespace
@@ -295,135 +415,199 @@ class HidReportDescriptorTest : public testing::Test {
}
public:
- 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) {
+ void ParseDescriptor(const std::string& expected,
+ const uint8_t* bytes,
+ size_t size) {
descriptor_ = new HidReportDescriptor(bytes, size);
- 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);
-
- ASSERT_EQ(expected_collections.size(), actual_collections.size());
-
- std::vector<HidCollectionInfo>::const_iterator actual_collections_iter =
- actual_collections.begin();
- std::vector<HidCollectionInfo>::const_iterator expected_collections_iter =
- expected_collections.begin();
-
- 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;
-
- 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));
-
- expected_collections_iter++;
- actual_collections_iter++;
+ std::stringstream actual;
+ actual << *descriptor_;
+
+ std::cout << "HID report descriptor:" << std::endl;
+ std::cout << actual.str();
+
+ // TODO(jracle@logitech.com): refactor string comparison in favor of
+ // testing individual fields.
+ ASSERT_EQ(expected, actual.str());
+ }
+
+ void GetTopLevelCollections(const std::vector<HidUsageAndPage>& expected,
+ const uint8_t* bytes,
+ size_t size) {
+ descriptor_ = new HidReportDescriptor(bytes, size);
+
+ std::vector<HidUsageAndPage> actual;
+ descriptor_->GetTopLevelCollections(&actual);
+
+ 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;
}
- 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);
+ ASSERT_THAT(actual, ContainerEq(expected));
}
private:
HidReportDescriptor* descriptor_;
};
-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, 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_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, TopLevelCollections_Keyboard) {
+ HidUsageAndPage expected[] = {
+ HidUsageAndPage(0x06, HidUsageAndPage::kPageGenericDesktop)};
+
+ GetTopLevelCollections(std::vector<HidUsageAndPage>(
+ expected, expected + ARRAYSIZE_UNSAFE(expected)),
+ kKeyboard,
+ sizeof(kKeyboard));
}
-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, 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_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, TopLevelCollections_Mouse) {
+ HidUsageAndPage expected[] = {
+ HidUsageAndPage(0x02, HidUsageAndPage::kPageGenericDesktop)};
+
+ GetTopLevelCollections(std::vector<HidUsageAndPage>(
+ expected, expected + ARRAYSIZE_UNSAFE(expected)),
+ kMouse,
+ sizeof(kMouse));
}
-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);
-
- HidCollectionInfo expected[] = {hidpp_short, hidpp_long, hidpp_dj};
- ValidateDetails(std::vector<HidCollectionInfo>(
- expected, expected + ARRAYSIZE_UNSAFE(expected)),
- 32,
- 32,
- 0,
+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"};
+
+ ParseDescriptor(std::string(expected),
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 470afa8..d7ab558 100644
--- a/device/hid/hid_service_linux.cc
+++ b/device/hid/hid_service_linux.cc
@@ -148,10 +148,7 @@ void HidServiceLinux::OnDeviceAdded(udev_device* device) {
device_file.Close();
HidReportDescriptor report_descriptor(rpt_desc.value, rpt_desc.size);
- report_descriptor.GetDetails(&device_info.collections,
- &device_info.max_input_report_size,
- &device_info.max_output_report_size,
- &device_info.max_feature_report_size);
+ report_descriptor.GetTopLevelCollections(&device_info.usages);
AddDevice(device_info);
}
diff --git a/device/hid/hid_service_mac.cc b/device/hid/hid_service_mac.cc
index 98bfd92..ed85ec2 100644
--- a/device/hid/hid_service_mac.cc
+++ b/device/hid/hid_service_mac.cc
@@ -7,19 +7,17 @@
#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 {
@@ -50,89 +48,6 @@ void EnumerateHidDevices(IOHIDManagerRef hid_manager,
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() {
@@ -221,23 +136,41 @@ void HidServiceMac::PlatformAddDevice(IOHIDDeviceRef hid_device) {
// 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 9f27cff..82477a5 100644
--- a/device/hid/hid_service_win.cc
+++ b/device/hid/hid_service_win.cc
@@ -187,50 +187,38 @@ void HidServiceWin::PlatformAddDevice(const std::string& device_path) {
PHIDP_PREPARSED_DATA preparsed_data;
if (HidD_GetPreparsedData(device_handle.Get(), &preparsed_data) &&
preparsed_data) {
- HIDP_CAPS capabilities = {0};
+ HIDP_CAPS capabilities;
if (HidP_GetCaps(preparsed_data, &capabilities) == HIDP_STATUS_SUCCESS) {
- 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 (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);
- }
- }
- }
- }
+ 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 (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);
- }
- }
- }
+ 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);
}
- device_info.collections.push_back(collection_info);
}
+ if (!device_info.has_report_id && capabilities.NumberInputButtonCaps > 0)
+ {
+ scoped_ptr<HIDP_BUTTON_CAPS[]> button_caps(
+ new HIDP_BUTTON_CAPS[capabilities.NumberInputButtonCaps]);
+ 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);
+ }
+ }
+
HidD_FreePreparsedData(preparsed_data);
}
diff --git a/device/hid/hid_usage_and_page.cc b/device/hid/hid_usage_and_page.cc
index 079ec66..773346b 100644
--- a/device/hid/hid_usage_and_page.cc
+++ b/device/hid/hid_usage_and_page.cc
@@ -6,31 +6,8 @@
namespace device {
-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;
+bool HidUsageAndPage::operator==(const HidUsageAndPage& other) const {
+ return usage == other.usage && usage_page == other.usage_page;
}
} // namespace device
diff --git a/device/hid/hid_usage_and_page.h b/device/hid/hid_usage_and_page.h
index 635e9b3c..98ac80d 100644
--- a/device/hid/hid_usage_and_page.h
+++ b/device/hid/hid_usage_and_page.h
@@ -126,8 +126,7 @@ struct HidUsageAndPage {
uint16_t usage;
Page usage_page;
- // Indicates whether this usage is protected by Chrome.
- bool IsProtected() const;
+ bool operator==(const HidUsageAndPage& other) const;
};
} // namespace device
diff --git a/device/hid/hid_utils_mac.cc b/device/hid/hid_utils_mac.cc
new file mode 100644
index 0000000..46605d8
--- /dev/null
+++ b/device/hid/hid_utils_mac.cc
@@ -0,0 +1,45 @@
+// 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
new file mode 100644
index 0000000..e9b2524
--- /dev/null
+++ b/device/hid/hid_utils_mac.h
@@ -0,0 +1,30 @@
+// 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_