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 "android_runtime/AndroidRuntime.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->GetIntField(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 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->SetIntField(thiz, field_context, (int)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);
     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->SetIntField(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         int 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 -1;
    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;
    124 }
    125 
    126 static jint
    127 android_hardware_UsbDeviceConnection_release_interface(JNIEnv *env, jobject thiz, int 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 -1;
    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;
    140 }
    141 
    142 static jint
    143 android_hardware_UsbDeviceConnection_control_request(JNIEnv *env, jobject thiz,
    144         jint requestType, jint request, jint value, jint index,
    145         jbyteArray buffer, jint start, jint length, jint timeout)
    146 {
    147     struct usb_device* device = get_device_from_object(env, thiz);
    148     if (!device) {
    149         ALOGE("device is closed in native_control_request");
    150         return -1;
    151     }
    152 
    153     jbyte* bufferBytes = NULL;
    154     if (buffer) {
    155         bufferBytes = (jbyte*)env->GetPrimitiveArrayCritical(buffer, NULL);
    156     }
    157 
    158     jint result = usb_device_control_transfer(device, requestType, request,
    159             value, index, bufferBytes + start, length, timeout);
    160 
    161     if (bufferBytes) {
    162         env->ReleasePrimitiveArrayCritical(buffer, bufferBytes, 0);
    163     }
    164 
    165     return result;
    166 }
    167 
    168 static jint
    169 android_hardware_UsbDeviceConnection_bulk_request(JNIEnv *env, jobject thiz,
    170         jint endpoint, 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_bulk_transfer(device, endpoint, bufferBytes + start, length, timeout);
    184 
    185     if (bufferBytes) {
    186         env->ReleasePrimitiveArrayCritical(buffer, bufferBytes, 0);
    187     }
    188 
    189     return result;
    190 }
    191 
    192 static jobject
    193 android_hardware_UsbDeviceConnection_request_wait(JNIEnv *env, jobject thiz)
    194 {
    195     struct usb_device* device = get_device_from_object(env, thiz);
    196     if (!device) {
    197         ALOGE("device is closed in native_request_wait");
    198         return NULL;
    199     }
    200 
    201     struct usb_request* request = usb_request_wait(device);
    202     if (request)
    203         return (jobject)request->client_data;
    204     else
    205         return NULL;
    206 }
    207 
    208 static jstring
    209 android_hardware_UsbDeviceConnection_get_serial(JNIEnv *env, jobject thiz)
    210 {
    211     struct usb_device* device = get_device_from_object(env, thiz);
    212     if (!device) {
    213         ALOGE("device is closed in native_request_wait");
    214         return NULL;
    215     }
    216     char* serial = usb_device_get_serial(device);
    217     if (!serial)
    218         return NULL;
    219     jstring result = env->NewStringUTF(serial);
    220     free(serial);
    221     return result;
    222 }
    223 
    224 static JNINativeMethod method_table[] = {
    225     {"native_open",             "(Ljava/lang/String;Ljava/io/FileDescriptor;)Z",
    226                                         (void *)android_hardware_UsbDeviceConnection_open},
    227     {"native_close",            "()V",  (void *)android_hardware_UsbDeviceConnection_close},
    228     {"native_get_fd",           "()I",  (void *)android_hardware_UsbDeviceConnection_get_fd},
    229     {"native_get_desc",         "()[B", (void *)android_hardware_UsbDeviceConnection_get_desc},
    230     {"native_claim_interface",  "(IZ)Z",(void *)android_hardware_UsbDeviceConnection_claim_interface},
    231     {"native_release_interface","(I)Z", (void *)android_hardware_UsbDeviceConnection_release_interface},
    232     {"native_control_request",  "(IIII[BIII)I",
    233                                         (void *)android_hardware_UsbDeviceConnection_control_request},
    234     {"native_bulk_request",     "(I[BIII)I",
    235                                         (void *)android_hardware_UsbDeviceConnection_bulk_request},
    236     {"native_request_wait",             "()Landroid/hardware/usb/UsbRequest;",
    237                                         (void *)android_hardware_UsbDeviceConnection_request_wait},
    238     { "native_get_serial",      "()Ljava/lang/String;",
    239                                         (void*)android_hardware_UsbDeviceConnection_get_serial },
    240 };
    241 
    242 int register_android_hardware_UsbDeviceConnection(JNIEnv *env)
    243 {
    244     jclass clazz = env->FindClass("android/hardware/usb/UsbDeviceConnection");
    245     if (clazz == NULL) {
    246         ALOGE("Can't find android/hardware/usb/UsbDeviceConnection");
    247         return -1;
    248     }
    249     field_context = env->GetFieldID(clazz, "mNativeContext", "I");
    250     if (field_context == NULL) {
    251         ALOGE("Can't find UsbDeviceConnection.mNativeContext");
    252         return -1;
    253     }
    254 
    255     return AndroidRuntime::registerNativeMethods(env, "android/hardware/usb/UsbDeviceConnection",
    256             method_table, NELEM(method_table));
    257 }
    258