Home | History | Annotate | Download | only in jni
      1 /*
      2  * Copyright (C) 2010 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 "UsbRequestJNI"
     18 
     19 #include "utils/Log.h"
     20 
     21 #include "jni.h"
     22 #include <nativehelper/JNIHelp.h>
     23 #include "core_jni_helpers.h"
     24 
     25 #include <usbhost/usbhost.h>
     26 
     27 #include <stdio.h>
     28 
     29 using namespace android;
     30 
     31 static jfieldID field_context;
     32 
     33 struct usb_request* get_request_from_object(JNIEnv* env, jobject java_request)
     34 {
     35     return (struct usb_request*)env->GetLongField(java_request, field_context);
     36 }
     37 
     38 // in android_hardware_UsbDeviceConnection.cpp
     39 extern struct usb_device* get_device_from_object(JNIEnv* env, jobject connection);
     40 
     41 static jboolean
     42 android_hardware_UsbRequest_init(JNIEnv *env, jobject thiz, jobject java_device,
     43         jint ep_address, jint ep_attributes, jint ep_max_packet_size, jint ep_interval)
     44 {
     45     ALOGD("init\n");
     46 
     47     struct usb_device* device = get_device_from_object(env, java_device);
     48     if (!device) {
     49         ALOGE("device null in native_init");
     50         return JNI_FALSE;
     51     }
     52 
     53     // construct an endpoint descriptor from the Java object fields
     54     struct usb_endpoint_descriptor desc;
     55     desc.bLength = USB_DT_ENDPOINT_SIZE;
     56     desc.bDescriptorType = USB_DT_ENDPOINT;
     57     desc.bEndpointAddress = ep_address;
     58     desc.bmAttributes = ep_attributes;
     59     desc.wMaxPacketSize = ep_max_packet_size;
     60     desc.bInterval = ep_interval;
     61 
     62     struct usb_request* request = usb_request_new(device, &desc);
     63     if (request)
     64         env->SetLongField(thiz, field_context, (jlong)request);
     65     return (request != NULL);
     66 }
     67 
     68 static void
     69 android_hardware_UsbRequest_close(JNIEnv *env, jobject thiz)
     70 {
     71     ALOGD("close\n");
     72     struct usb_request* request = get_request_from_object(env, thiz);
     73     if (request) {
     74         usb_request_free(request);
     75         env->SetLongField(thiz, field_context, 0);
     76     }
     77 }
     78 
     79 static jboolean
     80 android_hardware_UsbRequest_queue_array(JNIEnv *env, jobject thiz,
     81         jbyteArray buffer, jint length, jboolean out)
     82 {
     83     struct usb_request* request = get_request_from_object(env, thiz);
     84     if (!request) {
     85         ALOGE("request is closed in native_queue");
     86         return JNI_FALSE;
     87     }
     88 
     89     if (buffer && length) {
     90         request->buffer = malloc(length);
     91         if (!request->buffer)
     92             return JNI_FALSE;
     93         memset(request->buffer, 0, length);
     94         if (out) {
     95             // copy data from Java buffer to native buffer
     96             env->GetByteArrayRegion(buffer, 0, length, (jbyte *)request->buffer);
     97         }
     98     } else {
     99         request->buffer = NULL;
    100     }
    101     request->buffer_length = length;
    102 
    103     // save a reference to ourselves so UsbDeviceConnection.waitRequest() can find us
    104     request->client_data = (void *)env->NewGlobalRef(thiz);
    105 
    106     if (usb_request_queue(request)) {
    107         if (request->buffer) {
    108             // free our buffer if usb_request_queue fails
    109             free(request->buffer);
    110             request->buffer = NULL;
    111         }
    112         env->DeleteGlobalRef((jobject)request->client_data);
    113         return JNI_FALSE;
    114     }
    115     return JNI_TRUE;
    116 }
    117 
    118 static jint
    119 android_hardware_UsbRequest_dequeue_array(JNIEnv *env, jobject thiz,
    120         jbyteArray buffer, jint length, jboolean out)
    121 {
    122     struct usb_request* request = get_request_from_object(env, thiz);
    123     if (!request) {
    124         ALOGE("request is closed in native_dequeue");
    125         return (jint) -1;
    126     }
    127 
    128     if (buffer && length && request->buffer && !out) {
    129         // copy data from native buffer to Java buffer
    130         env->SetByteArrayRegion(buffer, 0, length, (jbyte *)request->buffer);
    131     }
    132     free(request->buffer);
    133     env->DeleteGlobalRef((jobject)request->client_data);
    134     return (jint) request->actual_length;
    135 }
    136 
    137 static jboolean
    138 android_hardware_UsbRequest_queue_direct(JNIEnv *env, jobject thiz,
    139         jobject buffer, jint length, jboolean out)
    140 {
    141     struct usb_request* request = get_request_from_object(env, thiz);
    142     if (!request) {
    143         ALOGE("request is closed in native_queue");
    144         return JNI_FALSE;
    145     }
    146 
    147     if (buffer && length) {
    148         request->buffer = env->GetDirectBufferAddress(buffer);
    149         if (!request->buffer)
    150             return JNI_FALSE;
    151     } else {
    152         request->buffer = NULL;
    153     }
    154     request->buffer_length = length;
    155 
    156     // save a reference to ourselves so UsbDeviceConnection.waitRequest() can find us
    157     // we also need this to make sure our native buffer is not deallocated
    158     // while IO is active
    159     request->client_data = (void *)env->NewGlobalRef(thiz);
    160 
    161     if (usb_request_queue(request)) {
    162         request->buffer = NULL;
    163         env->DeleteGlobalRef((jobject)request->client_data);
    164         return JNI_FALSE;
    165     }
    166     return JNI_TRUE;
    167 }
    168 
    169 static jboolean
    170 android_hardware_UsbRequest_queue(JNIEnv *env, jobject thiz, jobject buffer, jint offset,
    171         jint length)
    172 {
    173     struct usb_request* request = get_request_from_object(env, thiz);
    174     if (!request) {
    175         ALOGE("request is closed in native_queue");
    176         return JNI_FALSE;
    177     }
    178 
    179     if (buffer == NULL) {
    180         request->buffer = NULL;
    181         request->buffer_length = 0;
    182     } else {
    183         request->buffer = (void *)((char *)env->GetDirectBufferAddress(buffer) + offset);
    184         request->buffer_length = length;
    185     }
    186 
    187     // Save a reference to ourselves so UsbDeviceConnection.waitRequest() can find us.
    188     // We also need this to make sure our native buffer is not deallocated while IO is active.
    189     request->client_data = (void *)env->NewGlobalRef(thiz);
    190 
    191     int err = usb_request_queue(request);
    192 
    193     if (err != 0) {
    194         request->buffer = NULL;
    195         env->DeleteGlobalRef((jobject)request->client_data);
    196         return JNI_FALSE;
    197     }
    198     return JNI_TRUE;
    199 }
    200 
    201 static jint
    202 android_hardware_UsbRequest_dequeue_direct(JNIEnv *env, jobject thiz)
    203 {
    204     struct usb_request* request = get_request_from_object(env, thiz);
    205     if (!request) {
    206         ALOGE("request is closed in native_dequeue");
    207         return (jint) -1;
    208     }
    209     // all we need to do is delete our global ref
    210     env->DeleteGlobalRef((jobject)request->client_data);
    211     return (jint) request->actual_length;
    212 }
    213 
    214 static jboolean
    215 android_hardware_UsbRequest_cancel(JNIEnv *env, jobject thiz)
    216 {
    217     struct usb_request* request = get_request_from_object(env, thiz);
    218     if (!request) {
    219         ALOGE("request is closed in native_cancel");
    220         return JNI_FALSE;
    221     }
    222     return (usb_request_cancel(request) == 0);
    223 }
    224 
    225 static const JNINativeMethod method_table[] = {
    226     {"native_init",             "(Landroid/hardware/usb/UsbDeviceConnection;IIII)Z",
    227                                             (void *)android_hardware_UsbRequest_init},
    228     {"native_close",            "()V",      (void *)android_hardware_UsbRequest_close},
    229     {"native_queue",            "(Ljava/nio/ByteBuffer;II)Z",
    230                                             (void *)android_hardware_UsbRequest_queue},
    231     {"native_queue_array",      "([BIZ)Z",  (void *)android_hardware_UsbRequest_queue_array},
    232     {"native_dequeue_array",    "([BIZ)I",  (void *)android_hardware_UsbRequest_dequeue_array},
    233     {"native_queue_direct",     "(Ljava/nio/ByteBuffer;IZ)Z",
    234                                             (void *)android_hardware_UsbRequest_queue_direct},
    235     {"native_dequeue_direct",   "()I",      (void *)android_hardware_UsbRequest_dequeue_direct},
    236     {"native_cancel",           "()Z",      (void *)android_hardware_UsbRequest_cancel},
    237 };
    238 
    239 int register_android_hardware_UsbRequest(JNIEnv *env)
    240 {
    241     jclass clazz = env->FindClass("android/hardware/usb/UsbRequest");
    242     if (clazz == NULL) {
    243         ALOGE("Can't find android/hardware/usb/UsbRequest");
    244         return -1;
    245     }
    246     field_context = env->GetFieldID(clazz, "mNativeContext", "J");
    247     if (field_context == NULL) {
    248         ALOGE("Can't find UsbRequest.mNativeContext");
    249         return -1;
    250     }
    251 
    252     return RegisterMethodsOrDie(env, "android/hardware/usb/UsbRequest",
    253             method_table, NELEM(method_table));
    254 }
    255 
    256