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