From ed6178e93ceedcfb92ebdbf2952d845147106c9c Mon Sep 17 00:00:00 2001 From: Klaus Reimer Date: Sat, 13 Jul 2013 17:14:22 +0200 Subject: [PATCH] Implement a bunch of new libusb constants and wrapper functions and add support for SuperSpeed Endpoint Companion Descriptors. --- src/changes/changes.xml | 20 ++ src/main/c/build/common.sh | 2 +- src/main/c/src/EndpointDescriptor.h | 2 + src/main/c/src/LibUsb.c | 91 +++++++ src/main/c/src/Makefile.am | 3 +- .../c/src/SSEndpointCompanionDescriptor.c | 97 ++++++++ .../c/src/SSEndpointCompanionDescriptor.h | 17 ++ .../java/de/ailis/usb4java/libusb/LibUsb.java | 229 ++++++++++++++++-- .../usb4java/libusb/LibUsbException.java | 2 +- .../libusb/SSEndpointCompanionDescriptor.java | 143 +++++++++++ .../usb4java/libusb/LibUSBGlobalTest.java | 23 ++ .../de/ailis/usb4java/libusb/LibUSBTest.java | 88 ++++++- 12 files changed, 691 insertions(+), 26 deletions(-) create mode 100644 src/main/c/src/SSEndpointCompanionDescriptor.c create mode 100644 src/main/c/src/SSEndpointCompanionDescriptor.h create mode 100644 src/main/java/de/ailis/usb4java/libusb/SSEndpointCompanionDescriptor.java diff --git a/src/changes/changes.xml b/src/changes/changes.xml index 6885638..7e06536 100644 --- a/src/changes/changes.xml +++ b/src/changes/changes.xml @@ -8,6 +8,26 @@ Klaus Reimer + + + Using reunited libusb/libusbx 1.0.16 as backend. + + + Add new libusb constants: LOW_SPEED_OPERATION, FULL_SPEED_OPERATION, + HIGH_SPEED_OPERATION, SUPER_SPEED_OPERATION, BM_LPM_SUPPORT, + BM_LTM_SUPPORT, BT_WIRELESS_USB_DEVICE_CAPABILITY, BT_USB_2_0_EXTENSION, + BT_SS_USB_DEVICE_CAPABILITY, BT_CONTAINER_ID, CAP_HAS_HOTPLUG, + CAP_HAS_HID_ACCESS, CAP_SUPPORTS_DETACH_KERNEL_DRIVER, DT_BOS, + DT_DEVICE_CAPABILITY, DT_SS_ENDPOINT_COMPANION + + + Wrap new libusb methods: getPortNumbers, setAutoDetachKernelDriver, + setLocale, strError. + + + Implement support for SuperSpeed Endpoint Companion Descriptor. + + Rewritten library to use libusb 1.0 as backend. diff --git a/src/main/c/build/common.sh b/src/main/c/build/common.sh index 3d78949..c9eca51 100644 --- a/src/main/c/build/common.sh +++ b/src/main/c/build/common.sh @@ -6,7 +6,7 @@ LIBUSB="libusbx" LIBUSB_VERSION="1.0.16" LIBUSB_RC="-rc8" LIBUSBX_VERSION="1.0.16" -LIBUSBX_RC="-rc3" +LIBUSBX_RC="" build() { diff --git a/src/main/c/src/EndpointDescriptor.h b/src/main/c/src/EndpointDescriptor.h index 89d710a..74f9cf0 100644 --- a/src/main/c/src/EndpointDescriptor.h +++ b/src/main/c/src/EndpointDescriptor.h @@ -10,5 +10,7 @@ jobjectArray wrapEndpointDescriptors(JNIEnv*, int, const struct libusb_endpoint_descriptor*); +struct libusb_endpoint_descriptor* unwrapEndpointDescriptor(JNIEnv*, + jobject); #endif diff --git a/src/main/c/src/LibUsb.c b/src/main/c/src/LibUsb.c index d7af386..1457020 100644 --- a/src/main/c/src/LibUsb.c +++ b/src/main/c/src/LibUsb.c @@ -21,6 +21,8 @@ #include "DeviceList.h" #include "DeviceDescriptor.h" #include "ConfigDescriptor.h" +#include "EndpointDescriptor.h" +#include "SSEndpointCompanionDescriptor.h" #include "Transfer.h" static JavaVM *jvm; @@ -38,6 +40,17 @@ JNIEXPORT jobject JNICALL METHOD_NAME(LibUsb, getVersion) return wrapVersion(env, libusb_get_version()); } +/** + * int getApiVersion() + */ +JNIEXPORT jint JNICALL METHOD_NAME(LibUsb, getApiVersion) +( + JNIEnv *env, jclass class +) +{ + return LIBUSBX_API_VERSION; +} + /** * int init() */ @@ -502,6 +515,20 @@ JNIEXPORT jint JNICALL METHOD_NAME(LibUsb, attachKernelDriver) return libusb_attach_kernel_driver(dev_handle, iface); } +/** + * int attachKernelDriver(DeviceHandle, int) + */ +JNIEXPORT jint JNICALL METHOD_NAME(LibUsb, setAutoDetachKernelDriver) +( + JNIEnv *env, jclass class, jobject handle, jboolean enable +) +{ + NOT_NULL(env, handle, return 0); + libusb_device_handle *dev_handle = unwrapDeviceHandle(env, handle); + if (!dev_handle) return 0; + return libusb_set_auto_detach_kernel_driver(dev_handle, enable); +} + /** * boolean hasCapability(int) */ @@ -524,6 +551,31 @@ JNIEXPORT jstring JNICALL METHOD_NAME(LibUsb, errorName) return (*env)->NewStringUTF(env, libusb_error_name(code)); } +/** + * int setLocale(string) + */ +JNIEXPORT jint JNICALL METHOD_NAME(LibUsb, setLocale) +( + JNIEnv *env, jobject this, jstring locale +) +{ + const char *nativeLocale = (*env)->GetStringUTFChars(env, locale, 0); + int result = libusb_setlocale(nativeLocale); + (*env)->ReleaseStringUTFChars(env, locale, nativeLocale); + return result; +} + +/** + * string strError(int) + */ +JNIEXPORT jstring JNICALL METHOD_NAME(LibUsb, strError) +( + JNIEnv *env, jobject this, jint code +) +{ + return (*env)->NewStringUTF(env, libusb_strerror(code)); +} + /** * int le16ToCpu(int) */ @@ -663,6 +715,45 @@ JNIEXPORT void JNICALL METHOD_NAME(LibUsb, freeConfigDescriptor) resetConfigDescriptor(env, descriptor); } +/** + * int getSSEndpointCompanionDescriptor(Device, int, SSEndpointCompanionDescriptor) + */ +JNIEXPORT jint JNICALL METHOD_NAME(LibUsb, getSSEndpointCompanionDescriptor) +( + JNIEnv *env, jclass class, jobject context, jobject endpointDescriptor, + jobject companionDescriptor +) +{ + NOT_NULL(env, endpointDescriptor, return 0); + NOT_NULL(env, companionDescriptor, return 0); + libusb_context *ctx = unwrapContext(env, context); + struct libusb_endpoint_descriptor *endpoint_descriptor = + unwrapEndpointDescriptor(env, endpointDescriptor); + if (!endpoint_descriptor) return 0; + struct libusb_ss_endpoint_companion_descriptor *companion_descriptor; + int result = libusb_get_ss_endpoint_companion_descriptor(ctx, + endpoint_descriptor, &companion_descriptor); + if (!result) setSSEndpointCompanionDescriptor(env, companion_descriptor, + companionDescriptor); + return result; +} + +/** + * void freeSSEndpointCompanionDescriptor(SSEndpointCompanionDescriptor) + */ +JNIEXPORT void JNICALL METHOD_NAME(LibUsb, freeSSEndpointCompanionDescriptor) +( + JNIEnv *env, jclass class, jobject companionDescriptor +) +{ + if (!companionDescriptor) return; + struct libusb_ss_endpoint_companion_descriptor *companion_descriptor = + unwrapSSEndpointCompanionDescriptor(env, companionDescriptor); + if (!companion_descriptor) return; + libusb_free_ss_endpoint_companion_descriptor(companion_descriptor); + resetSSEndpointCompanionDescriptor(env, companionDescriptor); +} + /** * int getDescriptor(DeviceHandle, int, int, ByteBuffer) */ diff --git a/src/main/c/src/Makefile.am b/src/main/c/src/Makefile.am index 9be6ead..087404a 100644 --- a/src/main/c/src/Makefile.am +++ b/src/main/c/src/Makefile.am @@ -17,4 +17,5 @@ libusb4java_la_SOURCES = \ Interface.c \ InterfaceDescriptor.c \ EndpointDescriptor.c \ - Transfer.c \ No newline at end of file + Transfer.c \ + SSEndpointCompanionDescriptor.c \ No newline at end of file diff --git a/src/main/c/src/SSEndpointCompanionDescriptor.c b/src/main/c/src/SSEndpointCompanionDescriptor.c new file mode 100644 index 0000000..f8b0755 --- /dev/null +++ b/src/main/c/src/SSEndpointCompanionDescriptor.c @@ -0,0 +1,97 @@ +/* + * Copyright (C) 2013 Klaus Reimer (k@ailis.de) + * See COPYING file for copying conditions + */ + +#include "SSEndpointCompanionDescriptor.h" +#include "Interface.h" + +void setSSEndpointCompanionDescriptor(JNIEnv* env, + struct libusb_ss_endpoint_companion_descriptor* descriptor, jobject object) +{ + SET_POINTER(env, descriptor, object, "ssEndpointCompanionDescriptor"); +} + +struct libusb_ss_endpoint_companion_descriptor* + unwrapSSEndpointCompanionDescriptor(JNIEnv* env, jobject descriptor) +{ + UNWRAP_POINTER(env, descriptor, + struct libusb_ss_endpoint_companion_descriptor*, + "ssEndpointCompanionDescriptor"); +} + +void resetSSEndpointCompanionDescriptor(JNIEnv* env, jobject obj) +{ + RESET_POINTER(env, obj, "ssEndpointCompanionDescriptor"); +} + +/** + * byte bLength() + */ +JNIEXPORT jbyte JNICALL METHOD_NAME(SSEndpointCompanionDescriptor, bLength) +( + JNIEnv *env, jobject this +) +{ + struct libusb_ss_endpoint_companion_descriptor *descriptor = + unwrapSSEndpointCompanionDescriptor(env, this); + if (!descriptor) return 0; + return descriptor->bLength; +} + +/** + * byte bDescriptorType() + */ +JNIEXPORT jbyte JNICALL METHOD_NAME(SSEndpointCompanionDescriptor, + bDescriptorType) +( + JNIEnv *env, jobject this +) +{ + struct libusb_ss_endpoint_companion_descriptor *descriptor = + unwrapSSEndpointCompanionDescriptor(env, this); + if (!descriptor) return 0; + return descriptor->bDescriptorType; +} + +/** + * byte bMaxBurst() + */ +JNIEXPORT jbyte JNICALL METHOD_NAME(SSEndpointCompanionDescriptor, bMaxBurst) +( + JNIEnv *env, jobject this +) +{ + struct libusb_ss_endpoint_companion_descriptor *descriptor = + unwrapSSEndpointCompanionDescriptor(env, this); + if (!descriptor) return 0; + return descriptor->bMaxBurst; +} + +/** + * byte bmAttributes() + */ +JNIEXPORT jbyte JNICALL METHOD_NAME(SSEndpointCompanionDescriptor, bmAttributes) +( + JNIEnv *env, jobject this +) +{ + struct libusb_ss_endpoint_companion_descriptor *descriptor = + unwrapSSEndpointCompanionDescriptor(env, this); + if (!descriptor) return 0; + return descriptor->bmAttributes; +} + +/** + * short wBytesPerInterval() + */ +JNIEXPORT jshort JNICALL METHOD_NAME(SSEndpointCompanionDescriptor, wBytesPerInterval) +( + JNIEnv *env, jobject this +) +{ + struct libusb_ss_endpoint_companion_descriptor *descriptor = + unwrapSSEndpointCompanionDescriptor(env, this); + if (!descriptor) return 0; + return descriptor->wBytesPerInterval; +} diff --git a/src/main/c/src/SSEndpointCompanionDescriptor.h b/src/main/c/src/SSEndpointCompanionDescriptor.h new file mode 100644 index 0000000..58a71d6 --- /dev/null +++ b/src/main/c/src/SSEndpointCompanionDescriptor.h @@ -0,0 +1,17 @@ +/* + * Copyright (C) 2013 Klaus Reimer (k@ailis.de) + * See COPYING file for copying conditions + */ + +#ifndef USB4JAVA_SS_ENDPOINT_COMPANION_DESCRIPTOR_H +#define USB4JAVA_SS_ENDPOINT_COMPANION_DESCRIPTOR_H + +#include "usb4java.h" + +void setSSEndpointCompanionDescriptor(JNIEnv*, + struct libusb_ss_endpoint_companion_descriptor*, jobject); +struct libusb_ss_endpoint_companion_descriptor* + unwrapSSEndpointCompanionDescriptor(JNIEnv*, jobject); +void resetSSEndpointCompanionDescriptor(JNIEnv*, jobject); + +#endif diff --git a/src/main/java/de/ailis/usb4java/libusb/LibUsb.java b/src/main/java/de/ailis/usb4java/libusb/LibUsb.java index 3b5a760..208e065 100644 --- a/src/main/java/de/ailis/usb4java/libusb/LibUsb.java +++ b/src/main/java/de/ailis/usb4java/libusb/LibUsb.java @@ -107,27 +107,47 @@ public final class LibUsb /** The device is operating at super speed (5000MBit/s). */ public static final int SPEED_SUPER = 4; - - // Supported speeds (wSpeedSupported) bitfield. Indicates what speeds the - // device supports. - + + // Supported speeds (wSpeedSupported) bitfield. Indicates what speeds the + // device supports. + /** Low speed operation supported (1.5MBit/s). */ - public static final int LIBUSB_LOW_SPEED_OPERATION = 1; + public static final int LOW_SPEED_OPERATION = 1; /** Full speed operation supported (12MBit/s). */ - public static final int LIBUSB_FULL_SPEED_OPERATION = 2; + public static final int FULL_SPEED_OPERATION = 2; /** High speed operation supported (480MBit/s). */ - public static final int LIBUSB_HIGH_SPEED_OPERATION = 4; + public static final int HIGH_SPEED_OPERATION = 4; - /** Superspeed operation supported (5000MBit/s). */ - public static final int LIBUSB_SUPER_SPEED_OPERATION = 8; - - // Masks for the bits of the bmAttributes field of the USB 2.0 Extension + /** Superspeed operation supported (5000MBit/s). */ + public static final int SUPER_SPEED_OPERATION = 8; + + // Masks for the bits of the bmAttributes field of the USB 2.0 Extension // descriptor. - - /** Supports Link Power Management (LPM). */ - public static final int LIBUSB_BM_LPM_SUPPORT = 2; + + /** Supports Link Power Management (LPM). */ + public static final int BM_LPM_SUPPORT = 2; + + // Masks for the bits of the bmAttributes field field of the SuperSpeed USB + // Device Capability descriptor. + + /** Supports Latency Tolerance Messages (LTM). */ + public static final int BM_LTM_SUPPORT = 2; + + // USB capability types. + + /** Wireless USB device capability. */ + public static final int BT_WIRELESS_USB_DEVICE_CAPABILITY = 1; + + /** USB 2.0 extensions. */ + public static final int BT_USB_2_0_EXTENSION = 2; + + /** SuperSpeed USB device capability. */ + public static final int BT_SS_USB_DEVICE_CAPABILITY = 3; + + /** Container ID type. */ + public static final int BT_CONTAINER_ID = 4; // Standard requests, as defined in table 9-5 of the USB 3.0 specifications. @@ -202,11 +222,30 @@ public final class LibUsb /** Other. */ public static final int RECIPIENT_OTHER = 0x03; - // Capabilities supported by this instance of libusb. Test if the loaded - // library supports a given capability by calling hasCapability(). + // Capabilities supported by an instance of libusb on the current running + // platform. Test if the loaded library supports a given capability by + // calling {@link #hasCapability(int)} - /** The hasCapability() API is available. */ - public static final int CAP_HAS_CAPABILITY = 0x00; + /** The {@link #hasCapability(int)} API is available. */ + public static final int CAP_HAS_CAPABILITY = 0x0000; + + /** Hotplug support is available on this platform. */ + public static final int CAP_HAS_HOTPLUG = 0x0001; + + /** + * The library can access HID devices without requiring user intervention. + * Note that before being able to actually access an HID device, you may + * still have to call additional libusbx functions such as + * {@link #detachKernelDriver(DeviceHandle, int)}. + */ + public static final int CAP_HAS_HID_ACCESS = 0x0100; + + /** + * The library supports detaching of the default USB driver, using + * {@link #detachKernelDriver(DeviceHandle, int)}, if one is set by the OS + * kernel. + */ + public static final int CAP_SUPPORTS_DETACH_KERNEL_DRIVER = 0x0101; // Device and/or Interface Class codes. @@ -304,6 +343,20 @@ public final class LibUsb */ public static final int DT_ENDPOINT = 0x05; + /** + * BOS descriptor. + * + * @see BOSDescriptor + */ + public static final int DT_BOS = 0x0f; + + /** + * Device Capability descriptor. + * + * @see BosDevCapabilityDescriptor + */ + public static final int DT_DEVICE_CAPABILITY = 0x10; + /** HID descriptor. */ public static final int DT_HID = 0x21; @@ -316,9 +369,16 @@ public final class LibUsb /** Hub descriptor. */ public static final int DT_HUB = 0x29; - /** Hub descriptor. */ + /** SuperSpeed Hub descriptor. */ public static final int DT_SUPERSPEED_HUB = 0x2a; + /** + * SuperSpeed Endpoint Companion descriptor. + * + * @see SSEndpointCompanionDescriptor + */ + public static final int DT_SS_ENDPOINT_COMPANION = 0x30; + // Descriptor sizes per descriptor type /** Size of a device descriptor. */ @@ -497,6 +557,14 @@ public final class LibUsb // Empty } + /** + * Returns the API version of the underlying libusb library. It is defined + * as follows: (major << 24) | (minor << 16) | (16 bit incremental) + * + * @return The API version of the underlying libusb library. + */ + public static native int getApiVersion(); + /** * Initialize libusb. * @@ -633,9 +701,29 @@ public final class LibUsb * @return The number of elements filled, {@link #ERROR_OVERFLOW} if the * array is too small */ - public static native int getPortNumbers(final Device device, + public static native int getPortNumbers(final Device device, final byte[] path); + /** + * @deprecated Please use {@link #getPortNumbers(Device, byte[])} instead. + * + * @param context + * The context. + * @param device + * A device. + * @param path + * The array that should contain the port numbers. As per the USB + * 3.0 specs, the current maximum limit for the depth is 7. + * @return The number of elements filled, {@link #ERROR_OVERFLOW} if the + * array is too small + */ + @Deprecated + public static int getPortPaths(final Context context, + final Device device, final byte[] path) + { + return getPortNumbers(device, path); + } + /** * Get the the parent from the specified device [EXPERIMENTAL]. * @@ -1081,6 +1169,30 @@ public final class LibUsb public static native int attachKernelDriver(final DeviceHandle handle, final int interfaceNumber); + /** + * Enable/disable libusbx's automatic kernel driver detachment. + * + * When this is enabled libusbx will automatically detach the kernel driver + * on an interface when claiming the interface, and attach it when releasing + * the interface. + * + * Automatic kernel driver detachment is disabled on newly opened device + * handles by default. + * + * On platforms which do not have {@link #CAP_SUPPORTS_DETACH_KERNEL_DRIVER} + * this function will return {@link #ERROR_NOT_SUPPORTED}, and libusbx will + * continue as if this function was never called. + * + * @param handle + * A device handle. + * @param enable + * Whether to enable or disable auto kernel driver detachment + * @return {@link #SUCCESS} on success, {@link #ERROR_NOT_SUPPORTED} on + * platforms where the functionality is not available. + */ + public static native int setAutoDetachKernelDriver( + final DeviceHandle handle, final boolean enable); + /** * Check at runtime if the loaded library has a given capability. * @@ -1102,6 +1214,49 @@ public final class LibUsb */ public static native String errorName(final int errorCode); + /** + * Set the language, and only the language, not the encoding! used for + * translatable libusb messages. + * + * This takes a locale string in the default setlocale format: lang[-region] + * or lang[_country_region][.codeset]. Only the lang part of the string is + * used, and only 2 letter ISO 639-1 codes are accepted for it, such as + * "de". The optional region, country_region or codeset parts are ignored. + * This means that functions which return translatable strings will NOT + * honor the specified encoding. All strings returned are encoded as UTF-8 + * strings. + * + * If {@link #setLocale(String)} is not called, all messages will be in + * English. + * + * The following functions return translatable strings: libusb_strerror(). + * Note that the libusb log messages controlled through + * {@link #setDebug(Context, int)} are not translated, they are always in + * English. + * + * @param locale + * locale-string in the form of lang[_country_region][.codeset] + * or lang[-region], where lang is a 2 letter ISO 639-1 code. + * @return {@link #SUCCESS} on success, {@link #ERROR_INVALID_PARAM} if the + * locale doesn't meet the requirements, {@link #ERROR_NOT_FOUND} if + * the requested language is not supported, a error code on other + * errors. + */ + public static native int setLocale(final String locale); + + /** + * Returns a string with a short description of the given error code, this + * description is intended for displaying to the end user and will be in the + * language set by {@link #setLocale(String)}. + * + * The messages always start with a capital letter and end without any dot. + * + * @param errcode + * The error code whose description is desired. + * @return A short description of the error code. + */ + public static native String strError(final int errcode); + /** * Convert a 16-bit value from little-endian to host-endian format. * @@ -1268,6 +1423,40 @@ public final class LibUsb public static native void freeConfigDescriptor( final ConfigDescriptor descriptor); + /** + * Get an endpoints superspeed endpoint companion descriptor (if any) + * + * @param context + * The context to operate on, or NULL for the default context. + * @param endpointDescriptor + * Endpoint descriptor from which to get the superspeed endpoint + * companion descriptor. + * @param companionDescriptor + * Output location for the superspeed endpoint companion + * descriptor. Only valid if 0 was returned. Must be freed with + * {@link #freeSSEndpointCompanionDescriptor(SSEndpointCompanionDescriptor)} + * after use. + * @return {@link #SUCCESS} on success, {@link #ERROR_NOT_FOUND} if the + * descriptor does not exist, another error code on error + */ + public static native int getSSEndpointCompanionDescriptor( + final Context context, final EndpointDescriptor endpointDescriptor, + final SSEndpointCompanionDescriptor companionDescriptor); + + /** + * Free a superspeed endpoint companion descriptor obtained from + * {@link #getSSEndpointCompanionDescriptor(Context, EndpointDescriptor, SSEndpointCompanionDescriptor)} + * . + * + * It is safe to call this function with a NULL parameter, in which case the + * function simply returns. + * + * @param companionDescriptor + * The superspeed endpoint companion descriptor to free + */ + public static native void freeSSEndpointCompanionDescriptor( + final SSEndpointCompanionDescriptor companionDescriptor); + /** * Retrieve a descriptor from the default control pipe. * diff --git a/src/main/java/de/ailis/usb4java/libusb/LibUsbException.java b/src/main/java/de/ailis/usb4java/libusb/LibUsbException.java index d4af9fe..a59a084 100644 --- a/src/main/java/de/ailis/usb4java/libusb/LibUsbException.java +++ b/src/main/java/de/ailis/usb4java/libusb/LibUsbException.java @@ -31,7 +31,7 @@ public final class LibUsbException extends UsbException public LibUsbException(final String message, final int errorCode) { super(String.format("USB error %d: %s: %s", -errorCode, message, - LibUsb.errorName(errorCode))); + LibUsb.strError(errorCode))); this.errorCode = errorCode; } diff --git a/src/main/java/de/ailis/usb4java/libusb/SSEndpointCompanionDescriptor.java b/src/main/java/de/ailis/usb4java/libusb/SSEndpointCompanionDescriptor.java new file mode 100644 index 0000000..d37129a --- /dev/null +++ b/src/main/java/de/ailis/usb4java/libusb/SSEndpointCompanionDescriptor.java @@ -0,0 +1,143 @@ +/* + * Copyright 2013 Klaus Reimer + * See LICENSE.md for licensing information. + * + * Based on libusbx : + * + * Copyright 2001 Johannes Erdfelt + * Copyright 2007-2008 Daniel Drake + * Copyright 2012 Pete Batard + */ + +package de.ailis.usb4java.libusb; + +import org.apache.commons.lang3.builder.EqualsBuilder; +import org.apache.commons.lang3.builder.HashCodeBuilder; + +/** + * A structure representing the superspeed endpoint companion descriptor. + * + * This descriptor is documented in section 9.6.7 of the USB 3.0 specification. + * All multiple-byte fields are represented in host-endian format. + * + * @author Klaus Reimer (k@ailis.de) + */ +public final class SSEndpointCompanionDescriptor +{ + /** The native pointer to the descriptor structure. */ + private long ssEndpointCompanionDescriptor; + + /** + * Constructs a new descriptor which can be passed to the + * {@link LibUsb#getSSEndpointCompanionDescriptor(Context, EndpointDescriptor, SSEndpointCompanionDescriptor)} + * method. + */ + public SSEndpointCompanionDescriptor() + { + // Empty + } + + /** + * Returns the native pointer. + * + * @return The native pointer. + */ + public long getPointer() + { + return this.ssEndpointCompanionDescriptor; + } + + /** + * Returns the size of this descriptor (in bytes). + * + * @return The descriptor size in bytes; + */ + public native byte bLength(); + + /** + * Returns the descriptor type. + * + * @return The descriptor type. + */ + public native byte bDescriptorType(); + + /** + * Returns the maximum number of packets the endpoint can send or receive as + * part of a burst. + * + * @return The maximum number of packets as part of a burst. + */ + public native byte bMaxBurst(); + + /** + * Returns the attributes. In bulk endpoint: bits 4:0 represents the maximum + * number of streams the EP supports. In isochronous endpoint: bits 1:0 + * represents the Mult - a zero based value that determines the maximum + * number of packets within a service interval + * + * @return The attributes. + */ + public native byte bmAttributes(); + + /** + * Returns the total number of bytes this endpoint will transfer every + * service interval. Valid only for periodic endpoints. + * + * @return The total number of bytes per service interval. + */ + public native short wBytesPerInterval(); + + /** + * Returns a dump of this descriptor. + * + * @return The descriptor dump. + */ + public String dump() + { + return String.format("Device Descriptor:%n" + + " bLength %18d%n" + + " bDescriptorType %10d%n" + + " bMaxBurst %19s%n" + + " bmAttributes %13d %s%n" + + " wBytesPerInterval %10d", + bLength() & 0xff, + bDescriptorType() & 0xff, + bMaxBurst() & 0xff, + bmAttributes() & 0xff, + wBytesPerInterval() & 0xffff); + } + + @Override + public boolean equals(final Object obj) + { + if (obj == null) return false; + if (obj == this) return true; + if (obj.getClass() != getClass()) return false; + final SSEndpointCompanionDescriptor other = + (SSEndpointCompanionDescriptor) obj; + return new EqualsBuilder() + .append(bDescriptorType(), other.bDescriptorType()) + .append(bLength(), other.bLength()) + .append(bMaxBurst(), other.bMaxBurst()) + .append(bmAttributes(), other.bmAttributes()) + .append(wBytesPerInterval(), other.wBytesPerInterval()).isEquals(); + } + + @Override + public int hashCode() + { + return new HashCodeBuilder() + .append(bLength()) + .append(bDescriptorType()) + .append(bMaxBurst()) + .append(bmAttributes()) + .append(wBytesPerInterval()) + .toHashCode(); + } + + @Override + public String toString() + { + return dump(); + } +} diff --git a/src/test/java/de/ailis/usb4java/libusb/LibUSBGlobalTest.java b/src/test/java/de/ailis/usb4java/libusb/LibUSBGlobalTest.java index eb8b2d6..1236b9c 100644 --- a/src/test/java/de/ailis/usb4java/libusb/LibUSBGlobalTest.java +++ b/src/test/java/de/ailis/usb4java/libusb/LibUSBGlobalTest.java @@ -133,4 +133,27 @@ public class LibUSBGlobalTest assertEquals("LIBUSB_ERROR_IO", LibUsb.errorName(LibUsb.ERROR_IO)); assertEquals("**UNKNOWN**", LibUsb.errorName(0x1234)); } + + /** + * Tests the {@link LibUsb#strError(int)} method. + */ + @Test + public void testStrError() + { + assumeUsbTestsEnabled(); + assertEquals("Input/Output Error", LibUsb.strError(LibUsb.ERROR_IO)); + assertEquals("Other error", LibUsb.strError(0x1234)); + } + + /** + * Tests the {@link LibUsb#setLocale(String)} method. + */ + @Test + public void testSetLocale() + { + assumeUsbTestsEnabled(); + assertEquals(LibUsb.SUCCESS, LibUsb.setLocale("en")); + assertEquals(LibUsb.ERROR_NOT_FOUND, LibUsb.setLocale("zz")); + assertEquals(LibUsb.ERROR_INVALID_PARAM, LibUsb.setLocale("zzz")); + } } diff --git a/src/test/java/de/ailis/usb4java/libusb/LibUSBTest.java b/src/test/java/de/ailis/usb4java/libusb/LibUSBTest.java index a19053c..c2291ce 100644 --- a/src/test/java/de/ailis/usb4java/libusb/LibUSBTest.java +++ b/src/test/java/de/ailis/usb4java/libusb/LibUSBTest.java @@ -165,6 +165,16 @@ public class LibUSBTest assertTrue(version.toString().startsWith("1.0.")); } + /** + * Tests the {@link LibUsb#getApiVersion()} method. + */ + @Test + public void testGetApiVersion() + { + assumeUsbTestsEnabled(); + assertTrue(LibUsb.getApiVersion() >= 0x1000102); + } + /** * Tests the initialization and deinitialization of libusb with default * context. @@ -175,7 +185,7 @@ public class LibUSBTest assumeUsbTestsEnabled(); assertEquals(LibUsb.SUCCESS, LibUsb.init(null)); LibUsb.exit(null); - + try { // Double-exit should throw exception @@ -185,7 +195,7 @@ public class LibUSBTest catch (IllegalStateException e) { // Expected behavior - } + } } /** @@ -199,7 +209,7 @@ public class LibUSBTest Context context = new Context(); assertEquals(LibUsb.SUCCESS, LibUsb.init(context)); LibUsb.exit(context); - + try { LibUsb.exit(context); @@ -530,6 +540,28 @@ public class LibUSBTest LibUsb.attachKernelDriver(new DeviceHandle(), 0); } + /** + * Tests the {@link LibUsb#setAutoDetachKernelDriver(DeviceHandle, boolean)} + * method with uninitialized device handle. + */ + @Test(expected = IllegalStateException.class) + public void testSetAutoDetachKernelDriverWithUninitializedHandle() + { + assumeUsbTestsEnabled(); + LibUsb.setAutoDetachKernelDriver(new DeviceHandle(), true); + } + + /** + * Tests the {@link LibUsb#setAutoDetachKernelDriver(DeviceHandle, boolean)} + * method without a device handle. + */ + @Test(expected = IllegalArgumentException.class) + public void testSetAutoDetachKernelDriverWithoutHandle() + { + assumeUsbTestsEnabled(); + LibUsb.setAutoDetachKernelDriver(null, true); + } + /** * Tests the {@link LibUsb#getDeviceDescriptor(Device, DeviceDescriptor)} * method with uninitialized device. @@ -602,6 +634,56 @@ public class LibUSBTest LibUsb.freeConfigDescriptor(new ConfigDescriptor()); } + /** + * Tests the + * {@link LibUsb#getSSEndpointCompanionDescriptor(Context, EndpointDescriptor, SSEndpointCompanionDescriptor)} + * method with uninitialized endpoint. + */ + @Test(expected = IllegalStateException.class) + public void testGetSSEndpointCompanionDescriptorWithUninitializedEndpoint() + { + assumeUsbTestsEnabled(); + LibUsb.getSSEndpointCompanionDescriptor(null, new EndpointDescriptor(), + new SSEndpointCompanionDescriptor()); + } + + /** + * Tests the + * {@link LibUsb#getSSEndpointCompanionDescriptor(Context, EndpointDescriptor, SSEndpointCompanionDescriptor)} + * method without descriptors. + */ + @Test(expected = IllegalArgumentException.class) + public void testGetSSEndpointCompanionDescriptorWithoutDescriptors() + { + assumeUsbTestsEnabled(); + LibUsb.getSSEndpointCompanionDescriptor(null, null, null); + } + + /** + * Tests the + * {@link LibUsb#freeSSEndpointCompanionDescriptor(SSEndpointCompanionDescriptor)} + * method with uninitialized descriptor. + */ + @Test(expected = IllegalStateException.class) + public void testFreeSSEndpointCompanionDescriptorWithUninitializedDescriptor() + { + assumeUsbTestsEnabled(); + LibUsb.freeSSEndpointCompanionDescriptor(new SSEndpointCompanionDescriptor()); + } + + + /** + * Tests the + * {@link LibUsb#freeSSEndpointCompanionDescriptor(SSEndpointCompanionDescriptor)} + * method with null parameter. Must do nothing. + */ + @Test + public void testFreeSSEndpointCompanionDescriptorWithNull() + { + assumeUsbTestsEnabled(); + LibUsb.freeSSEndpointCompanionDescriptor(null); + } + /** * Tests the * {@link LibUsb#getDescriptor(DeviceHandle, int, int, ByteBuffer)} method