summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--device/hid/hid_connection.cc112
-rw-r--r--device/hid/hid_connection.h70
-rw-r--r--device/hid/hid_connection_linux.cc127
-rw-r--r--device/hid/hid_connection_linux.h31
-rw-r--r--device/hid/hid_connection_mac.cc119
-rw-r--r--device/hid/hid_connection_mac.h35
-rw-r--r--device/hid/hid_connection_unittest.cc53
-rw-r--r--device/hid/hid_connection_win.cc221
-rw-r--r--device/hid/hid_connection_win.h40
-rw-r--r--extensions/browser/api/hid/hid_api.cc62
-rw-r--r--extensions/browser/api/hid/hid_api.h15
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_;