Skip to content

Commit b74f240

Browse files
committed
Control requests use async IO internally (Windows)
1 parent 66b3861 commit b74f240

File tree

2 files changed

+60
-45
lines changed

2 files changed

+60
-45
lines changed

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

Lines changed: 59 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,7 @@ public class WindowsUSBDevice extends USBDeviceImpl {
3838
private List<InterfaceHandle> interfaceHandles_;
3939
private boolean isOpen_;
4040

41-
WindowsUSBDevice(WindowsUSBDeviceRegistry registry, String devicePath, Map<Integer, String> children,
41+
WindowsUSBDevice(String devicePath, Map<Integer, String> children,
4242
int vendorId, int productId, MemorySegment configDesc) {
4343
super(devicePath, vendorId, productId);
4444
asyncTask = WindowsAsyncTask.instance();
@@ -199,60 +199,42 @@ public synchronized void releaseInterface(int interfaceNumber) {
199199
setClaimed(interfaceNumber, false);
200200
}
201201

202-
private MemorySegment createSetupPacket(USBDirection direction, USBControlTransfer setup, MemorySegment data,
203-
Arena arena) {
204-
var setupPacket = new SetupPacket(arena);
205-
var bmRequest =
206-
(direction == USBDirection.IN ? 0x80 : 0) | (setup.requestType().ordinal() << 5) | setup.recipient().ordinal();
207-
setupPacket.setRequestType(bmRequest);
208-
setupPacket.setRequest(setup.request());
209-
setupPacket.setValue(setup.value());
210-
setupPacket.setIndex(setup.index());
211-
setupPacket.setLength(data != null ? (int) data.byteSize() : 0);
212-
return setupPacket.segment();
213-
}
214-
215202
@Override
216-
public byte[] controlTransferIn(USBControlTransfer setup, int length) {
217-
checkIsOpen();
218-
var intfHandle = findControlTransferInterface(setup);
219-
203+
public void controlTransferOut(USBControlTransfer setup, byte[] data) {
220204
try (var arena = Arena.openConfined()) {
221-
var buffer = arena.allocate(length);
222-
var setupPacket = createSetupPacket(USBDirection.IN, setup, buffer, arena);
223-
var lengthHolder = arena.allocate(JAVA_INT);
224-
var lastErrorState = arena.allocate(Win.LAST_ERROR_STATE.layout());
225205

226-
if (WinUSB2.WinUsb_ControlTransfer(intfHandle.interfaceHandle, setupPacket, buffer,
227-
(int) buffer.byteSize(), lengthHolder, NULL, lastErrorState) == 0)
228-
throwLastError(lastErrorState, "Control transfer IN failed");
206+
// copy data to native memory
207+
var transfer = createSyncControlTransfer();
208+
int dataLength = data != null ? data.length : 0;
209+
transfer.dataSize = dataLength;
210+
if (dataLength != 0) {
211+
var buffer = arena.allocate(data.length);
212+
buffer.copyFrom(MemorySegment.ofArray(data));
213+
transfer.data = buffer;
214+
} else {
215+
transfer.data = NULL;
216+
}
229217

230-
int rxLength = lengthHolder.get(JAVA_INT, 0);
231-
return buffer.asSlice(0, rxLength).toArray(JAVA_BYTE);
218+
synchronized (transfer) {
219+
submitControlTransfer(USBDirection.OUT, setup, transfer);
220+
waitForTransfer(transfer, 0, USBDirection.OUT, 0);
221+
}
232222
}
233223
}
234224

235225
@Override
236-
public void controlTransferOut(USBControlTransfer setup, byte[] data) {
237-
checkIsOpen();
238-
var intfHandle = findControlTransferInterface(setup);
239-
226+
public byte[] controlTransferIn(USBControlTransfer setup, int length) {
240227
try (var arena = Arena.openConfined()) {
228+
var transfer = createSyncControlTransfer();
229+
transfer.data = arena.allocate(length);
230+
transfer.dataSize = length;
241231

242-
// copy data to native memory
243-
int dataLength = data != null ? data.length : 0;
244-
MemorySegment buffer = arena.allocate(dataLength);
245-
if (dataLength != 0)
246-
buffer.copyFrom(MemorySegment.ofArray(data));
247-
248-
// create setup packet
249-
var setupPacket = createSetupPacket(USBDirection.OUT, setup, buffer, arena);
250-
var lengthHolder = arena.allocate(JAVA_INT);
251-
var lastErrorState = arena.allocate(Win.LAST_ERROR_STATE.layout());
232+
synchronized (transfer) {
233+
submitControlTransfer(USBDirection.IN, setup, transfer);
234+
waitForTransfer(transfer, 0, USBDirection.IN, 0);
235+
}
252236

253-
if (WinUSB2.WinUsb_ControlTransfer(intfHandle.interfaceHandle, setupPacket, buffer,
254-
(int) buffer.byteSize(), lengthHolder, NULL, lastErrorState) == 0)
255-
throwLastError(lastErrorState, "Control transfer OUT failed");
237+
return transfer.data.asSlice(0, transfer.resultSize).toArray(JAVA_BYTE);
256238
}
257239
}
258240

@@ -287,6 +269,12 @@ public byte[] transferIn(int endpointNumber, int timeout) {
287269
}
288270
}
289271

272+
private WindowsTransfer createSyncControlTransfer() {
273+
var transfer = new WindowsTransfer();
274+
transfer.completion = USBDeviceImpl::onSyncTransferCompleted;
275+
return transfer;
276+
}
277+
290278
private WindowsTransfer createSyncTransfer(MemorySegment data) {
291279
var transfer = new WindowsTransfer();
292280
transfer.data = data;
@@ -305,6 +293,33 @@ protected void throwOSException(int errorCode, String message, Object... args) {
305293
throwException(errorCode, message, args);
306294
}
307295

296+
synchronized void submitControlTransfer(USBDirection direction, USBControlTransfer setup, WindowsTransfer transfer) {
297+
checkIsOpen();
298+
var intfHandle = findControlTransferInterface(setup);
299+
300+
try (var arena = Arena.openConfined()) {
301+
var setupPacket = new SetupPacket(arena);
302+
var bmRequest =
303+
(direction == USBDirection.IN ? 0x80 : 0) | (setup.requestType().ordinal() << 5) | setup.recipient().ordinal();
304+
setupPacket.setRequestType(bmRequest);
305+
setupPacket.setRequest(setup.request());
306+
setupPacket.setValue(setup.value());
307+
setupPacket.setIndex(setup.index());
308+
setupPacket.setLength(transfer.dataSize);
309+
310+
var lastErrorState = arena.allocate(Win.LAST_ERROR_STATE.layout());
311+
asyncTask.prepareForSubmission(transfer);
312+
313+
// submit transfer
314+
if (WinUSB2.WinUsb_ControlTransfer(intfHandle.interfaceHandle, setupPacket.segment(), transfer.data,
315+
transfer.dataSize, NULL, transfer.overlapped, lastErrorState) == 0) {
316+
int err = Win.getLastError(lastErrorState);
317+
if (err != Kernel32.ERROR_IO_PENDING())
318+
throwException(err, "Submitting control transfer failed");
319+
}
320+
}
321+
}
322+
308323
synchronized void submitTransferOut(int endpointNumber, WindowsTransfer transfer) {
309324
var endpoint = getEndpoint(USBDirection.OUT, endpointNumber, USBTransferType.BULK, USBTransferType.INTERRUPT);
310325
var intfHandle = getInterfaceHandle(endpoint.interfaceNumber());

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -326,7 +326,7 @@ private USBDevice createDevice(String devicePath, Map<Integer, String> children,
326326

327327
var configDesc = getDescriptor(hubHandle, usbPortNum, CONFIGURATION_DESCRIPTOR_TYPE, 0, (short) 0, arena);
328328

329-
var device = new WindowsUSBDevice(this, devicePath, children, vendorId, productId, configDesc);
329+
var device = new WindowsUSBDevice(devicePath, children, vendorId, productId, configDesc);
330330
device.setFromDeviceDescriptor(descriptorSegment);
331331
device.setProductString(descriptorSegment, (index) -> getStringDescriptor(hubHandle, usbPortNum, index));
332332

0 commit comments

Comments
 (0)