From d80266929cd0d2c46f04d84201d807040bbf5cf2 Mon Sep 17 00:00:00 2001 From: Klaus Reimer Date: Sat, 5 Feb 2011 15:02:00 +0100 Subject: [PATCH] Removed some debugging output. Implemented non-portable libusb functions. Implemented force-claiming of interfaces (Only works when libusb supports detaching drivers) --- src/main/c/src/USB.c | 79 +++++++++++++++- src/main/java/de/ailis/usb4java/USB.java | 94 +++++++++++++++++++ .../usb4java/jsr80/UsbConfigurationImpl.java | 1 - .../usb4java/jsr80/UsbInterfaceImpl.java | 27 ++++-- 4 files changed, 188 insertions(+), 13 deletions(-) diff --git a/src/main/c/src/USB.c b/src/main/c/src/USB.c index 83bb368..e84eed4 100644 --- a/src/main/c/src/USB.c +++ b/src/main/c/src/USB.c @@ -72,7 +72,7 @@ JNIEXPORT jobject JNICALL METHOD_NAME(USB, usb_1get_1busses) /** - * USB_Handle usb_open(USB_Device) + * USB_Dev_Handle usb_open(USB_Device) */ JNIEXPORT jobject JNICALL METHOD_NAME(USB, usb_1open) @@ -85,7 +85,7 @@ JNIEXPORT jobject JNICALL METHOD_NAME(USB, usb_1open) /** - * int usb_close(USB_Handle) + * int usb_close(USB_Dev_Handle) */ JNIEXPORT jint JNICALL METHOD_NAME(USB, usb_1close) @@ -98,7 +98,7 @@ JNIEXPORT jint JNICALL METHOD_NAME(USB, usb_1close) /** - * int usb_set_configuration(USB_Handle handle, int configuration) + * int usb_set_configuration(USB_Dev_Handle handle, int configuration) */ JNIEXPORT jint JNICALL METHOD_NAME(USB, usb_1set_1configuration) @@ -197,7 +197,7 @@ JNIEXPORT jint JNICALL METHOD_NAME(USB, usb_1control_1msg) /** - * int usb_get_string(USB_Handle handle, int index, int langid, byte[] buffer, + * int usb_get_string(USB_Dev_Handle handle, int index, int langid, byte[] buffer, * int buflen) */ @@ -216,7 +216,7 @@ JNIEXPORT jint JNICALL METHOD_NAME(USB, usb_1get_1string) /** - * int usb_get_simple_string(USB_Handle handle, int index, ByteBuffer buffer) + * int usb_get_simple_string(USB_Dev_Handle handle, int index, ByteBuffer buffer) */ JNIEXPORT jint JNICALL METHOD_NAME(USB, usb_1get_1string_1simple) @@ -357,3 +357,72 @@ JNIEXPORT jstring JNICALL METHOD_NAME(USB, usb_1strerror) { return (*env)->NewStringUTF(env, usb_strerror()); } + + +/** + * int usb_detach_kernel_driver_np(USB_Dev_Handle handle, int iface) + */ + +#ifdef LIBUSB_HAS_DETACH_KERNEL_DRIVER_NP +JNIEXPORT jint JNICALL METHOD_NAME(USB, usb_1detach_1kernel_1driver_1np) +( + JNIEnv *env, jclass class, jobject handle, jint iface +) +{ + return usb_detach_kernel_driver_np(unwrap_usb_dev_handle(env, handle), iface); +} +#endif + + +/** + * int usb_get_driver_np(USB_Dev_Handle handle, int iface, ByteBuffer buffer) + */ + +#ifdef LIBUSB_HAS_GET_DRIVER_NP +JNIEXPORT jint JNICALL METHOD_NAME(USB, usb_1get_1driver_1np) +( + JNIEnv *env, jclass class, jobject handle, jint iface, jobject buffer +) +{ + void *buf = (*env)->GetDirectBufferAddress(env, buffer); + if (!buf) return -1; + jlong buflen = (*env)->GetDirectBufferCapacity(env, buffer); + return usb_get_driver_np(unwrap_usb_dev_handle(env, handle), + iface, buf, buflen); +} +#endif + + +/** + * boolean libusb_has_detach_kernel_driver_np() + */ + +JNIEXPORT jboolean JNICALL METHOD_NAME(USB, + libusb_1has_1detach_1kernel_1driver_1np) +( + JNIEnv *env, jclass class +) +{ + #ifdef LIBUSB_HAS_DETACH_KERNEL_DRIVER_NP + return 1; + #else + return 0; + #endif +} + + +/** + * boolean libusb_has_get_driver_np() + */ + +JNIEXPORT jboolean JNICALL METHOD_NAME(USB, libusb_1has_1get_1driver_1np) +( + JNIEnv *env, jclass class +) +{ + #ifdef LIBUSB_HAS_GET_DRIVER_NP + return 1; + #else + return 0; + #endif +} diff --git a/src/main/java/de/ailis/usb4java/USB.java b/src/main/java/de/ailis/usb4java/USB.java index cd6e240..369bdd8 100644 --- a/src/main/java/de/ailis/usb4java/USB.java +++ b/src/main/java/de/ailis/usb4java/USB.java @@ -764,4 +764,98 @@ public final class USB */ public static native String usb_strerror(); + + + /** + * Get driver name bound to interface. + * + * This function will obtain the name of the driver bound to the interface + * specified by the parameter interface and place it into the specified + * buffer. Returns 0 on success or < 0 on error. + * + * Implemented on Linux only. On other platforms an UnsatisfiedLinkError + * exception will be thrown. + * + * @param handle + * The USB device handle. + * @param iface + * The interface number. + * @param buffer + * The buffer to place the name in. + * @return 0 on success or < 0 on error. + */ + + public static native int usb_get_driver_np(USB_Dev_Handle handle, + int iface, ByteBuffer buffer); + + + /** + * Get driver name bound to interface. + * + * This function will obtain the name of the driver bound to the interface + * specified by the parameter interface. + * + * Implemented on Linux only. On other platforms an UnsatisfiedLinkError + * exception will be thrown. + * + * @param handle + * The USB device handle. + * @param iface + * The interface number. + * @return The driver name or null on error. + */ + + public static String usb_get_driver_np(final USB_Dev_Handle handle, + final int iface) + { + final ByteBuffer buffer = ByteBuffer.allocateDirect(MAX_STRING_SIZE); + final int result = usb_get_driver_np(handle, iface, buffer); + if (result < 0) return null; + buffer.rewind(); + int size = 0; + while (buffer.get() != 0) size++; + buffer.rewind(); + final byte[] bytes = new byte[size]; + buffer.get(bytes, 0, size); + return new String(bytes); + } + + + /** + * Detach kernel driver from interface. + * + * This function will detach a kernel driver from the interface specified by + * parameter interface. Applications using libusb can then try claiming the + * interface. Returns 0 on success or < 0 on error. + * + * Implemented on Linux only. On other platforms an UnsatisfiedLinkError + * exception will be thrown. + * + * @param handle + * The device handle. + * @param iface + * The interface number. + * @return 0 on success or < 0 on error. + */ + + public static native int usb_detach_kernel_driver_np(USB_Dev_Handle handle, + int iface); + + + /** + * Checks if libusb supports the usb_get_driver_np function. + * + * @return True if support is present, false if not. + */ + + public static native boolean libusb_has_get_driver_np(); + + + /** + * Checks if libusb supports the usb_detach_kernel_driver_np function. + * + * @return True if support is present, false if not. + */ + + public static native boolean libusb_has_detach_kernel_driver_np(); } diff --git a/src/main/java/de/ailis/usb4java/jsr80/UsbConfigurationImpl.java b/src/main/java/de/ailis/usb4java/jsr80/UsbConfigurationImpl.java index cb9a61b..96b386e 100644 --- a/src/main/java/de/ailis/usb4java/jsr80/UsbConfigurationImpl.java +++ b/src/main/java/de/ailis/usb4java/jsr80/UsbConfigurationImpl.java @@ -94,7 +94,6 @@ public final class UsbConfigurationImpl implements UsbConfiguration desc.bAlternateSetting() == 0) { this.activeSettings.put(ifaceNumber, usbInterface); - System.out.println("Active: " + usbInterface); } // Add the interface to the settings list diff --git a/src/main/java/de/ailis/usb4java/jsr80/UsbInterfaceImpl.java b/src/main/java/de/ailis/usb4java/jsr80/UsbInterfaceImpl.java index 177800e..fea5078 100644 --- a/src/main/java/de/ailis/usb4java/jsr80/UsbInterfaceImpl.java +++ b/src/main/java/de/ailis/usb4java/jsr80/UsbInterfaceImpl.java @@ -5,6 +5,9 @@ package de.ailis.usb4java.jsr80; +import static de.ailis.usb4java.USB.libusb_has_detach_kernel_driver_np; +import static de.ailis.usb4java.USB.usb_detach_kernel_driver_np; + import java.io.UnsupportedEncodingException; import java.util.ArrayList; import java.util.Collections; @@ -43,11 +46,14 @@ public final class UsbInterfaceImpl implements UsbInterface /** The endpoint address to endpoints mapping. */ private final Map endpointMap = - new HashMap(); + new HashMap(); /** The endpoints. */ private final List endpoints; + /** The USB device. */ + private final AbstractDevice device; + /** * Constructor. @@ -66,15 +72,16 @@ public final class UsbInterfaceImpl implements UsbInterface { this.configuration = configuration; this.descriptor = new UsbInterfaceDescriptorImpl(lowLevelDescriptor); + this.device = device; final List endpoints = new ArrayList(); for (final USB_Endpoint_Descriptor desc : lowLevelDescriptor - .endpoint()) + .endpoint()) { final UsbEndpointDescriptor descriptor = - new UsbEndpointDescriptorImpl(desc); + new UsbEndpointDescriptorImpl(desc); final UsbEndpoint endpoint = - new UsbEndpointImpl(this, descriptor, device); + new UsbEndpointImpl(this, descriptor, device); this.endpointMap.put(descriptor.bEndpointAddress(), endpoint); endpoints.add(endpoint); } @@ -131,6 +138,15 @@ public final class UsbInterfaceImpl implements UsbInterface USBLock.acquire(); try { + // Detach existing driver from the device if requested and + // libusb supports it. + if (policy != null && policy.forceClaim(this) + && libusb_has_detach_kernel_driver_np()) + { + usb_detach_kernel_driver_np(this.device.open(), + this.descriptor.bInterfaceNumber()); + } + device.setActiveUsbConfigurationNumber(this.configuration .getUsbConfigurationDescriptor().bConfigurationValue()); device.claimInterface(this.descriptor.bInterfaceNumber()); @@ -175,9 +191,6 @@ public final class UsbInterfaceImpl implements UsbInterface @Override public boolean isActive() { - System.out.println(this.configuration.getUsbInterface(this.descriptor - .bInterfaceNumber())); - System.out.println(this); return this.configuration.getUsbInterface(this.descriptor .bInterfaceNumber()) == this; }