• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 <nativehelper/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 
get_request_from_object(JNIEnv * env,jobject java_request)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
android_hardware_UsbRequest_init(JNIEnv * env,jobject thiz,jobject java_device,jint ep_address,jint ep_attributes,jint ep_max_packet_size,jint ep_interval)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
android_hardware_UsbRequest_close(JNIEnv * env,jobject thiz)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
android_hardware_UsbRequest_queue_array(JNIEnv * env,jobject thiz,jbyteArray buffer,jint length,jboolean out)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
android_hardware_UsbRequest_dequeue_array(JNIEnv * env,jobject thiz,jbyteArray buffer,jint length,jboolean out)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
android_hardware_UsbRequest_queue_direct(JNIEnv * env,jobject thiz,jobject buffer,jint length,jboolean out)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
android_hardware_UsbRequest_queue(JNIEnv * env,jobject thiz,jobject buffer,jint offset,jint length)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
android_hardware_UsbRequest_dequeue_direct(JNIEnv * env,jobject thiz)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
android_hardware_UsbRequest_cancel(JNIEnv * env,jobject thiz)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 
register_android_hardware_UsbRequest(JNIEnv * env)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