android_hardware_UsbDevice.cpp revision c4308f01c965571dc2354107c3574df113e397ee
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 "UsbDeviceJNI" 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#include <sys/types.h> 29#include <sys/stat.h> 30#include <fcntl.h> 31 32using namespace android; 33 34static jfieldID field_context; 35 36struct usb_device* get_device_from_object(JNIEnv* env, jobject javaDevice) 37{ 38 return (struct usb_device*)env->GetIntField(javaDevice, field_context); 39} 40 41// in android_hardware_UsbEndpoint.cpp 42extern struct usb_endpoint* get_endpoint_from_object(JNIEnv* env, jobject javaEndpoint); 43 44static jboolean 45android_hardware_UsbDevice_open(JNIEnv *env, jobject thiz, jstring deviceName, 46 jobject fileDescriptor) 47{ 48 int fd = getParcelFileDescriptorFD(env, fileDescriptor); 49 // duplicate the file descriptor, since ParcelFileDescriptor will eventually close its copy 50 fd = dup(fd); 51 if (fd < 0) 52 return false; 53 54 const char *deviceNameStr = env->GetStringUTFChars(deviceName, NULL); 55 struct usb_device* device = usb_device_new(deviceNameStr, fd); 56 if (device) { 57 env->SetIntField(thiz, field_context, (int)device); 58 } else { 59 LOGE("usb_device_open failed for %s", deviceNameStr); 60 close(fd); 61 } 62 63 env->ReleaseStringUTFChars(deviceName, deviceNameStr); 64 return (device != NULL); 65} 66 67static void 68android_hardware_UsbDevice_close(JNIEnv *env, jobject thiz) 69{ 70 LOGD("close\n"); 71 struct usb_device* device = get_device_from_object(env, thiz); 72 if (device) { 73 usb_device_close(device); 74 env->SetIntField(thiz, field_context, 0); 75 } 76} 77 78static jint 79android_hardware_UsbDevice_get_fd(JNIEnv *env, jobject thiz) 80{ 81 struct usb_device* device = get_device_from_object(env, thiz); 82 if (!device) { 83 LOGE("device is closed in native_get_fd"); 84 return -1; 85 } 86 return usb_device_get_fd(device); 87} 88 89static jboolean 90android_hardware_UsbDevice_claim_interface(JNIEnv *env, jobject thiz, int interfaceID, jboolean force) 91{ 92 struct usb_device* device = get_device_from_object(env, thiz); 93 if (!device) { 94 LOGE("device is closed in native_claim_interface"); 95 return -1; 96 } 97 98 int ret = usb_device_claim_interface(device, interfaceID); 99 if (ret && force && errno == EBUSY) { 100 // disconnect kernel driver and try again 101 usb_device_connect_kernel_driver(device, interfaceID, false); 102 ret = usb_device_claim_interface(device, interfaceID); 103 } 104 return ret == 0; 105} 106 107static jint 108android_hardware_UsbDevice_release_interface(JNIEnv *env, jobject thiz, int interfaceID) 109{ 110 struct usb_device* device = get_device_from_object(env, thiz); 111 if (!device) { 112 LOGE("device is closed in native_release_interface"); 113 return -1; 114 } 115 int ret = usb_device_release_interface(device, interfaceID); 116 if (ret == 0) { 117 // allow kernel to reconnect its driver 118 usb_device_connect_kernel_driver(device, interfaceID, true); 119 } 120 return ret; 121} 122 123static jint 124android_hardware_UsbDevice_control_request(JNIEnv *env, jobject thiz, 125 jint requestType, jint request, jint value, jint index, 126 jbyteArray buffer, jint length, jint timeout) 127{ 128 struct usb_device* device = get_device_from_object(env, thiz); 129 if (!device) { 130 LOGE("device is closed in native_control_request"); 131 return -1; 132 } 133 134 jbyte* bufferBytes = NULL; 135 if (buffer) { 136 if (env->GetArrayLength(buffer) < length) { 137 env->ThrowNew(env->FindClass("java/lang/ArrayIndexOutOfBoundsException"), NULL); 138 return -1; 139 } 140 bufferBytes = env->GetByteArrayElements(buffer, 0); 141 } 142 143 jint result = usb_device_control_transfer(device, requestType, request, 144 value, index, bufferBytes, length, timeout); 145 146 if (bufferBytes) 147 env->ReleaseByteArrayElements(buffer, bufferBytes, 0); 148 149 return result; 150} 151 152static jint 153android_hardware_UsbDevice_bulk_request(JNIEnv *env, jobject thiz, 154 jint endpoint, jbyteArray buffer, jint length, jint timeout) 155{ 156 struct usb_device* device = get_device_from_object(env, thiz); 157 if (!device) { 158 LOGE("device is closed in native_control_request"); 159 return -1; 160 } 161 162 jbyte* bufferBytes = NULL; 163 if (buffer) { 164 if (env->GetArrayLength(buffer) < length) { 165 env->ThrowNew(env->FindClass("java/lang/ArrayIndexOutOfBoundsException"), NULL); 166 return -1; 167 } 168 bufferBytes = env->GetByteArrayElements(buffer, 0); 169 } 170 171 jint result = usb_device_bulk_transfer(device, endpoint, bufferBytes, length, timeout); 172 173 if (bufferBytes) 174 env->ReleaseByteArrayElements(buffer, bufferBytes, 0); 175 176 return result; 177} 178 179static jobject 180android_hardware_UsbDevice_request_wait(JNIEnv *env, jobject thiz) 181{ 182 struct usb_device* device = get_device_from_object(env, thiz); 183 if (!device) { 184 LOGE("device is closed in native_request_wait"); 185 return NULL; 186 } 187 188 struct usb_request* request = usb_request_wait(device); 189 if (request) 190 return (jobject)request->client_data; 191 else 192 return NULL; 193} 194 195static jstring 196android_hardware_UsbDevice_get_serial(JNIEnv *env, jobject thiz) 197{ 198 struct usb_device* device = get_device_from_object(env, thiz); 199 if (!device) { 200 LOGE("device is closed in native_request_wait"); 201 return NULL; 202 } 203 char* serial = usb_device_get_serial(device); 204 if (!serial) 205 return NULL; 206 jstring result = env->NewStringUTF(serial); 207 free(serial); 208 return result; 209} 210 211static jint 212android_hardware_UsbDevice_get_device_id(JNIEnv *env, jobject clazz, jstring name) 213{ 214 const char *nameStr = env->GetStringUTFChars(name, NULL); 215 int id = usb_device_get_unique_id_from_name(nameStr); 216 env->ReleaseStringUTFChars(name, nameStr); 217 return id; 218} 219 220static jstring 221android_hardware_UsbDevice_get_device_name(JNIEnv *env, jobject clazz, jint id) 222{ 223 char* name = usb_device_get_name_from_unique_id(id); 224 jstring result = env->NewStringUTF(name); 225 free(name); 226 return result; 227} 228 229static JNINativeMethod method_table[] = { 230 {"native_open", "(Ljava/lang/String;Ljava/io/FileDescriptor;)Z", 231 (void *)android_hardware_UsbDevice_open}, 232 {"native_close", "()V", (void *)android_hardware_UsbDevice_close}, 233 {"native_get_fd", "()I", (void *)android_hardware_UsbDevice_get_fd}, 234 {"native_claim_interface", "(IZ)Z",(void *)android_hardware_UsbDevice_claim_interface}, 235 {"native_release_interface","(I)Z", (void *)android_hardware_UsbDevice_release_interface}, 236 {"native_control_request", "(IIII[BII)I", 237 (void *)android_hardware_UsbDevice_control_request}, 238 {"native_bulk_request", "(I[BII)I", 239 (void *)android_hardware_UsbDevice_bulk_request}, 240 {"native_request_wait", "()Landroid/hardware/usb/UsbRequest;", 241 (void *)android_hardware_UsbDevice_request_wait}, 242 { "native_get_serial", "()Ljava/lang/String;", 243 (void*)android_hardware_UsbDevice_get_serial }, 244 245 // static methods 246 { "native_get_device_id", "(Ljava/lang/String;)I", 247 (void*)android_hardware_UsbDevice_get_device_id }, 248 { "native_get_device_name", "(I)Ljava/lang/String;", 249 (void*)android_hardware_UsbDevice_get_device_name }, 250}; 251 252int register_android_hardware_UsbDevice(JNIEnv *env) 253{ 254 jclass clazz = env->FindClass("android/hardware/usb/UsbDevice"); 255 if (clazz == NULL) { 256 LOGE("Can't find android/hardware/usb/UsbDevice"); 257 return -1; 258 } 259 field_context = env->GetFieldID(clazz, "mNativeContext", "I"); 260 if (field_context == NULL) { 261 LOGE("Can't find UsbDevice.mNativeContext"); 262 return -1; 263 } 264 265 return AndroidRuntime::registerNativeMethods(env, "android/hardware/usb/UsbDevice", 266 method_table, NELEM(method_table)); 267} 268 269