diff options
author | csharp@chromium.org <csharp@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2014-07-03 17:14:13 +0000 |
---|---|---|
committer | csharp@chromium.org <csharp@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2014-07-03 17:14:13 +0000 |
commit | 0eac598eeed59ebebdeb0d44e93677fbb9cb9d5a (patch) | |
tree | 6c5033490339860687bd80a6f6a663784eddd654 /device/hid | |
parent | c9ab4198a25ff667f69acc6c9c8dad10c81bbe64 (diff) | |
download | chromium_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')
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_ |