Skip to content

Commit 66b3861

Browse files
committed
Bulk/interrupt transfer use async IO internally (Windows)
1 parent 0773a32 commit 66b3861

File tree

7 files changed

+295
-45
lines changed

7 files changed

+295
-45
lines changed

java-does-usb/jextract/windows/gen_win.cmd

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -139,3 +139,12 @@ call %JEXTRACT% --source --output ../../src/main/java ^
139139
--target-package net.codecrete.usb.windows.gen.ole32 ^
140140
--include-function CLSIDFromString ^
141141
windows_headers.h
142+
143+
call %JEXTRACT% --source --output ../../src/main/java ^
144+
-D _AMD64_ -D _M_AMD64=100 -D UNICODE -D _UNICODE ^
145+
-I "%SDK_DIR%\um" ^
146+
-I "%SDK_DIR%\shared" ^
147+
--header-class-name NtDll ^
148+
--target-package net.codecrete.usb.windows.gen.ntdll ^
149+
--include-constant STATUS_UNSUCCESSFUL ^
150+
windows_headers.h

java-does-usb/jextract/windows/windows_headers.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,3 +4,4 @@
44
#include <usbioctl.h>
55
#include <winusb.h>
66
#include <dbt.h>
7+
#include <ntstatus.h>

java-does-usb/src/main/java/net/codecrete/usb/windows/WindowsUSBDevice.java

