diff --git a/src/main/c/src/LibUsb.c b/src/main/c/src/LibUsb.c index 3b1d823..82fd392 100644 --- a/src/main/c/src/LibUsb.c +++ b/src/main/c/src/LibUsb.c @@ -609,12 +609,16 @@ JNIEXPORT jint JNICALL METHOD_NAME(LibUsb, getDeviceDescriptor) { NOT_NULL(env, device, return 0); NOT_NULL(env, descriptor, return 0); - NOT_SET(env, descriptor, "deviceDescriptorPointer", return 0); + libusb_device *dev = unwrapDevice(env, device); if (!dev) return 0; - struct libusb_device_descriptor *dev_desc = calloc(1, sizeof(*dev_desc)); - if (!dev_desc) return LIBUSB_ERROR_NO_MEM; + jclass cls = (*env)->GetObjectClass(env, descriptor); + jfieldID field = (*env)->GetFieldID(env, cls, "deviceDescriptorBuffer", "Ljava/nio/ByteBuffer;"); + jobject buffer = (*env)->GetObjectField(env, descriptor, field); + + // The Java code ensures this is an appropriately sized direct ByteBuffer. + struct libusb_device_descriptor *dev_desc = (*env)->GetDirectBufferAddress(env, buffer); int result = libusb_get_device_descriptor(dev, dev_desc); if (result == LIBUSB_SUCCESS) @@ -623,27 +627,22 @@ JNIEXPORT jint JNICALL METHOD_NAME(LibUsb, getDeviceDescriptor) } else { - // Free memory again on error. - free(dev_desc); + // Reset pointer on error, to ensure subsequent accesses will throw exceptions. + resetDeviceDescriptor(env, descriptor); } + return result; } /** - * void freeDeviceDescriptor(DeviceDescriptor) + * int deviceDescriptorStructSize() */ -JNIEXPORT void JNICALL METHOD_NAME(LibUsb, freeDeviceDescriptor) +JNIEXPORT jint JNICALL METHOD_NAME(LibUsb, deviceDescriptorStructSize) ( - JNIEnv *env, jclass class, jobject descriptor + JNIEnv *env, jclass class ) { - if (!descriptor) return; - struct libusb_device_descriptor *dev_desc = unwrapDeviceDescriptor(env, - descriptor); - if (!dev_desc) return; - - free(dev_desc); - resetDeviceDescriptor(env, descriptor); + return sizeof(struct libusb_device_descriptor); } /** diff --git a/src/main/java/de/ailis/usb4java/libusb/DeviceDescriptor.java b/src/main/java/de/ailis/usb4java/libusb/DeviceDescriptor.java index 1885168..bd3f5d3 100644 --- a/src/main/java/de/ailis/usb4java/libusb/DeviceDescriptor.java +++ b/src/main/java/de/ailis/usb4java/libusb/DeviceDescriptor.java @@ -18,11 +18,14 @@ package de.ailis.usb4java.libusb; +import java.nio.ByteBuffer; + import javax.usb.UsbDeviceDescriptor; import org.apache.commons.lang3.builder.EqualsBuilder; import org.apache.commons.lang3.builder.HashCodeBuilder; +import de.ailis.usb4java.utils.BufferUtils; import de.ailis.usb4java.utils.DescriptorUtils; /** @@ -38,13 +41,17 @@ public final class DeviceDescriptor implements UsbDeviceDescriptor /** The native pointer to the descriptor structure. */ private long deviceDescriptorPointer; + /** The Java ByteBuffer which contains the descriptor structure. */ + private final ByteBuffer deviceDescriptorBuffer; + /** * Constructs a new device descriptor which can be passed to the * {@link LibUsb#getDeviceDescriptor(Device, DeviceDescriptor)} method. */ public DeviceDescriptor() { - // Empty + // Assign new buffer. + this.deviceDescriptorBuffer = BufferUtils.allocateByteBuffer(LibUsb.deviceDescriptorStructSize()); } /** diff --git a/src/main/java/de/ailis/usb4java/libusb/LibUsb.java b/src/main/java/de/ailis/usb4java/libusb/LibUsb.java index c8bf6f4..3fae444 100644 --- a/src/main/java/de/ailis/usb4java/libusb/LibUsb.java +++ b/src/main/java/de/ailis/usb4java/libusb/LibUsb.java @@ -808,7 +808,7 @@ public final class LibUsb * array is too small */ @Deprecated - public static int getPortPath(final Context context, final Device device, + public static int getPortPath(final Context context, final Device device, final ByteBuffer path) { return getPortNumbers(device, path); @@ -1389,21 +1389,12 @@ public final class LibUsb final DeviceDescriptor descriptor); /** - * Free a device descriptor obtained from - * {@link #getDeviceDescriptor(Device, DeviceDescriptor)}. + * Returns the size in bytes of the buffer that's required to hold all + * of a device descriptor's data. * - * It is safe to call this function with a NULL device parameter, in which - * case the function simply returns. - * - * This function is not present in the libusb-1.0 API, but since - * getDeviceDescriptor() requires memory to be allocated manually, - * a way to deallocate it from Java is required to avoid a memory leak. - * - * @param descriptor - * The device descriptor to free + * @return buffer size in bytes */ - public static native void freeDeviceDescriptor( - final DeviceDescriptor descriptor); + public static native int deviceDescriptorStructSize(); /** * Retrieve a string descriptor in C style ASCII. @@ -2430,15 +2421,15 @@ public final class LibUsb /** * Get the data section of a control transfer. - * + * * This convenience function is here to remind you that the data does not * start until 8 bytes into the actual buffer, as the setup packet comes * first. - * + * * Calling this function only makes sense from a transfer callback function, * or situations where you have already allocated a suitably sized buffer at * {@link Transfer#buffer()}. - * + * * @param transfer * A transfer. * @return The data section. @@ -2451,14 +2442,14 @@ public final class LibUsb /** * Get the control setup packet of a control transfer. - * + * * This convenience function is here to remind you that the control setup * occupies the first 8 bytes of the transfer data buffer. - * + * * Calling this function only makes sense from a transfer callback function, * or situations where you have already allocated a suitably sized buffer at * {@link Transfer#buffer()}. - * + * * @param transfer * A transfer. * @return The setup section. @@ -2471,10 +2462,10 @@ public final class LibUsb /** * Helper function to populate the setup packet (first 8 bytes of the data * buffer) for a control transfer. - * + * * The wIndex, wValue and wLength values should be given in host-endian byte * order. - * + * * @param buffer * Buffer to output the setup packet into. * @param bmRequestType @@ -2503,29 +2494,29 @@ public final class LibUsb /** * Helper function to populate the required {@link Transfer} fields for a * control transfer. - * + * * If you pass a transfer buffer to this function, the first 8 bytes will be * interpreted as a control setup packet, and the wLength field will be used * to automatically populate the length field of the transfer. Therefore the * recommended approach is: - * + * * 1. Allocate a suitably sized data buffer (including space for control * setup). - * + * * 2. Call * {@link #fillControlSetup(ByteBuffer, byte, byte, short, short, short)}. - * + * * 3. If this is a host-to-device transfer with a data stage, put the data * in place after the setup packet. - * + * * 4. Call this function. - * + * * 5. Call {@link #submitTransfer(Transfer)}. - * + * * It is also legal to pass a NULL buffer to this function, in which case * this function will not attempt to populate the length field. Remember * that you must then populate the buffer and length fields later. - * + * * @param transfer * The transfer to populate. * @param handle @@ -2562,7 +2553,7 @@ public final class LibUsb /** * Helper function to populate the required {@link Transfer} fields for a * bulk transfer. - * + * * @param transfer * The transfer to populate. * @param handle @@ -2595,7 +2586,7 @@ public final class LibUsb /** * Helper function to populate the required {@link Transfer} fields for an * interrupt transfer. - * + * * @param transfer * The transfer to populate. * @param handle @@ -2628,7 +2619,7 @@ public final class LibUsb /** * Helper function to populate the required {@link Transfer} fields for an * isochronous transfer. - * + * * @param transfer * The transfer to populate. * @param handle @@ -2665,7 +2656,7 @@ public final class LibUsb /** * Convenience function to set the length of all packets in an isochronous * transfer, based on the {@link Transfer#numIsoPackets()} field. - * + * * @param transfer * A transfer. * @param length @@ -2684,13 +2675,13 @@ public final class LibUsb /** * Convenience function to locate the position of an isochronous packet * within the buffer of an isochronous transfer. - * + * * This is a thorough function which loops through all preceding packets, * accumulating their lengths to find the position of the specified packet. * Typically you will assign equal lengths to each packet in the transfer, * and hence the above method is sub-optimal. You may wish to use * {@link #getIsoPacketBufferSimple(Transfer, int)} instead. - * + * * @param transfer * A transfer. * @param packet @@ -2723,15 +2714,15 @@ public final class LibUsb * Convenience function to locate the position of an isochronous packet * within the buffer of an isochronous transfer, for transfers where each * packet is of identical size. - * + * * This function relies on the assumption that every packet within the * transfer is of identical size to the first packet. Calculating the * location of the packet buffer is then just a simple calculation: buffer + * (packet_size * packet) - * + * * Do not use this function on transfers other than those that have * identical packet lengths for each packet. - * + * * @param transfer * A transfer. * @param packet @@ -2757,7 +2748,7 @@ public final class LibUsb /** * Processes a hotplug event from native code. - * + * * @param context * Context of this notification. * @param device @@ -2861,7 +2852,7 @@ public final class LibUsb /** * Internally called native method for registering a hotplug callback. - * + * * @param context * Context to register this callback with. * @param events @@ -2880,7 +2871,7 @@ public final class LibUsb * @param hotplugId * The hotplug callback ID. * @return {@link #SUCCESS} on success, some ERROR code on failure. - */ + */ static native int hotplugRegisterCallbackNative(final Context context, final int events, final int flags, final int vendorId, final int productId, final int deviceClass,