1 /* 2 * Copyright (C) 2011 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 "UsbDeviceConnectionJNI" 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 32 using namespace android; 33 34 static jfieldID field_context; 35 36 struct usb_device* get_device_from_object(JNIEnv* env, jobject connection) 37 { 38 return (struct usb_device*)env->GetIntField(connection, field_context); 39 } 40 41 static jboolean 42 android_hardware_UsbDeviceConnection_open(JNIEnv *env, jobject thiz, jstring deviceName, 43 jobject fileDescriptor) 44 { 45 int fd = jniGetFDFromFileDescriptor(env, fileDescriptor); 46 // duplicate the file descriptor, since ParcelFileDescriptor will eventually close its copy 47 fd = dup(fd); 48 if (fd < 0) 49 return false; 50 51 const char *deviceNameStr = env->GetStringUTFChars(deviceName, NULL); 52 struct usb_device* device = usb_device_new(deviceNameStr, fd); 53 if (device) { 54 env->SetIntField(thiz, field_context, (int)device); 55 } else { 56 ALOGE("usb_device_open failed for %s", deviceNameStr); 57 close(fd); 58 } 59 60 env->ReleaseStringUTFChars(deviceName, deviceNameStr); 61 return (device != NULL); 62 } 63 64 static void 65 android_hardware_UsbDeviceConnection_close(JNIEnv *env, jobject thiz) 66 { 67 ALOGD("close\n"); 68 struct usb_device* device = get_device_from_object(env, thiz); 69 if (device) { 70 usb_device_close(device); 71 env->SetIntField(thiz, field_context, 0); 72 } 73 } 74 75 static jint 76 android_hardware_UsbDeviceConnection_get_fd(JNIEnv *env, jobject thiz) 77 { 78 struct usb_device* device = get_device_from_object(env, thiz); 79 if (!device) { 80 ALOGE("device is closed in native_get_fd"); 81 return -1; 82 } 83 return usb_device_get_fd(device); 84 } 85 86 static jbyteArray 87 android_hardware_UsbDeviceConnection_get_desc(JNIEnv *env, jobject thiz) 88 { 89 char buffer[16384]; 90 int fd = android_hardware_UsbDeviceConnection_get_fd(env, thiz); 91 if (fd < 0) return NULL; 92 lseek(fd, 0, SEEK_SET); 93 int length = read(fd, buffer, sizeof(buffer)); 94 if (length < 0) return NULL; 95 96 jbyteArray ret = env->NewByteArray(length); 97 if (ret) { 98 jbyte* bytes = (jbyte*)env->GetPrimitiveArrayCritical(ret, 0); 99 if (bytes) { 100 memcpy(bytes, buffer, length); 101 env->ReleasePrimitiveArrayCritical(ret, bytes, 0); 102 } 103 } 104 return ret; 105 } 106 107 static jboolean 108 android_hardware_UsbDeviceConnection_claim_interface(JNIEnv *env, jobject thiz, 109 int interfaceID, jboolean force) 110 { 111 struct usb_device* device = get_device_from_object(env, thiz); 112 if (!device) { 113 ALOGE("device is closed in native_claim_interface"); 114 return -1; 115 } 116 117 int ret = usb_device_claim_interface(device, interfaceID); 118 if (ret && force && errno == EBUSY) { 119 // disconnect kernel driver and try again 120 usb_device_connect_kernel_driver(device, interfaceID, false); 121 ret = usb_device_claim_interface(device, interfaceID); 122 } 123 return ret == 0; 124 } 125 126 static jint 127 android_hardware_UsbDeviceConnection_release_interface(JNIEnv *env, jobject thiz, int interfaceID) 128 { 129 struct usb_device* device = get_device_from_object(env, thiz); 130 if (!device) { 131 ALOGE("device is closed in native_release_interface"); 132 return -1; 133 } 134 int ret = usb_device_release_interface(device, interfaceID); 135 if (ret == 0) { 136 // allow kernel to reconnect its driver 137 usb_device_connect_kernel_driver(device, interfaceID, true); 138 } 139 return ret; 140 } 141 142 static jint 143 android_hardware_UsbDeviceConnection_control_request(JNIEnv *env, jobject thiz, 144 jint requestType, jint request, jint value, jint index, 145 jbyteArray buffer, jint start, jint length, jint timeout) 146 { 147 struct usb_device* device = get_device_from_object(env, thiz); 148 if (!device) { 149 ALOGE("device is closed in native_control_request"); 150 return -1; 151 } 152 153 jbyte* bufferBytes = NULL; 154 if (buffer) { 155 bufferBytes = (jbyte*)env->GetPrimitiveArrayCritical(buffer, NULL); 156 } 157 158 jint result = usb_device_control_transfer(device, requestType, request, 159 value, index, bufferBytes + start, length, timeout); 160 161 if (bufferBytes) { 162 env->ReleasePrimitiveArrayCritical(buffer, bufferBytes, 0); 163 } 164 165 return result; 166 } 167 168 static jint 169 android_hardware_UsbDeviceConnection_bulk_request(JNIEnv *env, jobject thiz, 170 jint endpoint, jbyteArray buffer, jint start, jint length, jint timeout) 171 { 172 struct usb_device* device = get_device_from_object(env, thiz); 173 if (!device) { 174 ALOGE("device is closed in native_control_request"); 175 return -1; 176 } 177 178 jbyte* bufferBytes = NULL; 179 if (buffer) { 180 bufferBytes = (jbyte*)env->GetPrimitiveArrayCritical(buffer, NULL); 181 } 182 183 jint result = usb_device_bulk_transfer(device, endpoint, bufferBytes + start, length, timeout); 184 185 if (bufferBytes) { 186 env->ReleasePrimitiveArrayCritical(buffer, bufferBytes, 0); 187 } 188 189 return result; 190 } 191 192 static jobject 193 android_hardware_UsbDeviceConnection_request_wait(JNIEnv *env, jobject thiz) 194 { 195 struct usb_device* device = get_device_from_object(env, thiz); 196 if (!device) { 197 ALOGE("device is closed in native_request_wait"); 198 return NULL; 199 } 200 201 struct usb_request* request = usb_request_wait(device); 202 if (request) 203 return (jobject)request->client_data; 204 else 205 return NULL; 206 } 207 208 static jstring 209 android_hardware_UsbDeviceConnection_get_serial(JNIEnv *env, jobject thiz) 210 { 211 struct usb_device* device = get_device_from_object(env, thiz); 212 if (!device) { 213 ALOGE("device is closed in native_request_wait"); 214 return NULL; 215 } 216 char* serial = usb_device_get_serial(device); 217 if (!serial) 218 return NULL; 219 jstring result = env->NewStringUTF(serial); 220 free(serial); 221 return result; 222 } 223 224 static JNINativeMethod method_table[] = { 225 {"native_open", "(Ljava/lang/String;Ljava/io/FileDescriptor;)Z", 226 (void *)android_hardware_UsbDeviceConnection_open}, 227 {"native_close", "()V", (void *)android_hardware_UsbDeviceConnection_close}, 228 {"native_get_fd", "()I", (void *)android_hardware_UsbDeviceConnection_get_fd}, 229 {"native_get_desc", "()[B", (void *)android_hardware_UsbDeviceConnection_get_desc}, 230 {"native_claim_interface", "(IZ)Z",(void *)android_hardware_UsbDeviceConnection_claim_interface}, 231 {"native_release_interface","(I)Z", (void *)android_hardware_UsbDeviceConnection_release_interface}, 232 {"native_control_request", "(IIII[BIII)I", 233 (void *)android_hardware_UsbDeviceConnection_control_request}, 234 {"native_bulk_request", "(I[BIII)I", 235 (void *)android_hardware_UsbDeviceConnection_bulk_request}, 236 {"native_request_wait", "()Landroid/hardware/usb/UsbRequest;", 237 (void *)android_hardware_UsbDeviceConnection_request_wait}, 238 { "native_get_serial", "()Ljava/lang/String;", 239 (void*)android_hardware_UsbDeviceConnection_get_serial }, 240 }; 241 242 int register_android_hardware_UsbDeviceConnection(JNIEnv *env) 243 { 244 jclass clazz = env->FindClass("android/hardware/usb/UsbDeviceConnection"); 245 if (clazz == NULL) { 246 ALOGE("Can't find android/hardware/usb/UsbDeviceConnection"); 247 return -1; 248 } 249 field_context = env->GetFieldID(clazz, "mNativeContext", "I"); 250 if (field_context == NULL) { 251 ALOGE("Can't find UsbDeviceConnection.mNativeContext"); 252 return -1; 253 } 254 255 return AndroidRuntime::registerNativeMethods(env, "android/hardware/usb/UsbDeviceConnection", 256 method_table, NELEM(method_table)); 257 } 258