10792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang/*
20792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang * Copyright (C) 2014 The Android Open Source Project
30792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang *
40792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang * Licensed under the Apache License, Version 2.0 (the "License");
50792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang * you may not use this file except in compliance with the License.
60792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang * You may obtain a copy of the License at
70792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang *
80792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang *      http://www.apache.org/licenses/LICENSE-2.0
90792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang *
100792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang * Unless required by applicable law or agreed to in writing, software
110792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang * distributed under the License is distributed on an "AS IS" BASIS,
120792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
130792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang * See the License for the specific language governing permissions and
140792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang * limitations under the License.
150792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang */
160792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang
170792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang#define LOG_TAG "HdmiCecControllerJni"
180792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang
190792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang#define LOG_NDEBUG 1
200792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang
218c688ada2dc256a746429b10b2e7a47a52e9b02fJinsuk Kim#include <JNIHelp.h>
228c688ada2dc256a746429b10b2e7a47a52e9b02fJinsuk Kim#include <ScopedPrimitiveArray.h>
23e9c77c88ea34a66f83a94f960547275c0ff6bd07Jungshik Jang
244085d0ef62554c7e139b82bca0f97161bb159f8cJungshik Jang#include <cstring>
250792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang
264085d0ef62554c7e139b82bca0f97161bb159f8cJungshik Jang#include <android_os_MessageQueue.h>
270792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang#include <android_runtime/AndroidRuntime.h>
280792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang#include <android_runtime/Log.h>
290792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang#include <hardware/hdmi_cec.h>
30e9c77c88ea34a66f83a94f960547275c0ff6bd07Jungshik Jang#include <sys/param.h>
314085d0ef62554c7e139b82bca0f97161bb159f8cJungshik Jang#include <utils/Looper.h>
324085d0ef62554c7e139b82bca0f97161bb159f8cJungshik Jang#include <utils/RefBase.h>
330792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang
340792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jangnamespace android {
350792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang
360792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jangstatic struct {
37e9c77c88ea34a66f83a94f960547275c0ff6bd07Jungshik Jang    jmethodID handleIncomingCecCommand;
38e9c77c88ea34a66f83a94f960547275c0ff6bd07Jungshik Jang    jmethodID handleHotplug;
390792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang} gHdmiCecControllerClassInfo;
400792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang
410792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jangclass HdmiCecController {
420792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jangpublic:
434085d0ef62554c7e139b82bca0f97161bb159f8cJungshik Jang    HdmiCecController(hdmi_cec_device_t* device, jobject callbacksObj,
444085d0ef62554c7e139b82bca0f97161bb159f8cJungshik Jang            const sp<Looper>& looper);
45e9c77c88ea34a66f83a94f960547275c0ff6bd07Jungshik Jang
46e9c77c88ea34a66f83a94f960547275c0ff6bd07Jungshik Jang    void init();
47e9c77c88ea34a66f83a94f960547275c0ff6bd07Jungshik Jang
48e9c77c88ea34a66f83a94f960547275c0ff6bd07Jungshik Jang    // Send message to other device. Note that it runs in IO thread.
49e9c77c88ea34a66f83a94f960547275c0ff6bd07Jungshik Jang    int sendMessage(const cec_message_t& message);
50a9095ba488ea18aeafaf9c3a8258bf9f459bda71Jungshik Jang    // Add a logical address to device.
51a9095ba488ea18aeafaf9c3a8258bf9f459bda71Jungshik Jang    int addLogicalAddress(cec_logical_address_t address);
52a9095ba488ea18aeafaf9c3a8258bf9f459bda71Jungshik Jang    // Clear all logical address registered to the device.
53a9095ba488ea18aeafaf9c3a8258bf9f459bda71Jungshik Jang    void clearLogicaladdress();
54a9095ba488ea18aeafaf9c3a8258bf9f459bda71Jungshik Jang    // Get physical address of device.
55a9095ba488ea18aeafaf9c3a8258bf9f459bda71Jungshik Jang    int getPhysicalAddress();
56a9095ba488ea18aeafaf9c3a8258bf9f459bda71Jungshik Jang    // Get CEC version from driver.
57a9095ba488ea18aeafaf9c3a8258bf9f459bda71Jungshik Jang    int getVersion();
58a9095ba488ea18aeafaf9c3a8258bf9f459bda71Jungshik Jang    // Get vendor id used for vendor command.
59a9095ba488ea18aeafaf9c3a8258bf9f459bda71Jungshik Jang    uint32_t getVendorId();
600340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim    // Get Port information on all the HDMI ports.
610340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim    jobjectArray getPortInfos();
62092b445ef898e3c1e5b2918b554480940f0f5a28Jungshik Jang    // Set a flag and its value.
63092b445ef898e3c1e5b2918b554480940f0f5a28Jungshik Jang    void setOption(int flag, int value);
64092b445ef898e3c1e5b2918b554480940f0f5a28Jungshik Jang    // Set audio return channel status.
651481a4282818939436f590d8c88aea2d19166b8eJinsuk Kim    void setAudioReturnChannel(int port, bool flag);
66092b445ef898e3c1e5b2918b554480940f0f5a28Jungshik Jang    // Whether to hdmi device is connected to the given port.
67092b445ef898e3c1e5b2918b554480940f0f5a28Jungshik Jang    bool isConnected(int port);
680792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang
694085d0ef62554c7e139b82bca0f97161bb159f8cJungshik Jang    jobject getCallbacksObj() const {
704085d0ef62554c7e139b82bca0f97161bb159f8cJungshik Jang        return mCallbacksObj;
714085d0ef62554c7e139b82bca0f97161bb159f8cJungshik Jang    }
72e9c77c88ea34a66f83a94f960547275c0ff6bd07Jungshik Jang
734085d0ef62554c7e139b82bca0f97161bb159f8cJungshik Jangprivate:
74a6ce7708d6124224399241503fadcafe0c4684d4Jinsuk Kim    static const int INVALID_PHYSICAL_ADDRESS = 0xFFFF;
750792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang    static void onReceived(const hdmi_event_t* event, void* arg);
760792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang
77e9c77c88ea34a66f83a94f960547275c0ff6bd07Jungshik Jang    hdmi_cec_device_t* mDevice;
780792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang    jobject mCallbacksObj;
794085d0ef62554c7e139b82bca0f97161bb159f8cJungshik Jang    sp<Looper> mLooper;
800792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang};
810792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang
824085d0ef62554c7e139b82bca0f97161bb159f8cJungshik Jang// RefBase wrapper for hdmi_event_t. As hdmi_event_t coming from HAL
834085d0ef62554c7e139b82bca0f97161bb159f8cJungshik Jang// may keep its own lifetime, we need to copy it in order to delegate
844085d0ef62554c7e139b82bca0f97161bb159f8cJungshik Jang// it to service thread.
854085d0ef62554c7e139b82bca0f97161bb159f8cJungshik Jangclass CecEventWrapper : public LightRefBase<CecEventWrapper> {
864085d0ef62554c7e139b82bca0f97161bb159f8cJungshik Jangpublic:
874085d0ef62554c7e139b82bca0f97161bb159f8cJungshik Jang    CecEventWrapper(const hdmi_event_t& event) {
884085d0ef62554c7e139b82bca0f97161bb159f8cJungshik Jang        // Copy message.
894085d0ef62554c7e139b82bca0f97161bb159f8cJungshik Jang        switch (event.type) {
904085d0ef62554c7e139b82bca0f97161bb159f8cJungshik Jang        case HDMI_EVENT_CEC_MESSAGE:
914085d0ef62554c7e139b82bca0f97161bb159f8cJungshik Jang            mEvent.cec.initiator = event.cec.initiator;
924085d0ef62554c7e139b82bca0f97161bb159f8cJungshik Jang            mEvent.cec.destination = event.cec.destination;
934085d0ef62554c7e139b82bca0f97161bb159f8cJungshik Jang            mEvent.cec.length = event.cec.length;
944085d0ef62554c7e139b82bca0f97161bb159f8cJungshik Jang            std::memcpy(mEvent.cec.body, event.cec.body, event.cec.length);
954085d0ef62554c7e139b82bca0f97161bb159f8cJungshik Jang            break;
964085d0ef62554c7e139b82bca0f97161bb159f8cJungshik Jang        case HDMI_EVENT_HOT_PLUG:
974085d0ef62554c7e139b82bca0f97161bb159f8cJungshik Jang            mEvent.hotplug.connected = event.hotplug.connected;
98284c31b92e4e0d0b8095ae50c61db9c83c9d577cJinsuk Kim            mEvent.hotplug.port_id = event.hotplug.port_id;
994085d0ef62554c7e139b82bca0f97161bb159f8cJungshik Jang            break;
1004085d0ef62554c7e139b82bca0f97161bb159f8cJungshik Jang        default:
1014085d0ef62554c7e139b82bca0f97161bb159f8cJungshik Jang            // TODO: add more type whenever new type is introduced.
1024085d0ef62554c7e139b82bca0f97161bb159f8cJungshik Jang            break;
1034085d0ef62554c7e139b82bca0f97161bb159f8cJungshik Jang        }
1044085d0ef62554c7e139b82bca0f97161bb159f8cJungshik Jang    }
1050792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang
1064085d0ef62554c7e139b82bca0f97161bb159f8cJungshik Jang    const cec_message_t& cec() const {
1074085d0ef62554c7e139b82bca0f97161bb159f8cJungshik Jang        return mEvent.cec;
1084085d0ef62554c7e139b82bca0f97161bb159f8cJungshik Jang    }
109e9c77c88ea34a66f83a94f960547275c0ff6bd07Jungshik Jang
1104085d0ef62554c7e139b82bca0f97161bb159f8cJungshik Jang    const hotplug_event_t& hotplug() const {
1114085d0ef62554c7e139b82bca0f97161bb159f8cJungshik Jang        return mEvent.hotplug;
1124085d0ef62554c7e139b82bca0f97161bb159f8cJungshik Jang    }
113e9c77c88ea34a66f83a94f960547275c0ff6bd07Jungshik Jang
1144085d0ef62554c7e139b82bca0f97161bb159f8cJungshik Jang    virtual ~CecEventWrapper() {}
115e9c77c88ea34a66f83a94f960547275c0ff6bd07Jungshik Jang
1164085d0ef62554c7e139b82bca0f97161bb159f8cJungshik Jangprivate:
1174085d0ef62554c7e139b82bca0f97161bb159f8cJungshik Jang    hdmi_event_t mEvent;
1184085d0ef62554c7e139b82bca0f97161bb159f8cJungshik Jang};
119e9c77c88ea34a66f83a94f960547275c0ff6bd07Jungshik Jang
1204085d0ef62554c7e139b82bca0f97161bb159f8cJungshik Jang// Handler class to delegate incoming message to service thread.
1214085d0ef62554c7e139b82bca0f97161bb159f8cJungshik Jangclass HdmiCecEventHandler : public MessageHandler {
1224085d0ef62554c7e139b82bca0f97161bb159f8cJungshik Jangpublic:
1234085d0ef62554c7e139b82bca0f97161bb159f8cJungshik Jang    HdmiCecEventHandler(HdmiCecController* controller, const sp<CecEventWrapper>& event)
1244085d0ef62554c7e139b82bca0f97161bb159f8cJungshik Jang        : mController(controller),
1254085d0ef62554c7e139b82bca0f97161bb159f8cJungshik Jang          mEventWrapper(event) {
1264085d0ef62554c7e139b82bca0f97161bb159f8cJungshik Jang    }
1274085d0ef62554c7e139b82bca0f97161bb159f8cJungshik Jang
1284085d0ef62554c7e139b82bca0f97161bb159f8cJungshik Jang    virtual ~HdmiCecEventHandler() {}
1294085d0ef62554c7e139b82bca0f97161bb159f8cJungshik Jang
1304085d0ef62554c7e139b82bca0f97161bb159f8cJungshik Jang    void handleMessage(const Message& message) {
1314085d0ef62554c7e139b82bca0f97161bb159f8cJungshik Jang        switch (message.what) {
1324085d0ef62554c7e139b82bca0f97161bb159f8cJungshik Jang        case HDMI_EVENT_CEC_MESSAGE:
1334085d0ef62554c7e139b82bca0f97161bb159f8cJungshik Jang            propagateCecCommand(mEventWrapper->cec());
1344085d0ef62554c7e139b82bca0f97161bb159f8cJungshik Jang            break;
1354085d0ef62554c7e139b82bca0f97161bb159f8cJungshik Jang        case HDMI_EVENT_HOT_PLUG:
1364085d0ef62554c7e139b82bca0f97161bb159f8cJungshik Jang            propagateHotplugEvent(mEventWrapper->hotplug());
1374085d0ef62554c7e139b82bca0f97161bb159f8cJungshik Jang            break;
1384085d0ef62554c7e139b82bca0f97161bb159f8cJungshik Jang        default:
1394085d0ef62554c7e139b82bca0f97161bb159f8cJungshik Jang            // TODO: add more type whenever new type is introduced.
1404085d0ef62554c7e139b82bca0f97161bb159f8cJungshik Jang            break;
1414085d0ef62554c7e139b82bca0f97161bb159f8cJungshik Jang        }
1424085d0ef62554c7e139b82bca0f97161bb159f8cJungshik Jang    }
143e9c77c88ea34a66f83a94f960547275c0ff6bd07Jungshik Jang
1444085d0ef62554c7e139b82bca0f97161bb159f8cJungshik Jangprivate:
1454085d0ef62554c7e139b82bca0f97161bb159f8cJungshik Jang    // Propagate the message up to Java layer.
1464085d0ef62554c7e139b82bca0f97161bb159f8cJungshik Jang    void propagateCecCommand(const cec_message_t& message) {
1474085d0ef62554c7e139b82bca0f97161bb159f8cJungshik Jang        jint srcAddr = message.initiator;
1484085d0ef62554c7e139b82bca0f97161bb159f8cJungshik Jang        jint dstAddr = message.destination;
1494085d0ef62554c7e139b82bca0f97161bb159f8cJungshik Jang        JNIEnv* env = AndroidRuntime::getJNIEnv();
1504085d0ef62554c7e139b82bca0f97161bb159f8cJungshik Jang        jbyteArray body = env->NewByteArray(message.length);
1514085d0ef62554c7e139b82bca0f97161bb159f8cJungshik Jang        const jbyte* bodyPtr = reinterpret_cast<const jbyte *>(message.body);
1524085d0ef62554c7e139b82bca0f97161bb159f8cJungshik Jang        env->SetByteArrayRegion(body, 0, message.length, bodyPtr);
1534085d0ef62554c7e139b82bca0f97161bb159f8cJungshik Jang
1544085d0ef62554c7e139b82bca0f97161bb159f8cJungshik Jang        env->CallVoidMethod(mController->getCallbacksObj(),
1554085d0ef62554c7e139b82bca0f97161bb159f8cJungshik Jang                gHdmiCecControllerClassInfo.handleIncomingCecCommand, srcAddr,
1564085d0ef62554c7e139b82bca0f97161bb159f8cJungshik Jang                dstAddr, body);
1574085d0ef62554c7e139b82bca0f97161bb159f8cJungshik Jang        env->DeleteLocalRef(body);
1584085d0ef62554c7e139b82bca0f97161bb159f8cJungshik Jang
1594085d0ef62554c7e139b82bca0f97161bb159f8cJungshik Jang        checkAndClearExceptionFromCallback(env, __FUNCTION__);
1604085d0ef62554c7e139b82bca0f97161bb159f8cJungshik Jang    }
1614085d0ef62554c7e139b82bca0f97161bb159f8cJungshik Jang
1624085d0ef62554c7e139b82bca0f97161bb159f8cJungshik Jang    void propagateHotplugEvent(const hotplug_event_t& event) {
1634085d0ef62554c7e139b82bca0f97161bb159f8cJungshik Jang        // Note that this method should be called in service thread.
1644085d0ef62554c7e139b82bca0f97161bb159f8cJungshik Jang        JNIEnv* env = AndroidRuntime::getJNIEnv();
165284c31b92e4e0d0b8095ae50c61db9c83c9d577cJinsuk Kim        jint port = event.port_id;
16642230728b8212738c2351939c5577730f05a58deJungshik Jang        jboolean connected = (jboolean) event.connected;
1674085d0ef62554c7e139b82bca0f97161bb159f8cJungshik Jang        env->CallVoidMethod(mController->getCallbacksObj(),
16842230728b8212738c2351939c5577730f05a58deJungshik Jang                gHdmiCecControllerClassInfo.handleHotplug, port, connected);
1694085d0ef62554c7e139b82bca0f97161bb159f8cJungshik Jang
1704085d0ef62554c7e139b82bca0f97161bb159f8cJungshik Jang        checkAndClearExceptionFromCallback(env, __FUNCTION__);
1714085d0ef62554c7e139b82bca0f97161bb159f8cJungshik Jang    }
1724085d0ef62554c7e139b82bca0f97161bb159f8cJungshik Jang
1734085d0ef62554c7e139b82bca0f97161bb159f8cJungshik Jang    // static
1744085d0ef62554c7e139b82bca0f97161bb159f8cJungshik Jang    static void checkAndClearExceptionFromCallback(JNIEnv* env, const char* methodName) {
1754085d0ef62554c7e139b82bca0f97161bb159f8cJungshik Jang        if (env->ExceptionCheck()) {
1764085d0ef62554c7e139b82bca0f97161bb159f8cJungshik Jang            ALOGE("An exception was thrown by callback '%s'.", methodName);
1774085d0ef62554c7e139b82bca0f97161bb159f8cJungshik Jang            LOGE_EX(env);
1784085d0ef62554c7e139b82bca0f97161bb159f8cJungshik Jang            env->ExceptionClear();
1794085d0ef62554c7e139b82bca0f97161bb159f8cJungshik Jang        }
1804085d0ef62554c7e139b82bca0f97161bb159f8cJungshik Jang    }
1814085d0ef62554c7e139b82bca0f97161bb159f8cJungshik Jang
1824085d0ef62554c7e139b82bca0f97161bb159f8cJungshik Jang    HdmiCecController* mController;
1834085d0ef62554c7e139b82bca0f97161bb159f8cJungshik Jang    sp<CecEventWrapper> mEventWrapper;
1844085d0ef62554c7e139b82bca0f97161bb159f8cJungshik Jang};
1854085d0ef62554c7e139b82bca0f97161bb159f8cJungshik Jang
1864085d0ef62554c7e139b82bca0f97161bb159f8cJungshik JangHdmiCecController::HdmiCecController(hdmi_cec_device_t* device,
1874085d0ef62554c7e139b82bca0f97161bb159f8cJungshik Jang        jobject callbacksObj, const sp<Looper>& looper) :
1884085d0ef62554c7e139b82bca0f97161bb159f8cJungshik Jang    mDevice(device),
1894085d0ef62554c7e139b82bca0f97161bb159f8cJungshik Jang    mCallbacksObj(callbacksObj),
1904085d0ef62554c7e139b82bca0f97161bb159f8cJungshik Jang    mLooper(looper) {
1914085d0ef62554c7e139b82bca0f97161bb159f8cJungshik Jang}
1924085d0ef62554c7e139b82bca0f97161bb159f8cJungshik Jang
1934085d0ef62554c7e139b82bca0f97161bb159f8cJungshik Jangvoid HdmiCecController::init() {
1944085d0ef62554c7e139b82bca0f97161bb159f8cJungshik Jang    mDevice->register_event_callback(mDevice, HdmiCecController::onReceived, this);
195e9c77c88ea34a66f83a94f960547275c0ff6bd07Jungshik Jang}
196e9c77c88ea34a66f83a94f960547275c0ff6bd07Jungshik Jang
197e9c77c88ea34a66f83a94f960547275c0ff6bd07Jungshik Jangint HdmiCecController::sendMessage(const cec_message_t& message) {
198e9c77c88ea34a66f83a94f960547275c0ff6bd07Jungshik Jang    // TODO: propagate send_message's return value.
199e9c77c88ea34a66f83a94f960547275c0ff6bd07Jungshik Jang    return mDevice->send_message(mDevice, &message);
200e9c77c88ea34a66f83a94f960547275c0ff6bd07Jungshik Jang}
201e9c77c88ea34a66f83a94f960547275c0ff6bd07Jungshik Jang
202a9095ba488ea18aeafaf9c3a8258bf9f459bda71Jungshik Jangint HdmiCecController::addLogicalAddress(cec_logical_address_t address) {
203a9095ba488ea18aeafaf9c3a8258bf9f459bda71Jungshik Jang    return mDevice->add_logical_address(mDevice, address);
204a9095ba488ea18aeafaf9c3a8258bf9f459bda71Jungshik Jang}
205a9095ba488ea18aeafaf9c3a8258bf9f459bda71Jungshik Jang
206a9095ba488ea18aeafaf9c3a8258bf9f459bda71Jungshik Jangvoid HdmiCecController::clearLogicaladdress() {
207a9095ba488ea18aeafaf9c3a8258bf9f459bda71Jungshik Jang    mDevice->clear_logical_address(mDevice);
208a9095ba488ea18aeafaf9c3a8258bf9f459bda71Jungshik Jang}
209a9095ba488ea18aeafaf9c3a8258bf9f459bda71Jungshik Jang
210a9095ba488ea18aeafaf9c3a8258bf9f459bda71Jungshik Jangint HdmiCecController::getPhysicalAddress() {
211a6ce7708d6124224399241503fadcafe0c4684d4Jinsuk Kim    uint16_t addr;
212a6ce7708d6124224399241503fadcafe0c4684d4Jinsuk Kim    if (!mDevice->get_physical_address(mDevice, &addr)) {
213a6ce7708d6124224399241503fadcafe0c4684d4Jinsuk Kim        return addr;
214a9095ba488ea18aeafaf9c3a8258bf9f459bda71Jungshik Jang    }
215a6ce7708d6124224399241503fadcafe0c4684d4Jinsuk Kim    return INVALID_PHYSICAL_ADDRESS;
216a9095ba488ea18aeafaf9c3a8258bf9f459bda71Jungshik Jang}
217a9095ba488ea18aeafaf9c3a8258bf9f459bda71Jungshik Jang
218a9095ba488ea18aeafaf9c3a8258bf9f459bda71Jungshik Jangint HdmiCecController::getVersion() {
219a9095ba488ea18aeafaf9c3a8258bf9f459bda71Jungshik Jang    int version = 0;
220a9095ba488ea18aeafaf9c3a8258bf9f459bda71Jungshik Jang    mDevice->get_version(mDevice, &version);
221a9095ba488ea18aeafaf9c3a8258bf9f459bda71Jungshik Jang    return version;
222a9095ba488ea18aeafaf9c3a8258bf9f459bda71Jungshik Jang}
223a9095ba488ea18aeafaf9c3a8258bf9f459bda71Jungshik Jang
224a9095ba488ea18aeafaf9c3a8258bf9f459bda71Jungshik Janguint32_t HdmiCecController::getVendorId() {
225a9095ba488ea18aeafaf9c3a8258bf9f459bda71Jungshik Jang    uint32_t vendorId = 0;
226a9095ba488ea18aeafaf9c3a8258bf9f459bda71Jungshik Jang    mDevice->get_vendor_id(mDevice, &vendorId);
227a9095ba488ea18aeafaf9c3a8258bf9f459bda71Jungshik Jang    return vendorId;
228a9095ba488ea18aeafaf9c3a8258bf9f459bda71Jungshik Jang}
229a9095ba488ea18aeafaf9c3a8258bf9f459bda71Jungshik Jang
2300340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk KimjobjectArray HdmiCecController::getPortInfos() {
2310340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim    JNIEnv* env = AndroidRuntime::getJNIEnv();
23263dd3bb3602bc00557680432b08b49a5a15bcdb7Jinsuk Kim    jclass hdmiPortInfo = env->FindClass("android/hardware/hdmi/HdmiPortInfo");
2330340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim    if (hdmiPortInfo == NULL) {
2340340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim        return NULL;
2350340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim    }
2360340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim    jmethodID ctor = env->GetMethodID(hdmiPortInfo, "<init>", "(IIIZZZ)V");
2370340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim    if (ctor == NULL) {
2380340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim        return NULL;
2390340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim    }
2400340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim    hdmi_port_info* ports;
2410340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim    int numPorts;
2420340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim    mDevice->get_port_info(mDevice, &ports, &numPorts);
2430340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim    jobjectArray res = env->NewObjectArray(numPorts, hdmiPortInfo, NULL);
2440340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim
2450340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim    // MHL support field will be obtained from MHL HAL. Leave it to false.
2460340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim    jboolean mhlSupported = (jboolean) 0;
2470340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim    for (int i = 0; i < numPorts; ++i) {
2480340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim        hdmi_port_info* info = &ports[i];
2490340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim        jboolean cecSupported = (jboolean) info->cec_supported;
2500340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim        jboolean arcSupported = (jboolean) info->arc_supported;
251284c31b92e4e0d0b8095ae50c61db9c83c9d577cJinsuk Kim        jobject infoObj = env->NewObject(hdmiPortInfo, ctor, info->port_id, info->type,
2520340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim                info->physical_address, cecSupported, mhlSupported, arcSupported);
2530340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim        env->SetObjectArrayElement(res, i, infoObj);
2540340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim    }
2550340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim    return res;
2560340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim}
2570340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim
258092b445ef898e3c1e5b2918b554480940f0f5a28Jungshik Jangvoid HdmiCecController::setOption(int flag, int value) {
259092b445ef898e3c1e5b2918b554480940f0f5a28Jungshik Jang    mDevice->set_option(mDevice, flag, value);
260092b445ef898e3c1e5b2918b554480940f0f5a28Jungshik Jang}
261092b445ef898e3c1e5b2918b554480940f0f5a28Jungshik Jang
262092b445ef898e3c1e5b2918b554480940f0f5a28Jungshik Jang// Set audio return channel status.
2631481a4282818939436f590d8c88aea2d19166b8eJinsuk Kim  void HdmiCecController::setAudioReturnChannel(int port, bool enabled) {
2641481a4282818939436f590d8c88aea2d19166b8eJinsuk Kim    mDevice->set_audio_return_channel(mDevice, port, enabled ? 1 : 0);
265092b445ef898e3c1e5b2918b554480940f0f5a28Jungshik Jang}
266092b445ef898e3c1e5b2918b554480940f0f5a28Jungshik Jang
267092b445ef898e3c1e5b2918b554480940f0f5a28Jungshik Jang// Whether to hdmi device is connected to the given port.
268092b445ef898e3c1e5b2918b554480940f0f5a28Jungshik Jangbool HdmiCecController::isConnected(int port) {
269092b445ef898e3c1e5b2918b554480940f0f5a28Jungshik Jang    return mDevice->is_connected(mDevice, port) == HDMI_CONNECTED;
270092b445ef898e3c1e5b2918b554480940f0f5a28Jungshik Jang}
271092b445ef898e3c1e5b2918b554480940f0f5a28Jungshik Jang
2720792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang// static
2730792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jangvoid HdmiCecController::onReceived(const hdmi_event_t* event, void* arg) {
274e9c77c88ea34a66f83a94f960547275c0ff6bd07Jungshik Jang    HdmiCecController* controller = static_cast<HdmiCecController*>(arg);
275e9c77c88ea34a66f83a94f960547275c0ff6bd07Jungshik Jang    if (controller == NULL) {
2760792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang        return;
2770792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang    }
2780792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang
2794085d0ef62554c7e139b82bca0f97161bb159f8cJungshik Jang    sp<CecEventWrapper> spEvent(new CecEventWrapper(*event));
2804085d0ef62554c7e139b82bca0f97161bb159f8cJungshik Jang    sp<HdmiCecEventHandler> handler(new HdmiCecEventHandler(controller, spEvent));
2814085d0ef62554c7e139b82bca0f97161bb159f8cJungshik Jang    controller->mLooper->sendMessage(handler, event->type);
2820792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang}
2830792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang
2840792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang//------------------------------------------------------------------------------
285e9c77c88ea34a66f83a94f960547275c0ff6bd07Jungshik Jang#define GET_METHOD_ID(var, clazz, methodName, methodDescriptor) \
286e9c77c88ea34a66f83a94f960547275c0ff6bd07Jungshik Jang        var = env->GetMethodID(clazz, methodName, methodDescriptor); \
287e9c77c88ea34a66f83a94f960547275c0ff6bd07Jungshik Jang        LOG_FATAL_IF(! var, "Unable to find method " methodName);
288e9c77c88ea34a66f83a94f960547275c0ff6bd07Jungshik Jang
2894085d0ef62554c7e139b82bca0f97161bb159f8cJungshik Jangstatic jlong nativeInit(JNIEnv* env, jclass clazz, jobject callbacksObj,
2904085d0ef62554c7e139b82bca0f97161bb159f8cJungshik Jang        jobject messageQueueObj) {
291e9c77c88ea34a66f83a94f960547275c0ff6bd07Jungshik Jang    int err;
292e9c77c88ea34a66f83a94f960547275c0ff6bd07Jungshik Jang    hw_module_t* module;
2934085d0ef62554c7e139b82bca0f97161bb159f8cJungshik Jang    err = hw_get_module(HDMI_CEC_HARDWARE_MODULE_ID,
294e9c77c88ea34a66f83a94f960547275c0ff6bd07Jungshik Jang            const_cast<const hw_module_t **>(&module));
295e9c77c88ea34a66f83a94f960547275c0ff6bd07Jungshik Jang    if (err != 0) {
296e9c77c88ea34a66f83a94f960547275c0ff6bd07Jungshik Jang        ALOGE("Error acquiring hardware module: %d", err);
297e9c77c88ea34a66f83a94f960547275c0ff6bd07Jungshik Jang        return 0;
298e9c77c88ea34a66f83a94f960547275c0ff6bd07Jungshik Jang    }
2994085d0ef62554c7e139b82bca0f97161bb159f8cJungshik Jang
300e9c77c88ea34a66f83a94f960547275c0ff6bd07Jungshik Jang    hw_device_t* device;
3014085d0ef62554c7e139b82bca0f97161bb159f8cJungshik Jang    err = module->methods->open(module, HDMI_CEC_HARDWARE_INTERFACE, &device);
302e9c77c88ea34a66f83a94f960547275c0ff6bd07Jungshik Jang    if (err != 0) {
303e9c77c88ea34a66f83a94f960547275c0ff6bd07Jungshik Jang        ALOGE("Error opening hardware module: %d", err);
304e9c77c88ea34a66f83a94f960547275c0ff6bd07Jungshik Jang        return 0;
305e9c77c88ea34a66f83a94f960547275c0ff6bd07Jungshik Jang    }
3060792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang
3074085d0ef62554c7e139b82bca0f97161bb159f8cJungshik Jang    sp<MessageQueue> messageQueue =
3084085d0ef62554c7e139b82bca0f97161bb159f8cJungshik Jang            android_os_MessageQueue_getMessageQueue(env, messageQueueObj);
3094085d0ef62554c7e139b82bca0f97161bb159f8cJungshik Jang
3100792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang    HdmiCecController* controller = new HdmiCecController(
311e9c77c88ea34a66f83a94f960547275c0ff6bd07Jungshik Jang            reinterpret_cast<hdmi_cec_device*>(device),
3124085d0ef62554c7e139b82bca0f97161bb159f8cJungshik Jang            env->NewGlobalRef(callbacksObj),
3134085d0ef62554c7e139b82bca0f97161bb159f8cJungshik Jang            messageQueue->getLooper());
314e9c77c88ea34a66f83a94f960547275c0ff6bd07Jungshik Jang    controller->init();
315e9c77c88ea34a66f83a94f960547275c0ff6bd07Jungshik Jang
316e9c77c88ea34a66f83a94f960547275c0ff6bd07Jungshik Jang    GET_METHOD_ID(gHdmiCecControllerClassInfo.handleIncomingCecCommand, clazz,
317e9c77c88ea34a66f83a94f960547275c0ff6bd07Jungshik Jang            "handleIncomingCecCommand", "(II[B)V");
318e9c77c88ea34a66f83a94f960547275c0ff6bd07Jungshik Jang    GET_METHOD_ID(gHdmiCecControllerClassInfo.handleHotplug, clazz,
31942230728b8212738c2351939c5577730f05a58deJungshik Jang            "handleHotplug", "(IZ)V");
3200792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang
3210792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang    return reinterpret_cast<jlong>(controller);
3220792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang}
3230792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang
324e9c77c88ea34a66f83a94f960547275c0ff6bd07Jungshik Jangstatic jint nativeSendCecCommand(JNIEnv* env, jclass clazz, jlong controllerPtr,
325e9c77c88ea34a66f83a94f960547275c0ff6bd07Jungshik Jang        jint srcAddr, jint dstAddr, jbyteArray body) {
326e9c77c88ea34a66f83a94f960547275c0ff6bd07Jungshik Jang    cec_message_t message;
327e9c77c88ea34a66f83a94f960547275c0ff6bd07Jungshik Jang    message.initiator = static_cast<cec_logical_address_t>(srcAddr);
328e9c77c88ea34a66f83a94f960547275c0ff6bd07Jungshik Jang    message.destination = static_cast<cec_logical_address_t>(dstAddr);
329e9c77c88ea34a66f83a94f960547275c0ff6bd07Jungshik Jang
330e9c77c88ea34a66f83a94f960547275c0ff6bd07Jungshik Jang    jsize len = env->GetArrayLength(body);
331e9c77c88ea34a66f83a94f960547275c0ff6bd07Jungshik Jang    message.length = MIN(len, CEC_MESSAGE_BODY_MAX_LENGTH);
332e9c77c88ea34a66f83a94f960547275c0ff6bd07Jungshik Jang    ScopedByteArrayRO bodyPtr(env, body);
333d0efcbbbb5145da42beafd36f86a6d90047ce9afJae Seo    std::memcpy(message.body, bodyPtr.get(), message.length);
334e9c77c88ea34a66f83a94f960547275c0ff6bd07Jungshik Jang
335e9c77c88ea34a66f83a94f960547275c0ff6bd07Jungshik Jang    HdmiCecController* controller =
336e9c77c88ea34a66f83a94f960547275c0ff6bd07Jungshik Jang            reinterpret_cast<HdmiCecController*>(controllerPtr);
337e9c77c88ea34a66f83a94f960547275c0ff6bd07Jungshik Jang    return controller->sendMessage(message);
338e9c77c88ea34a66f83a94f960547275c0ff6bd07Jungshik Jang}
339e9c77c88ea34a66f83a94f960547275c0ff6bd07Jungshik Jang
340a6ce7708d6124224399241503fadcafe0c4684d4Jinsuk Kimstatic jint nativeAddLogicalAddress(JNIEnv* env, jclass clazz, jlong controllerPtr,
341a6ce7708d6124224399241503fadcafe0c4684d4Jinsuk Kim        jint logicalAddress) {
342a6ce7708d6124224399241503fadcafe0c4684d4Jinsuk Kim    HdmiCecController* controller = reinterpret_cast<HdmiCecController*>(controllerPtr);
343a6ce7708d6124224399241503fadcafe0c4684d4Jinsuk Kim    return controller->addLogicalAddress(static_cast<cec_logical_address_t>(logicalAddress));
344a9095ba488ea18aeafaf9c3a8258bf9f459bda71Jungshik Jang}
345a9095ba488ea18aeafaf9c3a8258bf9f459bda71Jungshik Jang
346a6ce7708d6124224399241503fadcafe0c4684d4Jinsuk Kimstatic void nativeClearLogicalAddress(JNIEnv* env, jclass clazz, jlong controllerPtr) {
347a6ce7708d6124224399241503fadcafe0c4684d4Jinsuk Kim    HdmiCecController* controller = reinterpret_cast<HdmiCecController*>(controllerPtr);
348a9095ba488ea18aeafaf9c3a8258bf9f459bda71Jungshik Jang    controller->clearLogicaladdress();
349a9095ba488ea18aeafaf9c3a8258bf9f459bda71Jungshik Jang}
350a9095ba488ea18aeafaf9c3a8258bf9f459bda71Jungshik Jang
351a6ce7708d6124224399241503fadcafe0c4684d4Jinsuk Kimstatic jint nativeGetPhysicalAddress(JNIEnv* env, jclass clazz, jlong controllerPtr) {
352a6ce7708d6124224399241503fadcafe0c4684d4Jinsuk Kim    HdmiCecController* controller = reinterpret_cast<HdmiCecController*>(controllerPtr);
353a9095ba488ea18aeafaf9c3a8258bf9f459bda71Jungshik Jang    return controller->getPhysicalAddress();
354a9095ba488ea18aeafaf9c3a8258bf9f459bda71Jungshik Jang}
355a9095ba488ea18aeafaf9c3a8258bf9f459bda71Jungshik Jang
356a6ce7708d6124224399241503fadcafe0c4684d4Jinsuk Kimstatic jint nativeGetVersion(JNIEnv* env, jclass clazz, jlong controllerPtr) {
357a6ce7708d6124224399241503fadcafe0c4684d4Jinsuk Kim    HdmiCecController* controller = reinterpret_cast<HdmiCecController*>(controllerPtr);
358a9095ba488ea18aeafaf9c3a8258bf9f459bda71Jungshik Jang    return controller->getVersion();
359a9095ba488ea18aeafaf9c3a8258bf9f459bda71Jungshik Jang}
360a9095ba488ea18aeafaf9c3a8258bf9f459bda71Jungshik Jang
361a9095ba488ea18aeafaf9c3a8258bf9f459bda71Jungshik Jangstatic jint nativeGetVendorId(JNIEnv* env, jclass clazz, jlong controllerPtr) {
362a6ce7708d6124224399241503fadcafe0c4684d4Jinsuk Kim    HdmiCecController* controller = reinterpret_cast<HdmiCecController*>(controllerPtr);
363a9095ba488ea18aeafaf9c3a8258bf9f459bda71Jungshik Jang    return controller->getVendorId();
364a9095ba488ea18aeafaf9c3a8258bf9f459bda71Jungshik Jang}
365a9095ba488ea18aeafaf9c3a8258bf9f459bda71Jungshik Jang
3660340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kimstatic jobjectArray nativeGetPortInfos(JNIEnv* env, jclass clazz, jlong controllerPtr) {
3670340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim    HdmiCecController* controller = reinterpret_cast<HdmiCecController*>(controllerPtr);
3680340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim    return controller->getPortInfos();
3690340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim}
3700340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim
371a6ce7708d6124224399241503fadcafe0c4684d4Jinsuk Kimstatic void nativeSetOption(JNIEnv* env, jclass clazz, jlong controllerPtr, jint flag, jint value) {
372a6ce7708d6124224399241503fadcafe0c4684d4Jinsuk Kim    HdmiCecController* controller = reinterpret_cast<HdmiCecController*>(controllerPtr);
373092b445ef898e3c1e5b2918b554480940f0f5a28Jungshik Jang    controller->setOption(flag, value);
374092b445ef898e3c1e5b2918b554480940f0f5a28Jungshik Jang}
375092b445ef898e3c1e5b2918b554480940f0f5a28Jungshik Jang
376092b445ef898e3c1e5b2918b554480940f0f5a28Jungshik Jangstatic void nativeSetAudioReturnChannel(JNIEnv* env, jclass clazz, jlong controllerPtr,
3771481a4282818939436f590d8c88aea2d19166b8eJinsuk Kim        jint port, jboolean enabled) {
378a6ce7708d6124224399241503fadcafe0c4684d4Jinsuk Kim    HdmiCecController* controller = reinterpret_cast<HdmiCecController*>(controllerPtr);
3791481a4282818939436f590d8c88aea2d19166b8eJinsuk Kim    controller->setAudioReturnChannel(port, enabled == JNI_TRUE);
380092b445ef898e3c1e5b2918b554480940f0f5a28Jungshik Jang}
381092b445ef898e3c1e5b2918b554480940f0f5a28Jungshik Jang
382092b445ef898e3c1e5b2918b554480940f0f5a28Jungshik Jangstatic jboolean nativeIsConnected(JNIEnv* env, jclass clazz, jlong controllerPtr, jint port) {
383a6ce7708d6124224399241503fadcafe0c4684d4Jinsuk Kim    HdmiCecController* controller = reinterpret_cast<HdmiCecController*>(controllerPtr);
384092b445ef898e3c1e5b2918b554480940f0f5a28Jungshik Jang    return controller->isConnected(port) ? JNI_TRUE : JNI_FALSE ;
385092b445ef898e3c1e5b2918b554480940f0f5a28Jungshik Jang}
386092b445ef898e3c1e5b2918b554480940f0f5a28Jungshik Jang
38776f6a86de25e1bf74717e047e55fd44b089673f3Daniel Micaystatic const JNINativeMethod sMethods[] = {
3880792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang    /* name, signature, funcPtr */
3894085d0ef62554c7e139b82bca0f97161bb159f8cJungshik Jang    { "nativeInit",
3904085d0ef62554c7e139b82bca0f97161bb159f8cJungshik Jang      "(Lcom/android/server/hdmi/HdmiCecController;Landroid/os/MessageQueue;)J",
3914085d0ef62554c7e139b82bca0f97161bb159f8cJungshik Jang      (void *) nativeInit },
392a9095ba488ea18aeafaf9c3a8258bf9f459bda71Jungshik Jang    { "nativeSendCecCommand", "(JII[B)I", (void *) nativeSendCecCommand },
393a9095ba488ea18aeafaf9c3a8258bf9f459bda71Jungshik Jang    { "nativeAddLogicalAddress", "(JI)I", (void *) nativeAddLogicalAddress },
394a9095ba488ea18aeafaf9c3a8258bf9f459bda71Jungshik Jang    { "nativeClearLogicalAddress", "(J)V", (void *) nativeClearLogicalAddress },
395a9095ba488ea18aeafaf9c3a8258bf9f459bda71Jungshik Jang    { "nativeGetPhysicalAddress", "(J)I", (void *) nativeGetPhysicalAddress },
396a9095ba488ea18aeafaf9c3a8258bf9f459bda71Jungshik Jang    { "nativeGetVersion", "(J)I", (void *) nativeGetVersion },
397a9095ba488ea18aeafaf9c3a8258bf9f459bda71Jungshik Jang    { "nativeGetVendorId", "(J)I", (void *) nativeGetVendorId },
3980340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim    { "nativeGetPortInfos",
39963dd3bb3602bc00557680432b08b49a5a15bcdb7Jinsuk Kim      "(J)[Landroid/hardware/hdmi/HdmiPortInfo;",
4000340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim      (void *) nativeGetPortInfos },
401092b445ef898e3c1e5b2918b554480940f0f5a28Jungshik Jang    { "nativeSetOption", "(JII)V", (void *) nativeSetOption },
4021481a4282818939436f590d8c88aea2d19166b8eJinsuk Kim    { "nativeSetAudioReturnChannel", "(JIZ)V", (void *) nativeSetAudioReturnChannel },
403092b445ef898e3c1e5b2918b554480940f0f5a28Jungshik Jang    { "nativeIsConnected", "(JI)Z", (void *) nativeIsConnected },
4040792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang};
4050792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang
4060792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang#define CLASS_PATH "com/android/server/hdmi/HdmiCecController"
4070792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang
4080792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jangint register_android_server_hdmi_HdmiCecController(JNIEnv* env) {
409a6ce7708d6124224399241503fadcafe0c4684d4Jinsuk Kim    int res = jniRegisterNativeMethods(env, CLASS_PATH, sMethods, NELEM(sMethods));
4100792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang    LOG_FATAL_IF(res < 0, "Unable to register native methods.");
4114048a4bcb1ea709ddb83a4fde3ff5c53e642f7d0Bernhard Rosenkränzer    (void)res; // Don't scream about unused variable in the LOG_NDEBUG case
4120792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang    return 0;
4130792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang}
4140792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang
4150792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang}  /* namespace android */
416