| OLD | NEW | 
|---|
|  | (Empty) | 
| 1 // Copyright 2014 The Chromium Authors. All rights reserved. |  | 
| 2 // Use of this source code is governed by a BSD-style license that can be |  | 
| 3 // found in the LICENSE file. |  | 
| 4 |  | 
| 5 #include "device/hid/hid_connection_mac.h" |  | 
| 6 |  | 
| 7 #include "base/bind.h" |  | 
| 8 #include "base/callback.h" |  | 
| 9 #include "base/mac/foundation_util.h" |  | 
| 10 #include "base/threading/thread_restrictions.h" |  | 
| 11 #include "base/tuple.h" |  | 
| 12 #include "device/hid/hid_service.h" |  | 
| 13 #include "device/hid/hid_service_mac.h" |  | 
| 14 #include "net/base/io_buffer.h" |  | 
| 15 |  | 
| 16 #include <CoreFoundation/CoreFoundation.h> |  | 
| 17 #include <IOKit/hid/IOHIDManager.h> |  | 
| 18 |  | 
| 19 namespace device { |  | 
| 20 |  | 
| 21 HidConnectionMac::HidConnectionMac(HidServiceMac* service, |  | 
| 22                                    HidDeviceInfo device_info, |  | 
| 23                                    IOHIDDeviceRef device) |  | 
| 24     : HidConnection(device_info), |  | 
| 25       service_(service), |  | 
| 26       device_(device), |  | 
| 27       disconnected_(false) { |  | 
| 28   DCHECK(thread_checker_.CalledOnValidThread()); |  | 
| 29 |  | 
| 30   message_loop_ = base::MessageLoopProxy::current(); |  | 
| 31 |  | 
| 32   CFRetain(device); |  | 
| 33   inbound_buffer_.reset((uint8_t*) malloc(device_info.input_report_size + 1)); |  | 
| 34   IOHIDDeviceRegisterInputReportCallback( |  | 
| 35       device_.get(), |  | 
| 36       inbound_buffer_.get(), |  | 
| 37       device_info.input_report_size + 1, |  | 
| 38       &HidConnectionMac::InputReportCallback, |  | 
| 39       this); |  | 
| 40   IOHIDDeviceOpen(device_, kIOHIDOptionsTypeNone); |  | 
| 41 } |  | 
| 42 HidConnectionMac::~HidConnectionMac() { |  | 
| 43   DCHECK(thread_checker_.CalledOnValidThread()); |  | 
| 44 |  | 
| 45   while (read_queue_.size()) { |  | 
| 46     read_queue_.front().c.Run(false, 0); |  | 
| 47     read_queue_.pop(); |  | 
| 48   } |  | 
| 49 |  | 
| 50   IOHIDDeviceClose(device_, kIOHIDOptionsTypeNone); |  | 
| 51 } |  | 
| 52 |  | 
| 53 void HidConnectionMac::InputReportCallback(void * context, |  | 
| 54                                            IOReturn result, |  | 
| 55                                            void * sender, |  | 
| 56                                            IOHIDReportType type, |  | 
| 57                                            uint32_t reportID, |  | 
| 58                                            uint8_t * report, |  | 
| 59                                            CFIndex reportLength) { |  | 
| 60   HidConnectionMac* connection = reinterpret_cast<HidConnectionMac*>(context); |  | 
| 61   size_t length = reportLength + (reportID != 0); |  | 
| 62   scoped_refptr<net::IOBuffer> buffer(new net::IOBuffer(length)); |  | 
| 63   if (reportID) { |  | 
| 64     buffer->data()[0] = reportID; |  | 
| 65     memcpy(buffer->data() + 1, report, reportLength); |  | 
| 66   } else { |  | 
| 67     memcpy(buffer->data(), report, reportLength); |  | 
| 68   } |  | 
| 69   connection->message_loop_->PostTask( |  | 
| 70       FROM_HERE, |  | 
| 71       base::Bind(&HidConnectionMac::ProcessInputReport, |  | 
| 72                  connection, |  | 
| 73                  type, |  | 
| 74                  buffer, |  | 
| 75                  length)); |  | 
| 76 } |  | 
| 77 |  | 
| 78 void HidConnectionMac::ProcessReadQueue() { |  | 
| 79   DCHECK(thread_checker_.CalledOnValidThread()); |  | 
| 80 |  | 
| 81   while(read_queue_.size() && input_reports_.size()) { |  | 
| 82     PendingRead read = read_queue_.front(); |  | 
| 83     read_queue_.pop(); |  | 
| 84     PendingReport report = input_reports_.front(); |  | 
| 85 |  | 
| 86     if (read.b < report.second) { |  | 
| 87       read.c.Run(false, report.second); |  | 
| 88     } else { |  | 
| 89       memcpy(read.a->data(), report.first->data(), report.second); |  | 
| 90       input_reports_.pop(); |  | 
| 91       read.c.Run(true, report.second); |  | 
| 92     } |  | 
| 93   } |  | 
| 94 } |  | 
| 95 |  | 
| 96 void HidConnectionMac::ProcessInputReport(IOHIDReportType type, |  | 
| 97                                           scoped_refptr<net::IOBuffer> report, |  | 
| 98                                           CFIndex reportLength) { |  | 
| 99   DCHECK(thread_checker_.CalledOnValidThread()); |  | 
| 100 |  | 
| 101   input_reports_.push(std::make_pair(report, reportLength)); |  | 
| 102   ProcessReadQueue(); |  | 
| 103 } |  | 
| 104 |  | 
| 105 void HidConnectionMac::WriteReport(IOHIDReportType type, |  | 
| 106                                    scoped_refptr<net::IOBuffer> buffer, |  | 
| 107                                    size_t size, |  | 
| 108                                    const IOCallback& callback) { |  | 
| 109   DCHECK(thread_checker_.CalledOnValidThread()); |  | 
| 110   if (disconnected_ || !device_) { |  | 
| 111     callback.Run(false, 0); |  | 
| 112     return; |  | 
| 113   } |  | 
| 114   const unsigned char* data_to_send = |  | 
| 115       reinterpret_cast<const unsigned char*>(buffer->data()); |  | 
| 116   size_t length_to_send = size; |  | 
| 117   if (data_to_send[0] == 0x0) { |  | 
| 118       /* Not using numbered Reports. |  | 
| 119        Don't send the report number. */ |  | 
| 120       ++data_to_send; |  | 
| 121       --length_to_send; |  | 
| 122   } |  | 
| 123   IOReturn res = IOHIDDeviceSetReport(device_.get(), |  | 
| 124                                       type, |  | 
| 125                                       buffer->data()[0], /* Report ID*/ |  | 
| 126                                       data_to_send, |  | 
| 127                                       length_to_send); |  | 
| 128   if (res != kIOReturnSuccess) { |  | 
| 129     callback.Run(false, 0); |  | 
| 130   } else { |  | 
| 131     callback.Run(true, size); |  | 
| 132   } |  | 
| 133 } |  | 
| 134 |  | 
| 135 void HidConnectionMac::Read(scoped_refptr<net::IOBuffer> buffer, |  | 
| 136                             size_t size, |  | 
| 137                             const IOCallback& callback) { |  | 
| 138   DCHECK(thread_checker_.CalledOnValidThread()); |  | 
| 139   if (disconnected_ || !device_) { |  | 
| 140     callback.Run(false, 0); |  | 
| 141     return; |  | 
| 142   } |  | 
| 143   read_queue_.push(MakeTuple(buffer, size, callback)); |  | 
| 144   ProcessReadQueue(); |  | 
| 145 } |  | 
| 146 |  | 
| 147 void HidConnectionMac::Write(scoped_refptr<net::IOBuffer> buffer, |  | 
| 148                              size_t size, |  | 
| 149                              const IOCallback& callback) { |  | 
| 150   DCHECK(thread_checker_.CalledOnValidThread()); |  | 
| 151   WriteReport(kIOHIDReportTypeOutput, buffer, size, callback); |  | 
| 152 } |  | 
| 153 |  | 
| 154 void HidConnectionMac::SendFeatureReport(scoped_refptr<net::IOBuffer> buffer, |  | 
| 155                                          size_t size, |  | 
| 156                                          const IOCallback& callback) { |  | 
| 157   DCHECK(thread_checker_.CalledOnValidThread()); |  | 
| 158   WriteReport(kIOHIDReportTypeFeature, buffer, size, callback); |  | 
| 159 } |  | 
| 160 |  | 
| 161 void HidConnectionMac::GetFeatureReport(scoped_refptr<net::IOBuffer> buffer, |  | 
| 162                                         size_t size, |  | 
| 163                                         const IOCallback& callback) { |  | 
| 164   DCHECK(thread_checker_.CalledOnValidThread()); |  | 
| 165   if (disconnected_ || !device_ || device_info_.feature_report_size == 0) { |  | 
| 166     callback.Run(false, 0); |  | 
| 167     return; |  | 
| 168   } |  | 
| 169 |  | 
| 170   if (device_info_.feature_report_size != 0 && |  | 
| 171       device_info_.feature_report_size != size) { |  | 
| 172     callback.Run(false, 0); |  | 
| 173     return; |  | 
| 174   } |  | 
| 175 |  | 
| 176   CFIndex len = device_info_.feature_report_size; |  | 
| 177   IOReturn res = IOHIDDeviceGetReport(device_, |  | 
| 178                                       kIOHIDReportTypeFeature, |  | 
| 179                                       0, |  | 
| 180                                       (uint8_t*) buffer->data(), |  | 
| 181                                       &len); |  | 
| 182   if (res == kIOReturnSuccess) |  | 
| 183     callback.Run(true, len); |  | 
| 184   else |  | 
| 185     callback.Run(false, 0); |  | 
| 186 } |  | 
| 187 |  | 
| 188 }  // namespace device |  | 
| OLD | NEW | 
|---|