blob: 6bd67d1063d27039a8e63967d68d44a286d318a4 [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"
22#include "JNIHelp.h"
23#include "android_runtime/AndroidRuntime.h"
24
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{
35 return (struct usb_request*)env->GetIntField(java_request, field_context);
36}
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{
45 LOGD("init\n");
46
47 struct usb_device* device = get_device_from_object(env, java_device);
48 if (!device) {
49 LOGE("device null in native_init");
50 return 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->SetIntField(thiz, field_context, (int)request);
65 return (request != NULL);
66}
67
68static void
69android_hardware_UsbRequest_close(JNIEnv *env, jobject thiz)
70{
71 LOGD("close\n");
72 struct usb_request* request = get_request_from_object(env, thiz);
73 if (request) {
74 usb_request_free(request);
75 env->SetIntField(thiz, field_context, 0);
76 }
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) {
85 LOGE("request is closed in native_queue");
86 return false;
87 }
88
89 if (buffer && length) {
90 request->buffer = malloc(length);
91 if (!request->buffer)
92 return false;
93 if (out) {
94 // copy data from Java buffer to native buffer
95 env->GetByteArrayRegion(buffer, 0, length, (jbyte *)request->buffer);
96 }
97 } else {
98 request->buffer = NULL;
99 }
100 request->buffer_length = length;
101
102 if (usb_request_queue(request)) {
103 if (request->buffer) {
104 // free our buffer if usb_request_queue fails
105 free(request->buffer);
106 request->buffer = NULL;
107 }
108 return false;
109 } else {
Mike Lockwoodacc29cc2011-03-11 08:18:08 -0500110 // save a reference to ourselves so UsbDeviceConnection.waitRequest() can find us
Mike Lockwoode7d511e2010-12-30 13:39:37 -0500111 request->client_data = (void *)env->NewGlobalRef(thiz);
112 return true;
113 }
114}
115
116static void
117android_hardware_UsbRequest_dequeue_array(JNIEnv *env, jobject thiz,
118 jbyteArray buffer, jint length, jboolean out)
119{
120 struct usb_request* request = get_request_from_object(env, thiz);
121 if (!request) {
122 LOGE("request is closed in native_dequeue");
123 return;
124 }
125
126 if (buffer && length && request->buffer && !out) {
127 // copy data from native buffer to Java buffer
128 env->SetByteArrayRegion(buffer, 0, length, (jbyte *)request->buffer);
129 }
130 free(request->buffer);
131 env->DeleteGlobalRef((jobject)request->client_data);
132
133}
134
135static jboolean
136android_hardware_UsbRequest_queue_direct(JNIEnv *env, jobject thiz,
137 jobject buffer, jint length, jboolean out)
138{
139 struct usb_request* request = get_request_from_object(env, thiz);
140 if (!request) {
141 LOGE("request is closed in native_queue");
142 return false;
143 }
144
145 if (buffer && length) {
146 request->buffer = env->GetDirectBufferAddress(buffer);
147 if (!request->buffer)
148 return false;
149 } else {
150 request->buffer = NULL;
151 }
152 request->buffer_length = length;
153
154 if (usb_request_queue(request)) {
155 request->buffer = NULL;
156 return false;
157 } else {
Mike Lockwoodacc29cc2011-03-11 08:18:08 -0500158 // save a reference to ourselves so UsbDeviceConnection.waitRequest() can find us
Mike Lockwoode7d511e2010-12-30 13:39:37 -0500159 // we also need this to make sure our native buffer is not deallocated
160 // while IO is active
161 request->client_data = (void *)env->NewGlobalRef(thiz);
162 return true;
163 }
164}
165
166static void
167android_hardware_UsbRequest_dequeue_direct(JNIEnv *env, jobject thiz)
168{
169 struct usb_request* request = get_request_from_object(env, thiz);
170 if (!request) {
171 LOGE("request is closed in native_dequeue");
172 return;
173 }
174 // all we need to do is delete our global ref
175 env->DeleteGlobalRef((jobject)request->client_data);
176}
177
178static jboolean
179android_hardware_UsbRequest_cancel(JNIEnv *env, jobject thiz)
180{
181 struct usb_request* request = get_request_from_object(env, thiz);
182 if (!request) {
183 LOGE("request is closed in native_cancel");
184 return false;
185 }
186 return (usb_request_cancel(request) == 0);
187}
188
189static JNINativeMethod method_table[] = {
Mike Lockwoodacc29cc2011-03-11 08:18:08 -0500190 {"native_init", "(Landroid/hardware/usb/UsbDeviceConnection;IIII)Z",
Mike Lockwoode7d511e2010-12-30 13:39:37 -0500191 (void *)android_hardware_UsbRequest_init},
192 {"native_close", "()V", (void *)android_hardware_UsbRequest_close},
193 {"native_queue_array", "([BIZ)Z", (void *)android_hardware_UsbRequest_queue_array},
194 {"native_dequeue_array", "([BIZ)V", (void *)android_hardware_UsbRequest_dequeue_array},
195 {"native_queue_direct", "(Ljava/nio/ByteBuffer;IZ)Z",
196 (void *)android_hardware_UsbRequest_queue_direct},
197 {"native_dequeue_direct", "()V", (void *)android_hardware_UsbRequest_dequeue_direct},
198 {"native_cancel", "()Z", (void *)android_hardware_UsbRequest_cancel},
199};
200
201int register_android_hardware_UsbRequest(JNIEnv *env)
202{
Mike Lockwoodc4308f02011-03-01 08:04:54 -0800203 jclass clazz = env->FindClass("android/hardware/usb/UsbRequest");
Mike Lockwoode7d511e2010-12-30 13:39:37 -0500204 if (clazz == NULL) {
Mike Lockwoodc4308f02011-03-01 08:04:54 -0800205 LOGE("Can't find android/hardware/usb/UsbRequest");
Mike Lockwoode7d511e2010-12-30 13:39:37 -0500206 return -1;
207 }
208 field_context = env->GetFieldID(clazz, "mNativeContext", "I");
209 if (field_context == NULL) {
210 LOGE("Can't find UsbRequest.mNativeContext");
211 return -1;
212 }
213
Mike Lockwoodc4308f02011-03-01 08:04:54 -0800214 return AndroidRuntime::registerNativeMethods(env, "android/hardware/usb/UsbRequest",
Mike Lockwoode7d511e2010-12-30 13:39:37 -0500215 method_table, NELEM(method_table));
216}
217