vibrator: add initial forcefeedback vibrator HAL
This HAL talks to vibrators which are exposed as input devices using the
forcefeedback API.
This version includes lots of debugging spam.
diff --git a/vibrator/service.cpp b/vibrator/service.cpp
new file mode 100644
index 0000000..6d13730
--- /dev/null
+++ b/vibrator/service.cpp
@@ -0,0 +1,114 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#define LOG_TAG "android.hardware.vibrator@1.2-service.sdm845"
+
+#include <log/log.h>
+
+#include <android/hardware/vibrator/1.1/IVibrator.h>
+#include <hidl/HidlSupport.h>
+#include <hidl/HidlTransportSupport.h>
+#include <utils/Errors.h>
+#include <utils/StrongPointer.h>
+
+#include <linux/input.h>
+
+#include <iostream>
+#include <stdio.h>
+#include <dirent.h>
+#include <fcntl.h>
+
+#include "Vibrator.h"
+
+#define DEV_INPUT_DIR "/dev/input"
+
+using android::hardware::configureRpcThreadpool;
+using android::hardware::joinRpcThreadpool;
+using android::hardware::vibrator::V1_1::IVibrator;
+using android::hardware::vibrator::V1_1::implementation::Vibrator;
+using namespace android;
+
+// From : https://github.com/ubports/hfd-service/blob/xenial/src/vibrator-ff.cpp#L46
+static bool inputDevSupportsFF(std::string devname) {
+ int ret;
+ unsigned char features[1 + FF_MAX/8/sizeof(unsigned char)];
+ int tempFd = open(devname.c_str(), O_RDWR);
+ int request = EVIOCGBIT(EV_FF, sizeof(features)*sizeof(unsigned char));
+ bool supported = false;
+
+ ALOGE("CA:: %s: Testing device: %s", __func__, devname.c_str());
+
+ if ((ret = ioctl(tempFd, request, &features)) < 0) {
+ ALOGE("CA:: %s: ioctl() failed with errno = %d", __func__, ret);
+ supported = false;
+ }
+ if (testBit(FF_RUMBLE, features)) {
+ supported = true;
+ }
+
+ close(tempFd);
+ return supported;
+}
+
+// Returns path event path to to the first input device
+// which supports forcefeedback.
+// Adapted from getevent.c (I know this is bad)
+static std::string findFirstFFDevice() {
+ char devname[PATH_MAX];
+ char *filename;
+ struct dirent *de;
+ DIR *dir = opendir(DEV_INPUT_DIR);
+ if (dir == NULL)
+ return NULL;
+ strcpy(devname, DEV_INPUT_DIR);
+ filename = devname + strlen(devname);
+ *filename++ = '/';
+ while((de = readdir(dir))) {
+ if (std::string(de->d_name).find("event") == std::string::npos)
+ continue;
+ strcpy(filename, de->d_name);
+ // At this point devname is the full path to the dirent
+ std::string devpath(devname);
+ if (inputDevSupportsFF(devpath)) {
+ closedir(dir);
+ ALOGI("CA:: %s(): Found haptics device: %s", __func__, devpath.c_str());
+ return devpath;
+ }
+ }
+ closedir(dir);
+ return "";
+}
+
+
+status_t registerVibratorService() {
+ std::string hapticsDev = findFirstFFDevice();
+ if (hapticsDev.length() < 2)
+ return UNKNOWN_ERROR;
+ sp<IVibrator> vibrator = new Vibrator(hapticsDev);
+ ALOGI("CA:: %s", __func__);
+
+ return vibrator->registerAsService();
+}
+
+int main() {
+ configureRpcThreadpool(1, true);
+ status_t status = registerVibratorService();
+
+ if (status != OK) {
+ return status;
+ }
+
+ joinRpcThreadpool();
+}