1 /* 2 * Copyright (C) 2017 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 #include "HidRawDevice.h" 17 #include "HidLog.h" 18 #include "Utils.h" 19 20 #include <fcntl.h> 21 #include <linux/input.h> 22 #include <linux/hidraw.h> 23 #include <linux/hiddev.h> // HID_STRING_SIZE 24 #include <sys/ioctl.h> 25 #include <unistd.h> 26 27 #include <set> 28 29 namespace android { 30 namespace SensorHalExt { 31 32 using HidUtil::HidItem; 33 34 HidRawDevice::HidRawDevice( 35 const std::string &devName, const std::unordered_set<unsigned int> &usageSet) 36 : mDevFd(-1), mMultiIdDevice(false), mValid(false) { 37 // open device 38 mDevFd = ::open(devName.c_str(), O_RDWR); // read write? 39 if (mDevFd < 0) { 40 LOG_E << "Error in open device node: " << errno << " (" << ::strerror(errno) << ")" 41 << LOG_ENDL; 42 return; 43 } 44 45 // get device information, including hid descriptor 46 if (!populateDeviceInfo()) { 47 LOG_E << "Error obtaining HidRaw device information" << LOG_ENDL; 48 return; 49 } 50 51 if (!generateDigest(usageSet)) { 52 LOG_E << "Cannot parse hid descriptor" << LOG_ENDL; 53 return; 54 } 55 56 // digest error checking 57 std::unordered_set<unsigned int> reportIdSet; 58 for (auto const &digest : mDigestVector) { 59 for (auto const &packet : digest.packets) { 60 if (mReportTypeIdMap.emplace( 61 std::make_pair(packet.type, packet.id), &packet).second == false) { 62 LOG_E << "Same type - report id pair (" << packet.type << ", " << packet.id << ")" 63 << "is used by more than one usage collection" << LOG_ENDL; 64 return; 65 } 66 reportIdSet.insert(packet.id); 67 } 68 } 69 if (mReportTypeIdMap.empty()) { 70 return; 71 } 72 73 if (reportIdSet.size() > 1) { 74 if (reportIdSet.find(0) != reportIdSet.end()) { 75 LOG_E << "Default report id 0 is not expected when more than one report id is found." 76 << LOG_ENDL; 77 return; 78 } 79 mMultiIdDevice = true; 80 } else { // reportIdSet.size() == 1 81 mMultiIdDevice = !(reportIdSet.find(0) != reportIdSet.end()); 82 } 83 mValid = true; 84 } 85 86 HidRawDevice::~HidRawDevice() { 87 if (mDevFd > 0) { 88 ::close(mDevFd); 89 mDevFd = -1; 90 } 91 } 92 93 bool HidRawDevice::populateDeviceInfo() { 94 HidDeviceInfo info; 95 char buffer[HID_STRING_SIZE + 1]; 96 97 if (mDevFd < 0) { 98 return false; 99 } 100 101 // name 102 if (ioctl(mDevFd, HIDIOCGRAWNAME(sizeof(buffer) - 1), buffer) < 0) { 103 return false; 104 } 105 buffer[sizeof(buffer) - 1] = '\0'; 106 info.name = buffer; 107 108 // physical path 109 if (ioctl(mDevFd, HIDIOCGRAWPHYS(sizeof(buffer) - 1), buffer) < 0) { 110 return false; 111 } 112 buffer[sizeof(buffer) - 1] = '\0'; 113 info.physicalPath = buffer; 114 115 // raw device info 116 hidraw_devinfo devInfo; 117 if (ioctl(mDevFd, HIDIOCGRAWINFO, &devInfo) < 0) { 118 return false; 119 } 120 121 switch (devInfo.bustype) { 122 case BUS_USB: 123 info.busType = "USB"; 124 break; 125 case BUS_HIL: 126 info.busType = "HIL"; 127 break; 128 case BUS_BLUETOOTH: 129 info.busType = "Bluetooth"; 130 break; 131 case BUS_VIRTUAL: 132 info.busType = "Virtual"; 133 break; 134 default: 135 info.busType = "Other"; 136 break; 137 } 138 139 info.vendorId = devInfo.vendor; 140 info.productId = devInfo.vendor; 141 142 uint32_t descriptorSize; 143 /* Get Report Descriptor Size */ 144 if (ioctl(mDevFd, HIDIOCGRDESCSIZE, &descriptorSize) < 0) { 145 return false; 146 } 147 148 struct hidraw_report_descriptor reportDescriptor; 149 memset(&reportDescriptor, 0, sizeof(reportDescriptor)); 150 info.descriptor.resize(descriptorSize); 151 reportDescriptor.size = descriptorSize; 152 if (ioctl(mDevFd, HIDIOCGRDESC, &reportDescriptor) < 0) { 153 return false; 154 } 155 std::copy(reportDescriptor.value, reportDescriptor.value + descriptorSize, 156 info.descriptor.begin()); 157 mDeviceInfo = info; 158 return true; 159 } 160 161 bool HidRawDevice::generateDigest(const std::unordered_set<unsigned int> &usage) { 162 if (mDeviceInfo.descriptor.empty()) { 163 return false; 164 } 165 166 std::vector<HidItem> tokens = HidItem::tokenize(mDeviceInfo.descriptor); 167 HidParser parser; 168 if (!parser.parse(tokens)) { 169 return false; 170 } 171 172 parser.filterTree(); 173 mDigestVector = parser.generateDigest(usage); 174 175 return mDigestVector.size() > 0; 176 } 177 178 bool HidRawDevice::isValid() { 179 return mValid; 180 } 181 182 bool HidRawDevice::getFeature(uint8_t id, std::vector<uint8_t> *out) { 183 if (mDevFd < 0) { 184 return false; 185 } 186 187 if (out == nullptr) { 188 return false; 189 } 190 191 const HidParser::ReportPacket *packet = getReportPacket(HidParser::REPORT_TYPE_FEATURE, id); 192 if (packet == nullptr) { 193 LOG_E << "HidRawDevice::getFeature: unknown feature " << id << LOG_ENDL; 194 return false; 195 } 196 197 size_t size = packet->getByteSize() + 1; // report id size 198 199 std::lock_guard<std::mutex> l(mIoBufferLock); 200 if (mIoBuffer.size() < size) { 201 mIoBuffer.resize(size); 202 } 203 mIoBuffer[0] = id; 204 int res = ::ioctl(mDevFd, HIDIOCGFEATURE(size), mIoBuffer.data()); 205 if (res < 0) { 206 LOG_E << "HidRawDevice::getFeature: feature " << static_cast<int>(id) 207 << " ioctl returns " << res << " (" << ::strerror(res) << ")" << LOG_ENDL; 208 return false; 209 } 210 211 if (static_cast<size_t>(res) != size) { 212 LOG_E << "HidRawDevice::getFeature: get feature " << static_cast<int>(id) 213 << " returned " << res << " bytes, does not match expected " << size << LOG_ENDL; 214 return false; 215 } 216 if (mIoBuffer.front() != id) { 217 LOG_E << "HidRawDevice::getFeature: get feature " << static_cast<int>(id) 218 << " result has header " << mIoBuffer.front() << LOG_ENDL; 219 } 220 out->resize(size - 1); 221 std::copy(mIoBuffer.begin() + 1, mIoBuffer.begin() + size, out->begin()); 222 return true; 223 } 224 225 bool HidRawDevice::setFeature(uint8_t id, const std::vector<uint8_t> &in) { 226 if (mDevFd < 0) { 227 return false; 228 } 229 230 const HidParser::ReportPacket *packet = getReportPacket(HidParser::REPORT_TYPE_FEATURE, id); 231 if (packet == nullptr) { 232 LOG_E << "HidRawDevice::setFeature: Unknown feature " << id << LOG_ENDL; 233 return false; 234 } 235 236 size_t size = packet->getByteSize(); 237 if (size != in.size()) { 238 LOG_E << "HidRawDevice::setFeature: set feature " << id << " size mismatch, need " 239 << size << " bytes, have " << in.size() << " bytes" << LOG_ENDL; 240 return false; 241 } 242 243 ++size; // report id byte 244 std::lock_guard<std::mutex> l(mIoBufferLock); 245 if (mIoBuffer.size() < size) { 246 mIoBuffer.resize(size); 247 } 248 mIoBuffer[0] = id; 249 std::copy(in.begin(), in.end(), &mIoBuffer[1]); 250 int res = ::ioctl(mDevFd, HIDIOCSFEATURE(size), mIoBuffer.data()); 251 if (res < 0) { 252 LOG_E << "HidRawDevice::setFeature: feature " << id << " ioctl returns " << res 253 << " (" << ::strerror(res) << ")" << LOG_ENDL; 254 return false; 255 } 256 return true; 257 } 258 259 bool HidRawDevice::sendReport(uint8_t id, std::vector<uint8_t> &data) { 260 if (mDevFd < 0) { 261 return false; 262 } 263 264 const HidParser::ReportPacket *packet = getReportPacket(HidParser::REPORT_TYPE_OUTPUT, id); 265 if (packet == nullptr) { 266 LOG_E << "HidRawDevice::sendReport: unknown output " << id << LOG_ENDL; 267 return false; 268 } 269 270 size_t size = packet->getByteSize(); 271 if (size != data.size()) { 272 LOG_E << "HidRawDevice::sendReport: send report " << id << " size mismatch, need " 273 << size << " bytes, have " << data.size() << " bytes" << LOG_ENDL; 274 return false; 275 } 276 int res; 277 if (mMultiIdDevice) { 278 std::lock_guard<std::mutex> l(mIoBufferLock); 279 ++size; 280 if (mIoBuffer.size() < size) { 281 mIoBuffer.resize(size); 282 } 283 mIoBuffer[0] = id; 284 std::copy(mIoBuffer.begin() + 1, mIoBuffer.end(), data.begin()); 285 res = ::write(mDevFd, mIoBuffer.data(), size); 286 } else { 287 res = ::write(mDevFd, data.data(), size); 288 } 289 if (res < 0) { 290 LOG_E << "HidRawDevice::sendReport: output " << id << " write returns " << res 291 << " (" << ::strerror(res) << ")" << LOG_ENDL; 292 return false; 293 } 294 return true; 295 } 296 297 bool HidRawDevice::receiveReport(uint8_t *id, std::vector<uint8_t> *data) { 298 if (mDevFd < 0) { 299 return false; 300 } 301 302 uint8_t buffer[256]; 303 int res = ::read(mDevFd, buffer, 256); 304 if (res < 0) { 305 LOG_E << "HidRawDevice::receiveReport: read returns " << res 306 << " (" << ::strerror(res) << ")" << LOG_ENDL; 307 return false; 308 } 309 310 if (mMultiIdDevice) { 311 if (!(res > 1)) { 312 LOG_E << "read hidraw returns data too short, len: " << res << LOG_ENDL; 313 return false; 314 } 315 data->resize(static_cast<size_t>(res - 1)); 316 std::copy(buffer + 1, buffer + res, data->begin()); 317 *id = buffer[0]; 318 } else { 319 data->resize(static_cast<size_t>(res)); 320 std::copy(buffer, buffer + res, data->begin()); 321 *id = 0; 322 } 323 return true; 324 } 325 326 const HidParser::ReportPacket *HidRawDevice::getReportPacket(unsigned int type, unsigned int id) { 327 auto i = mReportTypeIdMap.find(std::make_pair(type, id)); 328 return (i == mReportTypeIdMap.end()) ? nullptr : i->second; 329 } 330 331 } // namespace SensorHalExt 332 } // namespace android 333