blob: 9bdb60542858b691e193c886007711c9967f13a1 [file] [log] [blame]
Mike Lockwoode7d511e2010-12-30 13:39:37 -05001/*
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"
Steven Moreland2279b252017-07-19 09:50:45 -070022#include <nativehelper/JNIHelp.h>
Andreas Gampeed6b9df2014-11-20 22:02:20 -080023#include "core_jni_helpers.h"
Mike Lockwoode7d511e2010-12-30 13:39:37 -050024
25#include <usbhost/usbhost.h>
26
27#include <stdio.h>
28
29using namespace android;
30
31static jfieldID field_context;
32
33struct usb_request* get_request_from_object(JNIEnv* env, jobject java_request)
34{
Ashok Bhat4838e332014-01-03 14:37:19 +000035 return (struct usb_request*)env->GetLongField(java_request, field_context);
Mike Lockwoode7d511e2010-12-30 13:39:37 -050036}
37
Mike Lockwoodacc29cc2011-03-11 08:18:08 -050038// in android_hardware_UsbDeviceConnection.cpp
39extern struct usb_device* get_device_from_object(JNIEnv* env, jobject connection);
Mike Lockwoode7d511e2010-12-30 13:39:37 -050040
41static jboolean
42android_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{
Steve Block5baa3a62011-12-20 16:23:08 +000045 ALOGD("init\n");
Mike Lockwoode7d511e2010-12-30 13:39:37 -050046
47 struct usb_device* device = get_device_from_object(env, java_device);
48 if (!device) {
Steve Block3762c312012-01-06 19:20:56 +000049 ALOGE("device null in native_init");
Philip P. Moltmann4346f3c2016-09-14 15:40:50 -070050 return JNI_FALSE;
Mike Lockwoode7d511e2010-12-30 13:39:37 -050051 }
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)
Ashok Bhat4838e332014-01-03 14:37:19 +000064 env->SetLongField(thiz, field_context, (jlong)request);
Mike Lockwoode7d511e2010-12-30 13:39:37 -050065 return (request != NULL);
66}
67
68static void
69android_hardware_UsbRequest_close(JNIEnv *env, jobject thiz)
70{
Steve Block5baa3a62011-12-20 16:23:08 +000071 ALOGD("close\n");
Mike Lockwoode7d511e2010-12-30 13:39:37 -050072 struct usb_request* request = get_request_from_object(env, thiz);
73 if (request) {
74 usb_request_free(request);
Ashok Bhat4838e332014-01-03 14:37:19 +000075 env->SetLongField(thiz, field_context, 0);
Mike Lockwoode7d511e2010-12-30 13:39:37 -050076 }
77}
78
79static jboolean
80android_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) {
Steve Block3762c312012-01-06 19:20:56 +000085 ALOGE("request is closed in native_queue");
Philip P. Moltmann4346f3c2016-09-14 15:40:50 -070086 return JNI_FALSE;
Mike Lockwoode7d511e2010-12-30 13:39:37 -050087 }
88
89 if (buffer && length) {
90 request->buffer = malloc(length);
91 if (!request->buffer)
Philip P. Moltmann4346f3c2016-09-14 15:40:50 -070092 return JNI_FALSE;
mike wakerlya3665ba2012-08-09 15:28:10 -070093 memset(request->buffer, 0, length);
Mike Lockwoode7d511e2010-12-30 13:39:37 -050094 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
Mike Lockwoodb2a46582014-05-20 11:33:35 -0700103 // save a reference to ourselves so UsbDeviceConnection.waitRequest() can find us
104 request->client_data = (void *)env->NewGlobalRef(thiz);
105
Mike Lockwoode7d511e2010-12-30 13:39:37 -0500106 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 }
Mike Lockwoodb2a46582014-05-20 11:33:35 -0700112 env->DeleteGlobalRef((jobject)request->client_data);
Philip P. Moltmann4346f3c2016-09-14 15:40:50 -0700113 return JNI_FALSE;
Mike Lockwoode7d511e2010-12-30 13:39:37 -0500114 }
Philip P. Moltmann4346f3c2016-09-14 15:40:50 -0700115 return JNI_TRUE;
Mike Lockwoode7d511e2010-12-30 13:39:37 -0500116}
117
Ashok Bhat4838e332014-01-03 14:37:19 +0000118static jint
Mike Lockwoode7d511e2010-12-30 13:39:37 -0500119android_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) {
Steve Block3762c312012-01-06 19:20:56 +0000124 ALOGE("request is closed in native_dequeue");
Ashok Bhat4838e332014-01-03 14:37:19 +0000125 return (jint) -1;
Mike Lockwoode7d511e2010-12-30 13:39:37 -0500126 }
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);
Ashok Bhat4838e332014-01-03 14:37:19 +0000134 return (jint) request->actual_length;
Mike Lockwoode7d511e2010-12-30 13:39:37 -0500135}
136
137static jboolean
138android_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) {
Steve Block3762c312012-01-06 19:20:56 +0000143 ALOGE("request is closed in native_queue");
Philip P. Moltmann4346f3c2016-09-14 15:40:50 -0700144 return JNI_FALSE;
Mike Lockwoode7d511e2010-12-30 13:39:37 -0500145 }
146
147 if (buffer && length) {
148 request->buffer = env->GetDirectBufferAddress(buffer);
149 if (!request->buffer)
Philip P. Moltmann4346f3c2016-09-14 15:40:50 -0700150 return JNI_FALSE;
Mike Lockwoode7d511e2010-12-30 13:39:37 -0500151 } else {
152 request->buffer = NULL;
153 }
154 request->buffer_length = length;
155
Mike Lockwoodb2a46582014-05-20 11:33:35 -0700156 // 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
Mike Lockwoode7d511e2010-12-30 13:39:37 -0500161 if (usb_request_queue(request)) {
162 request->buffer = NULL;
Mike Lockwoodb2a46582014-05-20 11:33:35 -0700163 env->DeleteGlobalRef((jobject)request->client_data);
Philip P. Moltmann4346f3c2016-09-14 15:40:50 -0700164 return JNI_FALSE;
Mike Lockwoode7d511e2010-12-30 13:39:37 -0500165 }
Philip P. Moltmann4346f3c2016-09-14 15:40:50 -0700166 return JNI_TRUE;
Mike Lockwoode7d511e2010-12-30 13:39:37 -0500167}
168
Philip P. Moltmann08b678c2016-10-18 17:43:37 -0700169static jboolean
Philip P. Moltmann91ed33b2017-04-03 09:35:34 -0700170android_hardware_UsbRequest_queue(JNIEnv *env, jobject thiz, jobject buffer, jint offset,
Philip P. Moltmann08b678c2016-10-18 17:43:37 -0700171 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
Ashok Bhat4838e332014-01-03 14:37:19 +0000201static jint
Mike Lockwoode7d511e2010-12-30 13:39:37 -0500202android_hardware_UsbRequest_dequeue_direct(JNIEnv *env, jobject thiz)
203{
204 struct usb_request* request = get_request_from_object(env, thiz);
205 if (!request) {
Steve Block3762c312012-01-06 19:20:56 +0000206 ALOGE("request is closed in native_dequeue");
Ashok Bhat4838e332014-01-03 14:37:19 +0000207 return (jint) -1;
Mike Lockwoode7d511e2010-12-30 13:39:37 -0500208 }
209 // all we need to do is delete our global ref
210 env->DeleteGlobalRef((jobject)request->client_data);
Ashok Bhat4838e332014-01-03 14:37:19 +0000211 return (jint) request->actual_length;
Mike Lockwoode7d511e2010-12-30 13:39:37 -0500212}
213
214static jboolean
215android_hardware_UsbRequest_cancel(JNIEnv *env, jobject thiz)
216{
217 struct usb_request* request = get_request_from_object(env, thiz);
218 if (!request) {
Steve Block3762c312012-01-06 19:20:56 +0000219 ALOGE("request is closed in native_cancel");
Philip P. Moltmann4346f3c2016-09-14 15:40:50 -0700220 return JNI_FALSE;
Mike Lockwoode7d511e2010-12-30 13:39:37 -0500221 }
222 return (usb_request_cancel(request) == 0);
223}
224
Daniel Micay76f6a862015-09-19 17:31:01 -0400225static const JNINativeMethod method_table[] = {
Mike Lockwoodacc29cc2011-03-11 08:18:08 -0500226 {"native_init", "(Landroid/hardware/usb/UsbDeviceConnection;IIII)Z",
Mike Lockwoode7d511e2010-12-30 13:39:37 -0500227 (void *)android_hardware_UsbRequest_init},
228 {"native_close", "()V", (void *)android_hardware_UsbRequest_close},
Philip P. Moltmann91ed33b2017-04-03 09:35:34 -0700229 {"native_queue", "(Ljava/nio/ByteBuffer;II)Z",
230 (void *)android_hardware_UsbRequest_queue},
Mike Lockwoode7d511e2010-12-30 13:39:37 -0500231 {"native_queue_array", "([BIZ)Z", (void *)android_hardware_UsbRequest_queue_array},
mike wakerlya3665ba2012-08-09 15:28:10 -0700232 {"native_dequeue_array", "([BIZ)I", (void *)android_hardware_UsbRequest_dequeue_array},
Mike Lockwoode7d511e2010-12-30 13:39:37 -0500233 {"native_queue_direct", "(Ljava/nio/ByteBuffer;IZ)Z",
234 (void *)android_hardware_UsbRequest_queue_direct},
mike wakerlya3665ba2012-08-09 15:28:10 -0700235 {"native_dequeue_direct", "()I", (void *)android_hardware_UsbRequest_dequeue_direct},
Mike Lockwoode7d511e2010-12-30 13:39:37 -0500236 {"native_cancel", "()Z", (void *)android_hardware_UsbRequest_cancel},
237};
238
239int register_android_hardware_UsbRequest(JNIEnv *env)
240{
Mike Lockwoodc4308f02011-03-01 08:04:54 -0800241 jclass clazz = env->FindClass("android/hardware/usb/UsbRequest");
Mike Lockwoode7d511e2010-12-30 13:39:37 -0500242 if (clazz == NULL) {
Steve Block3762c312012-01-06 19:20:56 +0000243 ALOGE("Can't find android/hardware/usb/UsbRequest");
Mike Lockwoode7d511e2010-12-30 13:39:37 -0500244 return -1;
245 }
Ashok Bhat4838e332014-01-03 14:37:19 +0000246 field_context = env->GetFieldID(clazz, "mNativeContext", "J");
Mike Lockwoode7d511e2010-12-30 13:39:37 -0500247 if (field_context == NULL) {
Steve Block3762c312012-01-06 19:20:56 +0000248 ALOGE("Can't find UsbRequest.mNativeContext");
Mike Lockwoode7d511e2010-12-30 13:39:37 -0500249 return -1;
250 }
251
Andreas Gampeed6b9df2014-11-20 22:02:20 -0800252 return RegisterMethodsOrDie(env, "android/hardware/usb/UsbRequest",
Mike Lockwoode7d511e2010-12-30 13:39:37 -0500253 method_table, NELEM(method_table));
254}
255