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->GetIntField(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->SetIntField(thiz, field_context, (int)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->SetIntField(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         if (out) {
     94             // copy data from Java buffer to native buffer
     95             env->GetByteArrayRegion(buffer, 0, length, (jbyte *)request->buffer);
     96         }
     97     } else {
     98         request->buffer = NULL;
     99     }
    100     request->buffer_length = length;
    101 
    102     if (usb_request_queue(request)) {
    103         if (request->buffer) {
    104             // free our buffer if usb_request_queue fails
    105             free(request->buffer);
    106             request->buffer = NULL;
    107         }
    108         return false;
    109     } else {
    110         // save a reference to ourselves so UsbDeviceConnection.waitRequest() can find us
    111         request->client_data = (void *)env->NewGlobalRef(thiz);
    112         return true;
    113     }
    114 }
    115 
    116 static void
    117 android_hardware_UsbRequest_dequeue_array(JNIEnv *env, jobject thiz,
    118         jbyteArray buffer, jint length, jboolean out)
    119 {
    120     struct usb_request* request = get_request_from_object(env, thiz);
    121     if (!request) {
    122         ALOGE("request is closed in native_dequeue");
    123         return;
    124     }
    125 
    126     if (buffer && length && request->buffer && !out) {
    127         // copy data from native buffer to Java buffer
    128         env->SetByteArrayRegion(buffer, 0, length, (jbyte *)request->buffer);
    129     }
    130     free(request->buffer);
    131     env->DeleteGlobalRef((jobject)request->client_data);
    132 
    133 }
    134 
    135 static jboolean
    136 android_hardware_UsbRequest_queue_direct(JNIEnv *env, jobject thiz,
    137         jobject buffer, jint length, jboolean out)
    138 {
    139     struct usb_request* request = get_request_from_object(env, thiz);
    140     if (!request) {
    141         ALOGE("request is closed in native_queue");
    142         return false;
    143     }
    144 
    145     if (buffer && length) {
    146         request->buffer = env->GetDirectBufferAddress(buffer);
    147         if (!request->buffer)
    148             return false;
    149     } else {
    150         request->buffer = NULL;
    151     }
    152     request->buffer_length = length;
    153 
    154     if (usb_request_queue(request)) {
    155         request->buffer = NULL;
    156         return false;
    157     } else {
    158         // save a reference to ourselves so UsbDeviceConnection.waitRequest() can find us
    159         // we also need this to make sure our native buffer is not deallocated
    160         // while IO is active
    161         request->client_data = (void *)env->NewGlobalRef(thiz);
    162         return true;
    163     }
    164 }
    165 
    166 static void
    167 android_hardware_UsbRequest_dequeue_direct(JNIEnv *env, jobject thiz)
    168 {
    169     struct usb_request* request = get_request_from_object(env, thiz);
    170     if (!request) {
    171         ALOGE("request is closed in native_dequeue");
    172         return;
    173     }
    174     // all we need to do is delete our global ref
    175     env->DeleteGlobalRef((jobject)request->client_data);
    176 }
    177 
    178 static jboolean
    179 android_hardware_UsbRequest_cancel(JNIEnv *env, jobject thiz)
    180 {
    181     struct usb_request* request = get_request_from_object(env, thiz);
    182     if (!request) {
    183         ALOGE("request is closed in native_cancel");
    184         return false;
    185     }
    186     return (usb_request_cancel(request) == 0);
    187 }
    188 
    189 static JNINativeMethod method_table[] = {
    190     {"native_init",             "(Landroid/hardware/usb/UsbDeviceConnection;IIII)Z",
    191                                             (void *)android_hardware_UsbRequest_init},
    192     {"native_close",            "()V",      (void *)android_hardware_UsbRequest_close},
    193     {"native_queue_array",      "([BIZ)Z",  (void *)android_hardware_UsbRequest_queue_array},
    194     {"native_dequeue_array",    "([BIZ)V",  (void *)android_hardware_UsbRequest_dequeue_array},
    195     {"native_queue_direct",     "(Ljava/nio/ByteBuffer;IZ)Z",
    196                                             (void *)android_hardware_UsbRequest_queue_direct},
    197     {"native_dequeue_direct",   "()V",      (void *)android_hardware_UsbRequest_dequeue_direct},
    198     {"native_cancel",           "()Z",      (void *)android_hardware_UsbRequest_cancel},
    199 };
    200 
    201 int register_android_hardware_UsbRequest(JNIEnv *env)
    202 {
    203     jclass clazz = env->FindClass("android/hardware/usb/UsbRequest");
    204     if (clazz == NULL) {
    205         ALOGE("Can't find android/hardware/usb/UsbRequest");
    206         return -1;
    207     }
    208     field_context = env->GetFieldID(clazz, "mNativeContext", "I");
    209     if (field_context == NULL) {
    210         ALOGE("Can't find UsbRequest.mNativeContext");
    211         return -1;
    212     }
    213 
    214     return AndroidRuntime::registerNativeMethods(env, "android/hardware/usb/UsbRequest",
    215             method_table, NELEM(method_table));
    216 }
    217 
    218