Lines changed: 19 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -258,68 +258,43 @@ public void controlTransferOut(USBControlTransfer setup, byte[] data) {
258258

259259
@Override
260260
public void transferOut(int endpointNumber, byte[] data, int timeout) {
261-
checkIsOpen();
262-
263-
var endpoint = getEndpoint(USBDirection.OUT, endpointNumber, USBTransferType.BULK, USBTransferType.INTERRUPT);
264-
var intfHandle = getInterfaceHandle(endpoint.interfaceNumber());
265-
266261
try (var arena = Arena.openConfined()) {
267-
// set timeout
268-
var timeoutHolder = arena.allocate(JAVA_INT, timeout);
269-
var lastErrorState = arena.allocate(Win.LAST_ERROR_STATE.layout());
270-
271-
if (WinUSB2.WinUsb_SetPipePolicy(intfHandle.interfaceHandle, endpoint.endpointAddress(),
272-
WinUSB.PIPE_TRANSFER_TIMEOUT(), (int) timeoutHolder.byteSize(), timeoutHolder, lastErrorState) == 0)
273-
throwLastError(lastErrorState, "Setting timeout failed");
274-
275-
// copy data to native heap
276262
var buffer = arena.allocate(data.length);
277263
buffer.copyFrom(MemorySegment.ofArray(data));
278-
var lengthHolder = arena.allocate(JAVA_INT);
264+
var transfer = createSyncTransfer(buffer);
279265

280-
// send data
281-
if (WinUSB2.WinUsb_WritePipe(intfHandle.interfaceHandle, endpoint.endpointAddress(), buffer,
282-
(int) buffer.byteSize(), lengthHolder, NULL, lastErrorState) == 0) {
283-
int err = Win.getLastError(lastErrorState);
284-
if (err == Kernel32.ERROR_SEM_TIMEOUT())
285-
throw new USBTimeoutException("Transfer out aborted due to timeout");
286-
throwException(err, "Bulk/interrupt transfer OUT failed");
266+
synchronized (transfer) {
267+
submitTransferOut(endpointNumber, transfer);
268+
waitForTransfer(transfer, timeout, USBDirection.OUT, endpointNumber);
287269
}
288270
}
289271
}
290272

291273
@Override
292274
public byte[] transferIn(int endpointNumber, int timeout) {
293275
var endpoint = getEndpoint(USBDirection.IN, endpointNumber, USBTransferType.BULK, USBTransferType.INTERRUPT);
294-
var intfHandle = getInterfaceHandle(endpoint.interfaceNumber());
295276

296277
try (var arena = Arena.openConfined()) {
297-
// set timeout
298-
var timeoutHolder = arena.allocate(JAVA_INT, timeout);
299-
var lastErrorState = arena.allocate(Win.LAST_ERROR_STATE.layout());
300-
if (WinUSB2.WinUsb_SetPipePolicy(intfHandle.interfaceHandle, endpoint.endpointAddress(),
301-
WinUSB.PIPE_TRANSFER_TIMEOUT(), (int) timeoutHolder.byteSize(), timeoutHolder, lastErrorState) == 0)
302-
throwLastError(lastErrorState, "Setting timeout failed");
303-
304-
// create native heap buffer for data
305278
var buffer = arena.allocate(endpoint.packetSize());
306-
var lengthHolder = arena.allocate(JAVA_INT);
279+
var transfer = createSyncTransfer(buffer);
307280

308-
// receive data
309-
if (WinUSB2.WinUsb_ReadPipe(intfHandle.interfaceHandle, endpoint.endpointAddress(), buffer,
310-
(int) buffer.byteSize(), lengthHolder, NULL, lastErrorState) == 0) {
311-
int err = Win.getLastError(lastErrorState);
312-
if (err == Kernel32.ERROR_SEM_TIMEOUT())
313-
throw new USBTimeoutException("Transfer in aborted due to timeout");
314-
throwException(err, "Bulk/interrupt transfer IN failed");
281+
synchronized (transfer) {
282+
submitTransferIn(endpointNumber, transfer);
283+
waitForTransfer(transfer, timeout, USBDirection.IN, endpointNumber);
315284
}
316285

317-
// copy data
318-
int len = lengthHolder.get(JAVA_INT, 0);
319-
return buffer.asSlice(0, len).toArray(JAVA_BYTE);
286+
return buffer.asSlice(0, transfer.resultSize).toArray(JAVA_BYTE);
320287
}
321288
}
322289

290+
private WindowsTransfer createSyncTransfer(MemorySegment data) {
291+
var transfer = new WindowsTransfer();
292+
transfer.data = data;
293+
transfer.dataSize = (int) data.byteSize();
294+
transfer.completion = USBDeviceImpl::onSyncTransferCompleted;
295+
return transfer;
296+
}
297+
323298
@Override
324299
protected Transfer createTransfer() {
325300
return new WindowsTransfer();
@@ -386,7 +361,7 @@ synchronized void configureForAsyncIo(USBDirection direction, int endpointNumber
386361
}
387362

388363
@Override
389-
public void clearHalt(USBDirection direction, int endpointNumber) {
364+
public synchronized void clearHalt(USBDirection direction, int endpointNumber) {
390365
var endpoint = getEndpoint(direction, endpointNumber, USBTransferType.BULK, USBTransferType.INTERRUPT);
391366
var intfHandle = getInterfaceHandle(endpoint.interfaceNumber());
392367

@@ -398,7 +373,7 @@ public void clearHalt(USBDirection direction, int endpointNumber) {
398373
}
399374

400375
@Override
401-
public void abortTransfers(USBDirection direction, int endpointNumber) {
376+
public synchronized void abortTransfers(USBDirection direction, int endpointNumber) {
402377
var endpoint = getEndpoint(direction, endpointNumber, USBTransferType.BULK, USBTransferType.INTERRUPT);
403378
var intfHandle = getInterfaceHandle(endpoint.interfaceNumber());
404379

java-does-usb/src/main/java/net/codecrete/usb/windows/WindowsUSBException.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
import net.codecrete.usb.USBStallException;
1111
import net.codecrete.usb.common.ForeignMemory;
1212
import net.codecrete.usb.windows.gen.kernel32.Kernel32;
13+
import net.codecrete.usb.windows.gen.ntdll.NtDll;
1314

1415
import java.lang.foreign.Arena;
1516
import java.lang.foreign.MemorySegment;
@@ -47,7 +48,7 @@ public WindowsUSBException(String message, int errorCode) {
4748
*/
4849
static void throwException(int errorCode, String message, Object... args) {
4950
var formattedMessage = String.format(message, args);
50-
if (errorCode == Kernel32.ERROR_GEN_FAILURE()) {
51+
if (errorCode == Kernel32.ERROR_GEN_FAILURE() || errorCode == NtDll.STATUS_UNSUCCESSFUL()) {
5152
throw new USBStallException(formattedMessage);
5253
} else {
5354
throw new WindowsUSBException(formattedMessage, errorCode);
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
// Generated by jextract
2+
3+
package net.codecrete.usb.windows.gen.ntdll;
4+
5+
import static java.lang.foreign.ValueLayout.*;
6+
final class Constants$root {
7+
8+
// Suppresses default constructor, ensuring non-instantiability.
9+
private Constants$root() {}
10+
static final OfBoolean C_BOOL$LAYOUT = JAVA_BOOLEAN;
11+
static final OfByte C_CHAR$LAYOUT = JAVA_BYTE;
12+
static final OfShort C_SHORT$LAYOUT = JAVA_SHORT;
13+
static final OfInt C_INT$LAYOUT = JAVA_INT;
14+
static final OfInt C_LONG$LAYOUT = JAVA_INT;
15+
static final OfLong C_LONG_LONG$LAYOUT = JAVA_LONG;
16+
static final OfFloat C_FLOAT$LAYOUT = JAVA_FLOAT;
17+
static final OfDouble C_DOUBLE$LAYOUT = JAVA_DOUBLE;
18+
static final OfAddress C_POINTER$LAYOUT = ADDRESS.withBitAlignment(64).asUnbounded();
19+
}
20+
21+
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
// Generated by jextract
2+
3+
package net.codecrete.usb.windows.gen.ntdll;
4+
5+
import static java.lang.foreign.ValueLayout.*;
6+
public class NtDll {
7+
8+
public static final OfByte C_CHAR = Constants$root.C_CHAR$LAYOUT;
9+
public static final OfShort C_SHORT = Constants$root.C_SHORT$LAYOUT;
10+
public static final OfInt C_INT = Constants$root.C_LONG$LAYOUT;
11+
public static final OfInt C_LONG = Constants$root.C_LONG$LAYOUT;
12+
public static final OfLong C_LONG_LONG = Constants$root.C_LONG_LONG$LAYOUT;
13+
public static final OfFloat C_FLOAT = Constants$root.C_FLOAT$LAYOUT;
14+
public static final OfDouble C_DOUBLE = Constants$root.C_DOUBLE$LAYOUT;
15+
public static final OfAddress C_POINTER = Constants$root.C_POINTER$LAYOUT;
16+
/**
17+
* {@snippet :
18+
* #define STATUS_UNSUCCESSFUL -1073741823
19+
* }
20+
*/
21+
public static int STATUS_UNSUCCESSFUL() {
22+
return (int)-1073741823L;
23+
}
24+
}
25+
26+

0 commit comments

Comments
 (0)