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 "core_jni_helpers.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->GetLongField(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 JNI_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->SetLongField(thiz, field_context, (jlong)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) ? JNI_TRUE : JNI_FALSE; 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->SetLongField(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 jint 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 JNI_FALSE; 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) ? JNI_TRUE : JNI_FALSE; 124 } 125 126 static jboolean 127 android_hardware_UsbDeviceConnection_release_interface(JNIEnv *env, jobject thiz, jint 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 JNI_FALSE; 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 == 0) ? JNI_TRUE : JNI_FALSE; 140 } 141 142 static jboolean 143 android_hardware_UsbDeviceConnection_set_interface(JNIEnv *env, jobject thiz, jint interfaceID, 144 jint alternateSetting) 145 { 146 struct usb_device* device = get_device_from_object(env, thiz); 147 if (!device) { 148 ALOGE("device is closed in native_set_interface"); 149 return JNI_FALSE; 150 } 151 int ret = usb_device_set_interface(device, interfaceID, alternateSetting); 152 return (ret == 0) ? JNI_TRUE : JNI_FALSE; 153 } 154 155 static jboolean 156 android_hardware_UsbDeviceConnection_set_configuration(JNIEnv *env, jobject thiz, jint configurationID) 157 { 158 struct usb_device* device = get_device_from_object(env, thiz); 159 if (!device) { 160 ALOGE("device is closed in native_set_configuration"); 161 return JNI_FALSE; 162 } 163 int ret = usb_device_set_configuration(device, configurationID); 164 return (ret == 0) ? JNI_TRUE : JNI_FALSE; 165 } 166 167 static jint 168 android_hardware_UsbDeviceConnection_control_request(JNIEnv *env, jobject thiz, 169 jint requestType, jint request, jint value, jint index, 170 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_control_transfer(device, requestType, request, 184 value, index, bufferBytes + start, length, timeout); 185 186 if (bufferBytes) { 187 env->ReleasePrimitiveArrayCritical(buffer, bufferBytes, 0); 188 } 189 190 return result; 191 } 192 193 static jint 194 android_hardware_UsbDeviceConnection_bulk_request(JNIEnv *env, jobject thiz, 195 jint endpoint, jbyteArray buffer, jint start, jint length, jint timeout) 196 { 197 struct usb_device* device = get_device_from_object(env, thiz); 198 if (!device) { 199 ALOGE("device is closed in native_control_request"); 200 return -1; 201 } 202 203 jbyte* bufferBytes = NULL; 204 if (buffer) { 205 bufferBytes = (jbyte*)env->GetPrimitiveArrayCritical(buffer, NULL); 206 } 207 208 jint result = usb_device_bulk_transfer(device, endpoint, bufferBytes + start, length, timeout); 209 210 if (bufferBytes) { 211 env->ReleasePrimitiveArrayCritical(buffer, bufferBytes, 0); 212 } 213 214 return result; 215 } 216 217 static jobject 218 android_hardware_UsbDeviceConnection_request_wait(JNIEnv *env, jobject thiz) 219 { 220 struct usb_device* device = get_device_from_object(env, thiz); 221 if (!device) { 222 ALOGE("device is closed in native_request_wait"); 223 return NULL; 224 } 225 226 struct usb_request* request = usb_request_wait(device); 227 if (request) 228 return (jobject)request->client_data; 229 else 230 return NULL; 231 } 232 233 static jstring 234 android_hardware_UsbDeviceConnection_get_serial(JNIEnv *env, jobject thiz) 235 { 236 struct usb_device* device = get_device_from_object(env, thiz); 237 if (!device) { 238 ALOGE("device is closed in native_request_wait"); 239 return NULL; 240 } 241 char* serial = usb_device_get_serial(device); 242 if (!serial) 243 return NULL; 244 jstring result = env->NewStringUTF(serial); 245 free(serial); 246 return result; 247 } 248 249 static const JNINativeMethod method_table[] = { 250 {"native_open", "(Ljava/lang/String;Ljava/io/FileDescriptor;)Z", 251 (void *)android_hardware_UsbDeviceConnection_open}, 252 {"native_close", "()V", (void *)android_hardware_UsbDeviceConnection_close}, 253 {"native_get_fd", "()I", (void *)android_hardware_UsbDeviceConnection_get_fd}, 254 {"native_get_desc", "()[B", (void *)android_hardware_UsbDeviceConnection_get_desc}, 255 {"native_claim_interface", "(IZ)Z",(void *)android_hardware_UsbDeviceConnection_claim_interface}, 256 {"native_release_interface","(I)Z", (void *)android_hardware_UsbDeviceConnection_release_interface}, 257 {"native_set_interface","(II)Z", (void *)android_hardware_UsbDeviceConnection_set_interface}, 258 {"native_set_configuration","(I)Z", (void *)android_hardware_UsbDeviceConnection_set_configuration}, 259 {"native_control_request", "(IIII[BIII)I", 260 (void *)android_hardware_UsbDeviceConnection_control_request}, 261 {"native_bulk_request", "(I[BIII)I", 262 (void *)android_hardware_UsbDeviceConnection_bulk_request}, 263 {"native_request_wait", "()Landroid/hardware/usb/UsbRequest;", 264 (void *)android_hardware_UsbDeviceConnection_request_wait}, 265 { "native_get_serial", "()Ljava/lang/String;", 266 (void*)android_hardware_UsbDeviceConnection_get_serial }, 267 }; 268 269 int register_android_hardware_UsbDeviceConnection(JNIEnv *env) 270 { 271 jclass clazz = FindClassOrDie(env, "android/hardware/usb/UsbDeviceConnection"); 272 field_context = GetFieldIDOrDie(env, clazz, "mNativeContext", "J"); 273 274 return RegisterMethodsOrDie(env, "android/hardware/usb/UsbDeviceConnection", 275 method_table, NELEM(method_table)); 276 } 277