blob: 2a05bc2d151c7a58443a01234406b3b4aee223c1 [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
Caleb Connolly542816b2021-08-12 15:31:07 +010051 ALOGE("%s: Testing device: %s", __func__, devname.c_str());
Caleb Connollyc445fab2021-08-11 14:42:57 +010052
53 if ((ret = ioctl(tempFd, request, &features)) < 0) {
Caleb Connolly542816b2021-08-12 15:31:07 +010054 ALOGE("%s: ioctl() failed with errno = %d", __func__, ret);
Caleb Connollyc445fab2021-08-11 14:42:57 +010055 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);
Caleb Connolly542816b2021-08-12 15:31:07 +010086 ALOGV("%s(): Found haptics device: %s", __func__, devpath.c_str());
Caleb Connollyc445fab2021-08-11 14:42:57 +010087 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);
Caleb Connollyc445fab2021-08-11 14:42:57 +0100100
101 return vibrator->registerAsService();
102}
103
104int main() {
105 configureRpcThreadpool(1, true);
106 status_t status = registerVibratorService();
107
108 if (status != OK) {
109 return status;
110 }
111
112 joinRpcThreadpool();
113}