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 "JNIHelp.h"
     23 #include "android_runtime/AndroidRuntime.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 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 false;
     87     }
     88 
     89     if (buffer && length) {
     90         request->buffer = malloc(length);
     91         if (!request->buffer)
     92             return 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 false;
    114     }
    115     return 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 false;
    145     }
    146 
    147     if (buffer && length) {
    148         request->buffer = env->GetDirectBufferAddress(buffer);
    149         if (!request->buffer)
    150             return 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 false;
    165     }
    166     return true;
    167 }
    168 
    169 static jint
    170 android_hardware_UsbRequest_dequeue_direct(JNIEnv *env, jobject thiz)
    171 {
    172     struct usb_request* request = get_request_from_object(env, thiz);
    173     if (!request) {
    174         ALOGE("request is closed in native_dequeue");
    175         return (jint) -1;
    176     }
    177     // all we need to do is delete our global ref
    178     env->DeleteGlobalRef((jobject)request->client_data);
    179     return (jint) request->actual_length;
    180 }
    181 
    182 static jboolean
    183 android_hardware_UsbRequest_cancel(JNIEnv *env, jobject thiz)
    184 {
    185     struct usb_request* request = get_request_from_object(env, thiz);
    186     if (!request) {
    187         ALOGE("request is closed in native_cancel");
    188         return false;
    189     }
    190     return (usb_request_cancel(request) == 0);
    191 }
    192 
    193 static JNINativeMethod method_table[] = {
    194     {"native_init",             "(Landroid/hardware/usb/UsbDeviceConnection;IIII)Z",
    195                                             (void *)android_hardware_UsbRequest_init},
    196     {"native_close",            "()V",      (void *)android_hardware_UsbRequest_close},
    197     {"native_queue_array",      "([BIZ)Z",  (void *)android_hardware_UsbRequest_queue_array},
    198     {"native_dequeue_array",    "([BIZ)I",  (void *)android_hardware_UsbRequest_dequeue_array},
    199     {"native_queue_direct",     "(Ljava/nio/ByteBuffer;IZ)Z",
    200                                             (void *)android_hardware_UsbRequest_queue_direct},
    201     {"native_dequeue_direct",   "()I",      (void *)android_hardware_UsbRequest_dequeue_direct},
    202     {"native_cancel",           "()Z",      (void *)android_hardware_UsbRequest_cancel},
    203 };
    204 
    205 int register_android_hardware_UsbRequest(JNIEnv *env)
    206 {
    207     jclass clazz = env->FindClass("android/hardware/usb/UsbRequest");
    208     if (clazz == NULL) {
    209         ALOGE("Can't find android/hardware/usb/UsbRequest");
    210         return -1;
    211     }
    212     field_context = env->GetFieldID(clazz, "mNativeContext", "J");
    213     if (field_context == NULL) {
    214         ALOGE("Can't find UsbRequest.mNativeContext");
    215         return -1;
    216     }
    217 
    218     return AndroidRuntime::registerNativeMethods(env, "android/hardware/usb/UsbRequest",
    219             method_table, NELEM(method_table));
    220 }
    221 
    222