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