blob: 6d13730d68e7a6fcdba2d99991fbcbe47e027ac2 [file] [log] [blame]
Caleb Connollyc445fab2021-08-11 14:42:57 +01001/*
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#define LOG_TAG "android.hardware.vibrator@1.2-service.sdm845"
17
18#include <log/log.h>
19
20#include <android/hardware/vibrator/1.1/IVibrator.h>
21#include <hidl/HidlSupport.h>
22#include <hidl/HidlTransportSupport.h>
23#include <utils/Errors.h>
24#include <utils/StrongPointer.h>
25
26#include <linux/input.h>
27
28#include <iostream>
29#include <stdio.h>
30#include <dirent.h>
31#include <fcntl.h>
32
33#include "Vibrator.h"
34
35#define DEV_INPUT_DIR "/dev/input"
36
37using android::hardware::configureRpcThreadpool;
38using android::hardware::joinRpcThreadpool;
39using android::hardware::vibrator::V1_1::IVibrator;
40using android::hardware::vibrator::V1_1::implementation::Vibrator;
41using namespace android;
42
43// From : https://github.com/ubports/hfd-service/blob/xenial/src/vibrator-ff.cpp#L46
44static bool inputDevSupportsFF(std::string devname) {
45 int ret;
46 unsigned char features[1 + FF_MAX/8/sizeof(unsigned char)];
47 int tempFd = open(devname.c_str(), O_RDWR);
48 int request = EVIOCGBIT(EV_FF, sizeof(features)*sizeof(unsigned char));
49 bool supported = false;
50
51 ALOGE("CA:: %s: Testing device: %s", __func__, devname.c_str());
52
53 if ((ret = ioctl(tempFd, request, &features)) < 0) {
54 ALOGE("CA:: %s: ioctl() failed with errno = %d", __func__, ret);
55 supported = false;
56 }
57 if (testBit(FF_RUMBLE, features)) {
58 supported = true;
59 }
60
61 close(tempFd);
62 return supported;
63}
64
65// Returns path event path to to the first input device
66// which supports forcefeedback.
67// Adapted from getevent.c (I know this is bad)
68static std::string findFirstFFDevice() {
69 char devname[PATH_MAX];
70 char *filename;
71 struct dirent *de;
72 DIR *dir = opendir(DEV_INPUT_DIR);
73 if (dir == NULL)
74 return NULL;
75 strcpy(devname, DEV_INPUT_DIR);
76 filename = devname + strlen(devname);
77 *filename++ = '/';
78 while((de = readdir(dir))) {
79 if (std::string(de->d_name).find("event") == std::string::npos)
80 continue;
81 strcpy(filename, de->d_name);
82 // At this point devname is the full path to the dirent
83 std::string devpath(devname);
84 if (inputDevSupportsFF(devpath)) {
85 closedir(dir);
86 ALOGI("CA:: %s(): Found haptics device: %s", __func__, devpath.c_str());
87 return devpath;
88 }
89 }
90 closedir(dir);
91 return "";
92}
93
94
95status_t registerVibratorService() {
96 std::string hapticsDev = findFirstFFDevice();
97 if (hapticsDev.length() < 2)
98 return UNKNOWN_ERROR;
99 sp<IVibrator> vibrator = new Vibrator(hapticsDev);
100 ALOGI("CA:: %s", __func__);
101
102 return vibrator->registerAsService();
103}
104
105int main() {
106 configureRpcThreadpool(1, true);
107 status_t status = registerVibratorService();
108
109 if (status != OK) {
110 return status;
111 }
112
113 joinRpcThreadpool();
114}