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 
HidRawDevice(const std::string & devName,const std::unordered_set<unsigned int> & usageSet)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 
~HidRawDevice()86 HidRawDevice::~HidRawDevice() {
87     if (mDevFd > 0) {
88         ::close(mDevFd);
89         mDevFd = -1;
90     }
91 }
92 
populateDeviceInfo()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 
generateDigest(const std::unordered_set<unsigned int> & usage)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 
isValid()178 bool HidRawDevice::isValid() {
179     return mValid;
180 }
181 
getFeature(uint8_t id,std::vector<uint8_t> * out)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 
setFeature(uint8_t id,const std::vector<uint8_t> & in)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 
sendReport(uint8_t id,std::vector<uint8_t> & data)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 
receiveReport(uint8_t * id,std::vector<uint8_t> * data)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 
getReportPacket(unsigned int type,unsigned int id)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