diff --git a/src/main/java/org/usb4java/javax/AbstractDevice.java b/src/main/java/org/usb4java/javax/AbstractDevice.java index 39da623..2d80522 100644 --- a/src/main/java/org/usb4java/javax/AbstractDevice.java +++ b/src/main/java/org/usb4java/javax/AbstractDevice.java @@ -74,6 +74,9 @@ abstract class AbstractDevice implements UsbDevice /** The numbers of the currently claimed interface. */ private Set claimedInterfaceNumbers = new HashSet(); + /** The numbers of the currently kernel claimed interface. */ + private Set claimedKernelInterfaceNumbers = new HashSet(); + /** The port this device is connected to. */ private UsbPort port; @@ -81,9 +84,6 @@ abstract class AbstractDevice implements UsbDevice private final ControlIrpQueue queue = new ControlIrpQueue(this, this.listeners); - /** If kernel driver was detached when interface was claimed. */ - private boolean detachedKernelDriver; - /** * Constructs a new device. * @@ -248,6 +248,14 @@ public final void close() } } + public final void reset() + { + if (this.handle != null) + { + LibUsb.resetDevice(this.handle); + } + } + @Override public final UsbPort getParentUsbPort() { @@ -400,6 +408,12 @@ final void setActiveUsbConfigurationNumber(final byte number) final void claimInterface(final byte number, final boolean force) throws UsbException { + if(this.claimedInterfaceNumbers.isEmpty()) { + // This prevent a libus bug where async read could lock + // forever after a full released interfaces + reset(); + } + if (this.claimedInterfaceNumbers.contains(number)) throw new UsbClaimException("An interface is already claimed"); @@ -420,7 +434,7 @@ final void claimInterface(final byte number, final boolean force) throw ExceptionUtils.createPlatformException( "Unable to detach kernel driver", result); } - this.detachedKernelDriver = true; + claimedKernelInterfaceNumbers.add(number); } } @@ -456,7 +470,7 @@ final void releaseInterface(final byte number) throws UsbException "Unable to release interface", result); } - if (this.detachedKernelDriver) + if (this.claimedKernelInterfaceNumbers.contains(number)) { result = LibUsb.attachKernelDriver(handle, number & 0xff); if (result < 0) @@ -464,9 +478,16 @@ final void releaseInterface(final byte number) throws UsbException throw ExceptionUtils.createPlatformException( "Unable to re-attach kernel driver", result); } + this.claimedKernelInterfaceNumbers.remove(number); } this.claimedInterfaceNumbers.remove(number); + + if(this.claimedInterfaceNumbers.isEmpty()) { + // This prevent a libus bug where async read could lock + // forever after a full released interfaces + reset(); + } } /** diff --git a/src/main/java/org/usb4java/javax/IrpQueue.java b/src/main/java/org/usb4java/javax/IrpQueue.java index ec1a04b..810baf0 100644 --- a/src/main/java/org/usb4java/javax/IrpQueue.java +++ b/src/main/java/org/usb4java/javax/IrpQueue.java @@ -167,6 +167,17 @@ private int write(final byte[] data, final int offset, final int len) // Short packet detected, aborting if (result < size) break; } + + // Handle bulk out transfert needing zlp to detect end of packet + if ((this.pipe.getUsbEndpoint().getDirection() == UsbConst.ENDPOINT_DIRECTION_OUT)) { + if (type == LibUsb.TRANSFER_TYPE_BULK) { + if ((len > 0) && (len % descriptor.wMaxPacketSize() == 0)) { + transfer(handle, descriptor, type, ByteBuffer.allocateDirect(0)); + } + } + } + + return written; }