1fe2188fa871f1d4470378c004ad44d4216202641Ben Fennema/*
2e96ece71fbd610603074755303e1d6cc3e505b00Zhengyin Qian * Copyright (C) 2016 The Android Open Source Project
3fe2188fa871f1d4470378c004ad44d4216202641Ben Fennema *
4e96ece71fbd610603074755303e1d6cc3e505b00Zhengyin Qian * Licensed under the Apache License, Version 2.0 (the "License");
5e96ece71fbd610603074755303e1d6cc3e505b00Zhengyin Qian * you may not use this file except in compliance with the License.
6e96ece71fbd610603074755303e1d6cc3e505b00Zhengyin Qian * You may obtain a copy of the License at
7fe2188fa871f1d4470378c004ad44d4216202641Ben Fennema *
8e96ece71fbd610603074755303e1d6cc3e505b00Zhengyin Qian *      http://www.apache.org/licenses/LICENSE-2.0
9e96ece71fbd610603074755303e1d6cc3e505b00Zhengyin Qian *
10e96ece71fbd610603074755303e1d6cc3e505b00Zhengyin Qian * Unless required by applicable law or agreed to in writing, software
11e96ece71fbd610603074755303e1d6cc3e505b00Zhengyin Qian * distributed under the License is distributed on an "AS IS" BASIS,
12e96ece71fbd610603074755303e1d6cc3e505b00Zhengyin Qian * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13e96ece71fbd610603074755303e1d6cc3e505b00Zhengyin Qian * See the License for the specific language governing permissions and
14e96ece71fbd610603074755303e1d6cc3e505b00Zhengyin Qian * limitations under the License.
15fe2188fa871f1d4470378c004ad44d4216202641Ben Fennema */
16fe2188fa871f1d4470378c004ad44d4216202641Ben Fennema
17fe2188fa871f1d4470378c004ad44d4216202641Ben Fennema#define LOG_TAG "NanohubHAL"
1896177b03ab7915a8abce9fcb14f61be2edab918fAlexey Polyudov
1996177b03ab7915a8abce9fcb14f61be2edab918fAlexey Polyudov#include <fcntl.h>
2096177b03ab7915a8abce9fcb14f61be2edab918fAlexey Polyudov#include <poll.h>
2196177b03ab7915a8abce9fcb14f61be2edab918fAlexey Polyudov#include <unistd.h>
2296177b03ab7915a8abce9fcb14f61be2edab918fAlexey Polyudov#include <sys/inotify.h>
2396177b03ab7915a8abce9fcb14f61be2edab918fAlexey Polyudov#include <sys/types.h>
2496177b03ab7915a8abce9fcb14f61be2edab918fAlexey Polyudov#include <sys/stat.h>
2596177b03ab7915a8abce9fcb14f61be2edab918fAlexey Polyudov
26fe2188fa871f1d4470378c004ad44d4216202641Ben Fennema#include <hardware/context_hub.h>
27fe2188fa871f1d4470378c004ad44d4216202641Ben Fennema#include <hardware/hardware.h>
2896177b03ab7915a8abce9fcb14f61be2edab918fAlexey Polyudov
2996177b03ab7915a8abce9fcb14f61be2edab918fAlexey Polyudov#include <utils/Log.h>
3070ab6271e35d78b86a68b00b663c177230697fb5Alexey Polyudov#include <cutils/properties.h>
3196177b03ab7915a8abce9fcb14f61be2edab918fAlexey Polyudov
32c8e09a8dc0eecf2e0fb473ff8d8c0574f7fbfa9cAlexey Polyudov#include <nanohub/nanohub.h>
33c8e09a8dc0eecf2e0fb473ff8d8c0574f7fbfa9cAlexey Polyudov
3496177b03ab7915a8abce9fcb14f61be2edab918fAlexey Polyudov#include <cinttypes>
3570ab6271e35d78b86a68b00b663c177230697fb5Alexey Polyudov#include <iomanip>
3670ab6271e35d78b86a68b00b663c177230697fb5Alexey Polyudov#include <sstream>
3796177b03ab7915a8abce9fcb14f61be2edab918fAlexey Polyudov
38fe2188fa871f1d4470378c004ad44d4216202641Ben Fennema#include "nanohub_perdevice.h"
39fe2188fa871f1d4470378c004ad44d4216202641Ben Fennema#include "system_comms.h"
40fe2188fa871f1d4470378c004ad44d4216202641Ben Fennema#include "nanohubhal.h"
4183110051b77fe8a6c4c31ef115ad745cea4d79a6Brian Duddie
423716b181acd60279ba61a0db235ca7267462567cPeng Xu#define NANOHUB_LOCK_DIR        "/data/vendor/sensor/nanohub_lock"
4383110051b77fe8a6c4c31ef115ad745cea4d79a6Brian Duddie#define NANOHUB_LOCK_FILE       NANOHUB_LOCK_DIR "/lock"
4483110051b77fe8a6c4c31ef115ad745cea4d79a6Brian Duddie#define NANOHUB_LOCK_DIR_PERMS  (S_IRUSR | S_IWUSR | S_IXUSR)
45fe2188fa871f1d4470378c004ad44d4216202641Ben Fennema
4696177b03ab7915a8abce9fcb14f61be2edab918fAlexey Polyudovnamespace android {
4796177b03ab7915a8abce9fcb14f61be2edab918fAlexey Polyudov
4896177b03ab7915a8abce9fcb14f61be2edab918fAlexey Polyudovnamespace nanohub {
49fe2188fa871f1d4470378c004ad44d4216202641Ben Fennema
5070ab6271e35d78b86a68b00b663c177230697fb5Alexey Polyudovinline std::ostream &operator << (std::ostream &os, const hub_app_name_t &appId)
5170ab6271e35d78b86a68b00b663c177230697fb5Alexey Polyudov{
5270ab6271e35d78b86a68b00b663c177230697fb5Alexey Polyudov    char vendor[6];
5370ab6271e35d78b86a68b00b663c177230697fb5Alexey Polyudov    __be64 beAppId = htobe64(appId.id);
5470ab6271e35d78b86a68b00b663c177230697fb5Alexey Polyudov    uint32_t seqId = appId.id & NANOAPP_VENDOR_ALL_APPS;
5570ab6271e35d78b86a68b00b663c177230697fb5Alexey Polyudov
5670ab6271e35d78b86a68b00b663c177230697fb5Alexey Polyudov    std::ios::fmtflags f(os.flags());
5770ab6271e35d78b86a68b00b663c177230697fb5Alexey Polyudov    memcpy(vendor, (void*)&beAppId, sizeof(vendor) - 1);
5870ab6271e35d78b86a68b00b663c177230697fb5Alexey Polyudov    vendor[sizeof(vendor) - 1] = 0;
5970ab6271e35d78b86a68b00b663c177230697fb5Alexey Polyudov    if (strlen(vendor) == 5)
6070ab6271e35d78b86a68b00b663c177230697fb5Alexey Polyudov        os << vendor << ", " << std::hex << std::setw(6)  << seqId;
6170ab6271e35d78b86a68b00b663c177230697fb5Alexey Polyudov    else
6270ab6271e35d78b86a68b00b663c177230697fb5Alexey Polyudov        os << "#" << std::hex << appId.id;
6370ab6271e35d78b86a68b00b663c177230697fb5Alexey Polyudov    os.flags(f);
6470ab6271e35d78b86a68b00b663c177230697fb5Alexey Polyudov
6570ab6271e35d78b86a68b00b663c177230697fb5Alexey Polyudov    return os;
6670ab6271e35d78b86a68b00b663c177230697fb5Alexey Polyudov}
6770ab6271e35d78b86a68b00b663c177230697fb5Alexey Polyudov
6870ab6271e35d78b86a68b00b663c177230697fb5Alexey Polyudovvoid dumpBuffer(const char *pfx, const hub_app_name_t &appId, uint32_t evtId, const void *data, size_t len, int status)
6970ab6271e35d78b86a68b00b663c177230697fb5Alexey Polyudov{
7070ab6271e35d78b86a68b00b663c177230697fb5Alexey Polyudov    std::ostringstream os;
7170ab6271e35d78b86a68b00b663c177230697fb5Alexey Polyudov    const uint8_t *p = static_cast<const uint8_t *>(data);
7270ab6271e35d78b86a68b00b663c177230697fb5Alexey Polyudov    os << pfx << ": [ID=" << appId << "; SZ=" << std::dec << len;
7370ab6271e35d78b86a68b00b663c177230697fb5Alexey Polyudov    if (evtId)
7470ab6271e35d78b86a68b00b663c177230697fb5Alexey Polyudov        os << "; EVT=" << std::hex << evtId;
7570ab6271e35d78b86a68b00b663c177230697fb5Alexey Polyudov    os << "]:" << std::hex;
7670ab6271e35d78b86a68b00b663c177230697fb5Alexey Polyudov    for (size_t i = 0; i < len; ++i) {
7717e6eabfe6229c7b42d078a89c4119fea7108788Alexey Polyudov        os << " "  << std::setfill('0') << std::setw(2) << (unsigned int)p[i];
7870ab6271e35d78b86a68b00b663c177230697fb5Alexey Polyudov    }
7970ab6271e35d78b86a68b00b663c177230697fb5Alexey Polyudov    if (status) {
8070ab6271e35d78b86a68b00b663c177230697fb5Alexey Polyudov        os << "; status=" << status << " [" << std::setfill('0') << std::setw(8) << status << "]";
8170ab6271e35d78b86a68b00b663c177230697fb5Alexey Polyudov    }
8270ab6271e35d78b86a68b00b663c177230697fb5Alexey Polyudov    ALOGI("%s", os.str().c_str());
8370ab6271e35d78b86a68b00b663c177230697fb5Alexey Polyudov}
8470ab6271e35d78b86a68b00b663c177230697fb5Alexey Polyudov
85fe2188fa871f1d4470378c004ad44d4216202641Ben Fennemastatic int rwrite(int fd, const void *buf, int len)
86fe2188fa871f1d4470378c004ad44d4216202641Ben Fennema{
87fe2188fa871f1d4470378c004ad44d4216202641Ben Fennema    int ret;
88fe2188fa871f1d4470378c004ad44d4216202641Ben Fennema
89fe2188fa871f1d4470378c004ad44d4216202641Ben Fennema    do {
90fe2188fa871f1d4470378c004ad44d4216202641Ben Fennema        ret = write(fd, buf, len);
91fe2188fa871f1d4470378c004ad44d4216202641Ben Fennema    } while (ret < 0 && errno == EINTR);
92fe2188fa871f1d4470378c004ad44d4216202641Ben Fennema
9396177b03ab7915a8abce9fcb14f61be2edab918fAlexey Polyudov    if (ret != len) {
94fe2188fa871f1d4470378c004ad44d4216202641Ben Fennema        return errno ? -errno : -EIO;
9596177b03ab7915a8abce9fcb14f61be2edab918fAlexey Polyudov    }
96fe2188fa871f1d4470378c004ad44d4216202641Ben Fennema
97fe2188fa871f1d4470378c004ad44d4216202641Ben Fennema    return 0;
98fe2188fa871f1d4470378c004ad44d4216202641Ben Fennema}
99fe2188fa871f1d4470378c004ad44d4216202641Ben Fennema
100fe2188fa871f1d4470378c004ad44d4216202641Ben Fennemastatic int rread(int fd, void *buf, int len)
101fe2188fa871f1d4470378c004ad44d4216202641Ben Fennema{
102fe2188fa871f1d4470378c004ad44d4216202641Ben Fennema    int ret;
103fe2188fa871f1d4470378c004ad44d4216202641Ben Fennema
104fe2188fa871f1d4470378c004ad44d4216202641Ben Fennema    do {
105fe2188fa871f1d4470378c004ad44d4216202641Ben Fennema        ret = read(fd, buf, len);
106fe2188fa871f1d4470378c004ad44d4216202641Ben Fennema    } while (ret < 0 && errno == EINTR);
107fe2188fa871f1d4470378c004ad44d4216202641Ben Fennema
108fe2188fa871f1d4470378c004ad44d4216202641Ben Fennema    return ret;
109fe2188fa871f1d4470378c004ad44d4216202641Ben Fennema}
110fe2188fa871f1d4470378c004ad44d4216202641Ben Fennema
11196177b03ab7915a8abce9fcb14f61be2edab918fAlexey Polyudovstatic bool init_inotify(pollfd *pfd) {
11283110051b77fe8a6c4c31ef115ad745cea4d79a6Brian Duddie    bool success = false;
11383110051b77fe8a6c4c31ef115ad745cea4d79a6Brian Duddie
11483110051b77fe8a6c4c31ef115ad745cea4d79a6Brian Duddie    mkdir(NANOHUB_LOCK_DIR, NANOHUB_LOCK_DIR_PERMS);
11583110051b77fe8a6c4c31ef115ad745cea4d79a6Brian Duddie    pfd->fd = inotify_init1(IN_NONBLOCK);
11683110051b77fe8a6c4c31ef115ad745cea4d79a6Brian Duddie    if (pfd->fd < 0) {
11783110051b77fe8a6c4c31ef115ad745cea4d79a6Brian Duddie        ALOGE("Couldn't initialize inotify: %s", strerror(errno));
1189bbfdff8a9baa3e2c9b258f326777d8234af7c44Brian Duddie    } else if (inotify_add_watch(pfd->fd, NANOHUB_LOCK_DIR, IN_CREATE | IN_DELETE) < 0) {
11983110051b77fe8a6c4c31ef115ad745cea4d79a6Brian Duddie        ALOGE("Couldn't add inotify watch: %s", strerror(errno));
12083110051b77fe8a6c4c31ef115ad745cea4d79a6Brian Duddie        close(pfd->fd);
12183110051b77fe8a6c4c31ef115ad745cea4d79a6Brian Duddie    } else {
12283110051b77fe8a6c4c31ef115ad745cea4d79a6Brian Duddie        pfd->events = POLLIN;
12383110051b77fe8a6c4c31ef115ad745cea4d79a6Brian Duddie        success = true;
12483110051b77fe8a6c4c31ef115ad745cea4d79a6Brian Duddie    }
12583110051b77fe8a6c4c31ef115ad745cea4d79a6Brian Duddie
12683110051b77fe8a6c4c31ef115ad745cea4d79a6Brian Duddie    return success;
12783110051b77fe8a6c4c31ef115ad745cea4d79a6Brian Duddie}
12883110051b77fe8a6c4c31ef115ad745cea4d79a6Brian Duddie
12996177b03ab7915a8abce9fcb14f61be2edab918fAlexey Polyudovstatic void discard_inotify_evt(pollfd &pfd) {
13096177b03ab7915a8abce9fcb14f61be2edab918fAlexey Polyudov    if ((pfd.revents & POLLIN)) {
13196177b03ab7915a8abce9fcb14f61be2edab918fAlexey Polyudov        char buf[sizeof(inotify_event) + NAME_MAX + 1];
13296177b03ab7915a8abce9fcb14f61be2edab918fAlexey Polyudov        int ret = read(pfd.fd, buf, sizeof(buf));
13396177b03ab7915a8abce9fcb14f61be2edab918fAlexey Polyudov        ALOGD("Discarded %d bytes of inotify data", ret);
13496177b03ab7915a8abce9fcb14f61be2edab918fAlexey Polyudov    }
13583110051b77fe8a6c4c31ef115ad745cea4d79a6Brian Duddie}
13683110051b77fe8a6c4c31ef115ad745cea4d79a6Brian Duddie
13796177b03ab7915a8abce9fcb14f61be2edab918fAlexey Polyudovstatic void wait_on_dev_lock(pollfd &pfd) {
13883110051b77fe8a6c4c31ef115ad745cea4d79a6Brian Duddie    // While the lock file exists, poll on the inotify fd (with timeout)
13996177b03ab7915a8abce9fcb14f61be2edab918fAlexey Polyudov    discard_inotify_evt(pfd);
14083110051b77fe8a6c4c31ef115ad745cea4d79a6Brian Duddie    while (access(NANOHUB_LOCK_FILE, F_OK) == 0) {
14183110051b77fe8a6c4c31ef115ad745cea4d79a6Brian Duddie        ALOGW("Nanohub is locked; blocking read thread");
14296177b03ab7915a8abce9fcb14f61be2edab918fAlexey Polyudov        int ret = poll(&pfd, 1, 5000);
14396177b03ab7915a8abce9fcb14f61be2edab918fAlexey Polyudov        if (ret > 0) {
14496177b03ab7915a8abce9fcb14f61be2edab918fAlexey Polyudov            discard_inotify_evt(pfd);
14583110051b77fe8a6c4c31ef115ad745cea4d79a6Brian Duddie        }
14683110051b77fe8a6c4c31ef115ad745cea4d79a6Brian Duddie    }
14783110051b77fe8a6c4c31ef115ad745cea4d79a6Brian Duddie}
14883110051b77fe8a6c4c31ef115ad745cea4d79a6Brian Duddie
149679ee8dd0d6f535da9062ddef53cf9b8b00bc3c2Brian DuddieNanoHub::NanoHub() {
150679ee8dd0d6f535da9062ddef53cf9b8b00bc3c2Brian Duddie    reset();
151679ee8dd0d6f535da9062ddef53cf9b8b00bc3c2Brian Duddie}
152679ee8dd0d6f535da9062ddef53cf9b8b00bc3c2Brian Duddie
153679ee8dd0d6f535da9062ddef53cf9b8b00bc3c2Brian DuddieNanoHub::~NanoHub() {
154679ee8dd0d6f535da9062ddef53cf9b8b00bc3c2Brian Duddie    if (mMsgCbkFunc) {
155679ee8dd0d6f535da9062ddef53cf9b8b00bc3c2Brian Duddie        ALOGD("Shutting down");
156679ee8dd0d6f535da9062ddef53cf9b8b00bc3c2Brian Duddie        closeHub();
157679ee8dd0d6f535da9062ddef53cf9b8b00bc3c2Brian Duddie    }
158679ee8dd0d6f535da9062ddef53cf9b8b00bc3c2Brian Duddie}
159679ee8dd0d6f535da9062ddef53cf9b8b00bc3c2Brian Duddie
160672acdeb3c63987a9a778dbcc84fe74e0fb4a5dbStephen Hinesint NanoHub::doSendToDevice(const hub_app_name_t name, const void *data, uint32_t len, uint32_t messageType)
161fe2188fa871f1d4470378c004ad44d4216202641Ben Fennema{
162672acdeb3c63987a9a778dbcc84fe74e0fb4a5dbStephen Hines    if (len > MAX_RX_PACKET) {
163fd9c05e653cf9de55c72afb85af849f5d932e1a1Alexey Polyudov        return -EINVAL;
16496177b03ab7915a8abce9fcb14f61be2edab918fAlexey Polyudov    }
165fd9c05e653cf9de55c72afb85af849f5d932e1a1Alexey Polyudov
1660ce3d053b7c75d4759e047653868cb1079e32252Alexey Polyudov    // transmit message to FW in CHRE format
1670ce3d053b7c75d4759e047653868cb1079e32252Alexey Polyudov    nano_message_chre msg = {
168fd9c05e653cf9de55c72afb85af849f5d932e1a1Alexey Polyudov        .hdr = {
1690ce3d053b7c75d4759e047653868cb1079e32252Alexey Polyudov            .eventId = APP_FROM_HOST_CHRE_EVENT_ID,
170672acdeb3c63987a9a778dbcc84fe74e0fb4a5dbStephen Hines            .appId = name.id,
17196177b03ab7915a8abce9fcb14f61be2edab918fAlexey Polyudov            .len = static_cast<uint8_t>(len),
1720ce3d053b7c75d4759e047653868cb1079e32252Alexey Polyudov            .appEventId = messageType,
17396177b03ab7915a8abce9fcb14f61be2edab918fAlexey Polyudov        },
174fd9c05e653cf9de55c72afb85af849f5d932e1a1Alexey Polyudov    };
175fe2188fa871f1d4470378c004ad44d4216202641Ben Fennema
176fd9c05e653cf9de55c72afb85af849f5d932e1a1Alexey Polyudov    memcpy(&msg.data[0], data, len);
177fe2188fa871f1d4470378c004ad44d4216202641Ben Fennema
178fd9c05e653cf9de55c72afb85af849f5d932e1a1Alexey Polyudov    return rwrite(mFd, &msg, len + sizeof(msg.hdr));
179fe2188fa871f1d4470378c004ad44d4216202641Ben Fennema}
180fe2188fa871f1d4470378c004ad44d4216202641Ben Fennema
18153d7164c9e25b417d597c102d92bae3050c149aeAlexey Polyudovvoid NanoHub::doSendToApp(HubMessage &&msg)
182fe2188fa871f1d4470378c004ad44d4216202641Ben Fennema{
18353d7164c9e25b417d597c102d92bae3050c149aeAlexey Polyudov    std::unique_lock<std::mutex> lk(mAppTxLock);
18453d7164c9e25b417d597c102d92bae3050c149aeAlexey Polyudov    mAppTxQueue.push_back((HubMessage &&)msg);
18553d7164c9e25b417d597c102d92bae3050c149aeAlexey Polyudov    lk.unlock();
18653d7164c9e25b417d597c102d92bae3050c149aeAlexey Polyudov    mAppTxCond.notify_all();
18753d7164c9e25b417d597c102d92bae3050c149aeAlexey Polyudov}
188fe2188fa871f1d4470378c004ad44d4216202641Ben Fennema
18953d7164c9e25b417d597c102d92bae3050c149aeAlexey Polyudovvoid* NanoHub::runAppTx()
19053d7164c9e25b417d597c102d92bae3050c149aeAlexey Polyudov{
19153d7164c9e25b417d597c102d92bae3050c149aeAlexey Polyudov    std::unique_lock<std::mutex> lk(mAppTxLock);
19253d7164c9e25b417d597c102d92bae3050c149aeAlexey Polyudov    while(true) {
19353d7164c9e25b417d597c102d92bae3050c149aeAlexey Polyudov        mAppTxCond.wait(lk, [this] { return !mAppTxQueue.empty() || mAppQuit; });
19453d7164c9e25b417d597c102d92bae3050c149aeAlexey Polyudov        if (mAppQuit) {
19553d7164c9e25b417d597c102d92bae3050c149aeAlexey Polyudov            break;
19653d7164c9e25b417d597c102d92bae3050c149aeAlexey Polyudov        }
19753d7164c9e25b417d597c102d92bae3050c149aeAlexey Polyudov        HubMessage &m = mAppTxQueue.front();
19853d7164c9e25b417d597c102d92bae3050c149aeAlexey Polyudov        lk.unlock();
19953d7164c9e25b417d597c102d92bae3050c149aeAlexey Polyudov        mMsgCbkFunc(0, &m, mMsgCbkData);
20053d7164c9e25b417d597c102d92bae3050c149aeAlexey Polyudov        lk.lock();
20153d7164c9e25b417d597c102d92bae3050c149aeAlexey Polyudov        mAppTxQueue.pop_front();
20253d7164c9e25b417d597c102d92bae3050c149aeAlexey Polyudov    };
20353d7164c9e25b417d597c102d92bae3050c149aeAlexey Polyudov    return NULL;
204fe2188fa871f1d4470378c004ad44d4216202641Ben Fennema}
205fe2188fa871f1d4470378c004ad44d4216202641Ben Fennema
20653d7164c9e25b417d597c102d92bae3050c149aeAlexey Polyudovvoid* NanoHub::runDeviceRx()
20796177b03ab7915a8abce9fcb14f61be2edab918fAlexey Polyudov{
20896177b03ab7915a8abce9fcb14f61be2edab918fAlexey Polyudov    enum {
20996177b03ab7915a8abce9fcb14f61be2edab918fAlexey Polyudov        IDX_NANOHUB,
21096177b03ab7915a8abce9fcb14f61be2edab918fAlexey Polyudov        IDX_CLOSE_PIPE,
21196177b03ab7915a8abce9fcb14f61be2edab918fAlexey Polyudov        IDX_INOTIFY
21296177b03ab7915a8abce9fcb14f61be2edab918fAlexey Polyudov    };
21396177b03ab7915a8abce9fcb14f61be2edab918fAlexey Polyudov    pollfd myFds[3] = {
21496177b03ab7915a8abce9fcb14f61be2edab918fAlexey Polyudov        [IDX_NANOHUB] = { .fd = mFd, .events = POLLIN, },
21596177b03ab7915a8abce9fcb14f61be2edab918fAlexey Polyudov        [IDX_CLOSE_PIPE] = { .fd = mThreadClosingPipe[0], .events = POLLIN, },
21683110051b77fe8a6c4c31ef115ad745cea4d79a6Brian Duddie    };
21796177b03ab7915a8abce9fcb14f61be2edab918fAlexey Polyudov    pollfd &inotifyFd = myFds[IDX_INOTIFY];
21896177b03ab7915a8abce9fcb14f61be2edab918fAlexey Polyudov    bool hasInotify = false;
21983110051b77fe8a6c4c31ef115ad745cea4d79a6Brian Duddie    int numPollFds = 2;
220fe2188fa871f1d4470378c004ad44d4216202641Ben Fennema
22196177b03ab7915a8abce9fcb14f61be2edab918fAlexey Polyudov    if (init_inotify(&inotifyFd)) {
22296177b03ab7915a8abce9fcb14f61be2edab918fAlexey Polyudov        numPollFds++;
22396177b03ab7915a8abce9fcb14f61be2edab918fAlexey Polyudov        hasInotify = true;
22483110051b77fe8a6c4c31ef115ad745cea4d79a6Brian Duddie    }
22583110051b77fe8a6c4c31ef115ad745cea4d79a6Brian Duddie
22670ab6271e35d78b86a68b00b663c177230697fb5Alexey Polyudov    setDebugFlags(property_get_int32("persist.nanohub.debug", 0));
22770ab6271e35d78b86a68b00b663c177230697fb5Alexey Polyudov
228fe2188fa871f1d4470378c004ad44d4216202641Ben Fennema    while (1) {
22996177b03ab7915a8abce9fcb14f61be2edab918fAlexey Polyudov        int ret = poll(myFds, numPollFds, -1);
230fe2188fa871f1d4470378c004ad44d4216202641Ben Fennema        if (ret <= 0) {
231710367565483bf7e01d5a2c7ab51d931f082bab8Andrew Rossignol            ALOGD("poll returned with an error: %s", strerror(errno));
232fe2188fa871f1d4470378c004ad44d4216202641Ben Fennema            continue;
233fe2188fa871f1d4470378c004ad44d4216202641Ben Fennema        }
234fe2188fa871f1d4470378c004ad44d4216202641Ben Fennema
23596177b03ab7915a8abce9fcb14f61be2edab918fAlexey Polyudov        if (hasInotify) {
23696177b03ab7915a8abce9fcb14f61be2edab918fAlexey Polyudov            wait_on_dev_lock(inotifyFd);
23783110051b77fe8a6c4c31ef115ad745cea4d79a6Brian Duddie        }
23883110051b77fe8a6c4c31ef115ad745cea4d79a6Brian Duddie
23996177b03ab7915a8abce9fcb14f61be2edab918fAlexey Polyudov        if (myFds[IDX_NANOHUB].revents & POLLIN) { // we have data
240fe2188fa871f1d4470378c004ad44d4216202641Ben Fennema
24196177b03ab7915a8abce9fcb14f61be2edab918fAlexey Polyudov            nano_message msg;
242fe2188fa871f1d4470378c004ad44d4216202641Ben Fennema
243fd9c05e653cf9de55c72afb85af849f5d932e1a1Alexey Polyudov            ret = rread(mFd, &msg, sizeof(msg));
244fe2188fa871f1d4470378c004ad44d4216202641Ben Fennema            if (ret <= 0) {
245b143f602214a5b711b5c9b1c3a11c8bd49f84764Greg Kaiser                ALOGE("read failed with %d", ret);
246fe2188fa871f1d4470378c004ad44d4216202641Ben Fennema                break;
247fe2188fa871f1d4470378c004ad44d4216202641Ben Fennema            }
248fd9c05e653cf9de55c72afb85af849f5d932e1a1Alexey Polyudov            if (ret < (int)sizeof(msg.hdr)) {
249b143f602214a5b711b5c9b1c3a11c8bd49f84764Greg Kaiser                ALOGE("Only read %d bytes", ret);
250b143f602214a5b711b5c9b1c3a11c8bd49f84764Greg Kaiser                break;
251b143f602214a5b711b5c9b1c3a11c8bd49f84764Greg Kaiser            }
252b143f602214a5b711b5c9b1c3a11c8bd49f84764Greg Kaiser
25396177b03ab7915a8abce9fcb14f61be2edab918fAlexey Polyudov            uint32_t len = msg.hdr.len;
254fe2188fa871f1d4470378c004ad44d4216202641Ben Fennema
255fd9c05e653cf9de55c72afb85af849f5d932e1a1Alexey Polyudov            if (len > sizeof(msg.data)) {
256b143f602214a5b711b5c9b1c3a11c8bd49f84764Greg Kaiser                ALOGE("malformed packet with len %" PRIu32, len);
257fe2188fa871f1d4470378c004ad44d4216202641Ben Fennema                break;
258fe2188fa871f1d4470378c004ad44d4216202641Ben Fennema            }
259fe2188fa871f1d4470378c004ad44d4216202641Ben Fennema
2600ce3d053b7c75d4759e047653868cb1079e32252Alexey Polyudov            // receive message from FW in legacy format
261fd9c05e653cf9de55c72afb85af849f5d932e1a1Alexey Polyudov            if (ret != (int)(sizeof(msg.hdr) + len)) {
26296177b03ab7915a8abce9fcb14f61be2edab918fAlexey Polyudov                ALOGE("Expected %zu bytes, read %d bytes", sizeof(msg.hdr) + len, ret);
263fe2188fa871f1d4470378c004ad44d4216202641Ben Fennema                break;
264fe2188fa871f1d4470378c004ad44d4216202641Ben Fennema            }
265fe2188fa871f1d4470378c004ad44d4216202641Ben Fennema
26696177b03ab7915a8abce9fcb14f61be2edab918fAlexey Polyudov            ret = SystemComm::handleRx(&msg);
26796177b03ab7915a8abce9fcb14f61be2edab918fAlexey Polyudov            if (ret < 0) {
26896177b03ab7915a8abce9fcb14f61be2edab918fAlexey Polyudov                ALOGE("SystemComm::handleRx() returned %d", ret);
26996177b03ab7915a8abce9fcb14f61be2edab918fAlexey Polyudov            } else if (ret) {
270b78969e7bce5b6d57a3e6b99315f44fe77b5d2b6Alexey Polyudov                hub_app_name_t app_name = { .id = msg.hdr.appId };
27170ab6271e35d78b86a68b00b663c177230697fb5Alexey Polyudov                if (messageTracingEnabled()) {
272b78969e7bce5b6d57a3e6b99315f44fe77b5d2b6Alexey Polyudov                    dumpBuffer("DEV -> APP", app_name, msg.hdr.eventId, &msg.data[0], msg.hdr.len);
27370ab6271e35d78b86a68b00b663c177230697fb5Alexey Polyudov                }
27453d7164c9e25b417d597c102d92bae3050c149aeAlexey Polyudov                doSendToApp(HubMessage(&app_name, msg.hdr.eventId, &msg.data[0], msg.hdr.len));
27596177b03ab7915a8abce9fcb14f61be2edab918fAlexey Polyudov            }
276fe2188fa871f1d4470378c004ad44d4216202641Ben Fennema        }
277fe2188fa871f1d4470378c004ad44d4216202641Ben Fennema
27896177b03ab7915a8abce9fcb14f61be2edab918fAlexey Polyudov        if (myFds[IDX_CLOSE_PIPE].revents & POLLIN) { // we have been asked to die
279fe2188fa871f1d4470378c004ad44d4216202641Ben Fennema            ALOGD("thread exiting");
280fe2188fa871f1d4470378c004ad44d4216202641Ben Fennema            break;
281fe2188fa871f1d4470378c004ad44d4216202641Ben Fennema        }
282fe2188fa871f1d4470378c004ad44d4216202641Ben Fennema    }
283fe2188fa871f1d4470378c004ad44d4216202641Ben Fennema
284fe2188fa871f1d4470378c004ad44d4216202641Ben Fennema    close(mFd);
285fe2188fa871f1d4470378c004ad44d4216202641Ben Fennema    return NULL;
286fe2188fa871f1d4470378c004ad44d4216202641Ben Fennema}
287fe2188fa871f1d4470378c004ad44d4216202641Ben Fennema
28896177b03ab7915a8abce9fcb14f61be2edab918fAlexey Polyudovint NanoHub::openHub()
289fe2188fa871f1d4470378c004ad44d4216202641Ben Fennema{
290fe2188fa871f1d4470378c004ad44d4216202641Ben Fennema    int ret = 0;
291fe2188fa871f1d4470378c004ad44d4216202641Ben Fennema
292fe2188fa871f1d4470378c004ad44d4216202641Ben Fennema    mFd = open(get_devnode_path(), O_RDWR);
293fe2188fa871f1d4470378c004ad44d4216202641Ben Fennema    if (mFd < 0) {
294fe2188fa871f1d4470378c004ad44d4216202641Ben Fennema        ALOGE("cannot find hub devnode '%s'", get_devnode_path());
295fe2188fa871f1d4470378c004ad44d4216202641Ben Fennema        ret = -errno;
296fe2188fa871f1d4470378c004ad44d4216202641Ben Fennema        goto fail_open;
297fe2188fa871f1d4470378c004ad44d4216202641Ben Fennema    }
298fe2188fa871f1d4470378c004ad44d4216202641Ben Fennema
299fe2188fa871f1d4470378c004ad44d4216202641Ben Fennema    if (pipe(mThreadClosingPipe)) {
300fe2188fa871f1d4470378c004ad44d4216202641Ben Fennema        ALOGE("failed to create signal pipe");
301fe2188fa871f1d4470378c004ad44d4216202641Ben Fennema        ret = -errno;
302fe2188fa871f1d4470378c004ad44d4216202641Ben Fennema        goto fail_pipe;
303fe2188fa871f1d4470378c004ad44d4216202641Ben Fennema    }
304fe2188fa871f1d4470378c004ad44d4216202641Ben Fennema
30553d7164c9e25b417d597c102d92bae3050c149aeAlexey Polyudov    mPollThread = std::thread([this] { runDeviceRx(); });
30653d7164c9e25b417d597c102d92bae3050c149aeAlexey Polyudov    mAppThread = std::thread([this] { runAppTx(); });
307fe2188fa871f1d4470378c004ad44d4216202641Ben Fennema    return 0;
308fe2188fa871f1d4470378c004ad44d4216202641Ben Fennema
309fe2188fa871f1d4470378c004ad44d4216202641Ben Fennemafail_pipe:
310fe2188fa871f1d4470378c004ad44d4216202641Ben Fennema    close(mFd);
311fe2188fa871f1d4470378c004ad44d4216202641Ben Fennema
312fe2188fa871f1d4470378c004ad44d4216202641Ben Fennemafail_open:
313fe2188fa871f1d4470378c004ad44d4216202641Ben Fennema    return ret;
314fe2188fa871f1d4470378c004ad44d4216202641Ben Fennema}
315fe2188fa871f1d4470378c004ad44d4216202641Ben Fennema
31696177b03ab7915a8abce9fcb14f61be2edab918fAlexey Polyudovint NanoHub::closeHub(void)
317fe2188fa871f1d4470378c004ad44d4216202641Ben Fennema{
318fe2188fa871f1d4470378c004ad44d4216202641Ben Fennema    char zero = 0;
319fe2188fa871f1d4470378c004ad44d4216202641Ben Fennema
32053d7164c9e25b417d597c102d92bae3050c149aeAlexey Polyudov    // stop mPollThread
32153d7164c9e25b417d597c102d92bae3050c149aeAlexey Polyudov    while(write(mThreadClosingPipe[1], &zero, 1) != 1) {
32253d7164c9e25b417d597c102d92bae3050c149aeAlexey Polyudov        continue;
32353d7164c9e25b417d597c102d92bae3050c149aeAlexey Polyudov    }
32453d7164c9e25b417d597c102d92bae3050c149aeAlexey Polyudov
32553d7164c9e25b417d597c102d92bae3050c149aeAlexey Polyudov    // stop mAppThread
32653d7164c9e25b417d597c102d92bae3050c149aeAlexey Polyudov    {
32753d7164c9e25b417d597c102d92bae3050c149aeAlexey Polyudov        std::unique_lock<std::mutex> lk(mAppTxLock);
32853d7164c9e25b417d597c102d92bae3050c149aeAlexey Polyudov        mAppQuit = true;
32953d7164c9e25b417d597c102d92bae3050c149aeAlexey Polyudov        lk.unlock();
33053d7164c9e25b417d597c102d92bae3050c149aeAlexey Polyudov        mAppTxCond.notify_all();
33153d7164c9e25b417d597c102d92bae3050c149aeAlexey Polyudov    }
332fe2188fa871f1d4470378c004ad44d4216202641Ben Fennema
333fe2188fa871f1d4470378c004ad44d4216202641Ben Fennema    //wait
3347adb1a0b7ba0f6c2ef0c3e44979a382314f0ab0cAlexey Polyudov    if (mPollThread.joinable()) {
3357adb1a0b7ba0f6c2ef0c3e44979a382314f0ab0cAlexey Polyudov        mPollThread.join();
3367adb1a0b7ba0f6c2ef0c3e44979a382314f0ab0cAlexey Polyudov    }
337fe2188fa871f1d4470378c004ad44d4216202641Ben Fennema
33853d7164c9e25b417d597c102d92bae3050c149aeAlexey Polyudov    //wait
33953d7164c9e25b417d597c102d92bae3050c149aeAlexey Polyudov    if (mAppThread.joinable()) {
34053d7164c9e25b417d597c102d92bae3050c149aeAlexey Polyudov        mAppThread.join();
34153d7164c9e25b417d597c102d92bae3050c149aeAlexey Polyudov    }
342fe2188fa871f1d4470378c004ad44d4216202641Ben Fennema    //cleanup
34396177b03ab7915a8abce9fcb14f61be2edab918fAlexey Polyudov    ::close(mThreadClosingPipe[0]);
34496177b03ab7915a8abce9fcb14f61be2edab918fAlexey Polyudov    ::close(mThreadClosingPipe[1]);
3455db89a8cfee5a45e9fb8185d4c08d0f7c9d2c9a2Alexey Polyudov    ::close(mFd);
34696177b03ab7915a8abce9fcb14f61be2edab918fAlexey Polyudov
34796177b03ab7915a8abce9fcb14f61be2edab918fAlexey Polyudov    reset();
348fe2188fa871f1d4470378c004ad44d4216202641Ben Fennema
349fe2188fa871f1d4470378c004ad44d4216202641Ben Fennema    return 0;
350fe2188fa871f1d4470378c004ad44d4216202641Ben Fennema}
351fe2188fa871f1d4470378c004ad44d4216202641Ben Fennema
35296177b03ab7915a8abce9fcb14f61be2edab918fAlexey Polyudovint NanoHub::doSubscribeMessages(uint32_t hub_id, context_hub_callback *cbk, void *cookie)
353fe2188fa871f1d4470378c004ad44d4216202641Ben Fennema{
35496177b03ab7915a8abce9fcb14f61be2edab918fAlexey Polyudov    if (hub_id) {
355fe2188fa871f1d4470378c004ad44d4216202641Ben Fennema        return -ENODEV;
35696177b03ab7915a8abce9fcb14f61be2edab918fAlexey Polyudov    }
35796177b03ab7915a8abce9fcb14f61be2edab918fAlexey Polyudov
3587adb1a0b7ba0f6c2ef0c3e44979a382314f0ab0cAlexey Polyudov    std::lock_guard<std::mutex> _l(mLock);
35996177b03ab7915a8abce9fcb14f61be2edab918fAlexey Polyudov    int ret = 0;
360fe2188fa871f1d4470378c004ad44d4216202641Ben Fennema
361fe2188fa871f1d4470378c004ad44d4216202641Ben Fennema    if (!mMsgCbkFunc && !cbk) { //we're off and staying off - do nothing
362fe2188fa871f1d4470378c004ad44d4216202641Ben Fennema
363fe2188fa871f1d4470378c004ad44d4216202641Ben Fennema        ALOGD("staying off");
36496177b03ab7915a8abce9fcb14f61be2edab918fAlexey Polyudov    } else if (cbk && mMsgCbkFunc) { //new callback but staying on
365fe2188fa871f1d4470378c004ad44d4216202641Ben Fennema
366fe2188fa871f1d4470378c004ad44d4216202641Ben Fennema        ALOGD("staying on");
36796177b03ab7915a8abce9fcb14f61be2edab918fAlexey Polyudov    } else if (mMsgCbkFunc) {     //we were on but turning off
368fe2188fa871f1d4470378c004ad44d4216202641Ben Fennema
369fe2188fa871f1d4470378c004ad44d4216202641Ben Fennema        ALOGD("turning off");
370fe2188fa871f1d4470378c004ad44d4216202641Ben Fennema
37196177b03ab7915a8abce9fcb14f61be2edab918fAlexey Polyudov        ret = closeHub();
37296177b03ab7915a8abce9fcb14f61be2edab918fAlexey Polyudov    } else if (cbk) {             //we're turning on
373fe2188fa871f1d4470378c004ad44d4216202641Ben Fennema
374fe2188fa871f1d4470378c004ad44d4216202641Ben Fennema        ALOGD("turning on");
37596177b03ab7915a8abce9fcb14f61be2edab918fAlexey Polyudov        ret = openHub();
376fe2188fa871f1d4470378c004ad44d4216202641Ben Fennema    }
377fe2188fa871f1d4470378c004ad44d4216202641Ben Fennema
378fe2188fa871f1d4470378c004ad44d4216202641Ben Fennema    mMsgCbkFunc = cbk;
379fe2188fa871f1d4470378c004ad44d4216202641Ben Fennema    mMsgCbkData = cookie;
380fe2188fa871f1d4470378c004ad44d4216202641Ben Fennema
381fe2188fa871f1d4470378c004ad44d4216202641Ben Fennema    return ret;
382fe2188fa871f1d4470378c004ad44d4216202641Ben Fennema}
383fe2188fa871f1d4470378c004ad44d4216202641Ben Fennema
38496177b03ab7915a8abce9fcb14f61be2edab918fAlexey Polyudovint NanoHub::doSendToNanohub(uint32_t hub_id, const hub_message_t *msg)
385fe2188fa871f1d4470378c004ad44d4216202641Ben Fennema{
38696177b03ab7915a8abce9fcb14f61be2edab918fAlexey Polyudov    if (hub_id) {
387fe2188fa871f1d4470378c004ad44d4216202641Ben Fennema        return -ENODEV;
38896177b03ab7915a8abce9fcb14f61be2edab918fAlexey Polyudov    }
389fe2188fa871f1d4470378c004ad44d4216202641Ben Fennema
39096177b03ab7915a8abce9fcb14f61be2edab918fAlexey Polyudov    int ret = 0;
3917adb1a0b7ba0f6c2ef0c3e44979a382314f0ab0cAlexey Polyudov    std::lock_guard<std::mutex> _l(mLock);
392fe2188fa871f1d4470378c004ad44d4216202641Ben Fennema
393fe2188fa871f1d4470378c004ad44d4216202641Ben Fennema    if (!mMsgCbkFunc) {
394fe2188fa871f1d4470378c004ad44d4216202641Ben Fennema        ALOGW("refusing to send a message when nobody around to get a reply!");
395fe2188fa871f1d4470378c004ad44d4216202641Ben Fennema        ret = -EIO;
39696177b03ab7915a8abce9fcb14f61be2edab918fAlexey Polyudov    } else {
397fd9c05e653cf9de55c72afb85af849f5d932e1a1Alexey Polyudov        if (!msg || !msg->message) {
398fe2188fa871f1d4470378c004ad44d4216202641Ben Fennema            ALOGW("not sending invalid message 1");
399fe2188fa871f1d4470378c004ad44d4216202641Ben Fennema            ret = -EINVAL;
40096177b03ab7915a8abce9fcb14f61be2edab918fAlexey Polyudov        } else if (get_hub_info()->os_app_name == msg->app_name) {
401fd9c05e653cf9de55c72afb85af849f5d932e1a1Alexey Polyudov            //messages to the "system" app are special - hal handles them
40270ab6271e35d78b86a68b00b663c177230697fb5Alexey Polyudov            if (messageTracingEnabled()) {
40370ab6271e35d78b86a68b00b663c177230697fb5Alexey Polyudov                dumpBuffer("APP -> HAL", msg->app_name, msg->message_type, msg->message, msg->message_len);
40470ab6271e35d78b86a68b00b663c177230697fb5Alexey Polyudov            }
40596177b03ab7915a8abce9fcb14f61be2edab918fAlexey Polyudov            ret = SystemComm::handleTx(msg);
4060ce3d053b7c75d4759e047653868cb1079e32252Alexey Polyudov        } else if (msg->message_len > MAX_RX_PACKET) {
407fe2188fa871f1d4470378c004ad44d4216202641Ben Fennema            ALOGW("not sending invalid message 2");
408fe2188fa871f1d4470378c004ad44d4216202641Ben Fennema            ret = -EINVAL;
40996177b03ab7915a8abce9fcb14f61be2edab918fAlexey Polyudov        } else {
41070ab6271e35d78b86a68b00b663c177230697fb5Alexey Polyudov            if (messageTracingEnabled()) {
4110ce3d053b7c75d4759e047653868cb1079e32252Alexey Polyudov                dumpBuffer("APP -> DEV", msg->app_name, msg->message_type, msg->message, msg->message_len);
41270ab6271e35d78b86a68b00b663c177230697fb5Alexey Polyudov            }
413672acdeb3c63987a9a778dbcc84fe74e0fb4a5dbStephen Hines            ret = doSendToDevice(msg->app_name, msg->message, msg->message_len, msg->message_type);
414fe2188fa871f1d4470378c004ad44d4216202641Ben Fennema        }
415fe2188fa871f1d4470378c004ad44d4216202641Ben Fennema    }
416fe2188fa871f1d4470378c004ad44d4216202641Ben Fennema
417fe2188fa871f1d4470378c004ad44d4216202641Ben Fennema    return ret;
418fe2188fa871f1d4470378c004ad44d4216202641Ben Fennema}
419fe2188fa871f1d4470378c004ad44d4216202641Ben Fennema
42096177b03ab7915a8abce9fcb14f61be2edab918fAlexey Polyudovstatic int hal_get_hubs(context_hub_module_t*, const context_hub_t ** list)
421fe2188fa871f1d4470378c004ad44d4216202641Ben Fennema{
422fe2188fa871f1d4470378c004ad44d4216202641Ben Fennema    *list = get_hub_info();
423fe2188fa871f1d4470378c004ad44d4216202641Ben Fennema
424fe2188fa871f1d4470378c004ad44d4216202641Ben Fennema    return 1; /* we have one hub */
425fe2188fa871f1d4470378c004ad44d4216202641Ben Fennema}
426fe2188fa871f1d4470378c004ad44d4216202641Ben Fennema
42796177b03ab7915a8abce9fcb14f61be2edab918fAlexey Polyudov}; // namespace nanohub
42896177b03ab7915a8abce9fcb14f61be2edab918fAlexey Polyudov
42996177b03ab7915a8abce9fcb14f61be2edab918fAlexey Polyudov}; // namespace android
43096177b03ab7915a8abce9fcb14f61be2edab918fAlexey Polyudov
43196177b03ab7915a8abce9fcb14f61be2edab918fAlexey Polyudovcontext_hub_module_t HAL_MODULE_INFO_SYM = {
432fe2188fa871f1d4470378c004ad44d4216202641Ben Fennema    .common = {
433fe2188fa871f1d4470378c004ad44d4216202641Ben Fennema        .tag = HARDWARE_MODULE_TAG,
434fe2188fa871f1d4470378c004ad44d4216202641Ben Fennema        .module_api_version = CONTEXT_HUB_DEVICE_API_VERSION_1_0,
435fe2188fa871f1d4470378c004ad44d4216202641Ben Fennema        .hal_api_version = HARDWARE_HAL_API_VERSION,
436fe2188fa871f1d4470378c004ad44d4216202641Ben Fennema        .id = CONTEXT_HUB_MODULE_ID,
437fd9c05e653cf9de55c72afb85af849f5d932e1a1Alexey Polyudov        .name = "Nanohub HAL",
438fe2188fa871f1d4470378c004ad44d4216202641Ben Fennema        .author = "Google",
439fe2188fa871f1d4470378c004ad44d4216202641Ben Fennema    },
440fe2188fa871f1d4470378c004ad44d4216202641Ben Fennema
44196177b03ab7915a8abce9fcb14f61be2edab918fAlexey Polyudov    .get_hubs = android::nanohub::hal_get_hubs,
44296177b03ab7915a8abce9fcb14f61be2edab918fAlexey Polyudov    .subscribe_messages = android::nanohub::NanoHub::subscribeMessages,
44396177b03ab7915a8abce9fcb14f61be2edab918fAlexey Polyudov    .send_message = android::nanohub::NanoHub::sendToNanohub,
444fe2188fa871f1d4470378c004ad44d4216202641Ben Fennema};
445