diff options
-rw-r--r-- | device/hid/hid_connection.cc | 112 | ||||
-rw-r--r-- | device/hid/hid_connection.h | 70 | ||||
-rw-r--r-- | device/hid/hid_connection_linux.cc | 127 | ||||
-rw-r--r-- | device/hid/hid_connection_linux.h | 31 | ||||
-rw-r--r-- | device/hid/hid_connection_mac.cc | 119 | ||||
-rw-r--r-- | device/hid/hid_connection_mac.h | 35 | ||||
-rw-r--r-- | device/hid/hid_connection_unittest.cc | 53 | ||||
-rw-r--r-- | device/hid/hid_connection_win.cc | 221 | ||||
-rw-r--r-- | device/hid/hid_connection_win.h | 40 | ||||
-rw-r--r-- | extensions/browser/api/hid/hid_api.cc | 62 | ||||
-rw-r--r-- | extensions/browser/api/hid/hid_api.h | 15 |
11 files changed, 438 insertions, 447 deletions
diff --git a/device/hid/hid_connection.cc b/device/hid/hid_connection.cc index c916d6a..5df2a01 100644 --- a/device/hid/hid_connection.cc +++ b/device/hid/hid_connection.cc @@ -12,8 +12,7 @@ namespace { // Functor used to filter collections by report ID. struct CollectionHasReportId { - explicit CollectionHasReportId(const uint8_t report_id) - : report_id_(report_id) {} + explicit CollectionHasReportId(uint8_t report_id) : report_id_(report_id) {} bool operator()(const HidCollectionInfo& info) const { if (info.report_ids.size() == 0 || @@ -40,7 +39,7 @@ struct CollectionIsProtected { }; bool FindCollectionByReportId(const HidDeviceInfo& device_info, - const uint8_t report_id, + uint8_t report_id, HidCollectionInfo* collection_info) { std::vector<HidCollectionInfo>::const_iterator collection_iter = std::find_if(device_info.collections.begin(), @@ -73,103 +72,104 @@ HidConnection::~HidConnection() { DCHECK(thread_checker_.CalledOnValidThread()); } -void HidConnection::Read(scoped_refptr<net::IOBufferWithSize> buffer, - const IOCallback& callback) { +void HidConnection::Read(const ReadCallback& 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 (device_info().has_report_id) { - expected_buffer_size++; - } - if (buffer->size() < expected_buffer_size) { - // Receive buffer is too small. - callback.Run(false, 0); + VLOG(1) << "This device does not support input reports."; + callback.Run(false, NULL, 0); return; } - PlatformRead(buffer, callback); + PlatformRead(callback); } -void HidConnection::Write(uint8_t report_id, - scoped_refptr<net::IOBufferWithSize> buffer, - const IOCallback& callback) { +void HidConnection::Write(scoped_refptr<net::IOBuffer> buffer, + size_t size, + const WriteCallback& callback) { DCHECK(thread_checker_.CalledOnValidThread()); if (device_info_.max_output_report_size == 0) { - // The device does not support output reports. - callback.Run(false, 0); + VLOG(1) << "This device does not support output reports."; + callback.Run(false); + return; + } + DCHECK_GE(size, 1u); + uint8_t report_id = buffer->data()[0]; + if (device_info().has_report_id != (report_id != 0)) { + VLOG(1) << "Invalid output report ID."; + callback.Run(false); return; } if (IsReportIdProtected(report_id)) { - callback.Run(false, 0); + VLOG(1) << "Attempt to set a protected output report."; + callback.Run(false); return; } - PlatformWrite(report_id, buffer, callback); + PlatformWrite(buffer, size, callback); } -void HidConnection::GetFeatureReport( - uint8_t report_id, - scoped_refptr<net::IOBufferWithSize> buffer, - const IOCallback& callback) { +void HidConnection::GetFeatureReport(uint8_t report_id, + const ReadCallback& callback) { DCHECK(thread_checker_.CalledOnValidThread()); if (device_info_.max_feature_report_size == 0) { - // The device does not support feature reports. - callback.Run(false, 0); + VLOG(1) << "This device does not support feature reports."; + callback.Run(false, NULL, 0); return; } - if (IsReportIdProtected(report_id)) { - callback.Run(false, 0); + if (device_info().has_report_id != (report_id != 0)) { + VLOG(1) << "Invalid feature report ID."; + callback.Run(false, NULL, 0); return; } - int expected_buffer_size = device_info_.max_feature_report_size; - if (device_info().has_report_id) { - expected_buffer_size++; - } - if (buffer->size() < expected_buffer_size) { - // Receive buffer is too small. - callback.Run(false, 0); + if (IsReportIdProtected(report_id)) { + VLOG(1) << "Attempt to get a protected feature report."; + callback.Run(false, NULL, 0); return; } - PlatformGetFeatureReport(report_id, buffer, callback); + PlatformGetFeatureReport(report_id, callback); } -void HidConnection::SendFeatureReport( - uint8_t report_id, - scoped_refptr<net::IOBufferWithSize> buffer, - const IOCallback& callback) { +void HidConnection::SendFeatureReport(scoped_refptr<net::IOBuffer> buffer, + size_t size, + const WriteCallback& callback) { DCHECK(thread_checker_.CalledOnValidThread()); if (device_info_.max_feature_report_size == 0) { - // The device does not support feature reports. - callback.Run(false, 0); + VLOG(1) << "This device does not support feature reports."; + callback.Run(false); + return; + } + DCHECK_GE(size, 1u); + uint8_t report_id = buffer->data()[0]; + if (device_info().has_report_id != (report_id != 0)) { + VLOG(1) << "Invalid feature report ID."; + callback.Run(false); return; } if (IsReportIdProtected(report_id)) { - callback.Run(false, 0); + VLOG(1) << "Attempt to set a protected feature report."; + callback.Run(false); return; } - PlatformSendFeatureReport(report_id, buffer, callback); + PlatformSendFeatureReport(buffer, size, callback); } -bool HidConnection::CompleteRead(scoped_refptr<net::IOBufferWithSize> buffer, - int bytes_read, - const IOCallback& callback) { - DCHECK_LE(bytes_read, buffer->size()); - - if (bytes_read == 0 || IsReportIdProtected(buffer->data()[0])) { +bool HidConnection::CompleteRead(scoped_refptr<net::IOBuffer> buffer, + size_t size, + const ReadCallback& callback) { + DCHECK_GE(size, 1u); + uint8_t report_id = buffer->data()[0]; + if (IsReportIdProtected(report_id)) { + VLOG(1) << "Filtered a protected input report."; return false; } - callback.Run(true, bytes_read); + callback.Run(true, buffer, size); return true; } -bool HidConnection::IsReportIdProtected(const uint8_t report_id) { +bool HidConnection::IsReportIdProtected(uint8_t report_id) { HidCollectionInfo collection_info; if (FindCollectionByReportId(device_info_, report_id, &collection_info)) { return collection_info.usage.IsProtected(); diff --git a/device/hid/hid_connection.h b/device/hid/hid_connection.h index 631db1b..9d2503c2 100644 --- a/device/hid/hid_connection.h +++ b/device/hid/hid_connection.h @@ -22,23 +22,33 @@ class HidConnection : public base::RefCountedThreadSafe<HidConnection> { kAnyReportId = 0xFF, }; - typedef base::Callback<void(bool success, size_t size)> IOCallback; + typedef base::Callback< + void(bool success, scoped_refptr<net::IOBuffer> buffer, size_t size)> + ReadCallback; + typedef base::Callback<void(bool success)> WriteCallback; const HidDeviceInfo& device_info() const { return device_info_; } bool has_protected_collection() const { return has_protected_collection_; } 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); + // The report ID (or 0 if report IDs are not supported by the device) is + // always returned in the first byte of the buffer. + void Read(const ReadCallback& callback); + + // The report ID (or 0 if report IDs are not supported by the device) is + // always expected in the first byte of the buffer. + void Write(scoped_refptr<net::IOBuffer> buffer, + size_t size, + const WriteCallback& callback); + + // The report ID is not returned in the buffer. + void GetFeatureReport(uint8_t report_id, const ReadCallback& callback); + + // The report ID (or 0 if report IDs are not supported by the device) is + // always expected in the first byte of the buffer. + void SendFeatureReport(scoped_refptr<net::IOBuffer> buffer, + size_t size, + const WriteCallback& callback); protected: friend class base::RefCountedThreadSafe<HidConnection>; @@ -46,31 +56,27 @@ class HidConnection : public base::RefCountedThreadSafe<HidConnection> { 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; + virtual void PlatformRead(const ReadCallback& callback) = 0; + virtual void PlatformWrite(scoped_refptr<net::IOBuffer> buffer, + size_t size, + const WriteCallback& callback) = 0; + virtual void PlatformGetFeatureReport(uint8_t report_id, + const ReadCallback& callback) = 0; + virtual void PlatformSendFeatureReport(scoped_refptr<net::IOBuffer> buffer, + size_t size, + const WriteCallback& 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, - int bytes_read, - const IOCallback& callback); + bool CompleteRead(scoped_refptr<net::IOBuffer> buffer, + size_t size, + const ReadCallback& callback); private: - bool IsReportIdProtected(const uint8_t report_id); + bool IsReportIdProtected(uint8_t report_id); const HidDeviceInfo device_info_; bool has_protected_collection_; @@ -83,15 +89,15 @@ struct PendingHidReport { PendingHidReport(); ~PendingHidReport(); - scoped_refptr<net::IOBufferWithSize> buffer; + scoped_refptr<net::IOBuffer> buffer; + size_t size; }; struct PendingHidRead { PendingHidRead(); ~PendingHidRead(); - scoped_refptr<net::IOBufferWithSize> buffer; - HidConnection::IOCallback callback; + HidConnection::ReadCallback callback; }; } // namespace device diff --git a/device/hid/hid_connection_linux.cc b/device/hid/hid_connection_linux.cc index 5d6dd24..ac2e554 100644 --- a/device/hid/hid_connection_linux.cc +++ b/device/hid/hid_connection_linux.cc @@ -29,21 +29,6 @@ namespace device { -namespace { - -// Copies a buffer into a new one with a report ID byte inserted at the front. -scoped_refptr<net::IOBufferWithSize> CopyBufferWithReportId( - scoped_refptr<net::IOBufferWithSize> buffer, - uint8_t report_id) { - scoped_refptr<net::IOBufferWithSize> new_buffer( - new net::IOBufferWithSize(buffer->size() + 1)); - new_buffer->data()[0] = report_id; - memcpy(new_buffer->data() + 1, buffer->data(), buffer->size()); - return new_buffer; -} - -} // namespace - HidConnectionLinux::HidConnectionLinux(HidDeviceInfo device_info, std::string dev_node) : HidConnection(device_info) { @@ -91,73 +76,67 @@ HidConnectionLinux::~HidConnectionLinux() { Flush(); } -void HidConnectionLinux::PlatformRead( - scoped_refptr<net::IOBufferWithSize> buffer, - const IOCallback& callback) { +void HidConnectionLinux::PlatformRead(const ReadCallback& callback) { PendingHidRead pending_read; - pending_read.buffer = buffer; pending_read.callback = callback; pending_reads_.push(pending_read); ProcessReadQueue(); } -void HidConnectionLinux::PlatformWrite( - uint8_t report_id, - scoped_refptr<net::IOBufferWithSize> buffer, - const IOCallback& callback) { - // Linux always expects the first byte of the buffer to be the report ID. - buffer = CopyBufferWithReportId(buffer, report_id); - const int bytes_written = HANDLE_EINTR( - write(device_file_.GetPlatformFile(), buffer->data(), buffer->size())); +void HidConnectionLinux::PlatformWrite(scoped_refptr<net::IOBuffer> buffer, + size_t size, + const WriteCallback& callback) { + // Linux expects the first byte of the buffer to always be a report ID so the + // buffer can be used directly. + const ssize_t bytes_written = + HANDLE_EINTR(write(device_file_.GetPlatformFile(), buffer->data(), size)); if (bytes_written < 0) { VPLOG(1) << "Write failed"; Disconnect(); - callback.Run(false, 0); + callback.Run(false); } else { - if (bytes_written != buffer->size()) { - LOG(WARNING) << "Incomplete HID write: " - << bytes_written << " != " << buffer->size(); + if (static_cast<size_t>(bytes_written) != size) { + LOG(WARNING) << "Incomplete HID write: " << bytes_written + << " != " << size; } - callback.Run(true, bytes_written == 0 ? 0 : bytes_written - 1); + callback.Run(true); } } void HidConnectionLinux::PlatformGetFeatureReport( uint8_t report_id, - scoped_refptr<net::IOBufferWithSize> buffer, - const IOCallback& callback) { - if (buffer->size() == 0) { - callback.Run(false, 0); - return; - } - - // The first byte of the destination buffer is the report ID being requested. + const ReadCallback& callback) { + // The first byte of the destination buffer is the report ID being requested + // and is overwritten by the feature report. + DCHECK_GT(device_info().max_feature_report_size, 0); + scoped_refptr<net::IOBufferWithSize> buffer( + new net::IOBufferWithSize(device_info().max_feature_report_size)); buffer->data()[0] = report_id; + int result = ioctl(device_file_.GetPlatformFile(), HIDIOCGFEATURE(buffer->size()), buffer->data()); if (result < 0) { VPLOG(1) << "Failed to get feature report"; - callback.Run(false, 0); + callback.Run(false, NULL, 0); } else { - callback.Run(true, result); + callback.Run(true, buffer, result); } } void HidConnectionLinux::PlatformSendFeatureReport( - uint8_t report_id, - scoped_refptr<net::IOBufferWithSize> buffer, - const IOCallback& callback) { - if (report_id != 0) - buffer = CopyBufferWithReportId(buffer, report_id); - int result = ioctl(device_file_.GetPlatformFile(), - HIDIOCSFEATURE(buffer->size()), - buffer->data()); + scoped_refptr<net::IOBuffer> buffer, + size_t size, + const WriteCallback& callback) { + // Linux expects the first byte of the buffer to always be a report ID so the + // buffer can be used directly. + int result = ioctl( + device_file_.GetPlatformFile(), HIDIOCSFEATURE(size), buffer->data()); if (result < 0) { VPLOG(1) << "Failed to send feature report"; - callback.Run(false, 0); + callback.Run(false); } else { - callback.Run(true, result); + callback.Run(true); } } @@ -165,9 +144,19 @@ 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)); + size_t expected_report_size = device_info().max_input_report_size + 1; + scoped_refptr<net::IOBuffer> buffer(new net::IOBuffer(expected_report_size)); + char* data = buffer->data(); + if (!device_info().has_report_id) { + // Linux will not prefix the buffer with a report ID if they are not used + // by the device. + data[0] = 0; + data++; + expected_report_size--; + } + + ssize_t bytes_read = HANDLE_EINTR( + read(device_file_.GetPlatformFile(), data, expected_report_size)); if (bytes_read < 0) { if (errno == EAGAIN) { return; @@ -176,12 +165,12 @@ void HidConnectionLinux::OnFileCanReadWithoutBlocking(int fd) { Disconnect(); return; } + if (!device_info().has_report_id) { + // Include the byte prepended earlier. + bytes_read++; + } - scoped_refptr<net::IOBufferWithSize> buffer = - new net::IOBufferWithSize(bytes_read); - memcpy(buffer->data(), raw_buffer, bytes_read); - - ProcessInputReport(buffer); + ProcessInputReport(buffer, bytes_read); } void HidConnectionLinux::OnFileCanWriteWithoutBlocking(int fd) { @@ -197,16 +186,17 @@ void HidConnectionLinux::Disconnect() { void HidConnectionLinux::Flush() { while (!pending_reads_.empty()) { - pending_reads_.front().callback.Run(false, 0); + pending_reads_.front().callback.Run(false, NULL, 0); pending_reads_.pop(); } } -void HidConnectionLinux::ProcessInputReport( - scoped_refptr<net::IOBufferWithSize> buffer) { +void HidConnectionLinux::ProcessInputReport(scoped_refptr<net::IOBuffer> buffer, + size_t size) { DCHECK(thread_checker().CalledOnValidThread()); PendingHidReport report; report.buffer = buffer; + report.size = size; pending_reports_.push(report); ProcessReadQueue(); } @@ -217,16 +207,9 @@ void HidConnectionLinux::ProcessReadQueue() { PendingHidRead read = pending_reads_.front(); PendingHidReport report = pending_reports_.front(); - if (read.buffer->size() < report.buffer->size()) { - read.callback.Run(false, 0); + pending_reports_.pop(); + if (CompleteRead(report.buffer, report.size, read.callback)) { pending_reads_.pop(); - } else { - memcpy(read.buffer->data(), report.buffer->data(), report.buffer->size()); - pending_reports_.pop(); - - if (CompleteRead(read.buffer, report.buffer->size(), read.callback)) { - pending_reads_.pop(); - } } } } diff --git a/device/hid/hid_connection_linux.h b/device/hid/hid_connection_linux.h index 1f5a7a8..1944a5b 100644 --- a/device/hid/hid_connection_linux.h +++ b/device/hid/hid_connection_linux.h @@ -18,33 +18,30 @@ class HidConnectionLinux : public HidConnection, public: HidConnectionLinux(HidDeviceInfo device_info, std::string dev_node); + private: + friend class base::RefCountedThreadSafe<HidConnectionLinux>; + virtual ~HidConnectionLinux(); + // 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 PlatformRead(const ReadCallback& callback) OVERRIDE; + virtual void PlatformWrite(scoped_refptr<net::IOBuffer> buffer, + size_t size, + const WriteCallback& callback) OVERRIDE; + virtual void PlatformGetFeatureReport(uint8_t report_id, + const ReadCallback& callback) OVERRIDE; virtual void PlatformSendFeatureReport( - uint8_t report_id, - scoped_refptr<net::IOBufferWithSize> buffer, - const IOCallback& callback) OVERRIDE; + scoped_refptr<net::IOBuffer> buffer, + size_t size, + const WriteCallback& callback) OVERRIDE; // base::MessagePumpLibevent::Watcher implementation. virtual void OnFileCanReadWithoutBlocking(int fd) OVERRIDE; virtual void OnFileCanWriteWithoutBlocking(int fd) OVERRIDE; - private: - friend class base::RefCountedThreadSafe<HidConnectionLinux>; - virtual ~HidConnectionLinux(); - void Disconnect(); void Flush(); - void ProcessInputReport(scoped_refptr<net::IOBufferWithSize> buffer); + void ProcessInputReport(scoped_refptr<net::IOBuffer> buffer, size_t size); void ProcessReadQueue(); base::File device_file_; diff --git a/device/hid/hid_connection_mac.cc b/device/hid/hid_connection_mac.cc index b357216..e06994c 100644 --- a/device/hid/hid_connection_mac.cc +++ b/device/hid/hid_connection_mac.cc @@ -21,7 +21,7 @@ HidConnectionMac::HidConnectionMac(HidDeviceInfo device_info) if (device_info.has_report_id) { expected_report_size++; } - inbound_buffer_.reset((uint8_t*)malloc(expected_report_size)); + inbound_buffer_.reset(new uint8_t[expected_report_size]); IOHIDDeviceRegisterInputReportCallback(device_.get(), inbound_buffer_.get(), expected_report_size, @@ -35,54 +35,52 @@ HidConnectionMac::~HidConnectionMac() { Flush(); } -void HidConnectionMac::PlatformRead(scoped_refptr<net::IOBufferWithSize> buffer, - const IOCallback& callback) { +void HidConnectionMac::PlatformRead(const ReadCallback& callback) { if (!device_) { - callback.Run(false, 0); + callback.Run(false, NULL, 0); return; } PendingHidRead pending_read; - pending_read.buffer = buffer; pending_read.callback = callback; pending_reads_.push(pending_read); ProcessReadQueue(); } -void HidConnectionMac::PlatformWrite( - uint8_t report_id, - scoped_refptr<net::IOBufferWithSize> buffer, - const IOCallback& callback) { - WriteReport(kIOHIDReportTypeOutput, report_id, buffer, callback); +void HidConnectionMac::PlatformWrite(scoped_refptr<net::IOBuffer> buffer, + size_t size, + const WriteCallback& callback) { + WriteReport(kIOHIDReportTypeOutput, buffer, size, callback); } -void HidConnectionMac::PlatformGetFeatureReport( - uint8_t report_id, - scoped_refptr<net::IOBufferWithSize> buffer, - const IOCallback& callback) { +void HidConnectionMac::PlatformGetFeatureReport(uint8_t report_id, + const ReadCallback& callback) { if (!device_) { - callback.Run(false, 0); + callback.Run(false, NULL, 0); return; } - uint8_t* feature_report_buffer = reinterpret_cast<uint8_t*>(buffer->data()); + scoped_refptr<net::IOBufferWithSize> buffer( + new net::IOBufferWithSize(device_info().max_feature_report_size)); CFIndex report_size = buffer->size(); - IOReturn result = IOHIDDeviceGetReport(device_, - kIOHIDReportTypeFeature, - report_id, - feature_report_buffer, - &report_size); - if (result == kIOReturnSuccess) - callback.Run(true, report_size); - else - callback.Run(false, 0); + IOReturn result = + IOHIDDeviceGetReport(device_, + kIOHIDReportTypeFeature, + report_id, + reinterpret_cast<uint8_t*>(buffer->data()), + &report_size); + if (result == kIOReturnSuccess) { + callback.Run(true, buffer, report_size); + } else { + callback.Run(false, NULL, 0); + } } void HidConnectionMac::PlatformSendFeatureReport( - uint8_t report_id, - scoped_refptr<net::IOBufferWithSize> buffer, - const IOCallback& callback) { - WriteReport(kIOHIDReportTypeFeature, report_id, buffer, callback); + scoped_refptr<net::IOBuffer> buffer, + size_t size, + const WriteCallback& callback) { + WriteReport(kIOHIDReportTypeFeature, buffer, size, callback); } void HidConnectionMac::InputReportCallback(void* context, @@ -93,10 +91,16 @@ void HidConnectionMac::InputReportCallback(void* context, uint8_t* report_bytes, CFIndex report_length) { HidConnectionMac* connection = static_cast<HidConnectionMac*>(context); - // report_id is already contained in report_bytes scoped_refptr<net::IOBufferWithSize> buffer; - buffer = new net::IOBufferWithSize(report_length); - memcpy(buffer->data(), report_bytes, report_length); + if (connection->device_info().has_report_id) { + // report_id is already contained in report_bytes + buffer = new net::IOBufferWithSize(report_length); + memcpy(buffer->data(), report_bytes, report_length); + } else { + buffer = new net::IOBufferWithSize(report_length + 1); + buffer->data()[0] = 0; + memcpy(buffer->data() + 1, report_bytes, report_length); + } connection->message_loop_->PostTask( FROM_HERE, @@ -104,39 +108,36 @@ void HidConnectionMac::InputReportCallback(void* context, } void HidConnectionMac::WriteReport(IOHIDReportType type, - uint8_t report_id, - scoped_refptr<net::IOBufferWithSize> buffer, - const IOCallback& callback) { + scoped_refptr<net::IOBuffer> buffer, + size_t size, + const WriteCallback& callback) { if (!device_) { - callback.Run(false, 0); + callback.Run(false); return; } - scoped_refptr<net::IOBufferWithSize> output_buffer; - if (report_id != 0) { - output_buffer = new net::IOBufferWithSize(buffer->size() + 1); - output_buffer->data()[0] = static_cast<uint8_t>(report_id); - memcpy(output_buffer->data() + 1, buffer->data(), buffer->size()); - } else { - output_buffer = new net::IOBufferWithSize(buffer->size()); - memcpy(output_buffer->data(), buffer->data(), buffer->size()); + uint8_t* data = reinterpret_cast<uint8_t*>(buffer->data()); + DCHECK(size >= 1); + uint8_t report_id = data[0]; + if (report_id == 0) { + // OS X only expects the first byte of the buffer to be the report ID if the + // report ID is non-zero. + ++data; + --size; } + IOReturn res = - IOHIDDeviceSetReport(device_.get(), - type, - report_id, - reinterpret_cast<uint8_t*>(output_buffer->data()), - output_buffer->size()); - if (res != kIOReturnSuccess) { - callback.Run(false, 0); + IOHIDDeviceSetReport(device_.get(), type, report_id, data, size); + if (res == kIOReturnSuccess) { + callback.Run(true); } else { - callback.Run(true, output_buffer->size()); + callback.Run(false); } } void HidConnectionMac::Flush() { while (!pending_reads_.empty()) { - pending_reads_.front().callback.Run(false, 0); + pending_reads_.front().callback.Run(false, NULL, 0); pending_reads_.pop(); } } @@ -146,6 +147,7 @@ void HidConnectionMac::ProcessInputReport( DCHECK(thread_checker().CalledOnValidThread()); PendingHidReport report; report.buffer = buffer; + report.size = buffer->size(); pending_reports_.push(report); ProcessReadQueue(); } @@ -156,16 +158,9 @@ void HidConnectionMac::ProcessReadQueue() { PendingHidRead read = pending_reads_.front(); PendingHidReport report = pending_reports_.front(); - if (read.buffer->size() < report.buffer->size()) { - read.callback.Run(false, 0); + pending_reports_.pop(); + if (CompleteRead(report.buffer, report.size, read.callback)) { pending_reads_.pop(); - } else { - memcpy(read.buffer->data(), report.buffer->data(), report.buffer->size()); - pending_reports_.pop(); - - if (CompleteRead(read.buffer, report.buffer->size(), read.callback)) { - pending_reads_.pop(); - } } } } diff --git a/device/hid/hid_connection_mac.h b/device/hid/hid_connection_mac.h index 02dde04..81153b6 100644 --- a/device/hid/hid_connection_mac.h +++ b/device/hid/hid_connection_mac.h @@ -28,24 +28,21 @@ 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; - private: virtual ~HidConnectionMac(); + // HidConnection implementation. + virtual void PlatformRead(const ReadCallback& callback) OVERRIDE; + virtual void PlatformWrite(scoped_refptr<net::IOBuffer> buffer, + size_t size, + const WriteCallback& callback) OVERRIDE; + virtual void PlatformGetFeatureReport(uint8_t report_id, + const ReadCallback& callback) OVERRIDE; + virtual void PlatformSendFeatureReport( + scoped_refptr<net::IOBuffer> buffer, + size_t size, + const WriteCallback& callback) OVERRIDE; + static void InputReportCallback(void* context, IOReturn result, void* sender, @@ -55,9 +52,9 @@ class HidConnectionMac : public HidConnection { CFIndex report_length); void WriteReport(IOHIDReportType type, - uint8_t report_id, - scoped_refptr<net::IOBufferWithSize> buffer, - const IOCallback& callback); + scoped_refptr<net::IOBuffer> buffer, + size_t size, + const WriteCallback& callback); void Flush(); void ProcessInputReport(scoped_refptr<net::IOBufferWithSize> buffer); @@ -65,7 +62,7 @@ class HidConnectionMac : public HidConnection { base::ScopedCFTypeRef<IOHIDDeviceRef> device_; scoped_refptr<base::MessageLoopProxy> message_loop_; - scoped_ptr<uint8_t, base::FreeDeleter> inbound_buffer_; + scoped_ptr<uint8_t[]> inbound_buffer_; std::queue<PendingHidReport> pending_reports_; std::queue<PendingHidRead> pending_reads_; diff --git a/device/hid/hid_connection_unittest.cc b/device/hid/hid_connection_unittest.cc index eb973f7..e5f215f 100644 --- a/device/hid/hid_connection_unittest.cc +++ b/device/hid/hid_connection_unittest.cc @@ -24,12 +24,23 @@ using net::IOBufferWithSize; class TestCompletionCallback { public: TestCompletionCallback() - : callback_(base::Bind(&TestCompletionCallback::SetResult, - base::Unretained(this))) {} + : read_callback_(base::Bind(&TestCompletionCallback::SetReadResult, + base::Unretained(this))), + write_callback_(base::Bind(&TestCompletionCallback::SetWriteResult, + base::Unretained(this))) {} + ~TestCompletionCallback() {} + + void SetReadResult(bool success, + scoped_refptr<net::IOBuffer> buffer, + size_t size) { + result_ = success; + buffer_ = buffer; + size_ = size; + run_loop_.Quit(); + } - void SetResult(bool success, size_t size) { + void SetWriteResult(bool success) { result_ = success; - transferred_ = size; run_loop_.Quit(); } @@ -38,14 +49,20 @@ class TestCompletionCallback { return result_; } - const HidConnection::IOCallback& callback() const { return callback_; } - size_t transferred() const { return transferred_; } + const HidConnection::ReadCallback& read_callback() { return read_callback_; } + const HidConnection::WriteCallback write_callback() { + return write_callback_; + } + scoped_refptr<net::IOBuffer> buffer() const { return buffer_; } + size_t size() const { return size_; } private: - const HidConnection::IOCallback callback_; base::RunLoop run_loop_; bool result_; - size_t transferred_; + size_t size_; + scoped_refptr<net::IOBuffer> buffer_; + HidConnection::ReadCallback read_callback_; + HidConnection::WriteCallback write_callback_; }; } // namespace @@ -113,20 +130,24 @@ TEST_F(HidConnectionTest, ReadWrite) { ASSERT_TRUE(conn); for (int i = 0; i < 8; ++i) { - scoped_refptr<IOBufferWithSize> write_buffer(new IOBufferWithSize(8)); - *(int64_t*)write_buffer->data() = i; + scoped_refptr<IOBufferWithSize> buffer(new IOBufferWithSize(9)); + buffer->data()[0] = 0; + for (int j = 1; j < buffer->size(); ++j) { + buffer->data()[j] = i + j - 1; + } TestCompletionCallback write_callback; - conn->Write(0, write_buffer, write_callback.callback()); + conn->Write(buffer, buffer->size(), write_callback.write_callback()); ASSERT_TRUE(write_callback.WaitForResult()); - ASSERT_EQ(8UL, write_callback.transferred()); - scoped_refptr<IOBufferWithSize> read_buffer(new IOBufferWithSize(8)); TestCompletionCallback read_callback; - conn->Read(read_buffer, read_callback.callback()); + conn->Read(read_callback.read_callback()); ASSERT_TRUE(read_callback.WaitForResult()); - ASSERT_EQ(8UL, read_callback.transferred()); - ASSERT_EQ(i, *(int64_t*)read_buffer->data()); + ASSERT_EQ(9UL, read_callback.size()); + ASSERT_EQ(0, read_callback.buffer()->data()[0]); + for (int j = 1; j < buffer->size(); ++j) { + ASSERT_EQ(i + j - 1, read_callback.buffer()->data()[j]); + } } } diff --git a/device/hid/hid_connection_win.cc b/device/hid/hid_connection_win.cc index dfebcba..8e00ae0 100644 --- a/device/hid/hid_connection_win.cc +++ b/device/hid/hid_connection_win.cc @@ -6,6 +6,7 @@ #include <cstring> +#include "base/bind.h" #include "base/files/file.h" #include "base/message_loop/message_loop.h" #include "base/win/object_watcher.h" @@ -27,10 +28,10 @@ namespace device { struct PendingHidTransfer : public base::RefCounted<PendingHidTransfer>, public base::win::ObjectWatcher::Delegate, public base::MessageLoop::DestructionObserver { - PendingHidTransfer(scoped_refptr<HidConnectionWin> connection, - scoped_refptr<net::IOBufferWithSize> target_buffer, - scoped_refptr<net::IOBufferWithSize> receive_buffer, - HidConnection::IOCallback callback); + typedef base::Callback<void(PendingHidTransfer*, bool)> Callback; + + PendingHidTransfer(scoped_refptr<net::IOBuffer> buffer, + const Callback& callback); void TakeResultFromWindowsAPI(BOOL result); @@ -42,10 +43,10 @@ struct PendingHidTransfer : public base::RefCounted<PendingHidTransfer>, // Implements base::MessageLoop::DestructionObserver virtual void WillDestroyCurrentMessageLoop() OVERRIDE; - scoped_refptr<HidConnectionWin> connection_; - scoped_refptr<net::IOBufferWithSize> target_buffer_; - scoped_refptr<net::IOBufferWithSize> receive_buffer_; - HidConnection::IOCallback callback_; + // The buffer isn't used by this object but it's important that a reference + // to it is held until the transfer completes. + scoped_refptr<net::IOBuffer> buffer_; + Callback callback_; OVERLAPPED overlapped_; base::win::ScopedHandle event_; base::win::ObjectWatcher watcher_; @@ -59,13 +60,9 @@ struct PendingHidTransfer : public base::RefCounted<PendingHidTransfer>, }; PendingHidTransfer::PendingHidTransfer( - scoped_refptr<HidConnectionWin> connection, - scoped_refptr<net::IOBufferWithSize> target_buffer, - scoped_refptr<net::IOBufferWithSize> receive_buffer, - HidConnection::IOCallback callback) - : connection_(connection), - target_buffer_(target_buffer), - receive_buffer_(receive_buffer), + scoped_refptr<net::IOBuffer> buffer, + const PendingHidTransfer::Callback& callback) + : buffer_(buffer), callback_(callback), event_(CreateEvent(NULL, FALSE, FALSE, NULL)) { memset(&overlapped_, 0, sizeof(OVERLAPPED)); @@ -77,23 +74,26 @@ PendingHidTransfer::~PendingHidTransfer() { } void PendingHidTransfer::TakeResultFromWindowsAPI(BOOL result) { - if (result || GetLastError() != ERROR_IO_PENDING) { - connection_->OnTransferFinished(this); - } else { + if (result) { + callback_.Run(this, true); + } else if (GetLastError() == ERROR_IO_PENDING) { base::MessageLoop::current()->AddDestructionObserver(this); AddRef(); watcher_.StartWatching(event_.Get(), this); + } else { + VPLOG(1) << "HID transfer failed"; + callback_.Run(this, false); } } void PendingHidTransfer::OnObjectSignaled(HANDLE event_handle) { - connection_->OnTransferFinished(this); + callback_.Run(this, true); Release(); } void PendingHidTransfer::WillDestroyCurrentMessageLoop() { watcher_.StopWatching(); - connection_->OnTransferCanceled(this); + callback_.Run(this, false); } HidConnectionWin::HidConnectionWin(const HidDeviceInfo& device_info) @@ -122,146 +122,139 @@ HidConnectionWin::~HidConnectionWin() { CancelIo(file_.Get()); } -void HidConnectionWin::PlatformRead(scoped_refptr<net::IOBufferWithSize> buffer, - const HidConnection::IOCallback& callback) { +void HidConnectionWin::PlatformRead( + const HidConnection::ReadCallback& callback) { // Windows will always include the report ID (including zero if report IDs // are not in use) in the buffer. - scoped_refptr<net::IOBufferWithSize> receive_buffer = + scoped_refptr<net::IOBufferWithSize> buffer = new net::IOBufferWithSize(device_info().max_input_report_size + 1); - - scoped_refptr<PendingHidTransfer> transfer( - new PendingHidTransfer(this, buffer, receive_buffer, callback)); + scoped_refptr<PendingHidTransfer> transfer(new PendingHidTransfer( + buffer, + base::Bind(&HidConnectionWin::OnReadComplete, this, buffer, callback))); transfers_.insert(transfer); transfer->TakeResultFromWindowsAPI( ReadFile(file_.Get(), - receive_buffer->data(), - static_cast<DWORD>(receive_buffer->size()), + buffer->data(), + static_cast<DWORD>(buffer->size()), NULL, transfer->GetOverlapped())); } -void HidConnectionWin::PlatformWrite( - uint8_t report_id, - scoped_refptr<net::IOBufferWithSize> buffer, - const HidConnection::IOCallback& callback) { +void HidConnectionWin::PlatformWrite(scoped_refptr<net::IOBuffer> buffer, + size_t size, + const WriteCallback& callback) { // The Windows API always wants either a report ID (if supported) or // zero at the front of every output report. - scoped_refptr<net::IOBufferWithSize> output_buffer( - new net::IOBufferWithSize(buffer->size() + 1)); - output_buffer->data()[0] = report_id; - memcpy(output_buffer->data() + 1, buffer->data(), buffer->size()); - - scoped_refptr<PendingHidTransfer> transfer( - new PendingHidTransfer(this, output_buffer, NULL, callback)); + scoped_refptr<PendingHidTransfer> transfer(new PendingHidTransfer( + buffer, base::Bind(&HidConnectionWin::OnWriteComplete, this, callback))); transfers_.insert(transfer); - transfer->TakeResultFromWindowsAPI( - WriteFile(file_.Get(), - output_buffer->data(), - static_cast<DWORD>(output_buffer->size()), - NULL, - transfer->GetOverlapped())); + transfer->TakeResultFromWindowsAPI(WriteFile(file_.Get(), + buffer->data(), + static_cast<DWORD>(size), + NULL, + transfer->GetOverlapped())); } -void HidConnectionWin::PlatformGetFeatureReport( - uint8_t report_id, - scoped_refptr<net::IOBufferWithSize> buffer, - const IOCallback& callback) { - int expected_report_size = device_info().max_feature_report_size; - if (device_info().has_report_id) { - expected_report_size++; - } - scoped_refptr<net::IOBufferWithSize> receive_buffer = - new net::IOBufferWithSize(expected_report_size); +void HidConnectionWin::PlatformGetFeatureReport(uint8_t report_id, + const ReadCallback& callback) { // 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)); + scoped_refptr<net::IOBufferWithSize> buffer = + new net::IOBufferWithSize(device_info().max_feature_report_size + 1); + buffer->data()[0] = report_id; + + scoped_refptr<PendingHidTransfer> transfer(new PendingHidTransfer( + buffer, + base::Bind( + &HidConnectionWin::OnReadFeatureComplete, this, buffer, callback))); transfers_.insert(transfer); transfer->TakeResultFromWindowsAPI( DeviceIoControl(file_.Get(), IOCTL_HID_GET_FEATURE, NULL, 0, - receive_buffer->data(), - static_cast<DWORD>(receive_buffer->size()), + buffer->data(), + static_cast<DWORD>(buffer->size()), NULL, transfer->GetOverlapped())); } void HidConnectionWin::PlatformSendFeatureReport( - uint8_t report_id, - scoped_refptr<net::IOBufferWithSize> buffer, - const IOCallback& callback) { + scoped_refptr<net::IOBuffer> buffer, + size_t size, + const WriteCallback& callback) { // The Windows API always wants either a report ID (if supported) or // zero at the front of every output report. - scoped_refptr<net::IOBufferWithSize> output_buffer(buffer); - output_buffer = new net::IOBufferWithSize(buffer->size() + 1); - output_buffer->data()[0] = report_id; - memcpy(output_buffer->data() + 1, buffer->data(), buffer->size()); - - scoped_refptr<PendingHidTransfer> transfer( - new PendingHidTransfer(this, output_buffer, NULL, callback)); + scoped_refptr<PendingHidTransfer> transfer(new PendingHidTransfer( + buffer, base::Bind(&HidConnectionWin::OnWriteComplete, this, callback))); transfer->TakeResultFromWindowsAPI( DeviceIoControl(file_.Get(), IOCTL_HID_SET_FEATURE, - output_buffer->data(), - static_cast<DWORD>(output_buffer->size()), + buffer->data(), + static_cast<DWORD>(size), NULL, 0, NULL, transfer->GetOverlapped())); } -void HidConnectionWin::OnTransferFinished( - scoped_refptr<PendingHidTransfer> transfer) { - transfers_.erase(transfer); +void HidConnectionWin::OnReadComplete(scoped_refptr<net::IOBuffer> buffer, + const ReadCallback& callback, + PendingHidTransfer* transfer, + bool signaled) { + if (!signaled) { + callback.Run(false, NULL, 0); + return; + } DWORD bytes_transferred; if (GetOverlappedResult( file_, transfer->GetOverlapped(), &bytes_transferred, FALSE)) { - if (bytes_transferred == 0) { - transfer->callback_.Run(true, 0); - return; - } - - 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 (!device_info().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_, bytes_transferred, transfer->callback_); + CompleteRead(buffer, bytes_transferred, callback); } else { - VPLOG(1) << "HID transfer failed"; - transfer->callback_.Run(false, 0); + VPLOG(1) << "HID read failed"; + callback.Run(false, NULL, 0); + } +} + +void HidConnectionWin::OnReadFeatureComplete( + scoped_refptr<net::IOBuffer> buffer, + const ReadCallback& callback, + PendingHidTransfer* transfer, + bool signaled) { + if (!signaled) { + callback.Run(false, NULL, 0); + return; + } + + DWORD bytes_transferred; + if (GetOverlappedResult( + file_, transfer->GetOverlapped(), &bytes_transferred, FALSE)) { + scoped_refptr<net::IOBuffer> new_buffer( + new net::IOBuffer(bytes_transferred - 1)); + memcpy(new_buffer->data(), buffer->data() + 1, bytes_transferred - 1); + CompleteRead(new_buffer, bytes_transferred, callback); + } else { + VPLOG(1) << "HID read failed"; + callback.Run(false, NULL, 0); } } -void HidConnectionWin::OnTransferCanceled( - scoped_refptr<PendingHidTransfer> transfer) { - transfers_.erase(transfer); - transfer->callback_.Run(false, 0); +void HidConnectionWin::OnWriteComplete(const WriteCallback& callback, + PendingHidTransfer* transfer, + bool signaled) { + if (!signaled) { + callback.Run(false); + return; + } + + DWORD bytes_transferred; + if (GetOverlappedResult( + file_, transfer->GetOverlapped(), &bytes_transferred, FALSE)) { + callback.Run(true); + } else { + VPLOG(1) << "HID write failed"; + callback.Run(false); + } } } // namespace device diff --git a/device/hid/hid_connection_win.h b/device/hid/hid_connection_win.h index 6706044..14548f0 100644 --- a/device/hid/hid_connection_win.h +++ b/device/hid/hid_connection_win.h @@ -20,31 +20,37 @@ 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; - private: friend class HidServiceWin; friend struct PendingHidTransfer; ~HidConnectionWin(); + // HidConnection implementation. + virtual void PlatformRead(const ReadCallback& callback) OVERRIDE; + virtual void PlatformWrite(scoped_refptr<net::IOBuffer> buffer, + size_t size, + const WriteCallback& callback) OVERRIDE; + virtual void PlatformGetFeatureReport(uint8_t report_id, + const ReadCallback& callback) OVERRIDE; + virtual void PlatformSendFeatureReport( + scoped_refptr<net::IOBuffer> buffer, + size_t size, + const WriteCallback& callback) OVERRIDE; + bool available() const { return file_.IsValid(); } - void OnTransferFinished(scoped_refptr<PendingHidTransfer> transfer); - void OnTransferCanceled(scoped_refptr<PendingHidTransfer> transfer); + void OnReadComplete(scoped_refptr<net::IOBuffer> buffer, + const ReadCallback& callback, + PendingHidTransfer* transfer, + bool signaled); + void OnReadFeatureComplete(scoped_refptr<net::IOBuffer> buffer, + const ReadCallback& callback, + PendingHidTransfer* transfer, + bool signaled); + void OnWriteComplete(const WriteCallback& callback, + PendingHidTransfer* transfer, + bool signaled); base::win::ScopedHandle file_; diff --git a/extensions/browser/api/hid/hid_api.cc b/extensions/browser/api/hid/hid_api.cc index 208af12..e710af0 100644 --- a/extensions/browser/api/hid/hid_api.cc +++ b/extensions/browser/api/hid/hid_api.cc @@ -183,36 +183,24 @@ void HidReceiveFunction::AsyncWorkStart() { } scoped_refptr<device::HidConnection> connection = resource->connection(); - has_report_id_ = connection->device_info().has_report_id; - int size = connection->device_info().max_input_report_size; - if (has_report_id_) { - ++size; // One byte at the beginning of the buffer for the report ID. - } - buffer_ = new net::IOBufferWithSize(size); - connection->Read(buffer_, base::Bind(&HidReceiveFunction::OnFinished, this)); + connection->Read(base::Bind(&HidReceiveFunction::OnFinished, this)); } -void HidReceiveFunction::OnFinished(bool success, size_t bytes) { +void HidReceiveFunction::OnFinished(bool success, + scoped_refptr<net::IOBuffer> buffer, + size_t size) { if (!success) { CompleteWithError(kErrorTransfer); return; } - int report_id = 0; - const char* data = buffer_->data(); - if (has_report_id_) { - if (bytes < 1) { - CompleteWithError(kErrorTransfer); - return; - } - report_id = data[0]; - data++; - bytes--; - } + DCHECK_GE(size, 1u); + int report_id = reinterpret_cast<uint8_t*>(buffer->data())[0]; scoped_ptr<base::ListValue> result(new base::ListValue()); result->Append(new base::FundamentalValue(report_id)); - result->Append(base::BinaryValue::CreateWithCopiedBuffer(data, bytes)); + result->Append( + base::BinaryValue::CreateWithCopiedBuffer(buffer->data() + 1, size - 1)); SetResultList(result.Pass()); AsyncWorkCompleted(); } @@ -237,14 +225,15 @@ void HidSendFunction::AsyncWorkStart() { } scoped_refptr<net::IOBufferWithSize> buffer( - new net::IOBufferWithSize(parameters_->data.size())); - memcpy(buffer->data(), parameters_->data.c_str(), parameters_->data.size()); - resource->connection()->Write(static_cast<uint8_t>(parameters_->report_id), - buffer, - base::Bind(&HidSendFunction::OnFinished, this)); + new net::IOBufferWithSize(parameters_->data.size() + 1)); + buffer->data()[0] = static_cast<uint8_t>(parameters_->report_id); + memcpy( + buffer->data() + 1, parameters_->data.c_str(), parameters_->data.size()); + resource->connection()->Write( + buffer, buffer->size(), base::Bind(&HidSendFunction::OnFinished, this)); } -void HidSendFunction::OnFinished(bool success, size_t bytes) { +void HidSendFunction::OnFinished(bool success) { if (!success) { CompleteWithError(kErrorTransfer); return; @@ -272,21 +261,21 @@ void HidReceiveFeatureReportFunction::AsyncWorkStart() { } scoped_refptr<device::HidConnection> connection = resource->connection(); - const int size = connection->device_info().max_feature_report_size; - buffer_ = new net::IOBufferWithSize(size); connection->GetFeatureReport( static_cast<uint8_t>(parameters_->report_id), - buffer_, base::Bind(&HidReceiveFeatureReportFunction::OnFinished, this)); } -void HidReceiveFeatureReportFunction::OnFinished(bool success, size_t bytes) { +void HidReceiveFeatureReportFunction::OnFinished( + bool success, + scoped_refptr<net::IOBuffer> buffer, + size_t size) { if (!success) { CompleteWithError(kErrorTransfer); return; } - SetResult(base::BinaryValue::CreateWithCopiedBuffer(buffer_->data(), bytes)); + SetResult(base::BinaryValue::CreateWithCopiedBuffer(buffer->data(), size)); AsyncWorkCompleted(); } @@ -308,16 +297,19 @@ void HidSendFeatureReportFunction::AsyncWorkStart() { CompleteWithError(kErrorConnectionNotFound); return; } + scoped_refptr<net::IOBufferWithSize> buffer( - new net::IOBufferWithSize(parameters_->data.size())); - memcpy(buffer->data(), parameters_->data.c_str(), parameters_->data.size()); + new net::IOBufferWithSize(parameters_->data.size() + 1)); + buffer->data()[0] = static_cast<uint8_t>(parameters_->report_id); + memcpy( + buffer->data() + 1, parameters_->data.c_str(), parameters_->data.size()); resource->connection()->SendFeatureReport( - static_cast<uint8_t>(parameters_->report_id), buffer, + buffer->size(), base::Bind(&HidSendFeatureReportFunction::OnFinished, this)); } -void HidSendFeatureReportFunction::OnFinished(bool success, size_t bytes) { +void HidSendFeatureReportFunction::OnFinished(bool success) { if (!success) { CompleteWithError(kErrorTransfer); return; diff --git a/extensions/browser/api/hid/hid_api.h b/extensions/browser/api/hid/hid_api.h index 6a8808f..7683a63 100644 --- a/extensions/browser/api/hid/hid_api.h +++ b/extensions/browser/api/hid/hid_api.h @@ -112,10 +112,10 @@ class HidReceiveFunction : public HidAsyncApiFunction { private: virtual ~HidReceiveFunction(); - void OnFinished(bool success, size_t bytes); + void OnFinished(bool success, + scoped_refptr<net::IOBuffer> buffer, + size_t size); - bool has_report_id_; - scoped_refptr<net::IOBufferWithSize> buffer_; scoped_ptr<core_api::hid::Receive::Params> parameters_; DISALLOW_COPY_AND_ASSIGN(HidReceiveFunction); @@ -134,7 +134,7 @@ class HidSendFunction : public HidAsyncApiFunction { private: virtual ~HidSendFunction(); - void OnFinished(bool success, size_t bytes); + void OnFinished(bool success); scoped_ptr<core_api::hid::Send::Params> parameters_; @@ -155,9 +155,10 @@ class HidReceiveFeatureReportFunction : public HidAsyncApiFunction { private: virtual ~HidReceiveFeatureReportFunction(); - void OnFinished(bool success, size_t bytes); + void OnFinished(bool success, + scoped_refptr<net::IOBuffer> buffer, + size_t size); - scoped_refptr<net::IOBufferWithSize> buffer_; scoped_ptr<core_api::hid::ReceiveFeatureReport::Params> parameters_; DISALLOW_COPY_AND_ASSIGN(HidReceiveFeatureReportFunction); @@ -176,7 +177,7 @@ class HidSendFeatureReportFunction : public HidAsyncApiFunction { private: virtual ~HidSendFeatureReportFunction(); - void OnFinished(bool success, size_t bytes); + void OnFinished(bool success); scoped_ptr<core_api::hid::SendFeatureReport::Params> parameters_; |