| /* |
| * Copyright (C) 2010 The Android Open Source Project |
| * |
| * Licensed under the Apache License, Version 2.0 (the "License"); |
| * you may not use this file except in compliance with the License. |
| * You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| */ |
| |
| #define LOG_TAG "UsbRequestJNI" |
| |
| #include "utils/Log.h" |
| |
| #include "jni.h" |
| #include <nativehelper/JNIHelp.h> |
| #include "core_jni_helpers.h" |
| |
| #include <usbhost/usbhost.h> |
| |
| #include <stdio.h> |
| |
| using namespace android; |
| |
| static jfieldID field_context; |
| |
| struct usb_request* get_request_from_object(JNIEnv* env, jobject java_request) |
| { |
| return (struct usb_request*)env->GetLongField(java_request, field_context); |
| } |
| |
| // in android_hardware_UsbDeviceConnection.cpp |
| extern struct usb_device* get_device_from_object(JNIEnv* env, jobject connection); |
| |
| static jboolean |
| android_hardware_UsbRequest_init(JNIEnv *env, jobject thiz, jobject java_device, |
| jint ep_address, jint ep_attributes, jint ep_max_packet_size, jint ep_interval) |
| { |
| ALOGD("init\n"); |
| |
| struct usb_device* device = get_device_from_object(env, java_device); |
| if (!device) { |
| ALOGE("device null in native_init"); |
| return JNI_FALSE; |
| } |
| |
| // construct an endpoint descriptor from the Java object fields |
| struct usb_endpoint_descriptor desc; |
| desc.bLength = USB_DT_ENDPOINT_SIZE; |
| desc.bDescriptorType = USB_DT_ENDPOINT; |
| desc.bEndpointAddress = ep_address; |
| desc.bmAttributes = ep_attributes; |
| desc.wMaxPacketSize = ep_max_packet_size; |
| desc.bInterval = ep_interval; |
| |
| struct usb_request* request = usb_request_new(device, &desc); |
| if (request) |
| env->SetLongField(thiz, field_context, (jlong)request); |
| return (request != NULL); |
| } |
| |
| static void |
| android_hardware_UsbRequest_close(JNIEnv *env, jobject thiz) |
| { |
| ALOGD("close\n"); |
| struct usb_request* request = get_request_from_object(env, thiz); |
| if (request) { |
| usb_request_free(request); |
| env->SetLongField(thiz, field_context, 0); |
| } |
| } |
| |
| static jboolean |
| android_hardware_UsbRequest_queue_array(JNIEnv *env, jobject thiz, |
| jbyteArray buffer, jint length, jboolean out) |
| { |
| struct usb_request* request = get_request_from_object(env, thiz); |
| if (!request) { |
| ALOGE("request is closed in native_queue"); |
| return JNI_FALSE; |
| } |
| |
| if (buffer && length) { |
| request->buffer = malloc(length); |
| if (!request->buffer) |
| return JNI_FALSE; |
| memset(request->buffer, 0, length); |
| if (out) { |
| // copy data from Java buffer to native buffer |
| env->GetByteArrayRegion(buffer, 0, length, (jbyte *)request->buffer); |
| } |
| } else { |
| request->buffer = NULL; |
| } |
| request->buffer_length = length; |
| |
| // save a reference to ourselves so UsbDeviceConnection.waitRequest() can find us |
| request->client_data = (void *)env->NewGlobalRef(thiz); |
| |
| if (usb_request_queue(request)) { |
| if (request->buffer) { |
| // free our buffer if usb_request_queue fails |
| free(request->buffer); |
| request->buffer = NULL; |
| } |
| env->DeleteGlobalRef((jobject)request->client_data); |
| return JNI_FALSE; |
| } |
| return JNI_TRUE; |
| } |
| |
| static jint |
| android_hardware_UsbRequest_dequeue_array(JNIEnv *env, jobject thiz, |
| jbyteArray buffer, jint length, jboolean out) |
| { |
| struct usb_request* request = get_request_from_object(env, thiz); |
| if (!request) { |
| ALOGE("request is closed in native_dequeue"); |
| return (jint) -1; |
| } |
| |
| if (buffer && length && request->buffer && !out) { |
| // copy data from native buffer to Java buffer |
| env->SetByteArrayRegion(buffer, 0, length, (jbyte *)request->buffer); |
| } |
| free(request->buffer); |
| env->DeleteGlobalRef((jobject)request->client_data); |
| return (jint) request->actual_length; |
| } |
| |
| static jboolean |
| android_hardware_UsbRequest_queue_direct(JNIEnv *env, jobject thiz, |
| jobject buffer, jint length, jboolean out) |
| { |
| struct usb_request* request = get_request_from_object(env, thiz); |
| if (!request) { |
| ALOGE("request is closed in native_queue"); |
| return JNI_FALSE; |
| } |
| |
| if (buffer && length) { |
| request->buffer = env->GetDirectBufferAddress(buffer); |
| if (!request->buffer) |
| return JNI_FALSE; |
| } else { |
| request->buffer = NULL; |
| } |
| request->buffer_length = length; |
| |
| // save a reference to ourselves so UsbDeviceConnection.waitRequest() can find us |
| // we also need this to make sure our native buffer is not deallocated |
| // while IO is active |
| request->client_data = (void *)env->NewGlobalRef(thiz); |
| |
| if (usb_request_queue(request)) { |
| request->buffer = NULL; |
| env->DeleteGlobalRef((jobject)request->client_data); |
| return JNI_FALSE; |
| } |
| return JNI_TRUE; |
| } |
| |
| static jboolean |
| android_hardware_UsbRequest_queue(JNIEnv *env, jobject thiz, jobject buffer, jint offset, |
| jint length) |
| { |
| struct usb_request* request = get_request_from_object(env, thiz); |
| if (!request) { |
| ALOGE("request is closed in native_queue"); |
| return JNI_FALSE; |
| } |
| |
| if (buffer == NULL) { |
| request->buffer = NULL; |
| request->buffer_length = 0; |
| } else { |
| request->buffer = (void *)((char *)env->GetDirectBufferAddress(buffer) + offset); |
| request->buffer_length = length; |
| } |
| |
| // Save a reference to ourselves so UsbDeviceConnection.waitRequest() can find us. |
| // We also need this to make sure our native buffer is not deallocated while IO is active. |
| request->client_data = (void *)env->NewGlobalRef(thiz); |
| |
| int err = usb_request_queue(request); |
| |
| if (err != 0) { |
| request->buffer = NULL; |
| env->DeleteGlobalRef((jobject)request->client_data); |
| return JNI_FALSE; |
| } |
| return JNI_TRUE; |
| } |
| |
| static jint |
| android_hardware_UsbRequest_dequeue_direct(JNIEnv *env, jobject thiz) |
| { |
| struct usb_request* request = get_request_from_object(env, thiz); |
| if (!request) { |
| ALOGE("request is closed in native_dequeue"); |
| return (jint) -1; |
| } |
| // all we need to do is delete our global ref |
| env->DeleteGlobalRef((jobject)request->client_data); |
| return (jint) request->actual_length; |
| } |
| |
| static jboolean |
| android_hardware_UsbRequest_cancel(JNIEnv *env, jobject thiz) |
| { |
| struct usb_request* request = get_request_from_object(env, thiz); |
| if (!request) { |
| ALOGE("request is closed in native_cancel"); |
| return JNI_FALSE; |
| } |
| return (usb_request_cancel(request) == 0); |
| } |
| |
| static const JNINativeMethod method_table[] = { |
| {"native_init", "(Landroid/hardware/usb/UsbDeviceConnection;IIII)Z", |
| (void *)android_hardware_UsbRequest_init}, |
| {"native_close", "()V", (void *)android_hardware_UsbRequest_close}, |
| {"native_queue", "(Ljava/nio/ByteBuffer;II)Z", |
| (void *)android_hardware_UsbRequest_queue}, |
| {"native_queue_array", "([BIZ)Z", (void *)android_hardware_UsbRequest_queue_array}, |
| {"native_dequeue_array", "([BIZ)I", (void *)android_hardware_UsbRequest_dequeue_array}, |
| {"native_queue_direct", "(Ljava/nio/ByteBuffer;IZ)Z", |
| (void *)android_hardware_UsbRequest_queue_direct}, |
| {"native_dequeue_direct", "()I", (void *)android_hardware_UsbRequest_dequeue_direct}, |
| {"native_cancel", "()Z", (void *)android_hardware_UsbRequest_cancel}, |
| }; |
| |
| int register_android_hardware_UsbRequest(JNIEnv *env) |
| { |
| jclass clazz = env->FindClass("android/hardware/usb/UsbRequest"); |
| if (clazz == NULL) { |
| ALOGE("Can't find android/hardware/usb/UsbRequest"); |
| return -1; |
| } |
| field_context = env->GetFieldID(clazz, "mNativeContext", "J"); |
| if (field_context == NULL) { |
| ALOGE("Can't find UsbRequest.mNativeContext"); |
| return -1; |
| } |
| |
| return RegisterMethodsOrDie(env, "android/hardware/usb/UsbRequest", |
| method_table, NELEM(method_table)); |
| } |
| |