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 "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