]>
Commit | Line | Data |
---|---|---|
13b2dfdc MC |
1 | diff -urp libusb-1.0.9.orig/libusb/io.c libusb-1.0.9/libusb/io.c |
2 | --- libusb-1.0.9.orig/libusb/io.c 2013-08-28 14:33:15.000000000 +0200 | |
3 | +++ libusb-1.0.9/libusb/io.c 2013-08-28 14:31:25.000000000 +0200 | |
4 | @@ -36,6 +36,14 @@ | |
5 | ||
6 | #include "libusbi.h" | |
7 | ||
8 | +#ifndef TIMESPEC_TO_TIMEVAL | |
9 | +#define TIMESPEC_TO_TIMEVAL(tv, ts) \ | |
10 | + do { \ | |
11 | + (tv)->tv_sec = (ts)->tv_sec; \ | |
12 | + (tv)->tv_usec = (ts)->tv_nsec / 1000; \ | |
13 | + } while (0) | |
14 | +#endif | |
15 | + | |
16 | /** | |
17 | * \page io Synchronous and asynchronous device I/O | |
18 | * | |
c8cf030a MC |
19 | --- libusb-1.0.19.orig/libusb/os/linux_usbfs.c 2014-05-30 11:18:28.000000000 +0200 |
20 | +++ libusb-1.0.19/libusb/os/linux_usbfs.c 2016-11-26 15:38:21.199383120 +0100 | |
21 | @@ -37,11 +37,31 @@ | |
e1dbb76d MC |
22 | #include <sys/types.h> |
23 | #include <sys/utsname.h> | |
24 | #include <unistd.h> | |
25 | +#ifdef __ANDROID__ | |
26 | +#include <jni.h> | |
27 | +#endif | |
28 | ||
29 | #include "libusb.h" | |
30 | #include "libusbi.h" | |
31 | #include "linux_usbfs.h" | |
32 | ||
33 | +#ifdef __ANDROID__ | |
34 | +static JavaVM *g_jvm = NULL; | |
35 | +static jclass usb_helper_class; | |
c8cf030a | 36 | +static jclass usb_event_listener_class; |
e1dbb76d | 37 | +static jmethodID usb_helper_open_mid; |
c8cf030a MC |
38 | +static jmethodID usb_helper_start_event_monitor_mid; |
39 | +static jmethodID usb_helper_stop_event_monitor_mid; | |
40 | +static jmethodID usb_helper_scan_devices_mid; | |
41 | +static jmethodID usb_event_listener_init_mid; | |
e1dbb76d | 42 | +static int usb_helper_open(const char *pathname, int flags); |
c8cf030a MC |
43 | +static int usb_helper_start_event_monitor(void); |
44 | +static int usb_helper_stop_event_monitor(void); | |
45 | +static int usb_helper_scan_devices (struct libusb_context *ctx); | |
46 | +static void usb_helper_hotplug_poll(void); | |
47 | +static void usb_helper_on_usb_device_action(JNIEnv *env, jobject self, jstring name, jboolean removed); | |
e1dbb76d MC |
48 | +#endif |
49 | + | |
50 | /* sysfs vs usbfs: | |
51 | * opening a usbfs node causes the device to be resumed, so we attempt to | |
52 | * avoid this during enumeration. | |
c8cf030a | 53 | @@ -193,6 +213,11 @@ |
e1dbb76d MC |
54 | snprintf(path, PATH_MAX, "%s/%03d/%03d", |
55 | usbfs_path, dev->bus_number, dev->device_address); | |
56 | ||
57 | +#ifdef __ANDROID__ | |
58 | + if (g_jvm) | |
59 | + fd = usb_helper_open(path, mode); | |
60 | + else | |
61 | +#endif | |
62 | fd = open(path, mode); | |
63 | if (fd != -1) | |
64 | return fd; /* Success */ | |
c8cf030a MC |
65 | @@ -369,6 +394,13 @@ |
66 | struct stat statbuf; | |
67 | int r; | |
68 | ||
69 | +#ifdef __ANDROID__ | |
70 | + if (g_jvm) { | |
71 | + usbfs_path = "/dev/bus/usb"; | |
72 | + sysfs_can_relate_devices = 0; | |
73 | + sysfs_has_descriptors = 0; | |
74 | + } else | |
75 | +#endif | |
76 | usbfs_path = find_usbfs_path(); | |
77 | if (!usbfs_path) { | |
78 | usbi_err(ctx, "could not find usbfs"); | |
79 | @@ -467,6 +499,10 @@ | |
80 | ||
81 | static int linux_start_event_monitor(void) | |
82 | { | |
83 | +#ifdef __ANDROID__ | |
84 | + if (g_jvm) | |
85 | + return usb_helper_start_event_monitor(); | |
86 | +#endif | |
87 | #if defined(USE_UDEV) | |
88 | return linux_udev_start_event_monitor(); | |
89 | #else | |
90 | @@ -476,6 +512,10 @@ | |
91 | ||
92 | static int linux_stop_event_monitor(void) | |
93 | { | |
94 | +#ifdef __ANDROID__ | |
95 | + if (g_jvm) | |
96 | + return usb_helper_stop_event_monitor(); | |
97 | +#endif | |
98 | #if defined(USE_UDEV) | |
99 | return linux_udev_stop_event_monitor(); | |
100 | #else | |
101 | @@ -489,6 +529,11 @@ | |
102 | ||
103 | usbi_mutex_static_lock(&linux_hotplug_lock); | |
104 | ||
105 | +#ifdef __ANDROID__ | |
106 | + if (g_jvm) | |
107 | + ret = usb_helper_scan_devices(ctx); | |
108 | + else | |
109 | +#endif | |
110 | #if defined(USE_UDEV) | |
111 | ret = linux_udev_scan_devices(ctx); | |
112 | #else | |
113 | @@ -502,6 +547,11 @@ | |
114 | ||
115 | static void op_hotplug_poll(void) | |
116 | { | |
117 | +#ifdef __ANDROID__ | |
118 | + if (g_jvm) | |
119 | + usb_helper_hotplug_poll(); | |
120 | + else | |
121 | +#endif | |
122 | #if defined(USE_UDEV) | |
123 | linux_udev_hotplug_poll(); | |
124 | #else | |
125 | @@ -994,6 +1044,10 @@ | |
126 | /* XXX -- can we figure out the topology when using usbfs? */ | |
127 | if (NULL == sysfs_dir || 0 == strncmp(sysfs_dir, "usb", 3)) { | |
128 | /* either using usbfs or finding the parent of a root hub */ | |
129 | +#ifdef __ANDROID__ | |
130 | + if (g_jvm) | |
131 | + dev->port_number = dev->device_address; | |
132 | +#endif | |
133 | return LIBUSB_SUCCESS; | |
134 | } | |
135 | ||
136 | @@ -2693,3 +2747,262 @@ | |
e1dbb76d MC |
137 | .transfer_priv_size = sizeof(struct linux_transfer_priv), |
138 | .add_iso_packet_size = 0, | |
139 | }; | |
140 | + | |
141 | +#ifdef __ANDROID__ | |
142 | +jint JNI_OnLoad(JavaVM *vm, void *reserved) | |
143 | +{ | |
c8cf030a MC |
144 | + static JNINativeMethod jni_method = { |
145 | + "onUsbDeviceAction", | |
146 | + "(Ljava/lang/String;Z)V", | |
147 | + (void*)usb_helper_on_usb_device_action | |
148 | + }; | |
149 | + | |
e1dbb76d MC |
150 | + JNIEnv* env; |
151 | + g_jvm = vm; | |
152 | + if ((*vm)->GetEnv(vm, (void **)&env, JNI_VERSION_1_6) != JNI_OK) { | |
153 | + return -1; | |
154 | + } | |
155 | + | |
156 | + jclass helper = (*env)->FindClass(env, "org/sigrok/androidutils/UsbHelper"); | |
c8cf030a | 157 | + jclass event_listener = (*env)->FindClass(env, "org/sigrok/androidutils/UsbEventListenerStub"); |
e1dbb76d | 158 | + |
c8cf030a | 159 | + if (helper && event_listener) { |
e1dbb76d MC |
160 | + |
161 | + usb_helper_class = (jclass)(*env)->NewGlobalRef(env, helper); | |
162 | + | |
163 | + usb_helper_open_mid = (*env)->GetStaticMethodID(env, helper, "open", | |
164 | + "(Ljava/lang/String;I)I"); | |
c8cf030a MC |
165 | + usb_helper_start_event_monitor_mid = (*env)->GetStaticMethodID(env, helper, "startEventMonitor", |
166 | + "(Lorg/sigrok/androidutils/UsbEventListener;)V"); | |
167 | + usb_helper_stop_event_monitor_mid = (*env)->GetStaticMethodID(env, helper, "stopEventMonitor", | |
168 | + "()V"); | |
169 | + usb_helper_scan_devices_mid = (*env)->GetStaticMethodID(env, helper, "scanDevices", | |
170 | + "()[Ljava/lang/String;"); | |
e1dbb76d MC |
171 | + (*env)->DeleteLocalRef(env, helper); |
172 | + | |
c8cf030a MC |
173 | + usb_event_listener_class = (jclass)(*env)->NewGlobalRef(env, event_listener); |
174 | + usb_event_listener_init_mid = (*env)->GetMethodID(env, event_listener, "<init>", | |
175 | + "()V"); | |
176 | + if ((*env)->RegisterNatives(env, event_listener, &jni_method, 1) < 0) { | |
177 | + if ((*env)->ExceptionCheck(env)) { | |
178 | + (*env)->ExceptionClear(env); | |
179 | + } | |
180 | + g_jvm = NULL; | |
181 | + } | |
182 | + | |
183 | + (*env)->DeleteLocalRef(env, event_listener); | |
184 | + | |
e1dbb76d MC |
185 | + } else { |
186 | + if ((*env)->ExceptionCheck(env)) { | |
187 | + (*env)->ExceptionClear(env); | |
188 | + } | |
189 | + g_jvm = NULL; | |
190 | + } | |
191 | + | |
192 | + return JNI_VERSION_1_6; | |
193 | +} | |
194 | + | |
195 | +void JNI_OnUnload(JavaVM *vm, void *reserved) | |
196 | +{ | |
197 | + JNIEnv* env; | |
198 | + if ((*vm)->GetEnv(vm, (void **)&env, JNI_VERSION_1_6) != JNI_OK) { | |
199 | + return; | |
200 | + } | |
201 | + | |
202 | + jclass helper = usb_helper_class; | |
c8cf030a | 203 | + jclass event_listener = usb_event_listener_class; |
e1dbb76d | 204 | + usb_helper_class = NULL; |
c8cf030a | 205 | + usb_event_listener_class = NULL; |
e1dbb76d MC |
206 | + if (helper) |
207 | + (*env)->DeleteGlobalRef(env, helper); | |
c8cf030a MC |
208 | + if (event_listener) { |
209 | + (*env)->UnregisterNatives(env, event_listener); | |
210 | + (*env)->DeleteGlobalRef(env, event_listener); | |
211 | + } | |
e1dbb76d MC |
212 | + g_jvm = NULL; |
213 | +} | |
214 | + | |
215 | +static int usb_helper_open(const char *pathname, int flags) | |
216 | +{ | |
217 | + JNIEnv* env; | |
218 | + int res; | |
219 | + jint st; | |
220 | + int do_detach = 0; | |
221 | + | |
222 | + if (g_jvm == NULL) { | |
223 | + return -1; | |
224 | + } | |
225 | + st = (*g_jvm)->GetEnv(g_jvm, (void **)&env, JNI_VERSION_1_6); | |
226 | + | |
227 | + if (st == JNI_EDETACHED) { | |
228 | + st = (*g_jvm)->AttachCurrentThread(g_jvm, &env, NULL); | |
229 | + do_detach = 1; | |
230 | + } | |
231 | + | |
232 | + if (st != JNI_OK) { | |
233 | + return -1; | |
234 | + } | |
235 | + | |
236 | + jstring string = (*env)->NewStringUTF(env, pathname); | |
237 | + res = (*env)->CallStaticIntMethod(env, usb_helper_class, usb_helper_open_mid, string, (jint)flags); | |
238 | + (*env)->DeleteLocalRef(env, string); | |
239 | + | |
240 | + if (do_detach) { | |
241 | + (*g_jvm)->DetachCurrentThread(g_jvm); | |
242 | + } | |
243 | + | |
c8cf030a MC |
244 | + if (res >= 0) { |
245 | + /* Rewind so that descriptors can be read */ | |
246 | + lseek(res, SEEK_SET, 0); | |
247 | + } | |
248 | + | |
249 | + return res; | |
250 | +} | |
251 | + | |
252 | +static int usb_helper_start_event_monitor(void) | |
253 | +{ | |
254 | + JNIEnv* env; | |
255 | + jint st; | |
256 | + int do_detach = 0; | |
257 | + int res = 0; | |
258 | + jobject usb_event_listener; | |
259 | + | |
260 | + if (g_jvm == NULL) { | |
261 | + return LIBUSB_ERROR_OTHER; | |
262 | + } | |
263 | + st = (*g_jvm)->GetEnv(g_jvm, (void **)&env, JNI_VERSION_1_6); | |
264 | + | |
265 | + if (st == JNI_EDETACHED) { | |
266 | + st = (*g_jvm)->AttachCurrentThread(g_jvm, &env, NULL); | |
267 | + do_detach = 1; | |
268 | + } | |
269 | + | |
270 | + if (st != JNI_OK) { | |
271 | + return LIBUSB_ERROR_OTHER; | |
272 | + } | |
273 | + | |
274 | + usb_event_listener = (*env)->NewObject(env, usb_event_listener_class, usb_event_listener_init_mid); | |
275 | + if (usb_event_listener == NULL) | |
276 | + res = LIBUSB_ERROR_OTHER; | |
277 | + else { | |
278 | + (*env)->CallStaticVoidMethod(env, usb_helper_class, usb_helper_start_event_monitor_mid, usb_event_listener); | |
279 | + (*env)->DeleteLocalRef(env, usb_event_listener); | |
280 | + } | |
281 | + | |
282 | + if (do_detach) { | |
283 | + (*g_jvm)->DetachCurrentThread(g_jvm); | |
284 | + } | |
285 | + | |
286 | + return res; | |
287 | +} | |
288 | + | |
289 | +static int usb_helper_stop_event_monitor(void) | |
290 | +{ | |
291 | + JNIEnv* env; | |
292 | + jint st; | |
293 | + int do_detach = 0; | |
294 | + | |
295 | + if (g_jvm == NULL) { | |
296 | + return LIBUSB_ERROR_OTHER; | |
297 | + } | |
298 | + st = (*g_jvm)->GetEnv(g_jvm, (void **)&env, JNI_VERSION_1_6); | |
299 | + | |
300 | + if (st == JNI_EDETACHED) { | |
301 | + st = (*g_jvm)->AttachCurrentThread(g_jvm, &env, NULL); | |
302 | + do_detach = 1; | |
303 | + } | |
304 | + | |
305 | + if (st != JNI_OK) { | |
306 | + return LIBUSB_ERROR_OTHER; | |
307 | + } | |
308 | + | |
309 | + (*env)->CallStaticVoidMethod(env, usb_helper_class, usb_helper_stop_event_monitor_mid); | |
310 | + | |
311 | + if (do_detach) { | |
312 | + (*g_jvm)->DetachCurrentThread(g_jvm); | |
313 | + } | |
314 | + | |
315 | + return 0; | |
316 | +} | |
317 | + | |
318 | +static int usb_helper_scan_devices (struct libusb_context *ctx) | |
319 | +{ | |
320 | + JNIEnv* env; | |
321 | + int res = 0; | |
322 | + jint st; | |
323 | + int do_detach = 0; | |
324 | + | |
325 | + if (g_jvm == NULL) { | |
326 | + return LIBUSB_ERROR_OTHER; | |
327 | + } | |
328 | + st = (*g_jvm)->GetEnv(g_jvm, (void **)&env, JNI_VERSION_1_6); | |
329 | + | |
330 | + if (st == JNI_EDETACHED) { | |
331 | + st = (*g_jvm)->AttachCurrentThread(g_jvm, &env, NULL); | |
332 | + do_detach = 1; | |
333 | + } | |
334 | + | |
335 | + if (st != JNI_OK) { | |
336 | + return LIBUSB_ERROR_OTHER; | |
337 | + } | |
338 | + | |
339 | + jobject arr = (*env)->CallStaticObjectMethod(env, usb_helper_class, usb_helper_scan_devices_mid); | |
340 | + | |
341 | + if (arr == NULL) | |
342 | + res = LIBUSB_ERROR_OTHER; | |
343 | + else { | |
344 | + jsize i, len = (*env)->GetArrayLength(env, arr); | |
345 | + for (i=0; i<len; i++) { | |
346 | + jobject str = (*env)->GetObjectArrayElement(env, arr, i); | |
347 | + if (str) { | |
348 | + const char *ustr = (*env)->GetStringUTFChars(env, str, NULL); | |
349 | + if (ustr) { | |
350 | + unsigned busnum, devaddr; | |
351 | + if (2 != sscanf(ustr, "/dev/bus/usb/%u/%u", | |
352 | + &busnum, &devaddr) || | |
353 | + linux_enumerate_device(ctx, busnum, devaddr, NULL)) { | |
354 | + usbi_dbg("failed to enumerate device %s", ustr); | |
355 | + } | |
356 | + (*env)->ReleaseStringUTFChars(env, str, ustr); | |
357 | + } else | |
358 | + res = LIBUSB_ERROR_OTHER; | |
359 | + (*env)->DeleteLocalRef(env, str); | |
360 | + } else | |
361 | + res = LIBUSB_ERROR_OTHER; | |
362 | + if (res) | |
363 | + break; | |
364 | + } | |
365 | + (*env)->DeleteLocalRef(env, arr); | |
366 | + } | |
367 | + | |
368 | + if (do_detach) { | |
369 | + (*g_jvm)->DetachCurrentThread(g_jvm); | |
370 | + } | |
371 | + | |
e1dbb76d MC |
372 | + return res; |
373 | +} | |
c8cf030a MC |
374 | + |
375 | +static void usb_helper_hotplug_poll(void) | |
376 | +{ | |
377 | +} | |
378 | + | |
379 | +static void usb_helper_on_usb_device_action(JNIEnv *env, jobject self, jstring name, jboolean removed) | |
380 | +{ | |
381 | + usbi_mutex_static_lock(&linux_hotplug_lock); | |
382 | + if (name) { | |
383 | + const char *ustr = (*env)->GetStringUTFChars(env, name, NULL); | |
384 | + if (ustr) { | |
385 | + unsigned busnum, devaddr; | |
386 | + if (2 == sscanf(ustr, "/dev/bus/usb/%u/%u", | |
387 | + &busnum, &devaddr)) { | |
388 | + if (removed) | |
389 | + linux_device_disconnected(busnum, devaddr, NULL); | |
390 | + else | |
391 | + linux_hotplug_enumerate(busnum, devaddr, NULL); | |
392 | + } | |
393 | + (*env)->ReleaseStringUTFChars(env, name, ustr); | |
394 | + } | |
395 | + } | |
396 | + usbi_mutex_static_unlock(&linux_hotplug_lock); | |
397 | +} | |
e1dbb76d | 398 | +#endif |