Home | History | Annotate | Download | only in jni
      1 /*
      2  * Copyright (C) 2011 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 
     17 #define LOG_TAG "UsbDeviceConnectionJNI"
     18 
     19 #include "utils/Log.h"
     20 
     21 #include "jni.h"
     22 #include "JNIHelp.h"
     23 #include "core_jni_helpers.h"
     24 
     25 #include <usbhost/usbhost.h>
     26 
     27 #include <stdio.h>
     28 #include <sys/types.h>
     29 #include <sys/stat.h>
     30 #include <fcntl.h>
     31 
     32 using namespace android;
     33 
     34 static jfieldID field_context;
     35 
     36 struct usb_device* get_device_from_object(JNIEnv* env, jobject connection)
     37 {
     38     return (struct usb_device*)env->GetLongField(connection, field_context);
     39 }
     40 
     41 static jboolean
     42 android_hardware_UsbDeviceConnection_open(JNIEnv *env, jobject thiz, jstring deviceName,
     43         jobject fileDescriptor)
     44 {
     45     int fd = jniGetFDFromFileDescriptor(env, fileDescriptor);
     46     // duplicate the file descriptor, since ParcelFileDescriptor will eventually close its copy
     47     fd = dup(fd);
     48     if (fd < 0)
     49         return JNI_FALSE;
     50 
     51     const char *deviceNameStr = env->GetStringUTFChars(deviceName, NULL);
     52     struct usb_device* device = usb_device_new(deviceNameStr, fd);
     53     if (device) {
     54         env->SetLongField(thiz, field_context, (jlong)device);
     55     } else {
     56         ALOGE("usb_device_open failed for %s", deviceNameStr);
     57         close(fd);
     58     }
     59 
     60     env->ReleaseStringUTFChars(deviceName, deviceNameStr);
     61     return (device != NULL) ? JNI_TRUE : JNI_FALSE;
     62 }
     63 
     64 static void
     65 android_hardware_UsbDeviceConnection_close(JNIEnv *env, jobject thiz)
     66 {
     67     ALOGD("close\n");
     68     struct usb_device* device = get_device_from_object(env, thiz);
     69     if (device) {
     70         usb_device_close(device);
     71         env->SetLongField(thiz, field_context, 0);
     72     }
     73 }
     74 
     75 static jint
     76 android_hardware_UsbDeviceConnection_get_fd(JNIEnv *env, jobject thiz)
     77 {
     78     struct usb_device* device = get_device_from_object(env, thiz);
     79     if (!device) {
     80         ALOGE("device is closed in native_get_fd");
     81         return -1;
     82     }
     83     return usb_device_get_fd(device);
     84 }
     85 
     86 static jbyteArray
     87 android_hardware_UsbDeviceConnection_get_desc(JNIEnv *env, jobject thiz)
     88 {
     89     char buffer[16384];
     90     int fd = android_hardware_UsbDeviceConnection_get_fd(env, thiz);
     91     if (fd < 0) return NULL;
     92     lseek(fd, 0, SEEK_SET);
     93     int length = read(fd, buffer, sizeof(buffer));
     94     if (length < 0) return NULL;
     95 
     96     jbyteArray ret = env->NewByteArray(length);
     97     if (ret) {
     98         jbyte* bytes = (jbyte*)env->GetPrimitiveArrayCritical(ret, 0);
     99         if (bytes) {
    100             memcpy(bytes, buffer, length);
    101             env->ReleasePrimitiveArrayCritical(ret, bytes, 0);
    102         }
    103     }
    104     return ret;
    105 }
    106 
    107 static jboolean
    108 android_hardware_UsbDeviceConnection_claim_interface(JNIEnv *env, jobject thiz,
    109         jint interfaceID, jboolean force)
    110 {
    111     struct usb_device* device = get_device_from_object(env, thiz);
    112     if (!device) {
    113         ALOGE("device is closed in native_claim_interface");
    114         return JNI_FALSE;
    115     }
    116 
    117     int ret = usb_device_claim_interface(device, interfaceID);
    118     if (ret && force && errno == EBUSY) {
    119         // disconnect kernel driver and try again
    120         usb_device_connect_kernel_driver(device, interfaceID, false);
    121         ret = usb_device_claim_interface(device, interfaceID);
    122     }
    123     return (ret == 0) ? JNI_TRUE : JNI_FALSE;
    124 }
    125 
    126 static jboolean
    127 android_hardware_UsbDeviceConnection_release_interface(JNIEnv *env, jobject thiz, jint interfaceID)
    128 {
    129     struct usb_device* device = get_device_from_object(env, thiz);
    130     if (!device) {
    131         ALOGE("device is closed in native_release_interface");
    132         return JNI_FALSE;
    133     }
    134     int ret = usb_device_release_interface(device, interfaceID);
    135     if (ret == 0) {
    136         // allow kernel to reconnect its driver
    137         usb_device_connect_kernel_driver(device, interfaceID, true);
    138     }
    139     return (ret == 0) ? JNI_TRUE : JNI_FALSE;
    140 }
    141 
    142 static jboolean
    143 android_hardware_UsbDeviceConnection_set_interface(JNIEnv *env, jobject thiz, jint interfaceID,
    144         jint alternateSetting)
    145 {
    146     struct usb_device* device = get_device_from_object(env, thiz);
    147     if (!device) {
    148         ALOGE("device is closed in native_set_interface");
    149         return JNI_FALSE;
    150     }
    151     int ret = usb_device_set_interface(device, interfaceID, alternateSetting);
    152     return (ret == 0) ? JNI_TRUE : JNI_FALSE;
    153 }
    154 
    155 static jboolean
    156 android_hardware_UsbDeviceConnection_set_configuration(JNIEnv *env, jobject thiz, jint configurationID)
    157 {
    158     struct usb_device* device = get_device_from_object(env, thiz);
    159     if (!device) {
    160         ALOGE("device is closed in native_set_configuration");
    161         return JNI_FALSE;
    162     }
    163     int ret = usb_device_set_configuration(device, configurationID);
    164     return (ret == 0) ? JNI_TRUE : JNI_FALSE;
    165 }
    166 
    167 static jint
    168 android_hardware_UsbDeviceConnection_control_request(JNIEnv *env, jobject thiz,
    169         jint requestType, jint request, jint value, jint index,
    170         jbyteArray buffer, jint start, jint length, jint timeout)
    171 {
    172     struct usb_device* device = get_device_from_object(env, thiz);
    173     if (!device) {
    174         ALOGE("device is closed in native_control_request");
    175         return -1;
    176     }
    177 
    178     jbyte* bufferBytes = NULL;
    179     if (buffer) {
    180         bufferBytes = (jbyte*)env->GetPrimitiveArrayCritical(buffer, NULL);
    181     }
    182 
    183     jint result = usb_device_control_transfer(device, requestType, request,
    184             value, index, bufferBytes + start, length, timeout);
    185 
    186     if (bufferBytes) {
    187         env->ReleasePrimitiveArrayCritical(buffer, bufferBytes, 0);
    188     }
    189 
    190     return result;
    191 }
    192 
    193 static jint
    194 android_hardware_UsbDeviceConnection_bulk_request(JNIEnv *env, jobject thiz,
    195         jint endpoint, jbyteArray buffer, jint start, jint length, jint timeout)
    196 {
    197     struct usb_device* device = get_device_from_object(env, thiz);
    198     if (!device) {
    199         ALOGE("device is closed in native_control_request");
    200         return -1;
    201     }
    202 
    203     jbyte* bufferBytes = NULL;
    204     if (buffer) {
    205         bufferBytes = (jbyte*)env->GetPrimitiveArrayCritical(buffer, NULL);
    206     }
    207 
    208     jint result = usb_device_bulk_transfer(device, endpoint, bufferBytes + start, length, timeout);
    209 
    210     if (bufferBytes) {
    211         env->ReleasePrimitiveArrayCritical(buffer, bufferBytes, 0);
    212     }
    213 
    214     return result;
    215 }
    216 
    217 static jobject
    218 android_hardware_UsbDeviceConnection_request_wait(JNIEnv *env, jobject thiz)
    219 {
    220     struct usb_device* device = get_device_from_object(env, thiz);
    221     if (!device) {
    222         ALOGE("device is closed in native_request_wait");
    223         return NULL;
    224     }
    225 
    226     struct usb_request* request = usb_request_wait(device);
    227     if (request)
    228         return (jobject)request->client_data;
    229     else
    230         return NULL;
    231 }
    232 
    233 static jstring
    234 android_hardware_UsbDeviceConnection_get_serial(JNIEnv *env, jobject thiz)
    235 {
    236     struct usb_device* device = get_device_from_object(env, thiz);
    237     if (!device) {
    238         ALOGE("device is closed in native_request_wait");
    239         return NULL;
    240     }
    241     char* serial = usb_device_get_serial(device);
    242     if (!serial)
    243         return NULL;
    244     jstring result = env->NewStringUTF(serial);
    245     free(serial);
    246     return result;
    247 }
    248 
    249 static JNINativeMethod method_table[] = {
    250     {"native_open",             "(Ljava/lang/String;Ljava/io/FileDescriptor;)Z",
    251                                         (void *)android_hardware_UsbDeviceConnection_open},
    252     {"native_close",            "()V",  (void *)android_hardware_UsbDeviceConnection_close},
    253     {"native_get_fd",           "()I",  (void *)android_hardware_UsbDeviceConnection_get_fd},
    254     {"native_get_desc",         "()[B", (void *)android_hardware_UsbDeviceConnection_get_desc},
    255     {"native_claim_interface",  "(IZ)Z",(void *)android_hardware_UsbDeviceConnection_claim_interface},
    256     {"native_release_interface","(I)Z", (void *)android_hardware_UsbDeviceConnection_release_interface},
    257     {"native_set_interface","(II)Z",    (void *)android_hardware_UsbDeviceConnection_set_interface},
    258     {"native_set_configuration","(I)Z", (void *)android_hardware_UsbDeviceConnection_set_configuration},
    259     {"native_control_request",  "(IIII[BIII)I",
    260                                         (void *)android_hardware_UsbDeviceConnection_control_request},
    261     {"native_bulk_request",     "(I[BIII)I",
    262                                         (void *)android_hardware_UsbDeviceConnection_bulk_request},
    263     {"native_request_wait",             "()Landroid/hardware/usb/UsbRequest;",
    264                                         (void *)android_hardware_UsbDeviceConnection_request_wait},
    265     { "native_get_serial",      "()Ljava/lang/String;",
    266                                         (void*)android_hardware_UsbDeviceConnection_get_serial },
    267 };
    268 
    269 int register_android_hardware_UsbDeviceConnection(JNIEnv *env)
    270 {
    271     jclass clazz = FindClassOrDie(env, "android/hardware/usb/UsbDeviceConnection");
    272     field_context = GetFieldIDOrDie(env, clazz, "mNativeContext", "J");
    273 
    274     return RegisterMethodsOrDie(env, "android/hardware/usb/UsbDeviceConnection",
    275             method_table, NELEM(method_table));
    276 }
    277