| /* |
| * Copyright (C) 2011 The Android Open Source Project |
| * |
| * Copyright (C) 2013, 2014 Google, Inc. |
| * |
| * 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 "I2cServiceJNI" |
| #include "utils/Log.h" |
| |
| #include "jni.h" |
| #include "JNIHelp.h" |
| #include "android_runtime/AndroidRuntime.h" |
| |
| #include <fcntl.h> |
| #include <sys/ioctl.h> |
| #include <linux/i2c-dev.h> |
| #include <stdint.h> |
| |
| namespace android |
| { |
| |
| // These I/O direction and status enums must match those in |
| // I2cTransaction.java |
| |
| enum { |
| IO_DIRECTION_WRITE = 0, |
| IO_DIRECTION_READ = 1, |
| }; |
| |
| enum { |
| STATUS_NOT_STARTED = 1, |
| STATUS_OK = 0, |
| STATUS_ERR = -1, |
| }; |
| |
| static struct i2c_transaction_offsets_t |
| { |
| jfieldID mIoDirection; |
| jfieldID mStatus; |
| jfieldID mData; |
| } gI2cTransactionOffsets; |
| |
| static jint android_server_I2cService_native_perform_i2c_transactions( |
| JNIEnv *env, jobject thiz, jstring name, jint address, jobjectArray txns) |
| { |
| jint ret = 0; |
| |
| // Grab a file descriptor. |
| const char *pathStr = env->GetStringUTFChars(name, NULL); |
| int fd = open(pathStr, O_RDWR); |
| if (fd < 0) { |
| ALOGE("can't open %s", pathStr); |
| env->ReleaseStringUTFChars(name, pathStr); |
| return fd; |
| } |
| env->ReleaseStringUTFChars(name, pathStr); |
| |
| // Prepare the messages. |
| jsize nTxns = env->GetArrayLength(txns); |
| struct i2c_msg messages[nTxns]; |
| for (jsize i = 0; i < nTxns; i++) { |
| jobject txn = env->GetObjectArrayElement(txns, i); |
| jint iod = env->GetIntField(txn, gI2cTransactionOffsets.mIoDirection); |
| jobject dataObj = env->GetObjectField(txn, gI2cTransactionOffsets.mData); |
| jbyteArray *dataAp = reinterpret_cast<jbyteArray*>(&dataObj); |
| jsize dataLength = env->GetArrayLength(*dataAp); |
| jbyte *datap = env->GetByteArrayElements(*dataAp, NULL); |
| |
| messages[i].addr = (uint8_t)address; |
| messages[i].flags = (iod == IO_DIRECTION_READ) ? I2C_M_RD : 0; |
| messages[i].len = (short)dataLength; |
| messages[i].buf = (char*)datap; |
| |
| env->DeleteLocalRef(txn); |
| } |
| |
| // Do the I/O. |
| struct i2c_rdwr_ioctl_data packets; |
| packets.msgs = messages; |
| packets.nmsgs = nTxns; |
| int io_rc = ioctl(fd, I2C_RDWR, &packets); |
| if (io_rc < 0) { |
| ALOGE("I/O error: %d", io_rc); |
| ret = io_rc; |
| } |
| |
| // Release resources and set status codes. |
| for (jsize i = 0; i < nTxns; i++) { |
| jobject txn = env->GetObjectArrayElement(txns, i); |
| jobject dataObj = env->GetObjectField(txn, gI2cTransactionOffsets.mData); |
| jbyteArray *dataAp = reinterpret_cast<jbyteArray*>(&dataObj); |
| |
| env->ReleaseByteArrayElements(*dataAp, (jbyte*)messages[i].buf, 0); |
| env->SetIntField(txn, gI2cTransactionOffsets.mStatus, |
| ret < 0 ? STATUS_ERR : STATUS_OK); |
| |
| env->DeleteLocalRef(txn); |
| } |
| |
| // And done |
| close(fd); |
| return ret; |
| } |
| |
| static JNINativeMethod method_table[] = { |
| { "native_perform_i2c_transactions", "(Ljava/lang/String;I[Landroid/hardware/I2cTransaction;)I", |
| (void*)android_server_I2cService_native_perform_i2c_transactions }, |
| }; |
| |
| int register_android_server_I2cService(JNIEnv *env) |
| { |
| jclass clazz = env->FindClass("com/android/server/I2cService"); |
| if (clazz == NULL) { |
| ALOGE("Can't find com/android/server/I2cService"); |
| return -1; |
| } |
| clazz = env->FindClass("android/hardware/I2cTransaction"); |
| LOG_FATAL_IF(clazz == NULL, "Unable to find class android.hardware.I2cTransaction"); |
| gI2cTransactionOffsets.mIoDirection = env->GetFieldID(clazz, "ioDirection", "I"); |
| gI2cTransactionOffsets.mStatus = env->GetFieldID(clazz, "status", "I"); |
| gI2cTransactionOffsets.mData = env->GetFieldID(clazz, "data", "[B"); |
| return jniRegisterNativeMethods(env, "com/android/server/I2cService", |
| method_table, NELEM(method_table)); |
| } |
| |
| } |