blob: 4d73bf3d066d842dea2ca42305d3c926579f9b7b [file] [log] [blame]
Mike Lockwoodacc29cc2011-03-11 08:18:08 -05001/*
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
32using namespace android;
33
34static jfieldID field_context;
35
36struct usb_device* get_device_from_object(JNIEnv* env, jobject connection)
37{
38 return (struct usb_device*)env->GetIntField(connection, field_context);
39}
40
41static jboolean
42android_hardware_UsbDeviceConnection_open(JNIEnv *env, jobject thiz, jstring deviceName,
43 jobject fileDescriptor)
44{
Elliott Hughesa3804cf2011-04-11 16:50:19 -070045 int fd = jniGetFDFromFileDescriptor(env, fileDescriptor);
Mike Lockwoodacc29cc2011-03-11 08:18:08 -050046 // 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 LOGE("usb_device_open failed for %s", deviceNameStr);
57 close(fd);
58 }
59
60 env->ReleaseStringUTFChars(deviceName, deviceNameStr);
61 return (device != NULL);
62}
63
64static void
65android_hardware_UsbDeviceConnection_close(JNIEnv *env, jobject thiz)
66{
67 LOGD("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
75static jint
76android_hardware_UsbDeviceConnection_get_fd(JNIEnv *env, jobject thiz)
77{
78 struct usb_device* device = get_device_from_object(env, thiz);
79 if (!device) {
80 LOGE("device is closed in native_get_fd");
81 return -1;
82 }
83 return usb_device_get_fd(device);
84}
85
86static jboolean
87android_hardware_UsbDeviceConnection_claim_interface(JNIEnv *env, jobject thiz,
88 int interfaceID, jboolean force)
89{
90 struct usb_device* device = get_device_from_object(env, thiz);
91 if (!device) {
92 LOGE("device is closed in native_claim_interface");
93 return -1;
94 }
95
96 int ret = usb_device_claim_interface(device, interfaceID);
97 if (ret && force && errno == EBUSY) {
98 // disconnect kernel driver and try again
99 usb_device_connect_kernel_driver(device, interfaceID, false);
100 ret = usb_device_claim_interface(device, interfaceID);
101 }
102 return ret == 0;
103}
104
105static jint
106android_hardware_UsbDeviceConnection_release_interface(JNIEnv *env, jobject thiz, int interfaceID)
107{
108 struct usb_device* device = get_device_from_object(env, thiz);
109 if (!device) {
110 LOGE("device is closed in native_release_interface");
111 return -1;
112 }
113 int ret = usb_device_release_interface(device, interfaceID);
114 if (ret == 0) {
115 // allow kernel to reconnect its driver
116 usb_device_connect_kernel_driver(device, interfaceID, true);
117 }
118 return ret;
119}
120
121static jint
122android_hardware_UsbDeviceConnection_control_request(JNIEnv *env, jobject thiz,
123 jint requestType, jint request, jint value, jint index,
124 jbyteArray buffer, jint length, jint timeout)
125{
126 struct usb_device* device = get_device_from_object(env, thiz);
127 if (!device) {
128 LOGE("device is closed in native_control_request");
129 return -1;
130 }
131
132 jbyte* bufferBytes = NULL;
133 if (buffer) {
134 if (env->GetArrayLength(buffer) < length) {
Elliott Hughes8451b252011-04-07 19:17:57 -0700135 jniThrowException(env, "java/lang/ArrayIndexOutOfBoundsException", NULL);
Mike Lockwoodacc29cc2011-03-11 08:18:08 -0500136 return -1;
137 }
138 bufferBytes = env->GetByteArrayElements(buffer, 0);
139 }
140
141 jint result = usb_device_control_transfer(device, requestType, request,
142 value, index, bufferBytes, length, timeout);
143
144 if (bufferBytes)
145 env->ReleaseByteArrayElements(buffer, bufferBytes, 0);
146
147 return result;
148}
149
150static jint
151android_hardware_UsbDeviceConnection_bulk_request(JNIEnv *env, jobject thiz,
152 jint endpoint, jbyteArray buffer, jint length, jint timeout)
153{
154 struct usb_device* device = get_device_from_object(env, thiz);
155 if (!device) {
156 LOGE("device is closed in native_control_request");
157 return -1;
158 }
159
160 jbyte* bufferBytes = NULL;
161 if (buffer) {
162 if (env->GetArrayLength(buffer) < length) {
Elliott Hughes8451b252011-04-07 19:17:57 -0700163 jniThrowException(env, "java/lang/ArrayIndexOutOfBoundsException", NULL);
Mike Lockwoodacc29cc2011-03-11 08:18:08 -0500164 return -1;
165 }
166 bufferBytes = env->GetByteArrayElements(buffer, 0);
167 }
168
169 jint result = usb_device_bulk_transfer(device, endpoint, bufferBytes, length, timeout);
170
171 if (bufferBytes)
172 env->ReleaseByteArrayElements(buffer, bufferBytes, 0);
173
174 return result;
175}
176
177static jobject
178android_hardware_UsbDeviceConnection_request_wait(JNIEnv *env, jobject thiz)
179{
180 struct usb_device* device = get_device_from_object(env, thiz);
181 if (!device) {
182 LOGE("device is closed in native_request_wait");
183 return NULL;
184 }
185
186 struct usb_request* request = usb_request_wait(device);
187 if (request)
188 return (jobject)request->client_data;
189 else
190 return NULL;
191}
192
193static jstring
194android_hardware_UsbDeviceConnection_get_serial(JNIEnv *env, jobject thiz)
195{
196 struct usb_device* device = get_device_from_object(env, thiz);
197 if (!device) {
198 LOGE("device is closed in native_request_wait");
199 return NULL;
200 }
201 char* serial = usb_device_get_serial(device);
202 if (!serial)
203 return NULL;
204 jstring result = env->NewStringUTF(serial);
205 free(serial);
206 return result;
207}
208
209static JNINativeMethod method_table[] = {
210 {"native_open", "(Ljava/lang/String;Ljava/io/FileDescriptor;)Z",
211 (void *)android_hardware_UsbDeviceConnection_open},
212 {"native_close", "()V", (void *)android_hardware_UsbDeviceConnection_close},
213 {"native_get_fd", "()I", (void *)android_hardware_UsbDeviceConnection_get_fd},
214 {"native_claim_interface", "(IZ)Z",(void *)android_hardware_UsbDeviceConnection_claim_interface},
215 {"native_release_interface","(I)Z", (void *)android_hardware_UsbDeviceConnection_release_interface},
216 {"native_control_request", "(IIII[BII)I",
217 (void *)android_hardware_UsbDeviceConnection_control_request},
218 {"native_bulk_request", "(I[BII)I",
219 (void *)android_hardware_UsbDeviceConnection_bulk_request},
220 {"native_request_wait", "()Landroid/hardware/usb/UsbRequest;",
221 (void *)android_hardware_UsbDeviceConnection_request_wait},
222 { "native_get_serial", "()Ljava/lang/String;",
223 (void*)android_hardware_UsbDeviceConnection_get_serial },
224};
225
226int register_android_hardware_UsbDeviceConnection(JNIEnv *env)
227{
228 jclass clazz = env->FindClass("android/hardware/usb/UsbDeviceConnection");
229 if (clazz == NULL) {
230 LOGE("Can't find android/hardware/usb/UsbDeviceConnection");
231 return -1;
232 }
233 field_context = env->GetFieldID(clazz, "mNativeContext", "I");
234 if (field_context == NULL) {
235 LOGE("Can't find UsbDeviceConnection.mNativeContext");
236 return -1;
237 }
238
239 return AndroidRuntime::registerNativeMethods(env, "android/hardware/usb/UsbDeviceConnection",
240 method_table, NELEM(method_table));
241}