Home | History | Annotate | Download | only in dynamic_sensor
      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